大模型量化——对称和非对称量化精讲

2,135 阅读7分钟

什么是量化

把浮点类型(FP32,FP16)的模型参数和激活值,用整数(Int8,Int4)来代替,同时尽可能减少量化后模型推理的误差。最常见的策略就是对称量化和非对称量化。

为什么需要量化

不同精度的显存占用情况

让我们使用 llama-13B 的模型为例,下面计算了参数在不同精度情况下的显存占用情况。我们可以看出来使用精度较低的参数类型,可以极大减少模型的存储空间和显存的占用情况。

参数类型为 FP32 ,需要 52G
参数类型为 FP16 ,需要 26G
参数类型为 Int8,需要 13G
参数类型为 Int4 ,需要 6.5G

显存带宽容易成为瓶颈

这是一张 A100 的架构图,两边是显存,中间是 tensor core 。模型在进行推理的时候,需要频繁地将模型的权重参数和激活值从显存加载到 tensor core 里面进行计算,计算完成之后又将结果放回显存之中。交换的数据量大但带宽有限,所以制约大模型推理速度的就是显存带宽。如果模型进行量化,传输的数据量会变少,数据交换的时间也会减少,从而有效提升模型推理速度。

显卡算力优化

这是 A100 的算力情况,我们可以看到 A100 对于 Int8 计算速度是 FP16 的 2 倍,是 FP32 的 32 倍,这用朴素的思想也很好理解,比如对于两个计算公式 3.14159263.1415696 和 33 ,很明显后者好计算的多。由此我们知道显卡对整数运算速度快于浮点型数据,从而加快模型推理速度。

量化和反量化

我们不光需要考虑将浮点数转化为整数,而且还要考虑如何将整数还原回浮点数,并尽量保证减少推理误差。举例如下:

xf1>量化>xqxq>反量化>xf2xf2尽量接近xf1x_{f1} -> 量化 -> x_{q}\\ x_{q}-> 反量化 -> x_{f2} \\ 让 x_{f2} 尽量接近 x_{f1}

对称量化

原理

对称量化的核心思想是将浮点数量化为整数,且量化后的分布是关于零对称的。下面是以量化为 Int8 类型举例的核心算法公式,量化为其他类型的整数公式类似:

  1. 计算 Scale :
Scale=RmaxQmax\text{Scale} = \frac{|R_{\text{max}}|}{Q_{\text{max}}}
  1. 量化和反量化公式:
Q=Round(RScale)Q=Clip(Q,127,127)R=Q×Scale Q = \text{Round}\left(\frac{R}{\text{Scale}}\right)\\ Q = \text{Clip}(Q, -127, 127)\\ R' = Q \times \text{Scale}
  • Rmax|R_{\text{max}}|是原始浮点数范围内的最大绝对值。

  • QmaxQ_{\text{max}} 是量化后整数的最大绝对值。

  • RR 是要量化的浮点数。

  • QQ 是量化后的整数值,记得要向下取整,并且在 -127-127 (实际工程上一般舍弃 -128)范围内进行 clip ,控制不要使得量化后的值超出这个范围。

  • RR' 是反量化后恢复的近似浮点值。

这里有个细节需要着重强调一下,假设我们现在要将一个浮点列表 XX,值为 [-0.2, -0.05, 0.1] ,要转换成 Int8 类型范围是 -127 到 127 ,为了实现 XX 关于 0 的对称,所以需要在 XX 中增加一个虚拟值,也就是原始数组中绝对值最大值的那个数的相反数,变成了 [-0.2, -0.05, 0.1, 0.2] ,这样就可以将一个对称数组 XX量化到对称的 Int8 范围内(不包括 -128 ),计算 scale 的公式推演如下:

Scale=RmaxRminQmaxQmin=RmaxQmax\text{Scale} = \frac{R_{\text{max}} - R_{\text{min}}}{Q_{\text{max}} - Q_{\text{min}}} = \frac{|R_{\text{max}}|}{Q_{\text{max}}}

举例

原列表:

1.21-1.130.220.832.11-1.530.79-0.540.84

其中绝对值最大的值为:2.11

可以计算出缩放系数 scale : 2.11/127=0.01661417

对称量化后的列表:

72-691349127-9347-3350

反量化后的列表:

1.19622024-1.146377730.215984210.814094332.10999959-1.545117810.78086599-0.548267610.8307085

我们可以计算出来误差总和为 0.091890289 ,但是不大。

矩阵计算

上面的例子是一步一步进行计算的,对于矩阵来说还是太慢了,下面我们介绍直接使用矩阵进行对称的量化和反量化。假如有一个浮点类型的输入 XfX_{f} 矩阵,还有一个浮点类型的权重 WfW_{f} 矩阵,我们可以先对两个矩阵进行对称量化变成 XqX_{q}WqW_{q} ,这样就可以将两个浮点类型的矩阵的乘法,转换成两个整数类型的矩阵乘法,提升计算速度,代价就是计算出来的矩阵会出现由于对称量化造成的精度误差。公式如下,其中的两个 s 为两个矩阵的缩放系数:

XfWf=sxXq@swWq=sxsw(Xq@Wq)X_f W_f = s_x * X_q @ s_w * W_q = s_x * s_w * (X_q @ W_q)

优点

  • 简单高效,计算量低:对称量化不需要为每个值单独存储零点,因此存储和计算更加高效。
  • 保持动态范围:由于量化是关于零对称的,它可以保持原始数据的正负动态范围。
  • 容易理解,方便实现

缺点

  • 精度损失:由于量化步长的限制,可能会引入一些精度损失,尤其是在量化位数较低时。
  • 非线性:量化和反量化过程是非线性的,可能会影响模型的收敛和最终性能。
  • 如果出现极端值会影响量化效果,误差增大
  • 是一种非饱和量化,有些区域会由于对称量化被浪费掉,

非对称量化

原理

非对称量化是一种用于将浮点数转换为整数表示的量化方法。与对称量化不同的是,这种方法在数据具有偏移(即非对称分布)时更有效,因为它可以减少量化误差。非对称量化会分别找出浮点数的最小值和最大值,分别量化到目标整数范围的最小值和最大值,充分利用量化后的整数范围。这可以使用一个缩放因子(scale)和偏移量(zero-point)来实现。

  1. 计算 Scale 和 Zero-point:
Scale=RmaxRminQmaxQminZero-point=QminRminScale,结果要向下求整数\text{Scale} = \frac{R_{\text{max}} - R_{\text{min}}}{Q_{\text{max}} - Q_{\text{min}}} \\ \text{Zero-point} = Q_{\text{min}} - \frac{R_{\text{min}}}{\text{Scale}} ,结果要向下求整数
  1. 量化和反量化公式:
Q=Round(RScale+Zero-point),结果要向下求Q=Clip(Q,Qmin,Qmax)R=Scale×(QZero-point)Q = \text{Round}\left(\frac{R}{\text{Scale}} + \text{Zero-point}\right),结果要向下求\\ Q = \text{Clip}(Q, Q_{\text{min}}, Q_{\text{max}})\\ R' = \text{Scale} \times (Q - \text{Zero-point})

矩阵计算

上面的例子是一步一步进行计算的,对于矩阵来说还是太慢了,下面我们介绍直接使用矩阵进行非对称的量化和反量化。假如有一个浮点类型的输入 XfX_{f} 矩阵,还有一个浮点类型的权重 WfW_{f} 矩阵,我们可以先对两个矩阵进行对称量化变成 XqX_{q}WqW_{q} ,这样就可以将两个浮点类型的矩阵的乘法,转换成两个整数类型的矩阵乘法,提升计算速度,代价就是计算出来的矩阵会出现由于非对称量化造成的精度误差。公式如下,其中的两个 s 为两个矩阵的缩放系数,两个 z 为两个矩阵的 Zero-point\text{Zero-point} :

XfWf=(XqZx)sx@(WqZw)sw=sxsw(Xq@WqXq@ZwWq@Zx+Zx@Zw)X_f W_f = (X_q - Z_x) * s_x @ (W_q - Z_w) * s_w \\ = s_x * s_w *(X_q @ W_q - X_q @ Z_w - W_q @ Z_x + Z_x @ Z_w)

举例

原列表:

1.21-1.130.220.832.11-1.530.79-0.540.84

假如我们要量化到 0-255 范围的整数,可以计算出缩放系数 scale : (2.11+1.53)/256=0.0142745

可以计算出来Zero-point\text{Zero-point} : 0-(-1.53/scale) 并且向下取整为 107

对称量化后的列表:

19127122165254016269165

反量化后的列表:

1.19905882-1.141960780.214117650.827921572.09835294-1.527372550.78509804-0.542431370.82792157

我们可以看到还是有一定的误差,整体误差和为 0.05929411 ,起码从这个相同的例子中比对称量化误差要小。

优点

  • 对称量化优点: 量化后的数据是饱和的,即量化前的最小值对应量化范围的最小值,量化后的最大值对应量化范围的最大值。
  • 量化后的误差相对较小,精度较高

缺点

  • 需要的计算量较大,且计算复杂。

  • 出现极端值,量化后的数据就会分布不合理,有可能浪费很多整数,也有可能多个浮点数量化为一个整数,这些情况都会带来更大的误差。一般都是使用直方图可以有效过滤极端值,i计算量化前后的均方误差,找到合适的浮点数取值范围,或者对极端值进行单独处理。