【发布时间】:2018-01-25 08:08:37
【问题描述】:
我正在使用 Tensorflow 评估不同的图像分类模型,特别是使用不同设备的推理时间。 我想知道是否必须使用预训练模型。 我正在使用一个脚本生成 1000 个随机输入图像,将它们 1 个 1 个输入网络,并计算平均推理时间。
谢谢!
【问题讨论】:
标签: tensorflow evaluation inference
我正在使用 Tensorflow 评估不同的图像分类模型,特别是使用不同设备的推理时间。 我想知道是否必须使用预训练模型。 我正在使用一个脚本生成 1000 个随机输入图像,将它们 1 个 1 个输入网络,并计算平均推理时间。
谢谢!
【问题讨论】:
标签: tensorflow evaluation inference
让我从一个警告开始:
大多数人以错误的方式对神经网络进行适当的基准测试。对于 GPU,有磁盘 I/O、内存带宽、PCI 带宽和 GPU 速度本身。然后是在 TensorFlow 中使用 feed_dict 之类的实现错误。对于这些模型的有效训练也是如此。
让我们从一个考虑 GPU 的简单示例开始
import tensorflow as tf
import numpy as np
data = np.arange(9 * 1).reshape(1, 9).astype(np.float32)
data = tf.constant(data, name='data')
activation = tf.layers.dense(data, 10, name='fc')
with tf.Session(config=tf.ConfigProto(log_device_placement=True)) as sess:
sess.run(tf.global_variables_initializer())
print sess.run(activation)
它所做的只是创建一个 const 张量并应用一个全连接层。 所有操作都放在GPU上:
fc/bias: (VariableV2): /job:localhost/replica:0/task:0/device:GPU:0
2018-01-25 09:55:01.587959: I tensorflow/core/common_runtime/placer.cc:874] fc/bias: (VariableV2)/job:localhost/replica:0/task:0/device:GPU:0
fc/bias/read: (Identity): /job:localhost/replica:0/task:0/device:GPU:0
2018-01-25 09:55:01.587970: I tensorflow/core/common_runtime/placer.cc:874] fc/bias/read: (Identity)/job:localhost/replica:0/task:0/device:GPU:0
fc/bias/Assign: (Assign): /job:localhost/replica:0/task:0/device:GPU:0
2018-01-25 09:55:01.587979: I tensorflow/core/common_runtime/placer.cc:874] fc/bias/Assign: (Assign)/job:localhost/replica:0/task:0/device:GPU:0
fc/kernel: (VariableV2): /job:localhost/replica:0/task:0/device:GPU:0
2018-01-25 09:55:01.587988: I tensorflow/core/common_runtime/placer.cc:874] fc/kernel: (VariableV2)/job:localhost/replica:0/task:0/device:GPU:0
fc/kernel/read: (Identity): /job:localhost/replica:0/task:0/device:GPU:0
...
看起来不错,对吧?
对该图进行基准测试可能会粗略估计 TensorFlow 图的执行速度。只需将tf.layers.dense 替换为您的网络即可。如果你接受使用 pythons time 包的开销,你就完成了。
但不幸的是,这并不是故事的全部。
从 tensor-op 'fc/BiasAdd:0' 访问设备内存 (GPU) 并复制到主机内存 (CPU、RAM) 将结果复制回来。
因此,在某些时候存在 PCI 带宽限制。还有一个 python 解释器坐在某个地方,占用 CPU 周期。
此外,操作放置在 GPU 上,而不需要 值 本身。不确定,您使用的是哪个 TF 版本。但即使是tf.const 也不能保证在旧版本中放置在 GPU 上。我只有在编写自己的 Ops 时才注意到这一点。顺便说一句:在how TF decides where to place operations 上查看我的其他答案。
现在,最难的部分是:这取决于您的图表。将tf.cond/tf.where 放在某个地方会使事情更难进行基准测试。现在,您需要经历在有效训练深度网络时需要解决的所有这些难题。意思是,一个简单的 const 不能解决所有情况。
解决方案首先通过运行将/staging一些值直接放入GPU内存
stager = data_flow_ops.StagingArea([tf.float32])
enqeue_op = stager.put([dummy])
dequeue_op = tf.reduce_sum(stager.get())
for i in range(1000):
sess.run(enqeue_op)
事先。但同样,TF 资源管理器正在决定将值放在哪里(并且不能保证排序或删除/保留值)。
总结一下:基准测试是一项非常复杂的任务,因为基准测试 CUDA 代码很复杂。现在,你有了 CUDA 和另外的 python 部分。 这是一项非常主观的任务,取决于您对哪些部分感兴趣(只是图表,包括磁盘 i/o,...)
我通常使用tf.const 输入运行图表,如示例中所示,并使用profiler 查看图表中发生的情况。
有关如何提高运行时性能的一些一般性想法,您可能需要阅读 Tensorflow Performance Guide
【讨论】:
tensorflow 上进行推理的最佳实践是什么? [我在 tensorflow 文档中读到 feed_dict 很慢,应该只用于开发建议。我正在寻找一种进行快速推理的方法(可以排队 - 虽然 tensorflow 说使用 tf.data 但它似乎只对训练有用?)]
所以,澄清一下,您只对每个推理步骤的运行时间感兴趣,而不对准确性或任何与 ML 相关的性能指标感兴趣?
在这种情况下,如果您从预训练的检查点初始化您的模型,或者只是通过分配给图中每个变量的给定初始化程序(例如 truncated_normal 或常量)从头开始初始化模型,这无关紧要。
基本的数学运算将是相同的,主要是矩阵乘法运算,对于他们来说,执行基本的加法和乘法运算的值并不重要。
这可能有点不同,如果您的图表包含一些更高级的控制流结构,例如 tf.while_loop,这些结构可以根据某些张量的值影响图表的实际大小。
当然,在程序执行之初初始化图表所需的时间会有所不同,具体取决于您是从头开始初始化还是从检查点初始化。
希望这会有所帮助。
【讨论】: