Как разделить папки на 3 набора данных с помощью ImageDataGenerator?

Параметр validation_split может позволить ImageDataGenerator разделить наборы данных, считываемые из папки, на 2 разных непересекающихся набора. Есть ли способ создать 3 набора - наборов данных для обучения, проверки и оценки, используя его?

Я думаю о разделении набора данных на 2 набора данных, а затем о разделении второго набора данных на еще 2 набора данных.

      datagen = ImageDataGenerator(validation_split=0.5, rescale=1./255)

train_generator = datagen.flow_from_directory(
    TRAIN_DIR, 
    subset='training'
)

val_generator = datagen.flow_from_directory(
    TRAIN_DIR,
    subset='validation'
)

Здесь я думаю о разделении набора данных проверки на 2 набора с помощью val_generator. Один для проверки, а другой для оценки? Как я должен это делать?

2 ответа

мне нравится работать с flow_from_dataframe()метод ImageDataGenerator, где я взаимодействую с простым Pandas DataFrame (возможно, содержащим другие функции), а не с каталогом. Но вы можете легко изменить мой код, если настаиваете на flow_from_directory().

Так что это моя основная функция, например, для задачи регрессии, где мы пытаемся предсказать непрерывный :

      def get_generators(train_samp, test_samp, validation_split = 0.1):
    train_datagen = ImageDataGenerator(validation_split=validation_split, rescale = 1. / 255)
    test_datagen = ImageDataGenerator(rescale = 1. / 255)
    
    train_generator = train_datagen.flow_from_dataframe(
        dataframe = images_df[images_df.index.isin(train_samp)],
        directory = images_dir,
        x_col = 'img_file',
        y_col = 'y',
        target_size = (IMG_HEIGHT, IMG_WIDTH),
        class_mode = 'raw',
        batch_size = batch_size,
        shuffle = True,
        subset = 'training',
        validate_filenames = False
    )
    valid_generator = train_datagen.flow_from_dataframe(
        dataframe = images_df[images_df.index.isin(train_samp)],
        directory = images_dir,
        x_col = 'img_file',
        y_col = 'y',
        target_size = (IMG_HEIGHT, IMG_WIDTH),
        class_mode = 'raw',
        batch_size = batch_size,
        shuffle = False,
        subset = 'validation',
        validate_filenames = False
    )

    test_generator = test_datagen.flow_from_dataframe(
        dataframe = images_df[images_df.index.isin(test_samp)],
        directory = images_dir,
        x_col = 'img_file',
        y_col = 'y',
        target_size = (IMG_HEIGHT, IMG_WIDTH),
        class_mode = 'raw',
        batch_size = batch_size,
        shuffle = False,
        validate_filenames = False
    )
    return train_generator, valid_generator, test_generator

На что следует обратить внимание:

  • Я использую два генератора
  • Входными данными для функции являются индексы поезда/теста (например, полученные от Sklearn's train_test_split), которые используются для фильтрации индекса DataFrame.
  • Функция также принимает validation_splitпараметр для обучающего генератора
  • images_dfэто DataFrame где-то в глобальной памяти с соответствующими столбцами, такими как img_fileа также y.
  • Не нужно shuffleгенераторы проверки и тестирования

Это может быть дополнительно обобщено для нескольких выходов, классификации, что у вас есть.

В основном я разбивал данные на 80/10/10 для обучения, проверки и тестирования соответственно.

При работе с keras я предпочитаюtf.dataAPI , поскольку он обеспечивает хорошую абстракцию для сложных входных конвейеров.

Он не обеспечивает простой tf.data.DataSet.splitхотя функциональность

У меня есть эта функция (которую я нашел в чьем-то коде, а мой источник отсутствует), которую я постоянно использую

      def get_dataset_partitions_tf(ds: tf.data.Dataset, ds_size, train_split=0.8, val_split=0.1, test_split=0.1, shuffle=True, shuffle_size=10000):
    assert (train_split + test_split + val_split) == 1

    if shuffle:
    # Specify seed to always have the same split distribution between runs
        ds = ds.shuffle(shuffle_size, seed=12)

    train_size = int(train_split * ds_size)
    val_size = int(val_split * ds_size)

    train_ds = ds.take(train_size)    
    val_ds = ds.skip(train_size).take(val_size)
    test_ds = ds.skip(train_size).skip(val_size)

    return train_ds, val_ds, test_ds

Сначала прочитайте свой набор данных и получите его размер (с помощью метода Cardianlity ), затем передайте его в функцию, и все готово!

Этой функции можно задать флаг для перемешивания исходного набора данных перед созданием разбиений, это полезно для более реалистичных показателей проверки и тестирования.

Семя для перетасовки фиксировано, поэтому мы можем запускать одну и ту же функцию, а разбиения остаются прежними, что нам нужно для согласованных результатов.

Другие вопросы по тегам