使用Keras ImageDataGenerator时出现内存错误

时间:2018-03-23 22:07:01

标签: python tensorflow deep-learning keras

我试图使用带有TensorFlow后端的keras来预测图像中的特征。具体来说,我正在尝试使用keras ImageDataGenerator。该模型设置为运行4个时期并运行良好,直到第4个时期,它因MemoryError而失败。

我在运行Ubuntu Server 16.04 LTS(HVM),SSD卷类型的AWS g2.2xlarge实例上运行此模型。

训练图像是256x256 RGB像素图块(8位无符号),训练掩模是256x256单波段(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_batch

def 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.hdf5
Epoch 2/4
7569/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.hdf5
Epoch 3/4
7569/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.hdf5
Epoch 4/4
7569/7569 [==============================] - 3394s 448ms/step - loss: 0.0074 - binary_crossentropy: 0.0042 - jaccard_coef_int: 0.9975  

Epoch 00004: loss did not improve
Traceback (most recent call last):
  File "image_rec.py", line 291, in <module>
    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

5 个答案:

答案 0 :(得分:8)

似乎你的问题是由于数据太大了。我可以看到两种解决方案。第一个是通过spark在分布式系统中运行你的代码,我猜你没有这个支持,所以让我们继续前进到另一个。

第二个是我认为可行的。我会切片数据,我会尝试逐步喂养模型。我们可以用 Dask 来做到这一点。该库可以对数据进行切片并保存在对象中,然后您可以从磁盘中检索读取,只能在您想要的部分中进行读取。

如果您的图像大小为100x100的矩阵,我们可以检索每个阵列,而无需在内存中加载100个阵列。我们可以在内存中加载数组(释放前一个数组),这将是神经网络中的输入。

为此,您可以将np.array转换为dask数组并分配分区。例如:

>>> k = np.random.randn(10,10) # Matrix 10x10
>>> import dask.array as da
>>> k2 = da.from_array(k,chunks = 3)
dask.array<array, shape=(10, 10), dtype=float64, chunksize=(3, 3)>
>>> 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 :(得分:5)

你提供了相当令人困惑的代码(在我看来),即。没有看到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)

有关in the Keras documentation的更多信息。

  • 另请注意,如果您有32位,则memmap不允许超过2GB。

  • 您是否有机会使用tensorflow-gpu?也许你的gpu是不够的,你可以用tensorflow包来试试。

我强烈建议尝试一些memory profiling来查看更大的内存分配发生的位置。

如果不是内存不足的情况,那么处理模型中的数据可能是错误的,因为您的损失功能根本没有改善,例如它可能是错误的。

最后,这里的最后一个注释......最好将训练数据的memmap加载为read-only,因为你不想意外地弄乱数据。

更新:我们可以看到您已更新帖子并提供了train_generator方法的代码,但在您的通话中仍然没有调用该方法。

如果我认为您的train_generator方法中的通话中出现拼写错误 - generator而不是d1_model.fit_generator方法,那么fit_generator方法可能是不处理一批数据,但实际上整个training_imgs并且它会复制np.copy(x)调用中的整个数据集。

另外,如前所述,使用fitfit_generator方法确实存在(你可以找到其中一些,fe。here is an open one)Keras内存泄漏的一些问题。

答案 2 :(得分:4)

如果浮点精度太高,这在运行32位时很常见。你在运行32位吗?您也可以考虑对阵列进行转换或舍入。

答案 3 :(得分:4)

一般来说Keras / Tensorflow在资源使用方面非常好,但是已知的内存泄漏在过去已经引起了问题。要确保不是导致问题的那个,请尝试将这两行代码包含在您的培训脚本中:

# load the backend
from keras import backend as K

# prevent Tensorflow memory leakage
K.clear_session()

答案 4 :(得分:1)

我最近遇到了同样的问题。不知何故,FCN-8代码可以在我的tensorflow1.2 + keras2.0.9 + 8G RAM +1060计算机上成功运行,但在我的tf1.4 + keras2.1.5 + 16g ram + 1080ti计算机上使用modelcheckpoint时出现内存错误。