首页 > 解决方案 > 为什么放在 GPU 上的操作也会在 CPU 上执行(tensorflow)?

问题描述

我使用 tensorflow 分析器来分析我的模型,以查看每个操作消耗了多少时间。我发现一些奇怪的行为,例如,Conv2D放置在 GPU 上的操作(我设置log_device_placement=True查看放置)也有很大的 CPU 执行时间。这是我用来进行分析的代码(tensorflow 1.4.0):

import tensorflow as tf
from tensorflow.python.profiler import option_builder

builder = option_builder.ProfileOptionBuilder
run_options = tf.RunOptions(trace_level=tf.RunOptions.FULL_TRACE)
run_metadata = tf.RunMetadata()
# run and collect metadata
my_session.run(fetch_something, feed_dict=feed_dict, 
  options=run_options, run_metadata=run_metadata)
profiler_opts = builder(builder.time_and_memory()).order_by('micros').build()
# this will output the following results
tf.profiler.profile(my_graph, run_meta=run_metadata, cmd='scope', options=profiler_opts)

这是分析器的输出:

node name | requested bytes | total execution time | accelerator execution time | cpu execution time
MyScope/Conv2D (4511.35MB/4511.35MB, 823.47ms/823.47ms, 445.37ms/445.37ms, 378.11ms/378.11ms)

从分析结果来看,Conv2D操作 ( tf.nn.conv2d) 在 CPU 上耗时 378.11ms,在 GPU 上耗时 445.37ms。为什么 tensorflow 不只使用 GPU Conv2D?内存和GPU之间数据传输的CPU时间是因为这个操作占用了大量内存(4511.35MB)吗?

========更新========

我刚刚发现的另一个现象。当“请求的字节数”Conv2D很大时(在我的情况下> 4GB),CPU执行时间很长(大约400~500ms)。当“请求的字节”很小(在我的情况下为 1.5GB)时,CPU 执行时间很短(大约 15ms)。我猜CPU执行时间Conv2D与内存消耗有关。但是我不知道为什么在不同的批次(my_session.run)中,Conv2D使用不同数量的“请求的字节”。应用的张量在Conv2D不同批次中具有几乎相同的大小。

标签: pythontensorflowprofiler

解决方案


虽然我没有看到你的整个图表,但我假设你feed_dict不断地提供数据。
因此,每次评估张量时,它们都会获取基础数据集中下一个元素的值。这也需要CPU的时间。如果您有足够的数据通过对象在其中保存数据,则可以直接从GPU内存提供数据,请参阅文档tf.Tensor

如果所有输入数据都适合内存,那么从它们创建数据集的最简单方法是将它们转换为 tf.Tensor 对象并使用 Dataset.from_tensor_slices()。

来自tensorflow 文档相应部分的示例:

# Load the training data into two NumPy arrays, for example using `np.load()`.
with np.load("/var/data/training_data.npy") as data:
  features = data["features"]
  labels = data["labels"]

# Assume that each row of `features` corresponds to the same row as `labels`.
assert features.shape[0] == labels.shape[0]

dataset = tf.data.Dataset.from_tensor_slices((features, labels))

请注意,上面的代码片段会将特征和标签数组作为 tf.constant() 操作嵌入到您的 TensorFlow 图中。这适用于小型数据集,但会浪费内存——因为数组的内容将被复制多次——并且可能会遇到 tf.GraphDef 协议缓冲区的 2GB 限制。

但这种情况并非如此。因此,根据您提供的信息,我认为 CPU 消耗主要是(或完全)由于该图的下一个输入的数据馈送操作。


推荐阅读