【问题标题】:Loading batches of images in Keras from pandas dataframe从 Pandas 数据框加载 Keras 中的批量图像
【发布时间】:2019-01-21 09:54:28
【问题描述】:

我有一个包含两列的 pandas 数据框,一列有图像路径,另一列有字符串类标签。

我还编写了以下函数,它们从数据帧中加载图像,重新规范化它们并将类标签转换为 one-hot 向量。

def prepare_data(df):
    data_X, data_y = df.values[:,0], df.values[:,1]

    # Load images
    data_X = np.array([np.array(imread(fname)) for fname in data_X])

    # Normalize input
    data_X = data_X / 255 - 0.5

    # Prepare labels
    data_y = np.array([label2int[label] for label in data_y])
    data_y = to_categorical(data_y)

    return data_X, data_y

我想将此数据帧提供给 Keras CNN,但整个数据集太大而无法一次加载到内存中。

本网站的其他答案告诉我,为此我应该使用 Keras ImageDataGenerator,但老实说,我不明白如何从文档中做到这一点。

将延迟加载批次中的数据提供给模型的最简单方法是什么?

如果它是 ImageDataGenerator,我如何创建一个 ImageDataGenerator 来初始化 Dataframe 并通过我的函数传递批次以创建适当的 numpy 数组?以及如何使用 ImageDataGenerator 拟合模型?

【问题讨论】:

    标签: python pandas keras


    【解决方案1】:

    ImageDataGenerator 是一个高级类,它允许从多个源(来自np arrays、来自目录...)产生数据,并且包括用于执行图像增强等的实用函数。

    更新

    keras-preprocessing 1.0.4 开始,ImageDataGenerator 带有一个flow_from_dataframe method,它可以解决您的问题。它需要dataframedirectory 参数定义如下:

    dataframe: Pandas dataframe containing the filenames of the
               images in a column and classes in another or column/s
               that can be fed as raw target data.
    directory: string, path to the target directory that contains all
               the images mapped in the dataframe.
    

    所以不再需要自己实现。


    原答案如下

    在您的情况下,使用您描述的数据框,您还可以编写自己的自定义生成器,利用 prepare_data 函数中的逻辑作为更简约的解决方案。最好使用 Keras 的 Sequence 对象来执行此操作,因为它允许使用多处理(如果您使用的是 GPU,这将有助于避免出现瓶颈)。

    您可以查看Sequence 对象上的docs,它包含一个实现示例。最终,您的代码将是这样的(这是样板代码,您必须添加诸如 label2int 函数或图像预处理逻辑之类的细节):

    from keras.utils import Sequence
    class DataSequence(Sequence):
        """
        Keras Sequence object to train a model on larger-than-memory data.
        """
        def __init__(self, df, batch_size, mode='train'):
            self.df = df # your pandas dataframe
            self.bsz = batch_size # batch size
            self.mode = mode # shuffle when in train mode
    
            # Take labels and a list of image locations in memory
            self.labels = self.df['label'].values
            self.im_list = self.df['image_name'].tolist()
    
        def __len__(self):
            # compute number of batches to yield
            return int(math.ceil(len(self.df) / float(self.bsz)))
    
        def on_epoch_end(self):
            # Shuffles indexes after each epoch if in training mode
            self.indexes = range(len(self.im_list))
            if self.mode == 'train':
                self.indexes = random.sample(self.indexes, k=len(self.indexes))
    
        def get_batch_labels(self, idx):
            # Fetch a batch of labels
            return self.labels[idx * self.bsz: (idx + 1) * self.bsz]
    
        def get_batch_features(self, idx):
            # Fetch a batch of inputs
            return np.array([imread(im) for im in self.im_list[idx * self.bsz: (1 + idx) * self.bsz]])
    
        def __getitem__(self, idx):
            batch_x = self.get_batch_features(idx)
            batch_y = self.get_batch_labels(idx)
            return batch_x, batch_y
    

    您可以像自定义生成器一样传递此对象来训练您的模型:

    sequence = DataSequence(dataframe, batch_size)
    model.fit_generator(sequence, epochs=1, use_multiprocessing=True)
    

    如下所述,不需要实现洗牌逻辑。在fit_generator() 调用中将shuffle 参数设置为True 就足够了。来自docs

    随机播放:布尔值。是否打乱批次的顺序 每个时代的开始。仅与 Sequence 的实例一起使用 (keras.utils.Sequence)。当 steps_per_epoch 不是时无效 没有。

    【讨论】:

    • 您还需要在fit_generator 中指定steps_per_epoch 还是它会选择__len__?您在示例中使用 epochs=1 是否有任何相关原因?
    • 确实,生成器从批量大小和 len 推断每个 epoch 所需的步骤(在后台,这是在 Sequence 基类中实现的)。当然,我使用单个时代只是为了说明。
    • 另外值得注意的是,您不需要在on_epoch_end 中实现自己的洗牌。您可以在fit_generator 中设置shuffle=True,这将随机播放Sequence 的实例。
    • @sdcbr- 如果像素已经在DataFrame 中怎么办?喜欢this case ?
    【解决方案2】:

    我是 Keras 的新手,所以请谨慎对待我的建议。 我认为你应该使用 Keras ImageDataGenerator,特别是 flow_from_dataframe 选项,因为你说你有一个 Pandas 数据框。 Flow_from_dataframe 读取数据框的列以获取您的文件名和标签。

    下面是一个示例。在线查找教程。

    train_datagen = ImageDataGenerator(horizontal_flip=True,
                                       vertical_flip=False,
                                       rescale=1/255.0)
    
    train_generator = train_datagen.flow_from_dataframe(     
        dataframe=trainDataframe,  
        directory=imageDir,
        x_col="file", # name of col in data frame that contains file names
        y_col=y_col_list, # name of col with labels
        has_ext=True, 
        batch_size=batch_size,
        shuffle=True,
        save_to_dir=saveDir,
        target_size=(img_width,img_height),
        color_mode='grayscale',
        class_mode='categorical', # for classification task
        interpolation='bilinear')
    

    【讨论】:

      猜你喜欢
      • 2018-04-22
      • 1970-01-01
      • 1970-01-01
      • 2020-08-07
      • 2020-11-14
      • 1970-01-01
      • 2016-08-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多