3. 对称量化与非对称量化
量化压缩这个话题,说白了就是怎么用更少的比特数去表示模型里的权重和激活值。我刚开始接触这块时,觉得不就是把float转成int嘛,有啥难的?结果第一次动手做量化推理,模型精度直接崩了……后来才明白,选对量化方案是关键的第一步。
今天咱们就聊聊两种最基础的量化方式:对称量化和非对称量化。这两个概念搞懂了,后面那些更高级的量化方法你理解起来会轻松很多。
3.1 对称量化原理与公式
对称量化,名字就告诉你了——量化后的数值范围是对称的。什么意思呢?就是量化后的整数范围关于0对称。比如int8量化,范围就是[-128, 127]。
公式其实很简单:
量化:q = round(x / s)
反量化:x ≈ q * s
其中 s = max(|x_max|, |x_min|) / (2^(n-1) - 1)
这里s是缩放因子,n是量化比特数。对于int8,n=8,分母就是127。
我个人习惯用对称量化做权重量化。为什么?因为权重分布通常比较对称,正负值差不多。我在项目中遇到过用对称量化量化权重,精度损失几乎可以忽略不计。
但要注意一点——如果激活值全是正数(比如ReLU的输出),对称量化就浪费了一半的表示范围。你想想看,本来能表示[-128, 127],结果你只用到了[0, 127]那半边,这不浪费吗?
核心要点:对称量化没有零点偏移,计算简单,硬件实现友好。但遇到非对称分布的数据时,量化精度会打折扣。
3.2 非对称量化原理与公式
非对称量化就是为了解决上面那个问题而生的。它允许量化范围不关于0对称,通过引入零点(Zero Point)来偏移。
公式长这样:
量化:q = round(x / s) + zp
反量化:x ≈ (q - zp) * s
其中 s = (x_max - x_min) / (2^n - 1)
zp = round(-x_min / s)
你看,多了个zp(零点)。它的作用就是把浮点数的0映射到整数范围内的某个点。比如ReLU的输出范围是[0, 6],用非对称量化就能把[0, 6]完整映射到[0, 255],一点不浪费。
我曾经在一个语音模型上试过,激活值全是正数,用对称量化精度掉了2个点,换成非对称量化后只掉了0.3个点。差距还是很明显的。
我的建议:激活值量化优先考虑非对称方案,权重量化优先考虑对称方案。当然,具体选哪个还得看你的硬件支持情况。
3.3 零点(Zero Point)的作用
零点这东西,说白了就是个偏移量。它的核心作用有两个:
- 保证0的精确表示:浮点数0在量化后必须能精确表示,这对padding操作至关重要。你想想,如果0被量化成了3,那padding就变成了3,整个计算就乱套了。
- 充分利用量化范围:通过偏移,让量化范围和数据分布完美匹配。
嗯,这里要注意——零点本身也是要参与计算的。在矩阵乘法里,有零点的量化计算会比对称量化多几个操作:
y = s_w * s_x * (q_w · q_x - zp_x * sum(q_w) - zp_w * sum(q_x) + n * zp_w * zp_x)
看着复杂是吧?其实多出来的就是那几个带zp的项。我在做推理优化时,经常需要权衡:零点带来的精度提升,是否值得多出来的计算量?
避坑指南:我曾经在部署时发现,某些硬件对非对称量化的支持很差,零点计算会引入额外的延迟。所以选方案前,一定要先确认你的目标硬件支持什么。
3.4 两种方案的优缺点对比
咱们直接上表格,一目了然:
| 对比维度 | 对称量化 | 非对称量化 |
|---|---|---|
| 表示范围 | 关于0对称 | 可偏移,更灵活 |
| 计算复杂度 | 低,无零点计算 | 高,需处理零点 |
| 硬件友好度 | 高,很多硬件原生支持 | 中等,部分硬件支持不佳 |
| 精度表现 | 对称分布数据好 | 非对称分布数据好 |
| 适用场景 | 权重量化为主 | 激活值量化为主 |
我个人总结一下:
- 如果你做的是权重量化,优先选对称量化。权重分布通常对称,而且省掉零点计算能快不少。
- 如果你做的是激活值量化,特别是ReLU这类输出全正的激活函数,非对称量化更合适。
- 如果硬件支持有限,那就只能选对称量化,然后通过其他手段(比如调整数据分布)来弥补精度损失。
下面这张图能帮你快速理解两种方案的核心区别:
这张图很直观吧?左边对称量化,浮点数[-6, 6]映射到[-128, 127],0还是0。右边非对称量化,浮点数[0, 6]映射到[0, 255],0映射到了128(零点)。
好了,对称量化和非对称量化就聊到这儿。这两种方案是量化压缩的基石,后面的课程里我们会反复用到这些概念。下次咱们聊聊量化粒度的问题——是per-tensor量化好,还是per-channel量化更优?到时候见。
公众号:蓝海资料掘金营,微信deep3321