如何在Keras中正确使用ImageDataGenerator?

3

最近我在使用 Keras 进行数据增强,并使用基本的 ImageDataGenerator。我通过困难的方式学习到它实际上是一个生成器,而不是迭代器(因为 type(train_aug_ds) 返回 <class 'keras.preprocessing.image.DirectoryIterator'> 我以为它是一个迭代器)。我也查阅了几篇关于如何使用它的博客,但并不能回答我所有的问题。

所以,我像这样加载了我的数据:

train_aug = ImageDataGenerator(
    rescale=1./255,
    horizontal_flip=True,
    height_shift_range=0.1,
    width_shift_range=0.1,
    brightness_range=(0.5,1.5),
    zoom_range = [1, 1.5],
)
train_aug_ds = train_aug.flow_from_directory(
    directory='./train',
    target_size=image_size,
    batch_size=batch_size,
)

为了训练我的模型,我采取了以下步骤:

model.fit(
    train_aug_ds,
    epochs=150,
    validation_data=(valid_aug_ds,),
)

它能够正常工作,但让我有些困惑。因为train_aug_ds是一个生成器,所以它应该提供无限大的数据集。文档中表示:

当传入重复无限的数据集时,必须指定steps_per_epoch参数。

但我没有这样做,却仍然能运行。它是否会推断出步骤数量?此外,在批处理中它只使用了增强后的数据,还是也包括未增强的图像?因此,我的问题是如何正确地使用这个生成器和fit函数,以便在训练集中有所有的数据,包括原始的、未增强的图像和增强后的图像,并且可以循环多次/多个步骤(目前似乎每个epoch只有一个步骤)?

答案很好,非常感谢。很抱歉,我有几天没上线了。我已经接受它作为答案。 - dosvarog
1个回答

4

我认为文档可能会让人感到困惑,而且我想不同版本的Tensorflow和Keras的行为可能是不同的。例如,在这个帖子中,用户描述了你期望的确切行为。通常,flow_from_directory()方法允许您直接从目录中读取图像,并在模型正在训练时对其进行增强。正如已经在这里所述,每个时期它都会迭代每个文件夹中的每个样本。通过使用以下示例,您可以检查这一点(在TF 2.7上),只需查看进度条中的每个时期的步骤:

import tensorflow as tf

BATCH_SIZE = 64

flowers = tf.keras.utils.get_file(
    'flower_photos',
    'https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz',
    untar=True)

img_gen = tf.keras.preprocessing.image.ImageDataGenerator(
    rescale=1./255,
    horizontal_flip=True,
)

train_ds = img_gen.flow_from_directory(flowers, batch_size=BATCH_SIZE, shuffle=True, class_mode='sparse')
num_classes = 5

model = tf.keras.Sequential([
  tf.keras.layers.Conv2D(16, 3, padding='same', activation='relu', input_shape=(256, 256, 3)),
  tf.keras.layers.MaxPooling2D(),
  tf.keras.layers.Conv2D(32, 3, padding='same', activation='relu'),
  tf.keras.layers.MaxPooling2D(),
  tf.keras.layers.Conv2D(64, 3, padding='same', 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.keras.losses.SparseCategoricalCrossentropy(from_logits=True))

epochs=10
history = model.fit(
  train_ds,
  epochs=epochs
)

Found 3670 images belonging to 5 classes.
Epoch 1/10
 6/58 [==>...........................] - ETA: 3:02 - loss: 2.0608

如果您将flow_from_directory包装在tf.data.Dataset.from_generator中,就像这样:
train_ds = tf.data.Dataset.from_generator(
    lambda: img_gen.flow_from_directory(flowers, batch_size=BATCH_SIZE, shuffle=True, class_mode='sparse'),
    output_types=(tf.float32, tf.float32))

您会注意到进度条看起来像这样,因为steps_per_epoch没有被明确定义:
Epoch 1/10
Found 3670 images belonging to 5 classes.
     29/Unknown - 104s 4s/step - loss: 2.0364

如果您添加了此参数,您将在进度条中看到步骤:

history = model.fit(
  train_ds,
  steps_per_epoch = len(from_directory),
  epochs=epochs
)

Found 3670 images belonging to 5 classes.
Epoch 1/10
 3/58 [>.............................] - ETA: 3:19 - loss: 4.1357

最后回答你的问题:

如何正确使用此生成器与适合所有数据的函数,包括原始的非增强图像和增强图像,并循环多次/步骤?

您可以通过乘以某个因子来简单地增加steps_per_epoch超过样本数//批量大小

history = model.fit(
  train_ds,
  steps_per_epoch = len(from_directory)*2,
  epochs=epochs
)

Found 3670 images belonging to 5 classes.
Epoch 1/10
  1/116 [..............................] - ETA: 12:11 - loss: 1.5885

现在每个时期的步骤数从58增加到了116。


1
它在每个时期中迭代每个文件夹中的每个样本。这非常有帮助。TensorFlow的文档对生成器返回的内容非常模糊。 - Vincent Yuan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接