什么是量化
把浮点类型(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 ,很明显后者好计算的多。由此我们知道显卡对整数运算速度快于浮点型数据,从而加快模型推理速度。
量化和反量化
我们不光需要考虑将浮点数转化为整数,而且还要考虑如何将整数还原回浮点数,并尽量保证减少推理误差。举例如下:
对称量化
原理
对称量化的核心思想是将浮点数量化为整数,且量化后的分布是关于零对称的。下面是以量化为 Int8 类型举例的核心算法公式,量化为其他类型的整数公式类似:
- 计算 Scale :
- 量化和反量化公式:
-
是原始浮点数范围内的最大绝对值。
-
是量化后整数的最大绝对值。
-
是要量化的浮点数。
-
是量化后的整数值,记得要向下取整,并且在 -127-127 (实际工程上一般舍弃 -128)范围内进行 clip ,控制不要使得量化后的值超出这个范围。
-
是反量化后恢复的近似浮点值。
这里有个细节需要着重强调一下,假设我们现在要将一个浮点列表 ,值为 [-0.2, -0.05, 0.1] ,要转换成 Int8 类型范围是 -127 到 127 ,为了实现 关于 0 的对称,所以需要在 中增加一个虚拟值,也就是原始数组中绝对值最大值的那个数的相反数,变成了 [-0.2, -0.05, 0.1, 0.2] ,这样就可以将一个对称数组 量化到对称的 Int8 范围内(不包括 -128 ),计算 scale 的公式推演如下:
举例
原列表:
| 1.21 | -1.13 | 0.22 | 0.83 | 2.11 | -1.53 | 0.79 | -0.54 | 0.84 |
|---|
其中绝对值最大的值为:2.11
可以计算出缩放系数 scale : 2.11/127=0.01661417
对称量化后的列表:
| 72 | -69 | 13 | 49 | 127 | -93 | 47 | -33 | 50 |
|---|
反量化后的列表:
| 1.19622024 | -1.14637773 | 0.21598421 | 0.81409433 | 2.10999959 | -1.54511781 | 0.78086599 | -0.54826761 | 0.8307085 |
|---|
我们可以计算出来误差总和为 0.091890289 ,但是不大。
矩阵计算
上面的例子是一步一步进行计算的,对于矩阵来说还是太慢了,下面我们介绍直接使用矩阵进行对称的量化和反量化。假如有一个浮点类型的输入 矩阵,还有一个浮点类型的权重 矩阵,我们可以先对两个矩阵进行对称量化变成 和 ,这样就可以将两个浮点类型的矩阵的乘法,转换成两个整数类型的矩阵乘法,提升计算速度,代价就是计算出来的矩阵会出现由于对称量化造成的精度误差。公式如下,其中的两个 s 为两个矩阵的缩放系数:
优点
- 简单高效,计算量低:对称量化不需要为每个值单独存储零点,因此存储和计算更加高效。
- 保持动态范围:由于量化是关于零对称的,它可以保持原始数据的正负动态范围。
- 容易理解,方便实现
缺点
- 精度损失:由于量化步长的限制,可能会引入一些精度损失,尤其是在量化位数较低时。
- 非线性:量化和反量化过程是非线性的,可能会影响模型的收敛和最终性能。
- 如果出现极端值会影响量化效果,误差增大
- 是一种非饱和量化,有些区域会由于对称量化被浪费掉,
非对称量化
原理
非对称量化是一种用于将浮点数转换为整数表示的量化方法。与对称量化不同的是,这种方法在数据具有偏移(即非对称分布)时更有效,因为它可以减少量化误差。非对称量化会分别找出浮点数的最小值和最大值,分别量化到目标整数范围的最小值和最大值,充分利用量化后的整数范围。这可以使用一个缩放因子(scale)和偏移量(zero-point)来实现。
- 计算 Scale 和 Zero-point:
- 量化和反量化公式:
矩阵计算
上面的例子是一步一步进行计算的,对于矩阵来说还是太慢了,下面我们介绍直接使用矩阵进行非对称的量化和反量化。假如有一个浮点类型的输入 矩阵,还有一个浮点类型的权重 矩阵,我们可以先对两个矩阵进行对称量化变成 和 ,这样就可以将两个浮点类型的矩阵的乘法,转换成两个整数类型的矩阵乘法,提升计算速度,代价就是计算出来的矩阵会出现由于非对称量化造成的精度误差。公式如下,其中的两个 s 为两个矩阵的缩放系数,两个 z 为两个矩阵的 :
举例
原列表:
| 1.21 | -1.13 | 0.22 | 0.83 | 2.11 | -1.53 | 0.79 | -0.54 | 0.84 |
|---|
假如我们要量化到 0-255 范围的整数,可以计算出缩放系数 scale : (2.11+1.53)/256=0.0142745
可以计算出来: 0-(-1.53/scale) 并且向下取整为 107
对称量化后的列表:
| 191 | 27 | 122 | 165 | 254 | 0 | 162 | 69 | 165 |
|---|
反量化后的列表:
| 1.19905882 | -1.14196078 | 0.21411765 | 0.82792157 | 2.09835294 | -1.52737255 | 0.78509804 | -0.54243137 | 0.82792157 |
|---|
我们可以看到还是有一定的误差,整体误差和为 0.05929411 ,起码从这个相同的例子中比对称量化误差要小。
优点
- 对称量化优点: 量化后的数据是饱和的,即量化前的最小值对应量化范围的最小值,量化后的最大值对应量化范围的最大值。
- 量化后的误差相对较小,精度较高
缺点
-
需要的计算量较大,且计算复杂。
-
出现极端值,量化后的数据就会分布不合理,有可能浪费很多整数,也有可能多个浮点数量化为一个整数,这些情况都会带来更大的误差。一般都是使用直方图可以有效过滤极端值,i计算量化前后的均方误差,找到合适的浮点数取值范围,或者对极端值进行单独处理。