Tensorflow - 推理时间评估

Tensorflow - Inference time evaluation

我正在使用 Tensorflow 评估不同的图像分类模型,特别是使用不同设备的推理时间。 我想知道我是否必须使用预训练模型。 我正在使用生成 1000 个随机输入图像的脚本,将它们一张一张地馈送到网络,并计算平均推理时间。

谢谢!

所以,澄清一下,您只对每个推理步骤的运行时间感兴趣,而不对准确性或任何 ML 相关的性能指标感兴趣?

在这种情况下,无论是从预训练检查点初始化模型,还是通过分配给图中每个变量的给定初始化器(例如 truncated_normal 或常量)从头开始初始化模型,都没有太大关系。

底层的数学运算将是相同的,主要是矩阵乘法运算,对于那些执行底层加法和乘法运算的值并不重要(很多)。

如果您的图形包含一些更高级的控制流结构,例如 tf.while_loop,这可能会有所不同,这些结构可能会根据某些张量的值影响图形的实际大小。

当然,在程序执行一开始初始化图形所需的时间会有所不同,具体取决于您是从头开始还是从检查点进行初始化。

希望对您有所帮助。

让我先警告一下:

大多数人以错误的方式完成了神经网络的正确基准测试。对于 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)

它所做的只是创建一个常量张量并应用一个全连接层。 所有操作都放在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 包的开销,您就完成了。

但不幸的是,这并不是故事的全部。 从张量运算 'fc/BiasAdd:0' 访问设备内存 (GPU) 并将结果复制回主机内存(CPU、RAM)。 因此在某些时候存在 PCI 带宽限制。还有一个 python 口译员也在某处坐着,需要 CPU 个周期。

此外,操作放置在GPU上,本身不是必需的。不确定,您使用的是哪个 TF 版本。但即使是 tf.const 也不能保证在旧版本中放置在 GPU 上。我只在编写自己的 Ops 时才注意到这一点。顺便说一句:请参阅我在 .

上的其他回答

现在,困难的部分是:这取决于您的图表。让 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 资源管理器正在决定它把值放在哪里(并且不能保证排序或 dropping/keeping 值)。

总结一下:基准测试是一项非常复杂的任务,因为基准测试 CUDA 代码很复杂。现在,您拥有 CUDA 和 python 部分。 而且这是一个非常主观的任务,取决于你对哪些部分感兴趣(只是图表,包括磁盘 i/o, ...)

我通常 运行 图表中带有 tf.const 输入,并使用 profiler 查看图表中的情况。

有关如何提高 运行时间性能的一些一般性想法,您可能需要阅读 Tensorflow Performance Guide