使用KerasImageDataGenerator时出现内存错误
我试图使用带有TensorFlow后端的keras来预测图像中的特征.具体来说,我试图使用keras ImageDataGenerator.该模型设置为运行4个时期并运行良好,直到它失败并出现MemoryError的第4个时期.
我在运行Ubuntu Server 16.04 LTS(HVM),SSD卷类型的AWS g2.2xlarge实例上运行此模型.
训练图像是256×256 RGB像素块(8位无符号),训练掩码是256×256单波段(8位无符号)平铺数据,其中255 = =感兴趣的特征,0 ==其他所有.
以下3个函数是与此错误相关的函数.
我该如何解决这个MemoryError?
def train_model(): batch_size = 1 training_imgs = np.lib.format.open_memmap(filename=os.path.join(data_path, ‘data.npy’),mode=’r+’) training_masks = np.lib.format.open_memmap(filename=os.path.join(data_path, ‘mask.npy’),mode=’r+’) dl_model = create_model() print(dl_model.summary()) model_checkpoint = ModelCheckpoint(os.path.join(data_path,’mod_weight.hdf5′), mOnitor=’loss’,verbose=1, save_best_Only=True) dl_model.fit_generator(generator(training_imgs, training_masks, batch_size), steps_per_epoch=(len(training_imgs)/batch_size), epochs=4,verbose=1,callbacks=[model_checkpoint])def generator(train_imgs, train_masks=None, batch_size=None):# Create empty arrays to contain batch of features and labels# if train_masks is not None: train_imgs_batch = np.zeros((batch_size,y_to_res,x_to_res,bands)) train_masks_batch = np.zeros((batch_size,y_to_res,x_to_res,1)) while True: for i in range(batch_size): # choose random index in features index= random.choice(range(len(train_imgs))) train_imgs_batch[i] = train_imgs[index] train_masks_batch[i] = train_masks[index] yield train_imgs_batch, train_masks_batch else: rec_imgs_batch = np.zeros((batch_size,y_to_res,x_to_res,bands)) while True: for i in range(batch_size): # choose random index in features index= random.choice(range(len(train_imgs))) rec_imgs_batch[i] = train_imgs[index] yield rec_imgs_batchdef train_generator(train_images,train_masks,batch_size): data_gen_args=dict(rotation_range=90.,horizontal_flip=True,vertical_flip=True,rescale=1./255) image_datagen = ImageDataGenerator() mask_datagen = ImageDataGenerator()# # Provide the same seed and keyword arguments to the fit and flow methods seed = 1 image_datagen.fit(train_images, augment=True, seed=seed) mask_datagen.fit(train_masks, augment=True, seed=seed) image_generator = image_datagen.flow(train_images,batch_size=batch_size) mask_generator = mask_datagen.flow(train_masks,batch_size=batch_size) return zip(image_generator, mask_generator)
以下是模型的输出,详细说明了时期和错误信息:
Epoch 00001: loss improved from inf to 0.01683, saving model to /home/ubuntu/deep_learn/client_data/mod_weight.hdf5Epoch 2/47569/7569 [==============================] – 3394s 448ms/step – loss: 0.0049 – binary_crossentropy: 0.0027 – jaccard_coef_int: 0.9983 Epoch 00002: loss improved from 0.01683 to 0.00492, saving model to /home/ubuntu/deep_learn/client_data/mod_weight.hdf5Epoch 3/47569/7569 [==============================] – 3394s 448ms/step – loss: 0.0049 – binary_crossentropy: 0.0026 – jaccard_coef_int: 0.9982 Epoch 00003: loss improved from 0.00492 to 0.00488, saving model to /home/ubuntu/deep_learn/client_data/mod_weight.hdf5Epoch 4/47569/7569 [==============================] – 3394s 448ms/step – loss: 0.0074 – binary_crossentropy: 0.0042 – jaccard_coef_int: 0.9975 Epoch 00004: loss did not improveTraceback (most recent call last): File “image_rec.py”, line 291, in train_model() File “image_rec.py”, line 208, in train_model dl_model.fit_generator(train_generator(training_imgs,training_masks,batch_size),steps_per_epoch=1,epochs=1,workers=1) File “image_rec.py”, line 274, in train_generator image_datagen.fit(train_images, augment=True, seed=seed) File “/home/ubuntu/pyvirt_test/local/lib/python2.7/site-packages/keras/preprocessing/image.py”, line 753, in fit x = np.copy(x) File “/home/ubuntu/pyvirt_test/local/lib/python2.7/site-packages/numpy/lib/function_base.py”, line 1505, in copy return array(a, order=order, copy=True)MemoryError
Julio CamPla.. 9
看来你的问题是由于数据太大了.我可以看到两种解决方案.第一个是通过spark在分布式系统中运行你的代码,我想你没有这个支持,所以让我们继续前进到另一个.
第二个是我认为可行的.我会切片数据,我会尝试逐步喂养模型.我们可以用Dask做到这一点.该库可以对数据进行切片并保存在对象中,然后您可以从磁盘中检索读取,只能在您想要的部分中进行读取.
如果你有一个大小是100×100矩阵的图像,我们可以检索每个数组,而无需在内存中加载100个数组.我们可以在内存中加载数组(释放前一个数组),这将是神经网络中的输入.
为此,您可以将np.array转换为dask数组并分配分区.例如:
>>> k = np.random.randn(10,10) # Matrix 10×10>>> import dask.array as da>>> k2 = da.from_array(k,chunks = 3)dask.array>>> k2.to_delayed()array([[Delayed((‘array-a08c1d25b900d497cdcd233a7c5aa108’, 0, 0)), Delayed((‘array-a08c1d25b900d497cdcd233a7c5aa108’, 0, 1)), Delayed((‘array-a08c1d25b900d497cdcd233a7c5aa108’, 0, 2)), Delayed((‘array-a08c1d25b900d497cdcd233a7c5aa108’, 0, 3))], [Delayed((‘array-a08c1d25b900d497cdcd233a7c5aa108’, 1, 0)), Delayed((‘array-a08c1d25b900d497cdcd233a7c5aa108’, 1, 1)), Delayed((‘array-a08c1d25b900d497cdcd233a7c5aa108’, 1, 2)), Delayed((‘array-a08c1d25b900d497cdcd233a7c5aa108’, 1, 3))], [Delayed((‘array-a08c1d25b900d497cdcd233a7c5aa108’, 2, 0)), Delayed((‘array-a08c1d25b900d497cdcd233a7c5aa108’, 2, 1)), Delayed((‘array-a08c1d25b900d497cdcd233a7c5aa108’, 2, 2)), Delayed((‘array-a08c1d25b900d497cdcd233a7c5aa108’, 2, 3))], [Delayed((‘array-a08c1d25b900d497cdcd233a7c5aa108’, 3, 0)), Delayed((‘array-a08c1d25b900d497cdcd233a7c5aa108’, 3, 1)), Delayed((‘array-a08c1d25b900d497cdcd233a7c5aa108’, 3, 2)), Delayed((‘array-a08c1d25b900d497cdcd233a7c5aa108’, 3, 3))]], dtype=object)
在这里,您可以看到数据如何保存在对象中,然后您可以检索部分内容以提供模型.
要实现此解决方案,您必须在函数中引入一个循环,该循环调用每个分区并提供NN以获得增量训练.
有关更多信息,请参阅Dask文档
1> Julio CamPla..:
看来你的问题是由于数据太大了.我可以看到两种解决方案.第一个是通过spark在分布式系统中运行你的代码,我想你没有这个支持,所以让我们继续前进到另一个.
第二个是我认为可行的.我会切片数据,我会尝试逐步喂养模型.我们可以用Dask做到这一点.该库可以对数据进行切片并保存在对象中,然后您可以从磁盘中检索读取,只能在您想要的部分中进行读取.
如果你有一个大小是100×100矩阵的图像,我们可以检索每个数组,而无需在内存中加载100个数组.我们可以在内存中加载数组(释放前一个数组),这将是神经网络中的输入.
为此,您可以将np.array转换为dask数组并分配分区.例如:
>>> k = np.random.randn(10,10) # Matrix 10×10>>> import dask.array as da>>> k2 = da.from_array(k,chunks = 3)dask.array>>> k2.to_delayed()array([[Delayed((‘array-a08c1d25b900d497cdcd233a7c5aa108’, 0, 0)), Delayed((‘array-a08c1d25b900d497cdcd233a7c5aa108’, 0, 1)), Delayed((‘array-a08c1d25b900d497cdcd233a7c5aa108’, 0, 2)), Delayed((‘array-a08c1d25b900d497cdcd233a7c5aa108’, 0, 3))], [Delayed((‘array-a08c1d25b900d497cdcd233a7c5aa108’, 1, 0)), Delayed((‘array-a08c1d25b900d497cdcd233a7c5aa108’, 1, 1)), Delayed((‘array-a08c1d25b900d497cdcd233a7c5aa108’, 1, 2)), Delayed((‘array-a08c1d25b900d497cdcd233a7c5aa108’, 1, 3))], [Delayed((‘array-a08c1d25b900d497cdcd233a7c5aa108’, 2, 0)), Delayed((‘array-a08c1d25b900d497cdcd233a7c5aa108’, 2, 1)), Delayed((‘array-a08c1d25b900d497cdcd233a7c5aa108’, 2, 2)), Delayed((‘array-a08c1d25b900d497cdcd233a7c5aa108’, 2, 3))], [Delayed((‘array-a08c1d25b900d497cdcd233a7c5aa108’, 3, 0)), Delayed((‘array-a08c1d25b900d497cdcd233a7c5aa108’, 3, 1)), Delayed((‘array-a08c1d25b900d497cdcd233a7c5aa108’, 3, 2)), Delayed((‘array-a08c1d25b900d497cdcd233a7c5aa108’, 3, 3))]], dtype=object)
在这里,您可以看到数据如何保存在对象中,然后您可以检索部分内容以提供模型.
要实现此解决方案,您必须在函数中引入一个循环,该循环调用每个分区并提供NN以获得增量训练.
有关更多信息,请参阅Dask文档
2> CermakM..:
你提供了相当令人困惑的代码(在我看来),即.没有电话train_generator可见.我不确定这是一个由于大数据而导致内存不足的问题,因为你使用了memmap,但我们现在假设它是.
如果数据非常大并且因为您无论如何都要从目录加载图像,那么考虑使用方法可能是值得ImageDataGenerator的flow_from_directory.它需要稍微改变一下设计,这可能不是你想要的.
您可以按以下方式加载它:
train_datagen = ImageDataGenerator()train_generator = train_datagen.flow_from_directory( ‘data/train’, target_size=(256, 256), batch_size=batch_size, … # other configurations)
更多关于Keras文档的内容.
另请注意,如果您有32位,memmap则不允许超过2GB.
你tensorflow-gpu有机会使用吗?也许你的gpu是不够的,你可以试试这个tensorflow包.
我强烈建议尝试一些内存分析,以查看更大的内存分配发生的位置.
如果不是内存不足的情况,那么处理模型中的数据可能是错误的,因为您的损失功能根本没有改善,例如它可能是错误的.
最后,这里的最后一个注释..最好加载训练数据的memmap read-only,因为你不想意外地弄乱数据.
更新:我可以看到你已经更新了帖子并提供了train_generator方法的代码,但是在你的调用中仍然没有调用该方法.
如果我假设你在调用中有一个拼写错误 – train_generator而不是generator你方法中的d1_model.fit_generator方法,那么该fit_generator方法可能不会处理一批数据,但实际上总体而言training_imgs它会在np.copy(x)调用中复制整个集合.
另外,正如已经提到的那样,确实存在(你可以找到其中一些,fe.这里是一个开放的)使用fit和fit_generator方法时Keras内存泄漏的一些问题.