我正在运行一种遗传超参数搜索算法,它很快就会使所有可用内存饱和。
经过几次测试后,在不同时期之间以及在训练不同模型时,keras所需的内存量似乎都增加了。随着minibatch大小的增加,问题变得更加严重,minibatch大小为1〜5至少给了我足够的时间来查看内存使用率在最初的几次拟合中确实迅速增加,然后随着时间的推移缓慢但稳定地增加。 / p>
我已经检查了keras predict memory swap increase indefinitely,Keras: Out of memory when doing hyper parameter grid search和Keras (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
答案 0 :(得分:3)
因为在使用 model.fit() 等内置函数时 TensorFlow 2.4.1 似乎仍然存在内存泄漏 > 这是我的看法。
问题
解决方案
run_eagerly=True
参数添加到 model.compile()
函数。但是,这样做可能会导致 TensorFlow 的图形优化不再起作用,从而导致性能下降 (reference)。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 提供链接。
注意事项
tcmalloc
代替默认的 malloc
分配器在一定程度上缓解了内存泄漏。如需参考,请参阅 here 或 here。我希望这也能帮助其他人,并为您节省一些在互联网上进行研究的时间。
答案 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/}/
方法时就可以了。
我认为他们尚未解决此问题,因此我将避免使用内置的训练/评估/预测方法。