Python 如何编写高效的自定义Keras数据生成器
我想训练一个卷积递归神经网络用于视频帧预测。单个帧非常大,因此一次将整个训练数据拟合到内存中是一个挑战。因此,我按照一些在线教程创建了一个自定义数据生成器。在测试它时,它似乎可以工作,但是它比直接使用预加载的数据慢至少100倍。由于我只能在GPU上容纳大约8个批量大小的数据,我知道数据需要非常快地生成,然而,情况似乎并非如此 我在一个P100上训练我的型号,有32 GB的内存可供多达16个内核使用Python 如何编写高效的自定义Keras数据生成器,python,tensorflow,keras,Python,Tensorflow,Keras,我想训练一个卷积递归神经网络用于视频帧预测。单个帧非常大,因此一次将整个训练数据拟合到内存中是一个挑战。因此,我按照一些在线教程创建了一个自定义数据生成器。在测试它时,它似乎可以工作,但是它比直接使用预加载的数据慢至少100倍。由于我只能在GPU上容纳大约8个批量大小的数据,我知道数据需要非常快地生成,然而,情况似乎并非如此 我在一个P100上训练我的型号,有32 GB的内存可供多达16个内核使用 class DataGenerator(tf.keras.utils.Sequence): de
class DataGenerator(tf.keras.utils.Sequence):
def __init__(self, images, input_images=5, predict_images=5, batch_size=16, image_size=(200, 200),
channels=1):
self.images = images
self.input_images = input_images
self.predict_images = predict_images
self.batch_size = batch_size
self.image_size = image_size
self.channels = channels
self.nr_images = int(len(self.images)-input_images-predict_images)
def __len__(self):
return int(np.floor(self.nr_images) / self.batch_size)
def __getitem__(self, item):
# Randomly select the beginning image of each batch
batch_indices = random.sample(range(0, self.nr_images), self.batch_size)
# Allocate the output images
x = np.empty((self.batch_size, self.input_images,
*self.image_size, self.channels), dtype='uint8')
y = np.empty((self.batch_size, self.predict_images,
*self.image_size, self.channels), dtype='uint8')
# Get the list of input an prediction images
for i in range(self.batch_size):
list_images_input = range(batch_indices[i], batch_indices[i]+self.input_images)
list_images_predict = range(batch_indices[i]+self.input_images,
batch_indices[i]+self.input_images+self.predict_images)
for j, ID in enumerate(list_images_input):
x[i, ] = np.load(np.reshape(self.images[ID], (*self.imagesize, self.channels))
# Read in the prediction images
for j, ID in enumerate(list_images_predict):
y[i, ] = np.load(np.reshape(self.images[ID], (*self.imagesize, self.channels))
return x, y
# Training the model using fit_generator
params = {'batch_size': 8,
'input_images': 5,
'predict_images': 5,
'image_size': (100, 100),
'channels': 1
}
data_path = "input_frames/"
input_images = sorted(glob.glob(data_path + "*.png"))
training_generator = DataGenerator(input_images, **params)
model.fit_generator(generator=training_generator, epochs=10, workers=6)
我本以为Keras会在当前批次在GPU上处理时准备下一个数据批次,但它似乎没有赶上。换句话说,在将数据发送到GPU之前准备数据似乎是一个瓶颈
关于如何提高这样的数据生成器的性能有什么想法吗?是否缺少保证及时准备数据的东西
非常感谢 当您使用fit_generator时,有一个workers=设置可用于放大生成器工作人员的数量。但是,您应该确保考虑到getitem中的'item'参数,以确保不同的工作进程(未同步)根据项目索引返回不同的值。i、 e.不是随机抽样,也许只是返回基于索引的数据片段。您可以在开始之前洗牌整个数据集,以确保数据集顺序是随机的。您可以尝试使用use\u multiprocessing=True吗?这些是我使用您提供的数据生成器在基于GTX 1080Ti的系统上观察到的数字
model.fit_generator(generator=training_generator, epochs=10, workers=6)
148/148[====================================]-9s 60ms/步
model.fit_generator(generator=training_generator, epochs=10, workers=6, use_multiprocessing=True)
148/148[================================================]-2s 11ms/步我尝试过这个方法,但仍然比完全不使用数据生成器慢得多。使用预加载的数据,我可以在大约10分钟内完成一个历元,使用数据生成器(并使用_multiprocessing=True)将需要大约3小时30分钟,这是不可接受的。我仍然不知道为什么要花这么多时间,特别是因为我在我的发电机里什么都不做。我见过数据生成器动态调整图像大小,我认为这比加载准备好的numpy文件要昂贵得多。训练图像的数量是多少?另外,看起来您在发布代码之前做了一些编辑,因为存在一些语法错误。也许您可以自己调用生成器来分析代码。另外,看看CPU利用率等。总共有12000个培训视频,每个视频5帧。是的,我确实对代码进行了一些编辑,使其对我的问题更加简洁。我可以试一试分析,但我仍然很惊讶,为什么这个相对简单的生成器比在线的自定义数据生成器需要更多的时间来动态调整图像大小。你能解决这个问题吗?在使用简单的发电机时,我遇到了类似的问题。采集样本需要10分钟或更长时间。不,我没有。但是在Tensorflow 2中有一个数据类,它允许我们构建一个合适的输入管道。我想现在应该从这里开始。