"); //-->
作者丨田子宸@知乎(已授权)
来源丨https://zhuanlan.zhihu.com/p/411522457
编辑丨极市平台
导读
本文对衡量深度学习模型大小的一些常用指标,如计算量、参数量、访存量、内存占用等进行探讨,分析这些指标对模型部署推理的影响,尤其是计算量与访存量对模型推理速度的影响,并给出在不同硬件架构下设计网络结构的一些建议。
0、前言
当年头一次实习做算法的时候,主管给的第一个任务就是“把一个大的分割模型砍成一个小的”。当时并不理解模型“大”、“小”的真正含义,就简单的选取计算量作为评价指标,疯狂砍计算量(backbone 换 MobileNet/ShuffleNet、Conv 换成 DepthWise Conv、以及一些奇奇怪怪的融合结构等等),把模型计算量砍了将近 10 倍,结果一部署发现速度并没有快多少,反而是把最初的 ResNet 简单砍掉几个 block 效果更好。
也是从那时起接触了访存量、流水线、RoofLine 模型等概念,对模型推理速度的问题产生了兴趣,从此踏上了深度学习推理优化的不归路(划掉)。
如今做推理优化和 HPC 已经有一段时间了,还是偶尔能回想起当年不懂推理时设计的与硬件严重不匹配的模型。此外在工作中跟研究员沟通时,也会发现部分研究员对模型大小和模型推理速度的关系不太了解,设计出一些很难发挥硬件计算能力的模型结构。因此在这里对一些用于评价模型大小的指标——计算量、参数量、访存量、内存占用等指标进行详细探讨,分析这些指标会对模型的部署推理产生何种影响,详细讨论计算量和访存量对模型推理速度的影响,并给出不同硬件架构下设计高效网络结构的一些建议。
本文不仅仅是为了给出网络的设计建议,更是希望能够有效传达性能优化的基础理论知识,以及性能分析的基本思路,帮助各位同学减少网络设计与部署之间的 gap,更高效的完成网络设计与部署工作。非常希望本文能够对大家的工作有所帮助,也非常欢迎大家在评论区留言探讨。
一、常用的模型大小评估指标
目前常用于评价模型大小的指标有:计算量、参数量、访存量、内存占用等,这些指标从不同维度评价了模型的大小。本节仅作简单介绍,熟悉的小伙伴可以跳过此节,直接看后面的分析与探讨。
1. 计算量
计算量可以说是评价模型大小最常用的指标了,很多论文在跟 baseline 进行比较时,都会把计算量作为重要的比较依据。
计算量是模型所需的计算次数,反映了模型对硬件计算单元的需求。计算量一般用 OPs (Operations) ,即计算次数来表示。由于最常用的数据格式为 float32,因此也常常被写作 FLOPs (Floating Point Operations),即浮点计算次数。(这里为了跟传统习惯保持一致,下文就统一采用 FLOPs 啦)
模型的整体计算量等于模型中每个算子的计算量之和。而每个算子的计算量计算方法各不一致。例如对于 Eltwise Sum 来讲,两个大小均为 (N, C, H, W) 的 Tensor 相加,计算量就是 N x C x H x W;而对于卷积来说,计算量公式为(乘加各算一次):
PyTorch 有不少工具可以模型计算量,但需要注意的是这些工具有可能会遗漏一些算子的计算量,将其计算量算成 0,从而导致统计的计算量跟实际计算量有轻微的偏差,不过大多数情况下这些偏差影响不大。
2. 参数量
早期的论文也很喜欢用参数量来评价模型大小。
参数量是模型中的参数的总和,跟模型在磁盘中所需的空间大小直接相关。对于 CNN 来说参数主要由 Conv/FC 层的 Weight 构成,当然其他的一些算子也有参数,不过一般忽略不计了。
参数量往往是被算作访存量的一部分,因此参数量不直接影响模型推理性能。但是参数量一方面会影响内存占用,另一方面也会影响程序初始化的时间。
参数量会直接影响软件包的大小。当软件包大小是很重要的指标时,参数量至关重要,例如手机 APP 场景,往往对 APK 包的大小有比较严格的限制;此外有些嵌入式设备的 Flash 空间很小,如果模型磁盘所需空间很大的话,可能会放不下,因此也会对参数量有所要求。
除了在设计模型时减少参数量外,还可以通过压缩模型的方式降低软件包大小。例如 Caffe 和 ONNX 采用的 Protobuf 就会对模型进行高效的编码压缩。不过压缩模型会带来解压缩开销,会一定程度增加程序初始化的时间。
3. 访存量
访存量往往是最容易忽视的评价指标,但其实是现在的计算架构中对性能影响极大的指标。
访存量是指模型计算时所需访问存储单元的字节大小,反映了模型对存储单元带宽的需求。访存量一般用 Bytes(或者 KB/MB/GB)来表示,即模型计算到底需要存/取多少 Bytes 的数据。
和计算量一样,模型整体访存量等于模型各个算子的访存量之和。对于 Eltwise Sum 来讲,两个大小均为 (N, C, H, W) 的 Tensor 相加,访存量是 (2 + 1) x N x C x H x W x sizeof(data_type),其中 2 代表读两个 Tensor,1 代表写一个 Tensor;而对于卷积来说,访存量公式为:
访存量对模型的推理速度至关重要,设计模型时需要予以关注。
4. 内存占用
内存占用是指模型运行时,所占用的内存/显存大小。一般有工程意义的是最大内存占用,当然有的场景下会使用平均内存占用。这里要注意的是,内存占用 ≠ 访存量。
内存占用在论文里不常用,主要原因是其大小除了受模型本身影响外,还受软件实现的影响。例如有的框架为了保证推理速度,会将模型中每一个 Tensor 所需的内存都提前分配好,因此内存占用为网络所有 Tensor 大小的总和;但更多的框架会提供 lite 内存模式,即动态为 Tensor 分配内存,以最大程度节省内存占用(当然可能会牺牲一部分性能)。
和参数量一样,内存占用不会直接影响推理速度,往往算作访存量的一部分。但在同一平台上有多个任务并发的环境下,如推理服务器、车载平台、手机 APP,往往要求内存占用可控。可控一方面是指内存/显存占用量,如果占用太多,其他任务就无法在平台上运行;另一方面是指内存/显存的占用量不会大幅波动,影响其他任务的可用性。
5. 小结
计算量、参数量、访存量、内存占用从不同维度定义了模型的大小,应根据不同的场合选用合适的指标进行评价。
模型推理速度不单单受模型计算量的影响,也与访存量和一些其他因素息息相关。下文将详细讨论影响模型推理速度的因素。
二、计算量越小,模型推理就越快吗
答案是否定的。
实际上计算量和实际的推理速度之间没有直接的因果关系。计算量仅能作为模型推理速度的一个参考依据。
模型在特定硬件上的推理速度,除了受计算量影响外,还会受访存量、硬件特性、软件实现、系统环境等诸多因素影响,呈现出复杂的特性。因此,在手头有硬件且测试方便的情况下,实测是最准确的性能评估方式。
在设计网络结构时,如果有实测的条件,建议在模型迭代早期对性能也进行测试。一些 NAS 的方法也会对搜索出来的网络结构进行测速,或者干脆对硬件速度进行了建模,也作为初期搜索的重要参数。这种方法设计出来的网络在后期部署时,会极大减少因性能问题迭代优化的时间和人力开销。
这里我将讨论影响模型在硬件上推理速度的一些因素,一方面希望可以帮助手动/自动设计网络结构的同学更快的设计更高效的网络结构,另一方面希望当模型部署时性能出现问题时能够为大家提供分析原因的思路。
这一问题我将从如下 3 个点进行讨论:
计算密度与 RoofLine 模型
计算密集型算子与访存密集型算子
推理时间
1. 计算密度与 RoofLine 模型
计算密度是指一个程序在单位访存量下所需的计算量,单位是 FLOPs/Byte。其计算公式很简单,很多教材、资料里也称之为计算访存比,用于反映一个程序相对于访存来说计算的密集程度:
RoofLine 模型是一个用于评估程序在硬件上能达到的性能上界的模型,可用下图表示:
RoofLine 模型
用公式描述:
当程序的计算密度I较小时,程序访存多而计算少,性能受内存带宽限制,称为访存密集型程序,即图中橙色区域。在此区域的程序性能上界=计算密度×内存带宽,表现为图中的斜线,其中斜率为内存带宽的大小。计算密度越大,程序所能达到的速度上界越高,但使用的内存带宽始终为最大值。
反之如果计算密度I较大,程序性能受硬件最大计算峰值(下文简称为算力)限制,称为计算密集型程序,即图中蓝色区域。此时性能上界=硬件算力,表现为图中的横线。此时计算速度不受计算密度影响,但计算密度越大,所需内存带宽就越少。
在两条线的交点处,计算速度和内存带宽同时到达最大值。
在不同设备上,同一个程序的性质可能发生变化
在不同设备上,同一个程序的性质可能发生变化。例如上图中的程序2,在算力稍弱的设备2上属于计算密集型程序,而在算力较强的设备1上就属于访存密集型程序了(感谢评论区指正)。如果想要充分发挥设备1的性能,应当适当加大程序的计算密度(比如到程序3的位置)。
2. 计算密集型算子与访存密集型算子
网络中的算子可以根据计算密度进行分类。一般来讲,Conv、FC、Deconv 算子属于计算密集型算子;ReLU、EltWise Add、Concat 等属于访存密集型算子。
同一个算子也会因参数的不同而导致计算密度变化,甚至改变性质,比如在其他参数不变的前提下,增大 Conv 的 group,或者减小 Conv 的 input channel 都会减小计算密度。
举个栗子,对于不同参数的卷积,计算密度如下:
可以看到,不同参数下卷积算子的计算密度有很大的差异。第 4 个算子 Depthwise Conv 计算密度仅有 2.346,在当下的很多设备上都属于访存密集型算子。
算子的计算密度越大,约有可能提升硬件的计算效率,充分发挥硬件性能。我们以一个 Intel X86 服务器平台为例(10980 XE)。该平台 CPU 频率为 4.5 GHz,我们以 16 核为例,其理论 FP32 算力为 4.608 TFLOPs/s,内存带宽理论值为 96 GB/s。在此平台上的 RoofLine 模型为:
Intel 10980 XE 16 核 RoofLine 模型,以及各个算子的计算密度与性能
该平台“拐点”的计算密度为 48,计算较为密集的 OP1 和 OP2 处在计算密集区,能够达到平台的算力峰值;而 OP3 和 OP4 处在访存密集区,受内存带宽限制不能到达算力峰值,尤其是 OP4,由于计算访存比过低,计算效率仅有可怜的 4.9%,计算效率并不高。
*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。