Tensorflow内存溢出问题

Tensorflow.jpg

本文总结了Tensorflow内存溢出的各种原因,以及在此排查过程中使用的方法。
本文在实现Tensorflow模型的保存(save)和重新调用(restore)过程中,程序总是发生内存溢出而中止的问题,所以对其进行故障排查。

排查工具及步骤

1. Tensorboard

Tensorboard是Tensorflow提供的向用户展示模型结构以及运行结果等的可视化工具。当Tensorflow相关程序发生内存溢出,并且确认程序所使用的数据量并不大时,首先想到使用Tensorboard对模型结构进行可视化,在此之前,需要对模型中的各个变量(variable, placeholder)、节点(nodes)、以及节点域进行命名,从而方便可视化后对模型各个部分的辨别和故障排查。例如:

import tensorflow as tf
with tf.name_scope('Input'):
    batchX_placeholder = tf.placeholder(tf.float32, [input_size, look_back], name='Input_Placeholder')
    batchY_placeholder = tf.placeholder(tf.float32, [output_size, look_back], name='Output_Placeholder')

这段代码对应在Tensorboard中如下图所示:


input nodes.png

类似地,搭建出整个模型的结构图之后,通过如下代码将图保存在文件当中,之后就可以通过tensorboard --logdir=filedir --host=127.0.0.1运行Tensorboard,并使用浏览器打开。

train_writer = tf.summary.FileWriter('graph', sess.graph)  # save the graph

完成以上步骤后,进行核对,发现graph的结构会随着程序运行逐渐变大,原因在于在生成新的结构时,没有将之前的结构删去,于是,通过如下代码,每次生成新的图时,将之前的结构重置(删去):

tf.reset_default_graph()  # reset the previous graph and nodes

结果:Graph不再随着新的模型声明而积累旧的结构,内存溢出问题得到缓解,但并没有完全解决。

2. 内存监视

在查找了程序书写结构上的问题之后,没有什么头绪,于是尝试监视内存查看程序运行问题。

import psutil
def memory_monitor():
# https://github.com/giampaolo/psutil
# 1. virtual_memory():
#   total: total physical memory.
#   available: the memory that can be given instantly to processes without the system going into swap.
#              This is calculated by summing different memory values depending on the platform and it
#               is supposed to be used to monitor actual memory usage in a cross platform fashion.
# 2. swap_memory():
#   total: total swap memory in bytes
#   used: used swap memory in bytes
    print psutil.virtual_memory()
    print psutil.swap_memory()

将该函数插入到想要查看当前内存使用情况的位置,但是没有任何发现。

3. 给Tensorflow结构分配给不同的GPU

因为之前Tensorflow的结构是使用CPU进行运行,猜想如果将Tensorflow运算分配给不同的GPU,是否可以解决内存溢出的问题。

分配GPU和CPU的原则是,并行结构和运算分配给不同的GPU,主线运算分配给CPU。


tensorboard-gpu.png

如图所示,可以通过打开Tensorboard中的Device开关,可以在Graph中不同结构标识不同的device。

同样的,内存溢出的问题并没有得到解决。

4. 查看不同变量类型的增长情况以及调用结构

为了进一步查找导致内存溢出的增长源,采用python的gc模块对程序运行过程中的不同变量类型的增长情况以及调用结构进行分析。代码如下:

import objgraph
objgraph.show_growth()  # show the growth of the objects
objgraph.show_refs(variableName, filename='graph.png')  # show the reference structure of the variable

通过将show_growth()放置在程序单次循环的末尾,以及查看每次循环所带来的变量类型的增长情况进行分析,发现在Tensorflow模型的训练以及预测过程中,Tensor类型的变量数在不断增加,这就是导致内存溢出的关键。

其间,使用了gc.collect()对垃圾进行手动回收,但是没有解决问题。

虽然程序已经包含了之前的tf.reset_default_graph,但是变量数却在增加,这点非常奇怪。为了进一步排除问题的可能性,重新声明一个新的测试类,只包含了模型的声明,测试类的结构和调用方式仿照存在内存溢出问题的类,如下所示:

class testClass(object):
    def __init__(self):
        pass
    def test1(self, CF):
        print '------------------------'
        objgraph.show_growth()
        tf.reset_default_graph()
        '''Establish the model'''
        sess = tf.InteractiveSession()
        sess.run(tf.global_variables_initializer())
        sess.close()
        objgraph.show_growth()

    def test2(self, CF):
        print '------------------------'
        objgraph.show_growth()
        tf.reset_default_graph()
        '''Establish the model'''
        sess = tf.InteractiveSession()
        sess.run(tf.global_variables_initializer())
        sess.close()
        objgraph.show_growth()

经过测试发现,sess虽然是局部变量,但是如果不对sess进行close操作,那么之前所有的graph, nodes, variables等等Tensor将会全部被保留下来,(尽管已经完成了reset_default_graph),找到了根源之后,添加close操作,再通过show_growth可以观察到,在重复调用test1和test2时,内存不会产生之前无用的消耗和溢出。

至此,完成了对tensorflow内存溢出问题的排查和调试。

总结:

出现内存溢出问题,可能的原因有很多种,对于机器学习程序,从数据和模型两方面进行入手,首先确认数据的处理、调用等是否存在内存溢出的问题,这部分可以通过objgraph模块内的相关函数对其进行调试和排查;其次需要对Tensorflow的模型进行核查,是否存在旧的节点和图未删去、Session使用后未关闭等问题。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,816评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,729评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,300评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,780评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,890评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,084评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,151评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,912评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,355评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,666评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,809评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,504评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,150评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,121评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,628评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,724评论 2 351

推荐阅读更多精彩内容