计算神经网络推理时间的正确方法

前言

 在网络部署这一块中,计算网络的推理时间是至关重要的一方面,但是,正确而有意义地测量神经网络的推理时间或延迟的任务,需要深刻的理解。即使是有经验的程序员也经常会犯一些常见的错误,这些错误会导致不准确的延迟度量。
 在这篇文章中,我们回顾了一些应该解决的主要问题,以便正确地测量延迟时间。我们回顾了使GPU执行独特的主要过程,包括异步执行和GPU预热。然后我们共享代码样本,以便在GPU上正确地测量时间。最后,我们回顾了在gpu上量化推理时间时人们常犯的一些错误。
 参考:The Correct Way to Measure Inference Time of Deep Neural Networks

异步执行

 我们从讨论GPU的执行机制开始。在多线程或多设备编程中,两个独立的代码块可以并行执行;这意味着第二个代码块可能比第一个代码块先执行完成。这个过程称为异步执行。在深度学习环境中,我们经常使用这种执行,因为默认情况下GPU操作是异步的。
在这里插入图片描述
 异步执行为深度学习提供了巨大的优势,比如可以大幅减少运行时间。例如,在多批推理时,可以在CPU上对第二个batches进行预处理,而第一个batches在GPU上forward。显然,在推理时尽可能使用异步将是有益的。
 异步执行的效果对用户是不可见的,但是,当涉及到时间测量时,它可能是许多头痛的原因。当您使用Python中的“time”库计算时间时,测量将在CPU设备上执行。由于GPU的异步特性,停止计时的代码会在GPU进程完成之前执行。结果,计算的时间并不是正确的推理时间。请记住,我们想要使用异步,在这篇文章的后面,我们将解释如何正确地度量时间,尽管有异步进程。

GPU warm-up

 现代GPU设备可以存在于几种不同的电源状态之一。当GPU不被用于任何目的,并且持久化模式(即保持GPU打开)不被启用时,GPU会自动将其电源状态降低到非常低的水平,有时甚至完全关闭。在低功耗状态下,GPU会关闭不同的硬件,包括内存子系统、内部子系统,甚至是计算核心和缓存。
 任何试图与GPU交互的程序的调用都会导致驱动加载和/或初始化GPU。这个驱动程序加载行为是值得注意的。触发GPU初始化的应用程序可能会产生高达3秒的延迟,这是由于错误纠正代码的擦洗行为。例如,如果我们测量网络推理时间,推理一个例子需要10毫秒,推理1000个例子可能会导致我们的大部分运行时间浪费在初始化GPU上。当然,我们不想测量这些影响因素,因为测量的时间并不准确。这不能反映GPU已经初始化或工作在持久化模式下的生产环境。
 下面,让我们看看如何在测量时间时克服GPU的初始化。

正确测量推理时间的方法

 下面时pytorch正确测量推理时间的代码块。这里我使用Efficient-net-b0网络,也可以使用其它任何网络。在代码中,我们处理上面描述的两个注意事项。在我们进行任何时间测量之前,我们通过网络运行一些虚拟的例子来做一个“GPU warm-up”。这将自动初始化GPU,并防止它进入节电模式时,当我们测量时间时。接下来,我们使用tr.cuda.event在GPU上测量时间,这里我们使用torch.cuda.synchronize()是至关重要的。这行代码执行主机和设备(即GPU和CPU)之间的同步,因此,只有在GPU上运行完进程后,才会进行时间记录。这克服了不同步执行的问题。

model = EfficientNet.from_pretrained(‘efficientnet-b0’)
device = torch.device(“cuda”)
model.to(device)
dummy_input = torch.randn(1, 3,224,224,dtype=torch.float).to(device)
starter, ender = torch.cuda.Event(enable_timing=True), torch.cuda.Event(enable_timing=True)
repetitions = 300
timings=np.zeros((repetitions,1))
#GPU-WARM-UP
for _ in range(10):
   _ = model(dummy_input)
# MEASURE PERFORMANCE
with torch.no_grad():
  for rep in range(repetitions):
     starter.record()
     _ = model(dummy_input)
     ender.record()
     # WAIT FOR GPU SYNC
     torch.cuda.synchronize()
     curr_time = starter.elapsed_time(ender)
     timings[rep] = curr_time
mean_syn = np.sum(timings) / repetitions
std_syn = np.std(timings)
print(mean_syn)

测量时间时常见的错误

 当我们计算网络的推理时间是,我们的目标是只计算前向推理的时间。通常,即使是专家,也会在他们的测量中犯某些常见的错误。下面是常见错误的举例:

  1. 测量包括了CPU和GPU之间的数据传输。这通常是在CPU上创建一个张量,然后在GPU上执行推理时无意中完成的。这个内存分配需要相当长的时间。这个错误对测量的平均值和方差的影响如下:
    在这里插入图片描述
  2. 没有使用GPU warm-up。如上所述,第一次在GPU上运行是会初始化。GPU初始化需要3秒。
  3. 使用标准的CPU计时。最常见的错误是在没有同步的情况下测量时间。甚至有经验的程序员也会使用下面的代码。当然,这完全忽略了前面提到的异步执行,因此输出了错误的时间。此错误对测量值均值和方差的影响如下:
    在这里插入图片描述
s = time.time()
 _ = model(dummy_input)
curr_time = (time.time()-s )*1000
  1. 只进行一次推理。与计算机科学中的许多过程一样,神经网络的前馈具有(小)随机成分。运行时的差异可能非常大,尤其是在测量低延迟网络时。为此,必须在多个示例中运行网络(即多进行基础推理)然后计算平均的结果。
  • 5
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
贝叶斯神经网络是一种基于贝叶斯推理神经网络模型,它具有一些优点和缺点。以下是它们的一些常见优缺点: 优点: 1. 不确定性建模:贝叶斯神经网络能够对模型的不确定性进行建模,这对于处理数据不完整或噪声较大的情况非常有用。它可以给出每个预测的置信度,帮助决策过程更准确和可靠。 2. 鲁棒性:贝叶斯神经网络对于数据集中的离群值和噪声具有较强的鲁棒性。因为它能够在训练过程中自动调整模型的复杂度,减少过拟合的风险。 3. 参数共享:贝叶斯神经网络可以通过在概率模型中共享参数来减少模型的复杂度,并提高模型的泛化能力。这使得模型在处理大规模数据集时具有更好的效率。 缺点: 1. 计算复杂度:贝叶斯神经网络的训练和推理过程通常比传统的神经网络更加复杂和计算密集。这是因为需要进行概率推理和参数采样,增加了计算时间和空间成本。 2. 数据需求:贝叶斯神经网络通常需要更多的数据来训练和推断模型。这是因为贝叶斯方法需要更多的参数估计,而参数估计需要更多的数据支持。 3. 先验选择:贝叶斯神经网络需要选择合适的先验分布来描述参数的不确定性。不正确的先验选择可能导致模型表现不佳或收敛困难。 请注意,以上列出的优缺点并不是全部,而是一些常见的特点。贝叶斯神经网络的优缺点在具体应用中可能会有所不同。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值