我很困惑如何有效地将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.
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})
其中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
显然无法扩展。
有更好的方法吗?具体做法是:
或者
实际上,我很惊讶后者不是TensorFlow API的一部分。在不需要上述代码的情况下,不应该automatically break up calculations不适合设备吗?
我的代码中的完整示例:
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()
答案 0 :(得分:5)
简答: 你可以拆分计算,但是你需要考虑正确的方法。 此外,较小的批次是一个合理的习惯,在这里思考。
答案很长:
异构放置是可能的,但我认为它比你让它更容易参与。请考虑以下(抽象,简化)设置:
这里的问题是评估此网络所需的所有张量都不适合我们的GPU。不幸的是,它并不像“识别产生错误的特定代码块”那么简单,因为内存分配问题通常是一个总体问题。 I.E.,这些错误只是总数太大时的一个症状,并不表示特定的分配太大 - 你只是看到了打破骆驼背部的稻草,可以这么说。
正如您所指出的,我们希望在GPU上运行计算以获得更好的吞吐量,但随意分配将会在PCI接口上移动大量数据,从而丢掉我们可能获得的任何性能提升:
在左分区方案中,我们通过界面移动的数据远少于右边的数据。
除了有无数种其他方法可以对计算图进行分区以实现不同的平衡...
并且每个都在性能方面表现不同。这就是TF不对图表进行自动分区的原因。在一般情况下,这实际上不是一个简单的问题。
分区计算提示
具体回到你的问题。您的方法(较小的批次)是一种可行的方法。如果有效地缩小了所有分配请求的大小。如其他人所建议的那样对它进行分区也可能是一种可行的方法,但你应该聪明地做。尝试最小化设备间内存移动,并尝试将计算密集的图形片段(如一大块卷积层)放在同一设备上。
一个有用的策略可能是计算(通过手动或使用张量板)图表不同部分中张量的大小。这可以让您了解网络的大部分相对于彼此的情况。反过来,这为如何划分它提供了合理的指导。
最后,如果您只进行推理(无需培训),另一种解决方案是一次仅评估部分网络。这是使用较小批次的双重方法:您可以使用少量大批量的小型网络,而不是大批量的小型网络。
答案 1 :(得分:-1)
有没有办法在CPU上进行如上所述的计算,并且仍然可以在GPU上运行相同图形(例如训练)的计算?
您可以使用显式和嵌套设备放置。使用日志记录查看操作的放置位置。
config = tf.ConfigProto()
config.log_device_placement = True
s = tf.InteractiveSession(config=config)
with tf.device("/gpu:0"):
m = tf.matmul(tf.constant([[1,2,3,4]]), tf.constant([[1],[1],[1],[1]]))
with tf.device("/cpu:0"):
m = m + 1
s.run(m)