量化原理(上):对称量化 vs 非对称量化,量化参数的计算,INT8量化公式推导
大家好,我是你们的AI芯片部署讲师。今天咱们来聊聊量化原理的上半部分。
说实话,量化这个东西,刚接触时觉得挺玄乎的。把32位浮点数硬塞进8位整数里,信息肯定有损失啊。但我在项目中跑过上百个模型后,发现一个有意思的现象:大部分模型量化后,精度损失其实可以控制在1%以内。嗯,这就是我们今天要讲的核心——怎么做到这一点。
为什么需要量化?
先问个问题:你想想看,一个FP32的模型跑在手机上,功耗大概是多少?我实测过,差不多是INT8模型的4倍左右。说白了,量化就是用更少的比特数来表示数据。
好处很明显:
- 模型体积缩小4倍——FP32转INT8,存储直接砍到1/4
- 推理速度提升2-4倍——INT8的乘加运算比FP32快得多
- 功耗大幅降低——这对移动端和边缘设备太重要了
核心思想:量化就是用低精度整数去近似高精度浮点数,关键在于找到合适的映射关系。
对称量化 vs 非对称量化
这两种量化方式,说白了就是映射方式不同。我在部署YOLOv5时,两种都试过,踩了不少坑。
对称量化
对称量化的特点是:零点就是0。也就是说,浮点数的0映射到整数的0。
公式长这样:
Q = round(r / scale)
其中:
Q — 量化后的整数值
r — 原始浮点数值
scale — 缩放因子
举个例子:假设浮点数范围是[-10, 10],要量化到INT8(范围[-128, 127])。
scale = 10 / 127 ≈ 0.0787
浮点数 5.0 → 5.0 / 0.0787 ≈ 63.5 → round → 64
浮点数 -3.2 → -3.2 / 0.0787 ≈ -40.6 → round → -41
浮点数 0.0 → 0.0 / 0.0787 = 0 → 0
看到没?0映射到0,这就是对称。
我的经验:对称量化适合数据分布比较对称的场景,比如权重。我在部署ResNet时,权重的分布基本以0为中心,用对称量化效果很好。
非对称量化
非对称量化引入了零点(zero_point)。浮点数的0不一定映射到整数的0。
公式:
Q = round(r / scale) + zero_point
其中:
zero_point — 零点偏移量
还是刚才的例子,但这次浮点数范围是[-2, 10]:
scale = (10 - (-2)) / (255) = 12 / 255 ≈ 0.0471
zero_point = round(0 - (-2) / 0.0471) = round(42.5) = 43
浮点数 5.0 → 5.0 / 0.0471 + 43 ≈ 106.2 + 43 = 149.2 → round → 149
浮点数 -1.0 → -1.0 / 0.0471 + 43 ≈ -21.2 + 43 = 21.8 → round → 22
浮点数 0.0 → 0.0 / 0.0471 + 43 = 43
注意:0映射到了43,不是0。
避坑指南:我曾经在部署一个语音模型时,激活值分布严重偏斜(大部分在0-5之间,偶尔有负值)。用对称量化效果很差,换成非对称量化后精度直接提升了2.3%。所以,激活值推荐用非对称量化。
量化参数的计算
量化参数就两个:scale 和 zero_point。怎么算?我给大家总结一下。
Scale的计算
公式很简单:
对称量化:scale = max(|r_min|, |r_max|) / (Q_max - Q_min) / 2
非对称量化:scale = (r_max - r_min) / (Q_max - Q_min)
其中Q_max和Q_min是量化后的整数范围。INT8的话:
- 有符号:Q_min = -128, Q_max = 127
- 无符号:Q_min = 0, Q_max = 255
Zero_point的计算
对称量化:zero_point = 0(固定)
非对称量化:zero_point = round(Q_min - r_min / scale)
重要提醒:计算出的zero_point一定要做clip操作,确保在[Q_min, Q_max]范围内。我见过有人忘了这步,结果推理结果全乱了。
INT8量化公式推导
好了,我们来推导一下完整的INT8量化公式。别怕,其实就是初中数学。
假设我们要把浮点数r映射到整数Q,范围是[Q_min, Q_max]:
1. 线性映射关系:
r = scale * (Q - zero_point)
2. 反过来:
Q = round(r / scale) + zero_point
3. 反量化(推理时用):
r ≈ scale * (Q - zero_point)
为什么说「≈」?因为round操作引入了量化误差。这个误差范围是:
误差 ≤ scale / 2
所以scale越小,精度越高。但scale太小会导致Q溢出,需要做clip:
Q_clipped = clamp(Q, Q_min, Q_max)
我的建议:实际部署时,我习惯用校准数据集来统计r_min和r_max。选100-500张图片就够了,太多反而容易过拟合到异常值。
实战对比:对称 vs 非对称
我整理了一个表格,方便大家对比:
| 对比项 | 对称量化 | 非对称量化 |
|---|---|---|
| zero_point | 固定为0 | 需要计算 |
| 计算复杂度 | 低 | 稍高 |
| 适用场景 | 权重(分布对称) | 激活值(分布偏斜) |
| 精度损失 | 对称数据好 | 非对称数据好 |
| 硬件支持 | 几乎所有硬件 | 部分硬件不支持 |
我个人习惯是:权重用对称,激活用非对称。这个组合在大多数模型上表现都不错。
小结
今天的内容就到这里。总结一下:
- 量化就是用低精度整数近似高精度浮点数
- 对称量化:zero_point=0,适合权重
- 非对称量化:zero_point≠0,适合激活值
- scale和zero_point是核心参数,计算时要小心溢出
- INT8量化公式:Q = round(r/scale) + zero_point
下一讲我们会深入量化误差分析和校准方法。到时候我会分享一个我在MobileNet上踩过的坑——校准集选不好,精度直接掉5%。敬请期待!