【问题标题】:Keras split train test set when using ImageDataGenerator使用 ImageDataGenerator 时 Keras 拆分训练测试集
【发布时间】:2017-07-15 14:21:21
【问题描述】:

我有一个目录,其中包含图像的子文件夹(根据标签)。我想在 Keras 中使用 ImageDataGenerator 时将这些数据拆分为训练集和测试集。尽管 keras 中的 model.fit() 具有用于指定拆分的参数 validation_split,但我无法为 model.fit_generator() 找到相同的参数。怎么办?

train_datagen = ImageDataGenerator(rescale=1./255,
    shear_range=0.2,
    zoom_range=0.2,
    horizontal_flip=True)

train_generator = train_datagen.flow_from_directory(
    train_data_dir,
    target_size=(img_width, img_height),
    batch_size=32,
    class_mode='binary')

model.fit_generator(
    train_generator,
    samples_per_epoch=nb_train_samples,
    nb_epoch=nb_epoch,
    validation_data=??,
    nb_val_samples=nb_validation_samples)

我没有单独的验证数据目录,需要从训练数据中拆分出来

【问题讨论】:

  • 我相信您将不得不重新组织您的目录。例如,将您的数据放在 classes_directories 内的 sub_subdirectories "train" 和 "test" 中。
  • 这就是问题所在,我不想创建单独的目录。 keras 有没有办法在运行时处理/拆分它,就像它使用 fit() 函数一样
  • 我不知道。 Keras 无法处理存储数据集的所有可能方式。你必须适应它。函数式编程是输入 -> 黑盒 -> 输出。而且黑匣子的界面不可能100%灵活。为什么不能创建单独的目录?
  • 我有一个包含数千张图片的目录。要么我必须为此编写代码,要么手动完成。代码还需要处理来自每个类的正确分发..
  • 是的,这是可能的——但确实很麻烦。我做过一次——如果你愿意,我可以向你展示这个想法。

标签: keras train-test-split


【解决方案1】:

Keras 现在添加了使用 ImageDataGenerator 从单个目录拆分训练/验证:

train_datagen = ImageDataGenerator(rescale=1./255,
    shear_range=0.2,
    zoom_range=0.2,
    horizontal_flip=True,
    validation_split=0.2) # set validation split

train_generator = train_datagen.flow_from_directory(
    train_data_dir,
    target_size=(img_height, img_width),
    batch_size=batch_size,
    class_mode='binary',
    subset='training') # set as training data

validation_generator = train_datagen.flow_from_directory(
    train_data_dir, # same directory as training data
    target_size=(img_height, img_width),
    batch_size=batch_size,
    class_mode='binary',
    subset='validation') # set as validation data

model.fit_generator(
    train_generator,
    steps_per_epoch = train_generator.samples // batch_size,
    validation_data = validation_generator, 
    validation_steps = validation_generator.samples // batch_size,
    epochs = nb_epochs)

https://keras.io/preprocessing/image/

【讨论】:

  • validation_generator 是否也增加数据?从github.com/keras-team/keras/issues/5862 阅读 cmets 后,似乎确实如此。
  • 如何删除validation_generator的图像增强?
  • 创建两个 ImageDataGenerator 实例,一个用于训练,一个用于验证。对两者使用相同的种子。
  • 有没有办法同时生成第三个测试子集?我检查了文档,没有任何诸如testing_split
  • 我放弃与validation_split打交道。首先,如果我检查验证批次的形状,例如tf.shape(next(validation_generator)),它返回的批量大小为 0。此外,正如 @ArchitKithania 所提到的,无法定义 testing_split。我厌倦了浪费时间。我将通过定义 3 个不同的数据帧(我使用 flow_from_dataframe)手动拆分所有 3 个(训练、测试、有效)。
【解决方案2】:

例如,你有这样的文件夹

full_dataset
|--horse (40 images)
|--donkey (30 images)
|--cow ((50 images)
|--zebra (70 images)

第一路

image_generator = ImageDataGenerator(rescale=1/255, validation_split=0.2)    

train_dataset = image_generator.flow_from_directory(batch_size=32,
                                                 directory='full_dataset',
                                                 shuffle=True,
                                                 target_size=(280, 280), 
                                                 subset="training",
                                                 class_mode='categorical')

validation_dataset = image_generator.flow_from_directory(batch_size=32,
                                                 directory='full_dataset',
                                                 shuffle=True,
                                                 target_size=(280, 280), 
                                                 subset="validation",
                                                 class_mode='categorical')

第二种方式

import glob
horse = glob.glob('full_dataset/horse/*.*')
donkey = glob.glob('full_dataset/donkey/*.*')
cow = glob.glob('full_dataset/cow/*.*')
zebra = glob.glob('full_dataset/zebra/*.*')

data = []
labels = []

for i in horse:   
    image=tf.keras.preprocessing.image.load_img(i, color_mode='RGB', 
    target_size= (280,280))
    image=np.array(image)
    data.append(image)
    labels.append(0)
for i in donkey:   
    image=tf.keras.preprocessing.image.load_img(i, color_mode='RGB', 
    target_size= (280,280))
    image=np.array(image)
    data.append(image)
    labels.append(1)
for i in cow:   
    image=tf.keras.preprocessing.image.load_img(i, color_mode='RGB', 
    target_size= (280,280))
    image=np.array(image)
    data.append(image)
    labels.append(2)
for i in zebra:   
    image=tf.keras.preprocessing.image.load_img(i, color_mode='RGB', 
    target_size= (280,280))
    image=np.array(image)
    data.append(image)
    labels.append(3)

data = np.array(data)
labels = np.array(labels)

from sklearn.model_selection import train_test_split
X_train, X_test, ytrain, ytest = train_test_split(data, labels, test_size=0.2,
                                                random_state=42)

第一种方式的主要缺点,您不能用于显示图片。写validation_dataset[1]会出错。但如果我使用第一种方法,它会起作用:X_test[1]

【讨论】:

  • 但是在您的第一种方式中,是什么阻止了模型混合验证集和训练集数据? Keras 是否会跟踪每个文件使用了哪些单独的文件?
  • 是的,我认为,Keras 将跟踪基于 0.2*full 数据集的验证数据集(如果我设置“validation_split=0.2”)。然后,它将存储在“validation_dataset”中。
【解决方案3】:

如果我们在 ImageDataGenerator 中使用subset,那么相同的增强将应用于训练和验证。如果您只想在训练集上应用扩充,您可以使用split-folders 包拆分文件夹,该包可以使用pip 直接安装。

https://pypi.org/project/split-folders/

这会将数据集分成 train、val 和 test 目录,然后您可以为每个目录创建单独的生成器。

【讨论】:

    【解决方案4】:

    我有一个PR。一种方法是散列文件名并进行变体分配。

    例子:

    # -*- coding: utf-8 -*-
    """Train model using transfer learning."""
    import os
    import re
    import glob
    import hashlib
    import argparse
    import warnings
    
    import six
    import numpy as np
    import tensorflow as tf
    from tensorflow.python.platform import gfile
    from keras.models import Model
    from keras import backend as K
    from keras.optimizers import SGD
    from keras.layers import Dense, GlobalAveragePooling2D, Input
    from keras.applications.inception_v3 import InceptionV3
    from keras.preprocessing.image import (ImageDataGenerator, Iterator,
                                           array_to_img, img_to_array, load_img)
    from keras.callbacks import ModelCheckpoint, TensorBoard, EarlyStopping
    
    RANDOM_SEED = 0
    MAX_NUM_IMAGES_PER_CLASS = 2 ** 27 - 1  # ~134M
    VALID_IMAGE_FORMATS = frozenset(['jpg', 'jpeg', 'JPG', 'JPEG'])
    # we chose to train the top 2 inception blocks
    BATCH_SIZE = 100
    TRAINABLE_LAYERS = 172
    INCEPTIONV3_BASE_LAYERS = len(InceptionV3(weights=None, include_top=False).layers)
    
    STEPS_PER_EPOCH = 625
    VALIDATION_STEPS = 100
    MODEL_INPUT_WIDTH = 299
    MODEL_INPUT_HEIGHT = 299
    MODEL_INPUT_DEPTH = 3
    FC_LAYER_SIZE = 1024
    
    # Helper: Save the model.
    checkpointer = ModelCheckpoint(
        filepath='./output/checkpoints/inception.{epoch:03d}-{val_loss:.2f}.hdf5',
        verbose=1,
        save_best_only=True)
    
    # Helper: Stop when we stop learning.
    early_stopper = EarlyStopping(patience=10)
    
    # Helper: TensorBoard
    tensorboard = TensorBoard(log_dir='./output/')
    
    
    def as_bytes(bytes_or_text, encoding='utf-8'):
        """Converts bytes or unicode to `bytes`, using utf-8 encoding for text.
    
        # Arguments
            bytes_or_text: A `bytes`, `str`, or `unicode` object.
            encoding: A string indicating the charset for encoding unicode.
    
        # Returns
            A `bytes` object.
    
        # Raises
            TypeError: If `bytes_or_text` is not a binary or unicode string.
        """
        if isinstance(bytes_or_text, six.text_type):
            return bytes_or_text.encode(encoding)
        elif isinstance(bytes_or_text, bytes):
            return bytes_or_text
        else:
            raise TypeError('Expected binary or unicode string, got %r' %
                            (bytes_or_text,))
    
    
    class CustomImageDataGenerator(ImageDataGenerator):
        def flow_from_image_lists(self, image_lists,
                                  category, image_dir,
                                  target_size=(256, 256), color_mode='rgb',
                                  class_mode='categorical',
                                  batch_size=32, shuffle=True, seed=None,
                                  save_to_dir=None,
                                  save_prefix='',
                                  save_format='jpeg'):
            return ImageListIterator(
                image_lists, self,
                category, image_dir,
                target_size=target_size, color_mode=color_mode,
                class_mode=class_mode,
                data_format=self.data_format,
                batch_size=batch_size, shuffle=shuffle, seed=seed,
                save_to_dir=save_to_dir,
                save_prefix=save_prefix,
                save_format=save_format)
    
    
    class ImageListIterator(Iterator):
        """Iterator capable of reading images from a directory on disk.
    
        # Arguments
            image_lists: Dictionary of training images for each label.
            image_data_generator: Instance of `ImageDataGenerator`
                to use for random transformations and normalization.
            target_size: tuple of integers, dimensions to resize input images to.
            color_mode: One of `"rgb"`, `"grayscale"`. Color mode to read images.
            classes: Optional list of strings, names of sudirectories
                containing images from each class (e.g. `["dogs", "cats"]`).
                It will be computed automatically if not set.
            class_mode: Mode for yielding the targets:
                `"binary"`: binary targets (if there are only two classes),
                `"categorical"`: categorical targets,
                `"sparse"`: integer targets,
                `None`: no targets get yielded (only input images are yielded).
            batch_size: Integer, size of a batch.
            shuffle: Boolean, whether to shuffle the data between epochs.
            seed: Random seed for data shuffling.
            data_format: String, one of `channels_first`, `channels_last`.
            save_to_dir: Optional directory where to save the pictures
                being yielded, in a viewable format. This is useful
                for visualizing the random transformations being
                applied, for debugging purposes.
            save_prefix: String prefix to use for saving sample
                images (if `save_to_dir` is set).
            save_format: Format to use for saving sample images
                (if `save_to_dir` is set).
        """
    
        def __init__(self, image_lists, image_data_generator,
                     category, image_dir,
                     target_size=(256, 256), color_mode='rgb',
                     class_mode='categorical',
                     batch_size=32, shuffle=True, seed=None,
                     data_format=None,
                     save_to_dir=None, save_prefix='', save_format='jpeg'):
            if data_format is None:
                data_format = K.image_data_format()
    
            classes = list(image_lists.keys())
            self.category = category
            self.num_class = len(classes)
            self.image_lists = image_lists
            self.image_dir = image_dir
    
            how_many_files = 0
            for label_name in classes:
                for _ in self.image_lists[label_name][category]:
                    how_many_files += 1
    
            self.samples = how_many_files
            self.class2id = dict(zip(classes, range(len(classes))))
            self.id2class = dict((v, k) for k, v in self.class2id.items())
            self.classes = np.zeros((self.samples,), dtype='int32')
    
            self.image_data_generator = image_data_generator
            self.target_size = tuple(target_size)
            if color_mode not in {'rgb', 'grayscale'}:
                raise ValueError('Invalid color mode:', color_mode,
                                 '; expected "rgb" or "grayscale".')
            self.color_mode = color_mode
            self.data_format = data_format
            if self.color_mode == 'rgb':
                if self.data_format == 'channels_last':
                    self.image_shape = self.target_size + (3,)
                else:
                    self.image_shape = (3,) + self.target_size
            else:
                if self.data_format == 'channels_last':
                    self.image_shape = self.target_size + (1,)
                else:
                    self.image_shape = (1,) + self.target_size
    
            if class_mode not in {'categorical', 'binary', 'sparse', None}:
                raise ValueError('Invalid class_mode:', class_mode,
                                 '; expected one of "categorical", '
                                 '"binary", "sparse", or None.')
            self.class_mode = class_mode
            self.save_to_dir = save_to_dir
            self.save_prefix = save_prefix
            self.save_format = save_format
    
            i = 0
            self.filenames = []
            for label_name in classes:
                for j, _ in enumerate(self.image_lists[label_name][category]):
                    self.classes[i] = self.class2id[label_name]
                    img_path = get_image_path(self.image_lists,
                                              label_name,
                                              j,
                                              self.image_dir,
                                              self.category)
                    self.filenames.append(img_path)
                    i += 1
    
            print("Found {} {} files".format(len(self.filenames), category))
            super(ImageListIterator, self).__init__(self.samples, batch_size, shuffle,
                                                    seed)
    
        def next(self):
            """For python 2.x.
    
            # Returns
                The next batch.
            """
            with self.lock:
                index_array, current_index, current_batch_size = next(
                    self.index_generator)
            # The transformation of images is not under thread lock
            # so it can be done in parallel
            batch_x = np.zeros((current_batch_size,) + self.image_shape,
                               dtype=K.floatx())
            grayscale = self.color_mode == 'grayscale'
            # build batch of image data
            for i, j in enumerate(index_array):
                img = load_img(self.filenames[j],
                               grayscale=grayscale,
                               target_size=self.target_size)
                x = img_to_array(img, data_format=self.data_format)
                x = self.image_data_generator.random_transform(x)
                x = self.image_data_generator.standardize(x)
                batch_x[i] = x
            # optionally save augmented images to disk for debugging purposes
            if self.save_to_dir:
                for i in range(current_batch_size):
                    img = array_to_img(batch_x[i], self.data_format, scale=True)
                    fname = '{prefix}_{index}_{hash}.{format}'.format(
                        prefix=self.save_prefix,
                        index=current_index + i,
                        hash=np.random.randint(10000),
                        format=self.save_format)
                    img.save(os.path.join(self.save_to_dir, fname))
            # build batch of labels
            if self.class_mode == 'sparse':
                batch_y = self.classes[index_array]
            elif self.class_mode == 'binary':
                batch_y = self.classes[index_array].astype(K.floatx())
            elif self.class_mode == 'categorical':
                batch_y = np.zeros((len(batch_x), self.num_class),
                                   dtype=K.floatx())
                for i, label in enumerate(self.classes[index_array]):
                    batch_y[i, label] = 1.
            else:
                return batch_x
            return batch_x, batch_y
    
    
    # https://github.com/tensorflow/tensorflow/blob/master/tensorflow/examples/image_retraining/retrain.py
    def create_image_lists(image_dir, validation_pct=10):
        """Builds a list of training images from the file system.
    
        Analyzes the sub folders in the image directory, splits them into stable
        training, testing, and validation sets, and returns a data structure
        describing the lists of images for each label and their paths.
    
        # Arguments
            image_dir: string path to a folder containing subfolders of images.
            validation_pct: integer percentage of images reserved for validation.
    
        # Returns
            dictionary of label subfolder, with images split into training
            and validation sets within each label.
        """
        if not os.path.isdir(image_dir):
            raise ValueError("Image directory {} not found.".format(image_dir))
        image_lists = {}
        sub_dirs = [x[0] for x in os.walk(image_dir)]
        sub_dirs_without_root = sub_dirs[1:]  # first element is root directory
        for sub_dir in sub_dirs_without_root:
            file_list = []
            dir_name = os.path.basename(sub_dir)
            if dir_name == image_dir:
                continue
            print("Looking for images in '{}'".format(dir_name))
            for extension in VALID_IMAGE_FORMATS:
                file_glob = os.path.join(image_dir, dir_name, '*.' + extension)
                file_list.extend(glob.glob(file_glob))
            if not file_list:
                warnings.warn('No files found')
                continue
            if len(file_list) < 20:
                warnings.warn('Folder has less than 20 images, which may cause '
                              'issues.')
            elif len(file_list) > MAX_NUM_IMAGES_PER_CLASS:
                warnings.warn('WARNING: Folder {} has more than {} images. Some '
                              'images will never be selected.'
                              .format(dir_name, MAX_NUM_IMAGES_PER_CLASS))
            label_name = re.sub(r'[^a-z0-9]+', ' ', dir_name.lower())
            training_images = []
            validation_images = []
            for file_name in file_list:
                base_name = os.path.basename(file_name)
                # Get the hash of the file name and perform variant assignment.
                hash_name = hashlib.sha1(as_bytes(base_name)).hexdigest()
                hash_pct = ((int(hash_name, 16) % (MAX_NUM_IMAGES_PER_CLASS + 1)) *
                            (100.0 / MAX_NUM_IMAGES_PER_CLASS))
                if hash_pct < validation_pct:
                    validation_images.append(base_name)
                else:
                    training_images.append(base_name)
            image_lists[label_name] = {
                'dir': dir_name,
                'training': training_images,
                'validation': validation_images,
            }
        return image_lists
    
    
    # https://github.com/tensorflow/tensorflow/blob/master/tensorflow/examples/image_retraining/retrain.py
    def get_image_path(image_lists, label_name, index, image_dir, category):
        """"Returns a path to an image for a label at the given index.
    
        # Arguments
          image_lists: Dictionary of training images for each label.
          label_name: Label string we want to get an image for.
          index: Int offset of the image we want. This will be moduloed by the
          available number of images for the label, so it can be arbitrarily large.
          image_dir: Root folder string of the subfolders containing the training
          images.
          category: Name string of set to pull images from - training, testing, or
          validation.
    
        # Returns
          File system path string to an image that meets the requested parameters.
        """
        if label_name not in image_lists:
            raise ValueError('Label does not exist ', label_name)
        label_lists = image_lists[label_name]
        if category not in label_lists:
            raise ValueError('Category does not exist ', category)
        category_list = label_lists[category]
        if not category_list:
            raise ValueError('Label %s has no images in the category %s.',
                             label_name, category)
        mod_index = index % len(category_list)
        base_name = category_list[mod_index]
        sub_dir = label_lists['dir']
        full_path = os.path.join(image_dir, sub_dir, base_name)
        return full_path
    
    
    def get_generators(image_lists, image_dir):
        train_datagen = CustomImageDataGenerator(rescale=1. / 255,
                                                 horizontal_flip=True)
    
        test_datagen = CustomImageDataGenerator(rescale=1. / 255)
    
        train_generator = train_datagen.flow_from_image_lists(
            image_lists=image_lists,
            category='training',
            image_dir=image_dir,
            target_size=(MODEL_INPUT_HEIGHT, MODEL_INPUT_WIDTH),
            batch_size=BATCH_SIZE,
            class_mode='categorical',
            seed=RANDOM_SEED)
    
        validation_generator = test_datagen.flow_from_image_lists(
            image_lists=image_lists,
            category='validation',
            image_dir=image_dir,
            target_size=(MODEL_INPUT_HEIGHT, MODEL_INPUT_WIDTH),
            batch_size=BATCH_SIZE,
            class_mode='categorical',
            seed=RANDOM_SEED)
    
        return train_generator, validation_generator
    
    
    def get_model(num_classes, weights='imagenet'):
        # create the base pre-trained model
        # , input_tensor=input_tensor
        base_model = InceptionV3(weights=weights, include_top=False)
    
        # add a global spatial average pooling layer
        x = base_model.output
        x = GlobalAveragePooling2D()(x)
        # let's add a fully-connected layer
        x = Dense(FC_LAYER_SIZE, activation='relu')(x)
        # and a logistic layer -- let's say we have 2 classes
        predictions = Dense(num_classes, activation='softmax')(x)
    
        # this is the model we will train
        model = Model(inputs=[base_model.input], outputs=[predictions])
        return model
    
    
    def get_top_layer_model(model):
        """Used to train just the top layers of the model."""
        # first: train only the top layers (which were randomly initialized)
        # i.e. freeze all convolutional InceptionV3 layers
        for layer in model.layers[:INCEPTIONV3_BASE_LAYERS]:
            layer.trainable = False
        for layer in model.layers[INCEPTIONV3_BASE_LAYERS:]:
            layer.trainable = True
    
        # compile the model (should be done after setting layers to non-trainable)
        model.compile(optimizer='rmsprop', loss='categorical_crossentropy',
                      metrics=['accuracy'])
    
        return model
    
    
    def get_mid_layer_model(model):
        """After we fine-tune the dense layers, train deeper."""
        # freeze the first TRAINABLE_LAYER_INDEX layers and unfreeze the rest
        for layer in model.layers[:TRAINABLE_LAYERS]:
            layer.trainable = False
        for layer in model.layers[TRAINABLE_LAYERS:]:
            layer.trainable = True
    
        # we need to recompile the model for these modifications to take effect
        # we use SGD with a low learning rate
        model.compile(optimizer=SGD(lr=0.0001, momentum=0.9),
                      loss='categorical_crossentropy',
                      metrics=['accuracy'])
    
        return model
    
    
    def train_model(model, epochs, generators, callbacks=None):
        train_generator, validation_generator = generators
        model.fit_generator(
            train_generator,
            steps_per_epoch=STEPS_PER_EPOCH,
            validation_data=validation_generator,
            validation_steps=VALIDATION_STEPS,
            epochs=epochs,
            callbacks=callbacks)
        return model
    
    
    def main(image_dir, validation_pct):
        sub_dirs = [x[0] for x in gfile.Walk(image_dir)]
        num_classes = len(sub_dirs) - 1
        print("Number of classes found: {}".format(num_classes))
    
        model = get_model(num_classes)
    
        print("Using validation percent of %{}".format(validation_pct))
        image_lists = create_image_lists(image_dir, validation_pct)
    
        generators = get_generators(image_lists, image_dir)
    
        # Get and train the top layers.
        model = get_top_layer_model(model)
        model = train_model(model, epochs=10, generators=generators)
    
        # Get and train the mid layers.
        model = get_mid_layer_model(model)
        _ = train_model(model, epochs=100, generators=generators,
                        callbacks=[checkpointer, early_stopper, tensorboard])
    
        # save model
        model.save('./output/model.hdf5', overwrite=True)
    
    
    if __name__ == '__main__':
        parser = argparse.ArgumentParser()
        parser.add_argument('--image-dir', required=True, help='data directory')
        parser.add_argument('--validation-pct', default=10, help='validation percentage')
        args = parser.parse_args()
    
        os.makedirs('./output/checkpoints/', exist_ok=True)
    
        main(**vars(args))
    

    【讨论】:

      【解决方案5】:

      参考这个问题https://github.com/keras-team/keras/issues/597,可以使用下面的代码将整个集合拆分成train和val:

      train_datagen = ImageDataGenerator(rescale=1./255,
                                         rotation_range=20,
                                         width_shift_range=0.2,
                                         height_shift_range=0.2,
                                         horizontal_flip=True
                                         validation_split=0.2)  # val 20%
      
      val_datagen = ImageDataGenerator(rescale=1./255, validation_split=0.2)
      
      
      train_data = train_datagen.flow_from_directory(train_path, 
                                                     target_size=(224, 224), 
                                                     color_mode='rgb',
                                                     batch_size=BS, 
                                                     class_mode='categorical',
                                                     shuffle=True,
                                                     subset = 'training') 
      
      val_data = val_datagen.flow_from_directory(train_path, 
                                                 target_size=(224, 224), 
                                                 color_mode='rgb',
                                                 batch_size=BS, 
                                                 class_mode='categorical',
                                                 shuffle=False,
                                                 subset = 'validation')
      

      【讨论】:

      • 您是否做过任何测试以确保没有泄漏/重叠?
      • @ARAT 当然!我做了很多测试来确定这一点。如果您不信任,可以在 flow_from_directory 函数中使用这些参数(save_to_dir = None, save_prefix = "", save_format = "png")来测试图像的正确分割。有关详细信息,请参阅文档:keras.io/api/preprocessing/image
      • 这里会有图像重叠,2个数据生成器会独立从train_path读取。
      • @BenButterworth 没有重叠,因为 flow_from_directory() 将数据集拆分为相同顺序的切片(请参阅:github.com/keras-team/keras/issues/597)。但是,如果您不信任我,您可以为这两种方法设置相同的种子。虽然在这种情况下不需要种子,因为它用于训练阶段而不是用于分裂。
      • 我认为为了使其正确,您应该提供相同的seed
      【解决方案6】:

      这是一个简单的 tensorflow 2.0 代码

      from tensorflow.keras.preprocessing.image import ImageDataGenerator
      
      def image_data_generator(data_dir,
                             data_augment=False,
                             batch_size=BATCH_SIZE,
                             target_size=(100, 100),
                             color_mode='rgb',
                             class_mode='binary',
                             shuffle=True):
        if data_augment:
            datagen = ImageDataGenerator(rescale=1./255,
                                         rotation_range=20,
                                         width_shift_range=0.2,
                                         height_shift_range=0.2,
                                         shear_range=0.2,
                                         zoom_range=0.2,
                                         validation_split=0.2,#this is the trick
                                         horizontal_flip=True)
        else:
            datagen = ImageDataGenerator(rescale=1./255)
      
        generator = datagen.flow_from_directory(data_dir,
                                                target_size=target_size,
                                                color_mode=color_mode,
                                                batch_size=batch_size,
                                                shuffle=shuffle,
                                                class_mode=class_mode)
        return generator
      
      train_generator = image_data_generator('Your_DataBase_Path',data_augment=True)
      

      【讨论】:

        【解决方案7】:

        如果您想使用 VGG16 模型的预处理单元并将数据集拆分为 70% 的训练和 30% 的验证,请遵循以下方法:

        train_path = 'your dataset path'
        train_batch= 
        ImageDataGenerator(preprocessing_function=tf.keras.applications.vgg16.preprocess_input, validation_split=0.3) \
        .flow_from_directory(directory=train_path, target_size=(,), classes=['',''], batch_size= ,class_mode='categorical', subset='training')
        val_batch= 
        ImageDataGenerator(preprocessing_function=tf.keras.applications.vgg16.preprocess_input, validation_split=0.3) \
        .flow_from_directory(directory=train_path, target_size=(,), classes=['',''], batch_size=, class_mode='categorical', subset='validation')
        

        【讨论】:

          【解决方案8】:

          如果您只是想划分数据集进行训练和验证(不进行任何扩充等)

          from tensorflow.keras.applications.xception import preprocess_input
          from tensorflow.keras.preprocessing.image import ImageDataGenerator
          
          ds_gen = ImageDataGenerator(
              preprocessing_function=preprocess_input,
              validation_split=0.2 
          )
          
          train_ds = ds_gen.flow_from_directory(
            "/path/to/dataset", 
            seed=1,
            target_size=(150, 150), #adjust to your needs
            batch_size=32,#adjust to your needs
            class_mode='categorical',
            subset='training' 
          )
          
          val_ds = ds_gen.flow_from_directory(
            "/path/to/dataset",
            seed=1,
            target_size=(150, 150),
            batch_size=32,
            class_mode='categorical',
            subset='validation'
          )
          
          
          

          【讨论】:

            【解决方案9】:

            如果您使用的是 TensorFlow 2.x,您可以使用相同的 fit() 函数并将参数 validation_split 也用于 Image ImageDataGenerator

            【讨论】:

              【解决方案10】:

              如果您正在为分割任务寻找生成器中的训练/验证拆分,您可以使用以下 sn-p:

              from tensorflow.keras.preprocessing.image import ImageDataGenerator
              
              BATCH_SIZE = 16
              val_fraction = 0.1
              image_generator = ImageDataGenerator(rescale=1/255,
                                                   brightness_range=[0.75, 1.75],
                                                   validation_split=val_fraction)
              
              mask_generator = ImageDataGenerator(validation_split=val_fraction)
              
              train_image_generator = image_generator.flow_from_dataframe(df_img,
                                                                          directory=image_dir,
                                                                          x_col='image',
                                                                          class_mode=None,
                                                                          color_mode='rgb',
                                                                          target_size=(INPUT_SIZE, INPUT_SIZE),
                                                                          batch_size=BATCH_SIZE,
                                                                          shuffle=True,
                                                                          subset='training',
                                                                          seed=1)
              
              train_mask_generator = mask_generator.flow_from_dataframe(df_gt,
                                                                        directory=gt_dir,
                                                                        x_col='mask',
                                                                        color_mode='grayscale',
                                                                        class_mode=None,
                                                                        target_size=(INPUT_SIZE, INPUT_SIZE),
                                                                        batch_size=BATCH_SIZE,
                                                                        shuffle=True,
                                                                        subset='training',
                                                                        seed=1)
              
              validation_image_generator = image_generator.flow_from_dataframe(df_img,
                                                                          directory=image_dir,
                                                                          x_col='image',
                                                                          class_mode=None,
                                                                          color_mode='rgb',
                                                                          target_size=(INPUT_SIZE, INPUT_SIZE),
                                                                          batch_size=BATCH_SIZE,
                                                                          subset='validation',
                                                                          seed=1)
              
              validation_mask_generator = mask_generator.flow_from_dataframe(df_gt,
                                                                        directory=gt_dir,
                                                                        x_col='mask',
                                                                        color_mode='grayscale',
                                                                        class_mode=None,
                                                                        target_size=(INPUT_SIZE, INPUT_SIZE),
                                                                        batch_size=BATCH_SIZE,
                                                                        subset='validation',
                                                                        seed=1)
              
              train_generator = zip(train_image_generator, train_mask_generator)
              validation_generator = zip(validation_image_generator, validation_mask_generator)
              

              【讨论】:

                【解决方案11】:

                我不知道您是否仍然感兴趣,但我找到了以下解决方法。最重要的函数是GetTrainValidTestGeneratorFromDir,其他的只是被它使用。基本思想是首先使用validation_split 将ImageDataGenerator 除以二。通过这种方式,您将获得两个迭代器。您可以使用第二个作为测试迭代器。您将通过以下方式进一步划分第一个: 首先使用训练子集使用 flow_from_directory(这样您就可以确保排除测试数据)。现在您可以使用相同的生成器来获取两个划分的数据帧,然后您可以使用 flow_from_dataframe 函数。您将获得三个 ImageDataIterators 而无需更改文件夹

                # -*- coding: utf-8 -*-
                """
                Created on Thu Apr 15 10:15:18 2021
                
                @author: Alessandro
                """
                import pandas as pd
                from keras.preprocessing.image import ImageDataGenerator
                
                
                def ShuffleDataframe(thedataframe):
                    thedataframe = thedataframe.sample(n=len(thedataframe), random_state=42)
                    thedataframe = thedataframe.reset_index()
                    thedataframe.drop('index', axis='columns', inplace=True)
                    return(thedataframe)
                
                
                def TransformGeneratorClassNumberToLabels(theGenerator, theLabelsNumbers):
                    labelnames = theGenerator.class_indices
                    labelnames =  list(labelnames.keys())
                    theLabelsString = [labelnames[i] for i in theLabelsNumbers]
                    return(theLabelsString)
                
                
                def GetGeneratorDataframe(theGenerator):
                    training_filenames = theGenerator.filenames    
                    theLabelsNumbers = theGenerator.classes
                    
                    thelabelsString =  TransformGeneratorClassNumberToLabels(theGenerator, 
                                                                             theLabelsNumbers)
                
                    
                    
                    
                    thedataframe = pd.DataFrame({'File': training_filenames,
                                                'Label': thelabelsString})
                
                    thedataframe = ShuffleDataframe(thedataframe)
                    return(thedataframe)   
                
                def GetTrainValidTestGeneratorFromDir(thedirectory,
                                                      input_shape= (256, 256, 3),
                                                      validation_split=0.1,
                                                      rescaling = 1./255):
                    
                    train_datagen = ImageDataGenerator(rescale=1./255,
                                                       validation_split=0.2)   
                    
                    
                    train_and_valid_generator = train_datagen.flow_from_directory(thedirectory,
                                                                                  target_size=input_shape[0:2],
                                                                                  batch_size=20,
                                                                                  class_mode="categorical",
                                                                                  subset = 'training',
                                                                                  save_to_dir ='checkdir')
                    
                    test_generator = train_datagen.flow_from_directory(thedirectory,
                                                                       target_size=input_shape[0:2],
                                                                       batch_size=20,
                                                                       class_mode="categorical",
                                                                       subset = 'validation')
                    
                    thedataframe = GetGeneratorDataframe(train_and_valid_generator)
                    
                
                    class_mode = "categorical"
                        
                    training_generator = train_datagen.flow_from_dataframe(dataframe = thedataframe,
                                                                           directory = thedirectory,
                                                                           target_size=input_shape[0:2],
                                                                           x_col="File",
                                                                           y_col = "Label",
                                                                           subset= "training",
                                                                           class_mode=class_mode)    
                
                
                    validation_generator = train_datagen.flow_from_dataframe(dataframe = thedataframe,
                                                                             directory = thedirectory,
                                                                             target_size=input_shape[0:2],
                                                                             x_col="File",
                                                                             y_col = "Label",
                                                                             subset= "validation",
                                                                             class_mode=class_mode)
                    return training_generator, validation_generator, test_generator 
                
                
                input_shape = (450, 450, 3)
                myDir      = "MyFolder"
                
                (training_generator, 
                 validation_generator, 
                 test_generator) = GetTrainValidTestGeneratorFromDir(myDir)
                
                # next part is just to verify whhat you got
                
                training_dataframe = GetGeneratorDataframe(training_generator)
                valid_dataframe = GetGeneratorDataframe(validation_generator)
                test_dataframe = GetGeneratorDataframe(test_generator)
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2017-11-01
                  • 1970-01-01
                  • 2021-01-20
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多