Skip to content

Latest commit

 

History

History
103 lines (53 loc) · 8.24 KB

README.md

File metadata and controls

103 lines (53 loc) · 8.24 KB

这个子目录的初步设想是放一些手工对循环进行优化的例子,并讲解优化有用的原因(不可避免的会涉及到体系结构的一些东西)。 这个对自己其实也是一种巩固,之前其实也没有弄的特别清楚。

手工进行优化

利用tvm进行优化

相关知识

深度学习模型大小与模型推理速度的探讨

常用的模型大小评估指标

计算量

计算量是模型所需的计算次数,反映了模型对硬件计算单元的需求。计算量一般用 OPs (Operations) ,即计算次数来表示。由于最常用的数据格式为 float32,因此也常常被写作 FLOPs (Floating Point Operations),即浮点计算次数。

模型的整体计算量等于模型中每个算子的计算量之和。而每个算子的计算量计算方法各不一致。例如对于 Eltwise Sum 来讲,两个大小均为 $$(N, C, H, W)$$ 的 Tensor 相加,计算量就是 $$NCHW$$。而对于卷积来说,计算量公式为(乘加各算一次):$$FLOPs=NOCOHOWKHKWIC2$$

PyTorch 有不少工具可以模型计算量,但需要注意的是这些工具有可能会遗漏一些算子的计算量,将其计算量算成 0,从而导致统计的计算量跟实际计算量有轻微的偏差,不过大多数情况下这些偏差影响不大。

参数量

参数量是模型中的参数的总和,跟模型在磁盘中所需的空间大小直接相关。参数量往往是被算作访存量的一部分,因此参数量不直接影响模型推理性能。但是参数量一方面会影响内存占用,另一方面也会影响程序初始化的时间。

参数量会直接影响软件包的大小。当软件包大小是很重要的指标时,参数量至关重要。除了在设计模型时减少参数量外,还可以通过压缩模型的方式降低软件包大小。例如 Caffe 和 ONNX 采用的 Protobuf 就会对模型进行高效的编码压缩。不过压缩模型会带来解压缩开销,会一定程度增加程序初始化的时间。

访存量

访存量往往是最容易忽视的评价指标,但其实是现在的计算架构中对性能影响极大的指标。

访存量是指模型计算时所需访问存储单元的字节大小,反映了模型对存储单元带宽的需求。访存量一般用 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;

访存量对模型的推理速度至关重要,设计模型时需要予以关注。

内存占用

内存占用是指模型运行时,所占用的内存/显存大小。一般有工程意义的是最大内存占用,当然有的场景下会使用平均内存占用。这里要注意的是,内存占用 ≠ 访存量。

内存占用在论文里不常用,主要原因是其大小除了受模型本身影响外,还受软件实现的影响。例如有的框架为了保证推理速度,会将模型中每一个 Tensor 所需的内存都提前分配好,因此内存占用为网络所有 Tensor 大小的总和;但更多的框架会提供 lite 内存模式,即动态为 Tensor 分配内存,以最大程度节省内存占用(当然可能会牺牲一部分性能)。

和参数量一样,内存占用不会直接影响推理速度,往往算作访存量的一部分。但在同一平台上有多个任务并发的环境下,如推理服务器、车载平台、手机 APP,往往要求内存占用可控。可控一方面是指内存/显存占用量,如果占用太多,其他任务就无法在平台上运行;另一方面是指内存/显存的占用量不会大幅波动,影响其他任务的可用性。

计算量小,模型推理不一定快

模型在特定硬件上的推理速度,除了受计算量影响外,还会受访存量、硬件特性、软件实现、系统环境等诸多因素影响,呈现出复杂的特性。因此,在手头有硬件且测试方便的情况下,实测是最准确的性能评估方式。

计算密度与RoofLine模型

计算密度是指一个程序在单位访存量下所需的计算量,单位是 FLOPs/Byte。其计算公式很简单,很多教材、资料里也称之为计算访存比,用于反映一个程序相对于访存来说计算的密集程度:

计算密度I(FLOPs/Byte)=计算量(FLOPs)/访存量(Bytes)

RoofLine 模型是一个用于评估程序在硬件上能达到的性能上界的模型

计算速度(FLOPs/s)=min(计算密度*带宽, 峰值计算速度)

当程序的计算密度I较小时,程序访存多而计算少,性能受内存带宽限制,称为访存密集型程序。在此区域的程序性能上界=计算密度×内存带宽,表现为图中的斜线,其中斜率为内存带宽的大小。计算密度越大,程序所能达到的速度上界越高,但使用的内存带宽始终为最大值。

反之如果计算密度I较大,程序性能受硬件最大计算峰值(下文简称为算力)限制,称为计算密集型程序,即图中蓝色区域。此时性能上界=硬件算力,表现为图中的横线。此时计算速度不受计算密度影响,但计算密度越大,所需内存带宽就越少。

在两条线的交点处,计算速度和内存带宽同时到达最大值

计算密集型算子与访存密集型算子

一般来讲,Conv、FC、Deconv 算子属于计算密集型算子;ReLU、EltWise Add、Concat 等属于访存密集型算子。

同一个算子也会因参数的不同而导致计算密度变化,甚至改变性质,比如在其他参数不变的前提下,增大 Conv 的 group,或者减小 Conv 的 input channel 都会减小计算密度。算子的计算密度越大,约有可能提升硬件的计算效率,充分发挥硬件性能。

两个主流编译框架XLA(针对访存密集算子)和TVM(针对计算密集算子)

对于访存密集型算子,推理时间跟访存量呈线性关系,而对于计算密集型算子,推理时间跟计算量呈线性关系。

影响模型推理性能的其他因素

硬件限制的影响

以上文的 Intel X86 CPU 为例,我们之前计算的 avx512 理论算力为 4.608 TFLOPs/s,但这个数值的前提是频率能维持在 4.5 GHz。然而实际上在使用 16 核跑 avx512 指令时,CPU 频率会下降到约 2.9 GHz,此时理论算力仅剩下 2.96 TFLOPs/s,而实测值仅有 2.86 TFLOPs/s。

除了频率之外,有些芯片可能会因为一些设计上或实现上的原因,导致在实际使用时达不到理论峰值。比如一些低端芯片不支持多发射、不支持乱序执行、采用了阻塞式 Cache 等等,一些芯片甚至会有一些性能 bug,导致在实际使用时几乎到达不了理论峰值

内存同理,该平台理论带宽为 96GB/s,但实测下来最高读带宽仅有 74 GB/s,仅能到达理论带宽的 77%。

系统环境的影响

除非程序运行在裸机中,否则操作系统一定会对性能上界产生一定影响,比如操作系统在多核间的调度损失、操作系统的内存管理带来的损失、操作系统本身占用的运算资源等等。

这些问题可以通过软件进行一部分弥补,例如调度问题可以使用绑核来解决,缺页问题可以通过绑定物理页(需要内核态)或内存池来解决。因此操作系统带来的影响是可控的。

软件实现的影响

对于深度学习模型推理而言,推理框架对模型性能的影响主要体现在:是否充分利用了硬件的流水线资源、是否高效利用了硬件中的缓存、是否采用了时间复杂度更低的算法、是否解决了操作系统带来的性能损失(如上文的调度问题和内存缺页问题)、是否进行了正确高效的图优化等等。