量化方法对比
QAT 可以达到的精度较高,但是往往需要较多的量化训练时间,量化成本比较大。PTQ 的量化过程比较迅速,只需要少量数据集来校准,但是量化后精度往往损失较多,见表7-1。
表7-1 量化方法参数对比
量化方法 |
功能 |
经典适用场景 |
使用条件 |
易用性 |
精度损失 |
预期收益 |
量化训练 (QAT) |
通过 Finetune 训练将模型量化误差降到最小 |
对量化敏感的场景、模型,例如目标检测、分割、OCR 等 |
有大量带标签数据 |
好 |
极小 |
减少存续空间 4X,降低计算内存 |
静态离线量化 (PTQ Static) |
通过少量校准数据得到量化模型 |
对量化不敏感的场景,例如图像分类任务 |
有少量无标签数据 |
较好 |
较少 |
减少存续空间 4X,降低计算内存 |
动态离线量化 (PTQ Dynamic) |
仅量化模型的可学习权重 |
模型体积大、访存开销大的模型,例如 BERT 模型 |
无 |
一般 |
一般 |
减少存续空间 2/4X,降低计算内存 |
7.2.3 量化方法(饱和与非饱和)
模型量化桥接了定点与浮点,建立了一种有效的数据映射关系,使得以较小的精度损失代价获得了较好的收益。模型量化有两种映射方法,以 INT8 量化为例子:
1. 非饱和量化
非饱和量化方法计算浮点类型张量中绝对值的最大值 𝑎𝑏𝑠_𝑚𝑎𝑥,将其映射为 127,则量化比例因子(scale)等于 𝑎𝑏𝑠_𝑚𝑎𝑥/127,如图7-5所示。
图7-5 非饱和量化方法
2. 饱和量化
饱和量化方法使用 KL 散度计算一个合适的阈值 T (0<𝑇<𝑎𝑏𝑠_𝑚𝑎𝑥),将 ±|𝑇| 映射为 ±127,超出阈值 ±|𝑇| 外的直接映射为阈值 ±127,则量化比例因子(scale)等于 𝑇/127,如图7-6所示。
图7-6 饱和量化方法
7.2.4 量化类型(线性与非线性)
量化可以分为线性量化和非线性量化,目前主流的方法是线性量化。线性量化可以分为对称量化和非对称量化。要弄懂模型量化的原理就是要弄懂这种数据映射关系,浮点与定点数据的转换,公式如下:
𝑄=𝑅/𝑆+𝑍
:eqlabel:02Quant_eq1
𝑅=(𝑄−𝑍)∗𝑆
:eqlabel:02Quant_eq2
其中,𝑅 表示输入的浮点数据,𝑄 表示量化之后的定点数据,𝑍 表示零点(Zero Point)的数值,𝑆 表示缩放因子(Scale)的数值。
1. 对称量化
对称量化是非对称量化 𝑍=0 时的特例,即 𝑅𝑚𝑎𝑥 和 𝑅𝑚𝑖𝑛 关于 Z 对称。对称量化常用的方法是最大绝对值量化 (𝑎𝑏𝑠_𝑚𝑎𝑥),将输入缩放到 8 位范围 [−128,127],对称的量化算法原始浮点精度数据与量化后 INT8 数据的转换,如图7-7所示。
图7-7 对称量化方法
代码如下:
𝑖𝑛𝑡=𝑟𝑜𝑢𝑛𝑑[𝑓𝑙𝑜𝑎𝑡𝑠𝑐𝑎𝑙𝑒]
:eqlabel:02Quant_eq3
𝑠𝑐𝑎𝑙𝑒=(2·𝑚𝑎𝑥(|𝑥𝑚𝑖𝑛|,𝑥𝑚𝑎𝑥))𝑄𝑚𝑎𝑥−𝑄𝑚𝑖𝑛
:eqlabel:02Quant_eq4
其中,threshold 是阈值, 可以理解为张量的范围是 [−𝑡ℎ𝑟𝑒𝑠ℎ𝑜𝑙𝑑,𝑡ℎ𝑟𝑒𝑠ℎ𝑜𝑙𝑑]。一般来说,对于激活值,𝑠𝑐𝑎𝑙𝑒=𝑡ℎ𝑟𝑒𝑠ℎ𝑜𝑙𝑑/128。对于权重,𝑠𝑐𝑎𝑙𝑒=𝑡ℎ𝑟𝑒𝑠ℎ𝑜𝑙𝑑/127。
2. 非对称量化
非对称量化(Affifine Quantization)也称为 zero-point quantization,通过使用归一化动态范围 𝑛𝑑𝑥 进行缩放,然后通过零点 𝑧𝑝𝑥 进行移位,将输入分布移动到完整范围 [−128,127] 或者 [0,255]。通过这个仿射变换,任何输入张量都将使用数据类型的所有位,从而减小了非对称分布的量化误差,如图7-8所示。
图7-8 非对称量化方法
以线性量化的 MinMax 方法为例来求解 𝑆 和 𝑍:
𝑆=𝑅𝑚𝑎𝑥−𝑅𝑚𝑖𝑛𝑄𝑚𝑎𝑥−𝑄𝑚𝑖𝑛
:eqlabel:02Quant_eq5
𝑍=𝑄𝑚𝑎𝑥−𝑅𝑚𝑎𝑥𝑆
:eqlabel:02Quant_eq6
其中,𝑅𝑚𝑎𝑥 表示输入浮点数据中的最大值,𝑅𝑚𝑖𝑛 表示输入浮点数据中的最小值,𝑄𝑚𝑎𝑥 表示最大的定点值(127 / 255),𝑄𝑚𝑖𝑛 表示最小的定点值(-128 / 0)。
量化算法原始浮点精度数据与量化后 INT8 数据的转换,方法如下:
𝑓𝑙𝑜𝑎𝑡=𝑠𝑐𝑎𝑙𝑒×(𝑢𝑛𝑖𝑡8−𝑜𝑓𝑓𝑠𝑒𝑡)
:eqlabel:02Quant_eq7
通过原始 float32 高精度数据计算,得到 uint8 数据的转换,即为如下公式所示:
𝑢𝑖𝑛𝑡8=𝑟𝑜𝑢𝑛𝑑(𝑓𝑙𝑜𝑎𝑡𝑠𝑐𝑎𝑙𝑒)+𝑜𝑓𝑓𝑠𝑒𝑡
:eqlabel:02Quant_eq8
若待量化数据的取值范围为 [𝑋𝑚𝑖𝑛,𝑋𝑚𝑎𝑥],则 𝑠𝑐𝑎𝑙𝑒 的计算公式如下:
𝑠𝑐𝑎𝑙𝑒=𝑋𝑚𝑎𝑥−𝑋𝑚𝑖𝑛𝑄𝑚𝑎𝑥−𝑄𝑚𝑖𝑛
:eqlabel:02Quant_eq9
offset 的计算方式如下:
𝑜𝑓𝑓𝑠𝑒𝑡=𝑄𝑚𝑖𝑛−𝑟𝑜𝑢𝑛𝑑(𝑥𝑚𝑖𝑛𝑠𝑐𝑎𝑙𝑒)
:eqlabel:02Quant_eq10
当量化到 INT8 时, 𝑄𝑚𝑎𝑥=127,𝑄𝑚𝑖𝑛=−128; UINT8 时, 𝑄𝑚𝑎𝑥=255,𝑄𝑚𝑖𝑛=0。