Python 为什么在批量预测时,Tensorflow(和Keras)的每样本预测时间低于单个样本?
我正在使用我训练过的模型进行预测(仅限CPU)。我观察到,在Tensorflow和Keras上,使用Tensorflow后端时,与单个样本相比,使用一批样本时,每个样本的预测时间要少得多。此外,每个样本的时间似乎随着批量大小的增加而减少,直至达到内存施加的限制。例如,在纯Tensorflow上,单个样本的预测时间约为1.5秒,100个样本的预测时间约为17秒(每个样本时间约为0.17s),1000个样本的预测时间约为93秒(每个样本时间约为0.093s) 这是正常的行为吗?如果是,有没有直观的解释?我想这可能与初始化图形有关,但我需要一些澄清。另外,为什么随着预测样本数量的增加,每个样本的时间会下降?在我的用例中,我必须预测单个样本何时可用。所以,很明显,如果这是工作方式的话,我会在速度方面损失很多 提前感谢你的帮助 编辑:我正在添加一个最小的工作示例。我的模型有一个图像输入和4个向量输入,产生4个输出。我正在为速度测试将所有输入初始化为0(我想实际值对速度没有多大影响?)。初始化时间和推理时间分别计算。我发现初始化时间只是推断时间的一小部分(100个样本约0.1s)Python 为什么在批量预测时,Tensorflow(和Keras)的每样本预测时间低于单个样本?,python,performance,tensorflow,keras,runtime,Python,Performance,Tensorflow,Keras,Runtime,我正在使用我训练过的模型进行预测(仅限CPU)。我观察到,在Tensorflow和Keras上,使用Tensorflow后端时,与单个样本相比,使用一批样本时,每个样本的预测时间要少得多。此外,每个样本的时间似乎随着批量大小的增加而减少,直至达到内存施加的限制。例如,在纯Tensorflow上,单个样本的预测时间约为1.5秒,100个样本的预测时间约为17秒(每个样本时间约为0.17s),1000个样本的预测时间约为93秒(每个样本时间约为0.093s) 这是正常的行为吗?如果是,有没有直观的解
是的,这完全正常。这是因为当您在GPU(甚至多核CPU)上进行推理时,增加批处理大小可以更好地使用GPU并行计算资源,从而减少批处理中每个样本的时间。如果使用小批量,则会浪费GPU中可用的计算资源
描述了相同的效果,其中一个图包含一个图,显示了每个图像的推断时间与批量大小的关系。它显示的效果与您看到的效果相同。是的,这完全正常。这是因为当您在GPU(甚至多核CPU)上进行推理时,增加批处理大小可以更好地使用GPU并行计算资源,从而减少批处理中每个样本的时间。如果使用小批量,则会浪费GPU中可用的计算资源
描述了相同的效果,其中一个图包含一个图,显示了每个图像的推断时间与批量大小的关系。它显示了与您所看到的相同的效果。这在很大程度上取决于模型检测、部署方法和接口——您没有提供,甚至没有描述这些。在我的实践中,常见的原因包括:
- 模型初始化时间:您是否以某种方式为每个批次“唤醒”模型?如果,正如您所建议的,您为每个请求重新初始化了模型,那么我有点惊讶于开销并没有占您时间的更大比例
- 接口开销:示例如何进入/离开模型?这是在HTTP请求中吗?在HTTP请求中,每个请求而不是每个示例都会产生通信成本
- 简单模型I/O时间:如果您的模型一次读取整个批,那么打开和访问输入通道的延迟时间可能是延迟的主要因素
这些调查的结果将告诉您从使用模型的设计更改中可以获得什么好处。这在很大程度上取决于模型工具、部署方法和接口——您没有提供,甚至没有描述这些。在我的实践中,常见的原因包括:
- 模型初始化时间:您是否以某种方式为每个批次“唤醒”模型?如果,正如您所建议的,您为每个请求重新初始化了模型,那么我有点惊讶于开销并没有占您时间的更大比例
- 接口开销:示例如何进入/离开模型?这是在HTTP请求中吗?在HTTP请求中,每个请求而不是每个示例都会产生通信成本
- 简单模型I/O时间:如果您的模型一次读取整个批,那么打开和访问输入通道的延迟时间可能是延迟的主要因素
这些调查的结果将向您展示如何从使用模型的设计更改中获益。但我仅使用CPU进行推断,尽管该模型是用GPU训练的。我猜你所说的也适用于CPU推断?不过,论文中显示的图表非常有用,谢谢您的参考。@user6240174是的,它也适用于多核CPU,但我只使用CPU
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import time
import numpy as np
import tensorflow as tf
t00=time.time()
graph = tf.Graph()
graph_def = tf.GraphDef()
with open("output_graph.pb", "rb") as f:
graph_def.ParseFromString(f.read())
with graph.as_default():
tf.import_graph_def(graph_def)
# One image and 4 auxiliary scalar inputs
img_input_layer ="input"
qp4_input_layer ="qp4"
qp3_input_layer ="qp3"
qp2_input_layer ="qp2"
qp1_input_layer ="qp1"
input_name = "import/" + img_input_layer
qp4_input_name = "import/" + qp4_input_layer
qp3_input_name = "import/" + qp3_input_layer
qp2_input_name = "import/" + qp2_input_layer
qp1_input_name = "import/" + qp1_input_layer
input_operation_img = graph.get_operation_by_name(input_name)
input_operation_qp4 = graph.get_operation_by_name(qp4_input_name)
input_operation_qp3 = graph.get_operation_by_name(qp3_input_name)
input_operation_qp2 = graph.get_operation_by_name(qp2_input_name)
input_operation_qp1 = graph.get_operation_by_name(qp1_input_name)
output_operation=[]
for i in range(4):
output_operation.append(graph.get_operation_by_name("import/" + "output_"+str(i)).outputs)
#Initializing dummy inputs
n=100 # Number of samples for inference
img=np.zeros([n,64, 64,1])
qp4=np.zeros([n,1, 1,1])
qp3=np.zeros([n,2, 2,1])
qp2=np.zeros([n,4, 4,1])
qp1=np.zeros([n,8, 8,1])
t01=time.time()
print("Iniialization time",t01-t00)
t0=time.time()
with tf.Session(graph=graph) as sess:
results = sess.run(output_operation,
{input_operation_img.outputs[0]: img, input_operation_qp4.outputs[0]: qp4, input_operation_qp3.outputs[0]: qp3, input_operation_qp2.outputs[0]: qp2, input_operation_qp1.outputs[0]: qp1})
# print(results)
t1 = time.time()
print("Inference time", t1-t0)