作为GPU实现的一部分,我该怎么做才能在CPU上运行特定的TensorFlow计算?

时间:2016-05-19 15:09:00

标签: memory-management out-of-memory gpu 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.

某些特定操作偶尔崩溃,例如

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

显然无法扩展。

有更好的方法吗?具体做法是:

  • 有没有办法在CPU上进行如上所述的计算,并且仍然可以在GPU上运行相同图形(例如训练)的计算?

或者

  • 在这种情况下是否有更容易应用的成语(如批处理)以减少此类计算的内存需求?

实际上,我很惊讶后者不是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()

2 个答案:

答案 0 :(得分:5)

简答: 你可以拆分计算,但是你需要考虑正确的方法。 此外,较小的批次是一个合理的习惯,在这里思考。

答案很长:

异构放置是可能的,但我认为它比你让它更容易参与。请考虑以下(抽象,简化)设置:

setup

这里的问题是评估此网络所需的所有张量都不适合我们的G​​PU。不幸的是,它并不像“识别产生错误的特定代码块”那么简单,因为内存分配问题通常是一个总体问题。 I.E.,这些错误只是总数太大时的一个症状,并不表示特定的分​​配太大 - 你只是看到了打破骆驼背部的稻草,可以这么说。

正如您所指出的,我们希望在GPU上运行计算以获得更好的吞吐量,但随意分配将会在PCI接口上移动大量数据,从而丢掉我们可能获得的任何性能提升:

partitions

在左分区方案中,我们通过界面移动的数据远少于右边的数据。

除了有无数种其他方法可以对计算图进行分区以实现不同的平衡...

Other partitions

并且每个都在性能方面表现不同。这就是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)