什么限制了你的神经网络执行的速度

末鹿安然 提交于 2020-01-17 23:43:44

这周拜读了大神Forrest Iandola的一篇博客,大开眼界,忍不住翻译过来,供大家分享。原文链接如下:
https://medium.com/analytics-vidhya/not-all-tops-are-created-equal-e1911ffb4a82

摘要

限制了DNN在计算平台上的执行速度的六个常见原因。
1)内存访问过多
2)没有足够的并行
3)等待输入数据加载
4)糟糕的I/O ,内存和计算机制的重叠机制(overlap)
5)在专用的平台上没有使用专用的操作(不是所有的TOPs都是一样的,不同产品在某些运算上做了特殊优化)
6)未优化代码

在这里插入图片描述
深度学习处理器公司经常高调宣称他们的产品有惊人的处理速度。他们通常使用的度量标准有 TOPS(Tera Operations per Second), TMACS(Tera Multiply-Accumulate Instructions per Second)。这些指标的意义在哪,这些指标是否真的有用?

首先,看一下这些指标在深度学习中是怎么用的?

让我们思考一下,一个卷积层有尺寸为3x3x100的过滤器和100个输出通道。

1)假设这个卷基层的input grid 的尺寸是50x50x100. 所以,一次前向操作需要3310010050*50 = 225,000,000 MACs, 相当于450,000,000 OPs。一个MACs 等于2个OPs.
2)但是,当一个处理器公司宣称他们的产品能达到一定数量的MACs和OPs, 使用中确实能达到这个数量吗?好吧,处理器公司引用的这些数字实际是峰值(“peak”, 理论上的最好情况)。
3)事实上,你的情况可能有所不同。比如,最近的一篇论文,名字叫EMBench。论文中有展示了两种深度神经网络(DNNs),它们有相同的MACs,但是他们跑在一样的平台上,却有10倍延时的差距。

什么导致这个slowdown?下面我们展示了一个列表(不完整),列出了一些在计算平台上会阻止你的DNN获得理想峰值速度的问题。我们主要关注会限制DNN推理速度的一般问题,这些问题往往也会影响DNN训练速度。

1 内存访问过多

代码运行的速度受限于处理器运行的速度,这个是显而易见的。但是,在所有的计算平台上,内存访问的速度是比计算慢的。一个算法(或者DNN 层)中计算与没存访问的比例可以作为一个量度,称作为计算强度(arithmetic intensity),Williams等人在Roofline Model 这篇论文中国做了阐述。

每一个计算平台都有一个特定的计算强度的阈值,阈值以下执行速度受限于内存访问速读(而不是计算速度)。所以如果你的layer 的计算强度很低,那么执行速度的瓶颈在内存而不是在计算速度。

解决方法:

1) 调整你的DNN的各层,使之拥有更高的计算强度。比如,MobileNetV2 和 ShuffleNetV2 有相近的数量的MACs, 但是shuffleNetV2 有更高的计算强度。所以,shuffleNet在智能手机上运行速度比MobileNet快的多就一点也不惊奇了。(难度等级:容易)

  1. 在你的实现中,使用layer融合去计算多个layer的结果,再把各个层所有的结果写入主内存。比如,一整个mobileNet的模块(三个卷积层,一些RELU,一些batch-norms加速)可以在cache中完成,而不用写回内存。如果你的框架使用图编译器(graph compiler)可以支持layer fusion,比如张量虚拟机Tensor Virtual Machine (TVM),这将比较容易,否则将会有大量工作。(难度等级:高)
    batch-norms:https://blog.csdn.net/wzy_zju/article/details/81262453

3)调整你的计算平台,使之拥有更多的内存带宽。这在资金成本和能耗上将更加昂贵。或者,选一个拥有更多片内cache 的平台。(难度等级:视情况而定)

2 没有足够的并行(也叫做Work Starvation)

假设一种情况,你有一个GPU 能处理30,000个并发线程。你有个卷积层,过滤器尺寸1x1x10, input grid尺寸7x7x10 , 以及5个输出通道.
这一层的总共的计算量是111057*7 = 2450 MACs 。我们发现没有足够的工作分配给这个设备上的30,000个并发线程,让他们人手一个,因此在这次计算中有一些CPU的硬件资源是空闲的。当我们不能充分利用GPU的所有资源时,我们不可能达到厂家给出的那些最好的MACs值。
注意,这仅是一个很简单的例子。在实际过程中你通常需要在每个线程中运行多个MACs才能保证GPU在一段有意义的时间里。

解决方案:

1)如果可以,增加batch size(你的DNN网络并行处理的图片或者数据样本的数量)。在一些特定的实时性要求高的应用中,需要最低可能性的时延,batch size 被固定成了1,这种方法就不能用了。但是,一些跑在服务器上的离线的应用,一些需要并行处理多路摄像头的应用(比如汽车上的环视摄像头),这些可能会起作用。(难度等级:容易)

2)使网络更浅更宽。最近ML文献中的趋势是DNN更深了。在固定的计算预算(fixed budget of computing)的情况下,当卷积层越深,那么它就越薄,每一层的计算变少了,因此并行的工作变少了。当并行不足(work starvation)成为一个议题,它对抵制目前网络做的越来越深这种趋势是有意义的。同时,让我们对每一层有更多工作的浅层DNN网络进行实验也变得有意义。(难度等级:容易)

3)layer fusion(如上)

4)降级你的硬件。选择使用更便宜,TMAC/s 值更低的GPU,因为你根本用不上。比如,如果你的网络跑在亚马逊的网络服务器云上,你可以从NVIDIA V100-enabled P3 降级到 NVIDIA K80-enabled P2. 但是如果你在开发客户应用,你可能受你客户使用的设备支配,超出你的控制。(难度等级:视情况而定)

3 等待输入数据加载

在训练或者推理过程中,从摄像头传图片或者从硬盘上读到内存的时间是影响很大的。另外,从CPU的memeory传数据到GPU上或者其他加速器的memory上的时间也是有很大的影响的。当DNN应用于高精度图片,或者立体像素比如核磁共振成像(MRI:Magnetic Resonance Imaging)或者其他医疗扫描成像,数据加载可能是一个瓶颈。

解决方案:

1)压缩你的输入图片。哪里需要压缩,哪里需要解压缩,完全取决于你的输入输出的瓶颈在哪。比如,如果瓶颈在CPU和GPU之间的图像传输,你可以在CPU上压缩,把压缩后的图片发给GPU,在GPU上解压缩。如果你的平台上支持快速压缩的库,这个方法就直接了当。否则你有一堆的工作要做。(难度等级:取决于是否有支持的库)
2)买更快的硬件。如果磁盘是瓶颈,就买更快的磁盘。如果以太网是瓶颈,升级你的以太网。如果CPU的memory 是瓶颈,你可以更新换代。如果CPU到GPU的复制是瓶颈,就要确认你的总线至少是PCIe 3版本。如果你拥有硬件,这个也很容易解决。如果你是在云上或者你正在开发在客户本地跑的应用,这就比较难了。(难度等级:视情况而定)

4 糟糕的I/O ,内存和计算机制的重叠机制(overlap)

现代计算平台都有重叠I/O传输,内存传输和算术操作的能力。并且,如果你使用一个有后端的深度学习框架,比如cuDNN 或者MKLDNN,那么很大概率I/O, 内存和计算的重叠机制工作的很好。
然而,如果您编写自己的数据加载程序来获取自定义类型的数据,那么您有责任确保I/O重叠的发生,通常是在当前图像计算时预取下一批图像。而且,如果您为您的深度神经网络中使用的新操作编写自己的计算内核,那么您有责任确保内存传输和计算是重叠的。

解决方案:

1)当您写自己的数据加载程序时,如果可以就预取下一个批次(batch)的数据。(难度等级:简单)
2)在编写自己的计算内核时,您可能希望考虑显式地编写软件流水线(software pipelining)的代码,以使通信和计算重叠。或者,在编译器将您的代码转换成汇编代码之后,检查汇编代码(inspect the assembly code),看看数据是否在使用之前就已经预取了。难度等级:高)
Synchronization and Overlapped Input and Output:
https://docs.microsoft.com/en-us/windows/win32/sync/synchronization-and-overlapped-input-and-output

5 在专用的平台上没有使用专用的操作(不是所有的TOPs都是一样的,不同产品在某些运算上做了特殊优化)

有一部分产品,比如NVIDIA V100和Google TPU 之所以能突破TOP/s的峰值是因为专用性。比如,NVIDIA V100有 张量核(tensor cores),它在计算16位4x4的矩阵乘法运算时极度的快。
好消息就是如果你的深度神经网络层能够被掰成并行的4x4的矩阵乘法,你的卷积层将计算的特别快。但是这种处理器在计算大部分其他的计算时相对慢很多。
所以,如果我们设计我们的深度学习网络,把他们拆成一个个 4x4的矩阵乘法,他就能在现代的AI硬件上跑的快吗?并不是,Google TPUv1为256x256 8-bit矩阵乘法做了优化,Google TPUv2 为128x128 32-bit浮点数做矩阵乘法做了优化。华为麒麟970是一个智能手机芯片,它的神经处理单元为3x3 16-bit 浮点数矩阵运算做了优化。我们相信为DNN而优化的计算硬件将变得越来越多样化。

解决方案:

1)承认失败。没有任何一种深度神经网络设计能够在所有计算平台上实现最佳的TOP/s。(难度等级:容易)
2)重新设计DNN,以充分利用在计算平台上有效实现的操作。有几种方法可以做到这一点。一是考虑平台的优化目标,并选择合适的DNN层尺寸。另一种方法是评估平台上不同的层维度的时延,并选择运行速度快的维度。第三种方法是将这些测量值的查找表提供给神经结构搜索(NAS)系统(例如FBNet or SqueezeNAS),并允许NAS系统帮助设计正确的DNN。(难度等级:高,但我们预测这会越来越简单)

需要说明的是,我们相信随着神经结构搜索(NAS)的改进,为不同的平台创建不同的DNN将变得更容易。如果你有一个支持DNN的应用程序,它需要在每一部智能手机(从高通的gpu,到三星的gpu,再到华为的NPUs)上运行深度神经网络,那么NAS将对你大有帮助。
然而,维护所有这些不同的DN可能需要大量的工程工作。我们非常有兴趣去看,像Snapchat和Instagram这样需要在多种智能手机处理平台上运行的、支持DNN的移动应用,最终是如何解决这个问题的。

6 未优化代码

还有一些其他的问题可以阻止DNN在硬件平台上达到峰值/秒。以下是值得一提的项:

  1. 冷却和热功耗(thermal envelope)。当芯片过热,芯片的频率被限制时,你无法达到峰值/秒。
  2. 非均质性。今天的许多芯片都有几种处理器和加速器。实现制造商的峰值TOP/s通常需要充分利用一组异构计算单元。
  3. 内核启动开销。特别是在GPU上,启动每个GPU函数(通常称为内核)的延迟可能非常大。因此,特别是在具有大量轻量级层的深度神经网络中,内核启动开销可能是执行时间的主要因素。Layer fusion(如上所述)在这里很有帮助。

结论

现在,让我们回到最初的问题。当一家深度学习处理器公司告诉你他们的产品可以执行一定数量的TOP/s或TMAC/s时,这意味着什么?这些数字真的有用吗?
是的,这些数字是有用的,因为它让我们了解在这个平台上可以达到的最佳情况下的速度。然而,有许多需要注意的地方。为了达到接近最佳情况的速度,你必须努力工作。您可能需要仔细查看DNN及其实现中的内存带宽使用、I/O使用和每层并行性。你可能需要重新考虑你的DNN设计。您可能需要重新考虑您的实现,看看fusion layer之类的东西。您可能需要更改硬件,例如添加速度更快的硬盘,以跟上应用程序其余部分的速度。你愿意做的事情越多,你的应用就越有可能接近制造商所宣传的TOP/s或TMAC/s的数字。
最后,我们认为单DNN设计不可能在多种平台(如GPU和TPU;服务器和移动端)。DNN需要为每个计算平台定制,否则平台需要变得更加标准化。幸运的是,由于已经开源的DNN模型的多样性,以及神经结构搜索(NAS)的兴起,这在某种程度上变得更容易了。

最后,我们认为单个DNN设计不可能在多种平台(如GPU和TPU,服务器和移动)。dnn需要为每个计算平台定制,否则平台需要变得更加标准化。幸运的是,由于已经开源的DNN模型的多样性,以及神经结构搜索的兴起,这在某种程度上变得更容易了。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!