TensorFlow构建模型(图片数据加载)六

概要

本文内容来源于TensorFlow教程
本文主要介绍了三种图片数据的加载和预处理方法:

  1. 使用高级的Keras预处理工具(如tf.keras.utils.image_dataset_from_directory)和预处理层(如tf.keras.layers.Rescaling)从磁盘的图片目录中加载数据。
  2. 使用tf.data的框架写你自己的输入通道。
  3. TensorFlow Datasets中从可用的类别加载数据集。
内容
import numpy as np
import os
import PIL
import PIL.Image
import tensorflow as tf
import tensorflow_datasets as tfds
import pathlib

# 下载花的数据集
dataset_url = "https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz"
data_dir = tf.keras.utils.get_file(origin=dataset_url,
                                   fname='flower_photos',
                                   untar=True)
data_dir = pathlib.Path(data_dir)
os.listdir(data_dir)  # ['LICENSE.txt', 'tulips', 'roses', 'dandelion', 'daisy', 'sunflowers']
image_count = len(list(data_dir.glob('*/*.jpg')))
print(image_count)  # 3670

数据集的目录格式:

flowers_photos/
          daisy/
          dandelion/
          roses/
          sunflowers/
          tulips/

# 画图展示
roses = list(data_dir.glob('roses/*'))
PIL.Image.open(str(roses[0]))

在这里插入图片描述
使用tf.keras.utils.image_dataset_from_directory将图片数据集加载存入内存

batch_size = 32
img_height = 180
img_width = 180

train_ds = tf.keras.utils.image_dataset_from_directory(
  data_dir,
  validation_split=0.2,
  subset="training",
  seed=123,
  image_size=(img_height, img_width),
  batch_size=batch_size)

val_ds = tf.keras.utils.image_dataset_from_directory(
  data_dir,
  validation_split=0.2,
  subset="validation",
  seed=123,
  image_size=(img_height, img_width),
  batch_size=batch_size)

# 可视化图片
import matplotlib.pyplot as plt

plt.figure(figsize=(10, 10))
for images, labels in train_ds.take(1):
  for i in range(9):
    ax = plt.subplot(3, 3, i + 1)
    plt.imshow(images[i].numpy().astype("uint8"))
    plt.title(class_names[labels[i]])
    plt.axis("off")


# 查看训练集中数据的shape
for image_batch, labels_batch in train_ds:
  print(image_batch.shape)   # (32, 180, 180, 3)  32是batch size的大小,180 * 180是图片的维度,3是图片的通道数RGB格式
  print(labels_batch.shape)  # (32,)  batch_size=32
  break

# RGB通道图像的像素值在[0,255],为了更好的模型训练,进行放缩到[0,1]。
normalization_layer = tf.keras.layers.Rescaling(1./255)

# 也可以将其放缩到[-1,1]
# normalization_layer = tf.keras.layers.Rescaling(1./127.5, offset=-1)

normalized_ds = train_ds.map(lambda x, y: (normalization_layer(x), y))
image_batch, labels_batch = next(iter(normalized_ds))
first_image = image_batch[0]
# Notice the pixel values are now in `[0,1]`.
print(np.min(first_image), np.max(first_image))

这里注意,我们在使用tf.keras.utils.image_dataset_from_directory加载数据的时候使用image_size参数重新定义了图片的大小。这个步骤也可以定义在模型中,通过使用tf.keras.layers.Resizing
大数据集的情况数据加载有可能会成为模型训练的瓶颈,可以通过以下两种方法使用缓存的方式加载数据:

  1. Dataset.cache,数据集从磁盘上加载放入内存中,如果数据集太大内存放不下,则可以使用此方法创建一个性能磁盘缓存。
  2. Dataset.prefetch,训练时重叠数据预处理和模型执行。
AUTOTUNE = tf.data.AUTOTUNE

train_ds = train_ds.cache().prefetch(buffer_size=AUTOTUNE)
val_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE)

以上是使用tf.keras.utils.image_dataset_from_directory加载数据的方法,下面使用tf.data更好的控制数据输入,通过使用tf.data编写自己的数据输入通道。

list_ds = tf.data.Dataset.list_files(str(data_dir/'*/*'), shuffle=False)
list_ds = list_ds.shuffle(image_count, reshuffle_each_iteration=False)

for f in list_ds.take(5):
  print(f.numpy())

# 使用文件的树结构生成类别组数
class_names = np.array(sorted([item.name for item in data_dir.glob('*') if item.name != "LICENSE.txt"]))
print(class_names)
# 划分训练集和验证集
val_size = int(image_count * 0.2)
train_ds = list_ds.skip(val_size)
val_ds = list_ds.take(val_size)

print(tf.data.experimental.cardinality(train_ds).numpy())
print(tf.data.experimental.cardinality(val_ds).numpy())

# 转换文件路径成(img, label)对
def get_label(file_path):
  # Convert the path to a list of path components
  parts = tf.strings.split(file_path, os.path.sep)
  # The second to last is the class-directory
  one_hot = parts[-2] == class_names
  # Integer encode the label
  return tf.argmax(one_hot)

def decode_img(img):
  # Convert the compressed string to a 3D uint8 tensor
  img = tf.io.decode_jpeg(img, channels=3)
  # Resize the image to the desired size
  return tf.image.resize(img, [img_height, img_width])

def process_path(file_path):
  label = get_label(file_path)
  # Load the raw data from the file as a string
  img = tf.io.read_file(file_path)
  img = decode_img(img)
  return img, label

# 使用`Dataset.map`创建一个image,label对数据集
# Set `num_parallel_calls` so multiple images are loaded/processed in parallel.
train_ds = train_ds.map(process_path, num_parallel_calls=AUTOTUNE)
val_ds = val_ds.map(process_path, num_parallel_calls=AUTOTUNE)

for image, label in train_ds.take(1):
  print("Image shape: ", image.numpy().shape)
  print("Label: ", label.numpy())

为了性能配置数据集。

def configure_for_performance(ds):
  ds = ds.cache()  # 缓存
  ds = ds.shuffle(buffer_size=1000)  # 打乱数据
  ds = ds.batch(batch_size) # 批处理
  ds = ds.prefetch(buffer_size=AUTOTUNE) # 保证批量数据尽快可用
  return ds

train_ds = configure_for_performance(train_ds)
val_ds = configure_for_performance(val_ds)

# 可视化数据
image_batch, label_batch = next(iter(train_ds))

plt.figure(figsize=(10, 10))
for i in range(9):
  ax = plt.subplot(3, 3, i + 1)
  plt.imshow(image_batch[i].numpy().astype("uint8"))
  label = label_batch[i]
  plt.title(class_names[label])
  plt.axis("off")

使用TensorFlow数据集

(train_ds, val_ds, test_ds), metadata = tfds.load(
    'tf_flowers',
    split=['train[:80%]', 'train[80%:90%]', 'train[90%:]'],
    with_info=True,
    as_supervised=True,
)

num_classes = metadata.features['label'].num_classes
print(num_classes)

get_label_name = metadata.features['label'].int2str

image, label = next(iter(train_ds))
_ = plt.imshow(image)
_ = plt.title(get_label_name(label))

train_ds = configure_for_performance(train_ds)
val_ds = configure_for_performance(val_ds)
test_ds = configure_for_performance(test_ds)

为了完整性,我们构建了一个卷积网络训练模型。三个带最大池化的卷积层,一个全连接层

num_classes = 5

model = tf.keras.Sequential([
  tf.keras.layers.Rescaling(1./255),
  tf.keras.layers.Conv2D(32, 3, activation='relu'),
  tf.keras.layers.MaxPooling2D(),
  tf.keras.layers.Conv2D(32, 3, activation='relu'),
  tf.keras.layers.MaxPooling2D(),
  tf.keras.layers.Conv2D(32, 3, activation='relu'),
  tf.keras.layers.MaxPooling2D(),
  tf.keras.layers.Flatten(),
  tf.keras.layers.Dense(128, activation='relu'),
  tf.keras.layers.Dense(num_classes)
])

model.compile(
  optimizer='adam',
  loss=tf.losses.SparseCategoricalCrossentropy(from_logits=True),
  metrics=['accuracy'])

model.fit(
  train_ds,
  validation_data=val_ds,
  epochs=3
)

我们也可以自己写一个训练循环器替代model.fit,详情参考:从头编写训练循环

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值