Keras在每个时期占用的内存量会无限增加

时间:2018-12-08 13:48:19

标签: python-3.x tensorflow keras

我正在运行一种遗传超参数搜索算法,它很快就会使所有可用内存饱和。

经过几次测试后,在不同时期之间以及在训练不同模型时,keras所需的内存量似乎都增加了。随着minibatch大小的增加,问题变得更加严重,minibatch大小为1〜5至少给了我足够的时间来查看内存使用率在最初的几次拟合中确实迅速增加,然后随着时间的推移缓慢但稳定地增加。 / p>

我已经检查了keras predict memory swap increase indefinitelyKeras: Out of memory when doing hyper parameter grid searchKeras (TensorFlow, CPU): Training Sequential models in loop eats memory,所以我已经在每次迭代后清除keras会话并重置tensorflow的图。

我还尝试显式删除模型和历史记录对象并运行gc.collect(),但无济于事。

我在CPU上运行Keras 2.2.4,tensorflow 1.12.0,Python 3.7.0。我为每个基因运行的代码以及用于测量内存使用情况的回调:

import tensorflow as tf
import keras as K

class MemoryCallback(K.callbacks.Callback):
    def on_epoch_end(self, epoch, log={}):
        print(resource.getrusage(resource.RUSAGE_SELF).ru_maxrss)


def Rateme(self,loss,classnum,patience,epochs,DWIshape,Mapshape,lr,TRAINDATA,TESTDATA,TrueTrain, TrueTest,ModelBuilder,maxthreads):

K.backend.set_session(K.backend.tf.Session(config=K.backend.tf.ConfigProto(intra_op_parallelism_threads=maxthreads, inter_op_parallelism_threads=maxthreads)))

#Early Stopping
STOP=K.callbacks.EarlyStopping(monitor='val_acc', min_delta=0.001,
                               patience=patience, verbose=0, mode='max')
#Build model
Model=ModelBuilder(DWIshape, Mapshape, dropout=self.Dropout,
                      regularization=self.Regularization,
                      activ='relu', DWIconv=self.nDWI, DWIsize=self.sDWI,
                      classes=classnum, layers=self.nCNN,
                      filtersize=self.sCNN,
                      FClayers=self.FCL, last=self.Last)
#Compile
Model.compile(optimizer=K.optimizers.Adam(lr,decay=self.Decay), loss=loss, metrics=['accuracy'])
#Fit
his=Model.fit(x=TRAINDATA,y=TrueTrain,epochs=epochs,batch_size=5, shuffle=True, validation_data=(TESTDATA,TrueTest), verbose=0, callbacks=[STOP, MemoryCallback()]) #check verbose and callbacks
#Extract 
S=Model.evaluate(x=TESTDATA, y=TrueTest,verbose=1)[1]
del his
del Model
del rateme
K.backend.clear_session()
tf.reset_default_graph()
gc.collect()

return S

4 个答案:

答案 0 :(得分:3)

因为在使用 model.fit() 等内置函数时 TensorFlow 2.4.1 似乎仍然存在内存泄漏 > 这是我的看法。


问题

  • 尽管我运行的是 NVIDIA GeForce RTX 2080 TI GPU,但 RAM 使用量仍然很大。
  • 随着训练的进行而增加 epoch 时间。
  • 某种内存泄漏(感觉有点线性)。

解决方案

  • run_eagerly=True 参数添加到 model.compile() 函数。但是,这样做可能会导致 TensorFlow 的图形优化不再起作用,从而导致性能下降 (reference)。
  • 创建一个自定义回调,在每个时期 (reference) 结束时垃圾收集和清除 Keras 后端。
  • 请勿在 activation 中使用 tf.keras.layers 参数。将激活函数作为单独的层(reference)。
  • 使用 LeakyReLU 而不是 ReLU 作为激活函数 (reference)。

注意:由于所有要点都可以单独实现,因此您可以混合和匹配它们,直到获得适合您的结果。无论如何,这是一个代码片段,显示了所有解决方案:

import gc
from tensorflow.keras import backend as k
from tensorflow.keras.layers import Conv2D, BatchNormalization, ReLU
from tensorflow.keras.callbacks import Callback


class CovNet:
    ...
    x = Conv2d(
        ...,
        activation=None
    )(x)
    x = BatchNormalization()(x)
    x = ReLU()(x)  # or LeakyReLU
    ...

#--------------------------------------------------------------------------------

class ClearMemory(Callback):
    def on_epoch_end(self, epoch, logs=None):
        gc.collect()
        k.clear_session()

#--------------------------------------------------------------------------------

model.compile(
    ...,
    run_eagerly=True
)

#--------------------------------------------------------------------------------

model.fit(
    ...,
    callbacks=ClearMemory()
)

通过这些解决方案,我现在可以在占用更少 RAM 的情况下进行训练,纪元时间保持不变,如果仍然存在内存泄漏,则可以忽略不计。

感谢@Hongtao Yang 提供相关 GitHub issues 之一的链接,并感谢在 GitHub 上为他的 comment 提供链接。


注意事项

  • 如果以上方法都不适合您,您可能想尝试在 TensorFlow 中编写自己的训练循环。这是有关如何操作的guide
  • 人们还报告说,使用 tcmalloc 代替默认的 malloc 分配器在一定程度上缓解了内存泄漏。如需参考,请参阅 herehere

我希望这也能帮助其他人,并为您节省一些在互联网上进行研究的时间。

答案 1 :(得分:1)

Consuming the entire available memory是TF的默认行为。
您可以使用以下代码来限制TF中的内存消耗量:

import tensorflow as tf
from keras.backend.tensorflow_backend import set_session

config = tf.ConfigProto()
config.gpu_options.per_process_gpu_memory_fraction = 0.9 # fraction of memory
config.gpu_options.visible_device_list = "0"

set_session(tf.Session(config=config))

答案 2 :(得分:1)

最后,我只是使用bash脚本重新启动了每次训练之间的python会话,找不到更好的方法来避免内存占用爆炸

答案 3 :(得分:0)

也许this是一个相关问题?如果是这样,那么使用自定义训练循环而不是:s/}/方法时就可以了。

我认为他们尚未解决此问题,因此我将避免使用内置的训练/评估/预测方法。