oro*_*ome 3 memory-management gpu out-of-memory tensorflow
我对如何有效地将TensorFlow操作和变量分配给设备感到困惑。显然,至少对于我的基本卷积神经网络的实现而言,在GPU上放置尽可能多的操作是可取的。但是我目前可以访问的GPU的内存有限,并导致出现许多形式的警告
Ran out of memory trying to allocate 2.60GiB. The caller indicates that this is not a failure, but may mean that there could be performance gains if more memory is available.
某些特定操作偶尔会崩溃,例如
Run Code Online (Sandbox Code Playgroud)Ran out of memory trying to allocate 83.74MiB. See logs for memory state. Resource exhausted: OOM when allocating tensor with shape[28000,1,28,28]
可以通过在CPU上放置变量来避免这些情况,但是在我的实现中,这导致训练时期需要10倍的计算时间。
显然,理想的策略是识别出会产生错误的特定代码块,并尝试仅将这些代码放置在CPU上。但是我不清楚如何执行此操作,因为这些计算无法与需要GPU放置才能实现效率的计算隔离开来。
例如,只需使用以下内容在测试集上生成预测
evals = sess.run(tf.argmax(y, 1), feed_dict={x: use_x_all})
Run Code Online (Sandbox Code Playgroud)
当x是tf.placeholder我的模型的输入,并且y是我的网络的输出激活时,当use_x_all数组很大时(在此处带有28000示例)会产生上述错误。尝试将这种计算单独放在CPU上失败,这可能是因为网络评估产生y在GPU上。
因此,我(似乎)需要诉诸诸如
use_x_all, _ = data_loader.stack_data(use_data, as_cols=False)
use_x_split = np.split(use_x_all, splits)
for use_x in use_x_split:
# ... (full example below)
evals_part = sess.run(tf.argmax(y, 1), feed_dict={x: use_x})
# accumulate evals
Run Code Online (Sandbox Code Playgroud)
这显然无法扩展。
有没有更好的办法?特别:
或者
实际上,令我惊讶的是后者不是TensorFlow API的一部分。不需要上面的代码就可以自动分解不适合设备的计算吗?
我的代码中的完整示例:
f = open('{0:s}/{1:s}_{2:3.0f}.csv'.format(FLAGS.pred_dir, FLAGS.session_name,
10000*float(sess.run(accuracy, feed_dict=valid_feed))), 'w')
f.write('ImageId,Label\n')
use_x_all, _ = data_loader.stack_data(use_data, as_cols=False)
use_x_split = np.split(use_x_all, splits)
last = 0
buff = ''
for use_x in use_x_split:
evals = sess.run(tf.argmax(y, 1), feed_dict={x: use_x})
f.write('\n'.join('{0},{1}'.format(r[0]+ last, r[1]) for r in enumerate(evals, start=1)))
last += int(len(use_x_all)/splits)
if last < len(use_x_all):
f.write('\n')
f.close()
Run Code Online (Sandbox Code Playgroud)
简短的答案: 您可以拆分计算,但是您需要考虑正确的方法。同样,小批量生产是在这里考虑的合理习惯。
长答案:
可以进行异构放置,但是我认为这比您所允许的要复杂得多。考虑以下(抽象,简化)设置:
这里的问题是,评估该网络所需的所有张量都无法适合我们的GPU。不幸的是,由于内存分配问题通常是一个总的问题,所以它并不像“识别产生错误的特定代码块”那样简单。IE,这些错误只是总和过大的一种征兆,而不是表明特定分配过大的征兆-可以这么说,您只是看到一根破草的骆驼。
正如您所指出的那样,我们希望在GPU上运行计算以提高吞吐量,但是随意分配会在PCI接口上移动大量数据,从而浪费了我们将获得的任何性能提升:
在左侧的分区方案中,我们在接口上移动的数据比右侧的少得多。
除了可以通过多种其他方式划分计算图以实现不同的余额外...
而且每一项在性能方面都会有所不同。这就是为什么TF不会自动对图形进行分区的原因。在一般情况下,这实际上不是一个简单的问题。
分区计算技巧
回到具体的问题。您的方法(小批量)是一种可行的方法。如果有效地缩小了所有分配请求的大小。正如其他人建议的那样,对它进行分区可能也是可行的方法,但是您应该明智地进行此操作。尝试最小化设备间的内存移动,并尝试将计算密集的图形(如大卷积层)放置在同一设备上。
一种有用的策略可能是(手动或使用张量板)计算图形中不同部分的张量大小。这应该使您感觉到网络之间有多大相对关系。反过来,这为如何对其进行分区提供了合理的指导。
最后,如果您仅进行推理(不进行任何训练),则另一种解决方案是一次仅评估某些网络。这是使用较小批处理的一种双重方法:您可以使用一些具有几个大批处理的小型网络,而不是使用具有许多小批处理的大型网络。