如何使用Keras中的data generator

本文介绍了在Keras中使用数据生成器解决大规模数据集无法一次性加载内存的问题。通过创建自定义的data generator,实现了数据的批量生成,并在训练过程中利用多核并行处理,提高了模型训练效率。详细教程包括数据生成器的实现和Keras脚本的修改。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关于如何使用Keras中的data generator的具体例子

动机

如果你训练需要使用大规模数据集的模型的话,大概常会遇到一个问题:过大的数据集无法同时加载到内存中,然而模型的性能提升又不得不使用大规模数据集,所以如何在训练过程中调用体积庞大的数据集是一个非常现实的问题。
在这片博文中,将要介绍一种数据集逐批生成方法,来实时多核生成数据集并且可以立刻交付给你的深度学习模型

Tutorial

使用generator之前

在读这篇文章之前,你的Keras脚本文件可能看起来是这样:

import numpy as np
from keras.models import Sequential

# Load entire dataset
X, y = np.load('some_training_set_with_labels.npy')

# Design model
model = Sequential()
[...] # Your architecture
model.compile()

# Train model on your dataset
model.fit(x=X, y=y)

这篇文章就是要讲如何改变这种一次性加载所有数据集的方式,来解决由于数据集过大内存不足的问题。

接下来,我们来写一个generator解决以上问题,此外,这些代码也可以作为你创建自已的项目的一个很好的框架,你可以直接ctrl+C&V以下代码并根据自身情况做修改。

Notations

在开始之前,我们先看一下几个在处理大规模数据集时非常有用的小技巧。
ID:Python string,指代数据集的名称
你可以用以下框架来给你的数据集及标签命名:

  1. 创建一个名为partition的字典:
    partition['train'] : training IDs 的列表
    partition['validation'] : validation IDs 的列表
  2. 为每一个ID创建一个名为labels的字典,以labels[ID]命名
    例如,我们的训练集中包括id-1id-2id-3,以及相对应的标签012,以及包含一个id-41的训练集,在这种情况下,在Python中partitionlabels变量如下:
    >>> partition
    {'train': ['id-1', 'id-2', 'id-3'], 'validation': ['id-4']}
    
    >>> labels
    {'id-1': 0, 'id-2': 1, 'id-3': 2, 'id-4': 1}
    

并且,出于使工程模块化的原因,我们将Keras中几个类定义在不同的文件中,所以文件夹看起来大概是这样:

folder/
├── my_classes.py
├── keras_script.py
└── data/

其中,data/中默认是你的数据集的所在文件夹。

本篇tutorial中的code尽可能实现普适性,以便于你应用在自己的工程中。

Data generator

现在我们开始进入正题,如何在你的keras模型中使用Data generator。
首先,我们需要定义一个类的初始化函数,该类继承了keras.utils.Sequence特性以便我们使用一些非常好的功能,例如multi processing

def __init__(self, list_IDs, labels, batch_size=32, dim=(32,32,32), n_channels=1,
             n_classes=10, shuffle=True):
    'Initialization'
    self.dim = dim
    self.batch_size = batch_size
    self.labels = labels
    self.list_IDs = list_IDs
    self.n_channels = n_channels
    self.n_classes = n_classes
    self.shuffle = shuffle
    self.on_epoch_end()

这里,每当训练一回合的开始同时也是上一回合的结束,on_epoch_end方法就会被触发。如果shuffle被设置为True的话,我们在不同迭代的回合中将会得到一个打乱顺序的同批数据集。

def on_epoch_end(self):
  'Updates indexes after each epoch'
  self.indexes = np.arange(len(self.list_IDs))
  if self.shuffle == True:
      np.random.shuffle(self.indexes)

打乱同批喂给模型的数据集的次序对于提升模型的稳健性还是非常有用的。
接下来,是data generator的核心方法:生成多批次的数据集,负责这一项任务的private method叫做:_data_generation

def __data_generation(self, list_IDs_temp):
  'Generates data containing batch_size samples' # X : (n_samples, *dim, n_channels)
  # Initialization
  X = np.empty((self.batch_size, *self.dim, self.n_channels))
  y = np.empty((self.batch_size), dtype=int)

  # Generate data
  for i, ID in enumerate(list_IDs_temp):
      # Store sample
      X[i,] = np.load('data/' + ID + '.npy')

      # Store class
      y[i] = self.labels[ID]

  return X, keras.utils.to_categorical(y, num_classes=self.n_classes)

在生成数据的过程中,这一段代码从相应的ID.npy文件中读取Numpy数组,因为这段代码适用于多核操作,所以你可以做一些更复杂的操作(例如基于源文件计算)而不用训练过程中由于数据生成导致的瓶颈问题。

此外,需要注意的是,我们使用Keras自带的keras.utils.to_categorical函数将我们数值类型的标签存储为二进制形式(例如,如果有6类的话,转化为[0 0 1 0 0])。

接下来这部分我们将这三部分整合到一起,每一次调用请求返回一个batch,batch的大小通过以下函数计算:

def __len__(self):
  'Denotes the number of batches per epoch'
  return int(np.floor(len(self.list_IDs) / self.batch_size))

接下来,当某个相应的batch被调用时,生成器通过执行_getitem_方法来返回batch

def __getitem__(self, index):
  'Generate one batch of data'
  # Generate indexes of the batch
  indexes = self.indexes[index*self.batch_size:(index+1)*self.batch_size]

  # Find list of IDs
  list_IDs_temp = [self.list_IDs[k] for k in indexes]

  # Generate data
  X, y = self.__data_generation(list_IDs_temp)

  return X, y

完整的代码如下:

import numpy as np
import keras

class DataGenerator(keras.utils.Sequence):
    'Generates data for Keras'
    def __init__(self, list_IDs, labels, batch_size=32, dim=(32,32,32), n_channels=1,
                 n_classes=10, shuffle=True):
        'Initialization'
        self.dim = dim
        self.batch_size = batch_size
        self.labels = labels
        self.list_IDs = list_IDs
        self.n_channels = n_channels
        self.n_classes = n_classes
        self.shuffle = shuffle
        self.on_epoch_end()

    def __len__(self):
        'Denotes the number of batches per epoch'
        return int(np.floor(len(self.list_IDs) / self.batch_size))

    def __getitem__(self, index):
        'Generate one batch of data'
        # Generate indexes of the batch
        indexes = self.indexes[index*self.batch_size:(index+1)*self.batch_size]

        # Find list of IDs
        list_IDs_temp = [self.list_IDs[k] for k in indexes]

        # Generate data
        X, y = self.__data_generation(list_IDs_temp)

        return X, y

    def on_epoch_end(self):
        'Updates indexes after each epoch'
        self.indexes = np.arange(len(self.list_IDs))
        if self.shuffle == True:
            np.random.shuffle(self.indexes)

    def __data_generation(self, list_IDs_temp):
        'Generates data containing batch_size samples' # X : (n_samples, *dim, n_channels)
        # Initialization
        X = np.empty((self.batch_size, *self.dim, self.n_channels))
        y = np.empty((self.batch_size), dtype=int)

        # Generate data
        for i, ID in enumerate(list_IDs_temp):
            # Store sample
            X[i,] = np.load('data/' + ID + '.npy')

            # Store class
            y[i] = self.labels[ID]

        return X, keras.utils.to_categorical(y, num_classes=self.n_classes)

Keras Script

接下来就是如何将以上代码具体应用在我们的Keras模型中:

import numpy as np

from keras.models import Sequential
from my_classes import DataGenerator

# Parameters
params = {'dim': (32,32,32),
          'batch_size': 64,
          'n_classes': 6,
          'n_channels': 1,
          'shuffle': True}

# Datasets
partition = # IDs
labels = # Labels

# Generators
training_generator = DataGenerator(partition['train'], labels, **params)
validation_generator = DataGenerator(partition['validation'], labels, **params)

# Design model
model = Sequential()
[...] # Architecture
model.compile()

# Train model on dataset
model.fit_generator(generator=training_generator,
                    validation_data=validation_generator,
                    use_multiprocessing=True,
                    workers=6)

如上所示,我们调用fit_generator而非fit方法,接下来Keras会处理一切。

我们的这种实现方式可以使用fit_generator 中的multi processing设定,线程个数由n_workers定义。

总结

完成!接下来就可以通过以下命令来执行该文件:

python3 keras_script.py

你将会看到,在训练阶段,数据由多个CPU并行生成后直接输入模型。

原文出处:https://stanford.edu/~shervine/blog/keras-how-to-generate-data-on-the-fly

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值