Memory management 作为GPU实现的一部分,如何在CPU上运行特定的TensorFlow计算?

Memory management 作为GPU实现的一部分,如何在CPU上运行特定的TensorFlow计算?,memory-management,out-of-memory,gpu,tensorflow,Memory Management,Out Of Memory,Gpu,Tensorflow,我对如何有效地将TensorFlow操作和变量分配给设备感到困惑。很明显,至少对于我的基本卷积神经网络的实现,在GPU上放置尽可能多的操作是可取的。但是我目前可以访问的GPU内存有限,并导致许多表单警告 尝试分配2.60GiB时内存不足。调用者指出这不是故障,但可能意味着如果有更多内存可用,性能可能会提高。 以及某些特定操作的偶尔崩溃,如 通过在CPU上放置变量可以避免这些问题,但在我的实现中,这会导致训练周期的计算时间是原来的10倍 显然,理想的策略是识别产生错误的特定代码块,并尝试仅将这些代

我对如何有效地将TensorFlow操作和变量分配给设备感到困惑。很明显,至少对于我的基本卷积神经网络的实现,在GPU上放置尽可能多的操作是可取的。但是我目前可以访问的GPU内存有限,并导致许多表单警告

尝试分配2.60GiB时内存不足。调用者指出这不是故障,但可能意味着如果有更多内存可用,性能可能会提高。

以及某些特定操作的偶尔崩溃,如

通过在CPU上放置变量可以避免这些问题,但在我的实现中,这会导致训练周期的计算时间是原来的10倍

显然,理想的策略是识别产生错误的特定代码块,并尝试仅将这些代码块放在CPU上。但我不清楚如何做到这一点,因为这些计算不能与其他需要GPU布局才能实现效率的计算隔离开来

例如,简单地在测试集上生成预测

evals = sess.run(tf.argmax(y, 1), feed_dict={x: use_x_all})
其中,
x
是我的模型输入的
tf.占位符,
y
是我的网络的输出激活,当
use\u x\u 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的一部分。难道不可能在不需要上述代码的情况下,在设备上安装不合适的代码吗


我的代码的完整示例:

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()
f=open({0:s}/{1:s}{2:3.0f}.csv')。格式(FLAGS.pred_dir,FLAGS.session_name,
10000*float(sess.run(精度、进给量=有效进给量)),w)
f、 写入('ImageId,Label\n')
使用_x_uall,u=data\u loader.stack_data(使用_data,因为_cols=False)
use_x_split=np.split(use_x_all,splits)
最后一个=0
buff=“”
对于使用中的使用中的使用:
evals=sess.run(tf.argmax(y,1),feed_dict={x:use_x})
f、 在枚举(evals,start=1)中为r写入('\n'.join('{0},{1}).格式(r[0]+last,r[1]))
最后+=int(len(使用x_全部)/拆分)
如果最后一个
有没有一种方法可以将上面的计算放在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)

简短回答: 您可以拆分计算,但需要考虑一下正确的方法。 此外,在这里考虑小批量也是一个合理的习惯用法

长答案:

异构布局是可能的,但我认为这比你透露的要复杂得多。考虑下面的(抽象的,简化的)设置:

这里的问题是,评估该网络所需的所有张量都不适合我们的GPU。不幸的是,它不像“识别产生错误的特定代码块”那么简单,因为内存分配问题通常是一个聚合问题。也就是说,这些错误只是总数过大时的一种症状,而不是某一特定分配过大的迹象——可以说,你只是看到压垮骆驼背的稻草

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

在左侧分区方案中,我们在接口上移动的数据远远少于右侧

除了有无数的其他方法可以划分计算图以实现不同的平衡之外

在性能方面,每一个都将表现不同。这就是TF不自动划分图形的原因。在一般情况下,这实际上不是一个简单的问题

分区计算提示

回到具体的问题上来。您的方法(小批量)是一种可行的方法。If有效地缩小了所有分配请求的大小。正如其他人所建议的那样,分区也可能是一种可行的方法,但您应该明智地进行。尝试最小化设备间内存移动,并尝试将计算密集的图形块(如一块卷积层)放在同一设备上

一个有用的策略可能是计算(手动或使用tensorboard)图形不同部分中张量的大小。这应该会让您感觉到网络的各个部分之间的相对大小。这反过来为如何划分它提供了合理的指导


最后,如果您只进行推理(不进行培训),另一种解决方案是一次只评估部分网络。这是一种使用小批量的双重方法:您可以使用几个小网络和几个大批量,而不是一个包含许多小批量的大网络。

也可以作为TensorFlow进行提问。不,正如问题中所述,问题是图形
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)