Как правильно использовать ImageDataGenerator в Keras?

0

Вопрос

В последнее время я играю с увеличением данных в 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 иметь все данные в моем обучающем наборе, включая оригинальные, не дополненные изображения и дополненные изображения, и просматривать их несколько раз/шагов (сейчас кажется, что он делает только один шаг за эпоху)?

keras python tensorflow
2021-11-23 11:26:56
1

Лучший ответ

1

Я думаю, что документация может быть довольно запутанной, и я полагаю, что поведение отличается в зависимости от вашей версии 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 за number of samples // batch_size путем умножения на некоторый коэффициент:

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.

2021-11-23 17:22:32

На других языках

Эта страница на других языках

Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................