@深度神经网络推理时间的正确测量方法
本文插图
网络延迟是将深度网络部署到生产环境中要考虑的重要因素之一 。 大多数实际应用程序都需要非常快的推理时间 , 从几毫秒到一秒不等 。 但是 , 正确而有意义地测量神经网络的推理时间或延迟的任务需要对网络有深刻的理解 。 即使是经验丰富的程序员也经常会犯一些常见的错误 , 从而导致延迟测量不准确 。 这些错误有可能会引发错误的决策和不必要的支出 。
在这篇文章中 , 我们回顾了一些主要问题 , 应该正确地测量延迟时间 。 我们回顾了使GPU执行独特的主要过程 , 包括异步执行和GPU预热 。 然后 , 我们共享代码示例以在GPU上正确测量时间 。 最后 , 我们回顾了人们在量化GPU上的推理时间时常犯的一些错误 。
在这篇文章中 , 我们将回顾一些需要解决的主要问题 , 以便正确地度量延迟时间 。
异步执行
我们首先讨论GPU执行机制 。 在多线程或多设备编程中 , 两个独立的代码块可以并行执行 , 这意味着可以在第一个块完成之前执行第二个块 , 这个过程称为异步执行 。 在深度学习环境中 , 我们经常使用这种执行方式 , 因为GPU操作在默认情况下是异步的 。
本文插图
左:同步进程 , 其中进程A等待进程B的响应 , 然后才能继续工作 。 右:异步进程A继续工作 , 而无需等待进程B完成 。
异步执行为深度学习提供了巨大的优势 , 可以大大减少运行时间 。 例如 , 在推断多个批次时 , 第二个批次可以在CPU上进行预处理 , 而第一个批次则通过GPU上的网络进行前馈 。 通常 , 在推断时尽可能使用异步方式是有益的 。
异步执行的效果对用户是不可见的 , 但在进行时间测量时 , 可能会引起许多麻烦 。 当您使用Python中的“time”库计算时间时 , 测量是在CPU设备上执行的 , 由于GPU的异步特性 , 停止计时的代码行将在GPU进程完成之前执行 。 因此 , 这个时间将不正确或与实际推理时间无关 。
GPU warm-up(预热)
现代GPU设备可以存在于几种不同的电源状态之一 。 当GPU不被用于任何目的 , 且不启用持久模式时 , GPU会自动将其功耗状态降低到非常低的水平 , 有时甚至会完全关闭 。 在低功耗状态下 , GPU会关闭不同的硬件 , 包括显存子系统、内部子系统 , 甚至是计算核心和缓存 。
任何试图与GPU交互的程序的调用都会导致驱动程序加载和/或初始化GPU 。 这个驱动程序加载行为是值得注意的 。 由于纠错代码的清理行为 , 触发GPU初始化的应用程序可能会导致长达3秒钟的延迟 。
由于我们希望尽可能地启用GPU省电模式 , 因此让我们看一下如何在测量时间的同时克服GPU的初始化 。
测量推理时间的正确方法
下面的PyTorch代码片段展示了如何正确地度量时间 。 在这里 , 我们使用Efficient-net-b0 , 但您可以使用任何其他网络 。 在进行时间测量之前 , 我们通过网络运行一些虚拟实例来进行“ GPU warm-up” 。 这将自动初始化GPU , 并防止它在我们测量时间时进入省电模式 。 接下来 , 我们使用tr.cuda.event来测量GPU上的时间 。 在这里至关重要的是使用torch.cuda.synchronize() , 这行代码执行主机和设备之间的同步 , 在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)测量时间时的常见错误
- 人民网揭秘中国空间站(深度观察)
- 深度解读华为意义!即便美国停供芯片和系统,国产手机也不会崩
- 中国军魂官方深度国际|漠视生命何谈人权!造谣中伤“中国抗疫”有悖国际正义
- 直播南阳云播台我市将强力推进科技成果转化,加速产学研深度合作
- 科技叶涵雷柏XS100运动蓝牙耳机深度体验,运动达人的必备品
- Mi好物君5天深度体验怪我以前不识货,用了一年的苹果XR突然换上一加8Pro
- 游戏小解说深度好文,资深华尔街交易员独白:在中国股市能赚钱的只有一种人
- 老秦钢结构学校行业深度洗牌,建筑业发展态势:三大改变
- 科技来客「评测」不只是时尚,深度体验带你认识更加全面的华为nova7 SE
- 中国地震局网站震源深度8千米,缅甸发生2.9级地震