python - 为什么放在 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
不同批次中具有几乎相同的大小。
解决方案
虽然我没有看到你的整个图表,但我假设你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 消耗主要是(或完全)由于该图的下一个输入的数据馈送操作。
推荐阅读
- c# - 增加 .net core 3.1 中的令牌寿命
- c - 错误:下标值不是数组、指针或向量
- eclipse - CLI:用 Eclipse 比较两个文件?
- typescript - Vue 3 Typescript 类组件 - 类型 'typeof import(.../node_modules/vue/dist/vue")' 不是构造函数类型
- laravel - Laravel Forge + Laravel-echo-server + Let's Encrypt:如何避免 ERR_CERT_DATE_INVALID
- php - PHP - array_push 创建多维数组
- ruby-on-rails - 通过 docker 容器上的 FFI 调用 C 方法时出现分段错误
- keycloak - Keycloak RestAPI:将客户端角色分配给组
- python - 带有列表理解的 Pandas DataFrame 条件选择
- python - 将列表与 Python 中的字符串进行比较并突出显示匹配项