深度学习中做量化提升运行速度是最常用的方法,尤其是大模型这类非常吃GPU显存的方法。一般是高精度浮点数表示的网络权值以及激活值用低精度(例如8比特定点)来近似表示达到模型轻量化,加速深度学习模型推理,目前8比特推理已经比较成熟。比如int8量化,就是让原来32bit存储的数字映射到8bit存储。int8范围是[-128,127], uint8范围是[0,255]。
使用低精度的模型推理的优点:1. 模型存储主要是每个层的权值,量化后模型占用空间小,32比特可以缩减至8比特,并且激活值用8比特后,减小了内存的访问带宽需求。2:单位时间内处理定点运算指令比浮点数运算指令多。
一般按照量化阶段不同分为后量化和训练时量化,用的比较多的是后量化,像tensorRT和RKNN按照量化映射方法又可以分为对称量化和非对称量化。
非对称量化需要一个偏移量Z来完成零点的映射,即量化前的零点和量化后的零点不一致。非对称量化的一般公式为:
S=rmax−rminqmax−qminS=qmax−qminrmax−rmin
Z=qmax−Round(rmaxS)Z=qmax−Round(Srmax)
rmaxrmax和rminrmin表示真实数据的最大值和最小值, qmaxqmax和qminqmin表示量化后的最大值和最小值,例如uint8就是0和256。 Round()表示取整,如果是量化为int型。
q=Round(rS+Z)q=Round(Sr+Z)
r=(q−Z)∗Sr=(q−Z)∗S
对称算法是通过一个收缩因子,将FP32中的最大绝对值映射到8比特的最大值,最大绝对值的负值(注意此值不是fp32的最小值,是最大绝对值的相反数,故对称)映射到8比特的最小值。对称量化在量化前和量化后的零点保持一致,即零点对应,因此无需像非对称量化那样引入一个偏移量Z。 对称量化的一般公式为:
S=∣rmax∣∣qmax∣S=∣qmax∣∣rmax∣
q=Round(rS)q=Round(Sr)Round()表示取整,如果是量化为int型。
r=q∗Sr=q∗S
对称量化无需引入偏移量Z,因此计算量低,缺点是量化后的数据是非饱和的,即有一部分区域不存在量化的数据。
非对称量化因为额外引入了一个偏移量来修正零点,因此需要的计算量会大一点。优点是其量化后的数据是饱和的,即量化前的最小值对应量化范围的最小值,量化后的最大值对应量化范围的最大值。
对于fp32的值若均匀分布在0左右,映射后的值也会均匀分布,若fp32的值分布不均匀,映射后不能充分利用。所以非对称可以处理好FP32数据分布不均匀的情况。
若对称算法产生的量化后数据很多都是在【0,127】内,左边的范围利用很少,减弱了量化数据的表示能力,影响模型精度。
此外还有很多其他的魔改版本,比如激活值饱和量化,通过选择合适的阈值T来将一些范围利用少的情况去除,然后再做对称量化。从而也实现对应的饱和量化的操作。下图为魔改版本激活值饱和量化(右图),选择合适的阈值T。以及原始版本权值非饱和量化(左图)