4、对称量化与非对称量化:原理、公式推导与适用场景
聊到量化,绕不开两个基本概念——对称量化和非对称量化。说实话,我早年刚接触模型量化时,觉得这俩不就是个数学变换嘛,有啥好纠结的?直到我在一个低比特量化项目里,因为选错了量化方式,导致模型精度直接崩了……嗯,从那以后,我再也不敢小看这个选择了。
今天咱们就把这两个东西彻底讲透。从原理到公式,再到实际场景怎么选,一步到位。
4.1 先搞清楚:量化到底在做什么?
量化说白了,就是把连续的浮点数,映射到离散的整数空间。比如一个32位的float,我们想用8位的int来表示。这中间必然有精度损失,但换来的是存储和计算的大幅加速。
数学上,量化可以写成:
q = round(r / S) + Z
其中:
- r 是原始浮点值
- q 是量化后的整数值
- S 是缩放因子(scale)
- Z 是零点偏移(zero point)
反量化就是逆过程:
r ≈ (q - Z) * S
你看,核心就两个参数:S 和 Z。对称量化和非对称量化的区别,就在于 Z 怎么处理。
4.2 对称量化:简单粗暴,但有限制
对称量化,就是让量化后的整数范围关于0对称。换句话说,零点Z固定为0。
公式变成:
q = round(r / S)
r ≈ q * S
这里S怎么算?很简单:
S = max(|r_max|, |r_min|) / (Q_max - Q_min) * 2
或者更常见的写法:
S = max(|r_max|, |r_min|) / Q_max
其中Q_max是量化范围的最大值。比如int8,Q_max = 127,Q_min = -128。
关键点:对称量化只用一个参数S,实现简单,硬件友好。但代价是——如果数据分布不对称,会浪费量化范围。
举个例子。假设你的权重值范围是[-0.1, 1.0]。对称量化会取max(|-0.1|, |1.0|) = 1.0,然后映射到[-127, 127]。你想想看,负半轴只用了0.1的范围,但占用了整整127个整数刻度。这效率,说实话有点浪费。
4.3 非对称量化:灵活但复杂
非对称量化就不一样了。它允许零点Z不为0,可以自由偏移。
公式回到最原始的形式:
q = round(r / S) + Z
r ≈ (q - Z) * S
S和Z的计算:
S = (r_max - r_min) / (Q_max - Q_min)
Z = round(Q_max - r_max / S)
或者等价地:
Z = round(Q_min - r_min / S)
你看,非对称量化把整个浮点范围[r_min, r_max]完整地映射到整数范围[Q_min, Q_max]。数据分布不对称?没关系,Z会自动调整。
我个人习惯:在GGUF的源码里,非对称量化通常用于激活值(activations),因为激活值的分布往往不对称,比如ReLU之后全是非负数。对称量化则常用于权重(weights),因为权重的分布通常比较对称。
4.4 公式推导:从浮点到整数,再回来
咱们来手推一下。假设我们要把浮点范围[a, b]映射到整数范围[0, 255](uint8)。
第一步,计算缩放因子S:
S = (b - a) / (255 - 0) = (b - a) / 255
第二步,计算零点Z。我们希望浮点最小值a映射到整数0:
0 = round(a / S) + Z → Z = -round(a / S)
或者浮点最大值b映射到整数255:
255 = round(b / S) + Z → Z = 255 - round(b / S)
这两个公式算出来的Z应该一致(不考虑舍入误差)。
反量化时:
r = (q - Z) * S
举个例子。假设浮点范围是[-0.5, 1.5],量化到uint8 [0, 255]:
S = (1.5 - (-0.5)) / 255 = 2.0 / 255 ≈ 0.00784
Z = -round(-0.5 / 0.00784) = -round(-63.75) = 64
验证一下:浮点值0应该映射到整数64。因为0是范围的中点偏左一点,嗯,合理。
4.5 适用场景:什么时候选哪个?
这个问题,我在项目里踩过坑,总结了几条经验:
| 场景 | 推荐量化方式 | 原因 |
|---|---|---|
| 权重(weights) | 对称量化 | 权重分布通常对称,且对称量化硬件实现简单 |
| 激活值(activations) | 非对称量化 | 激活值分布不对称(如ReLU后全非负),非对称能充分利用量化范围 |
| 低比特量化(4-bit以下) | 对称量化 | 量化范围小,零点偏移带来的额外计算开销不划算 |
| 嵌入式/移动端推理 | 对称量化 | 硬件加速器(如NPU)通常只支持对称量化 |
| 高精度要求场景 | 非对称量化 | 能更精细地利用量化范围,减少精度损失 |
我曾经踩过的坑:在一个语音模型量化项目中,我默认用了对称量化。结果发现激活值的分布严重偏斜(大部分值集中在0附近,少数值很大)。对称量化把大量刻度浪费在了负半轴,导致精度暴跌。后来换成非对称量化,精度直接回升了2个点。所以,别偷懒,先看看你的数据分布。
4.6 核心逻辑图:对称 vs 非对称
下面这张图,我用SVG画了对称量化和非对称量化的核心区别。你看一眼就明白了。
4.7 在GGUF中的实际应用
GGUF作为GGML的模型格式,对量化方式做了大量优化。我翻过它的源码,发现一个有意思的设计:
- Q4_0、Q5_0、Q8_0 这些带"_0"的,用的是对称量化。适合权重。
- Q4_1、Q5_1 这些带"_1"的,用的是非对称量化。适合激活值或混合精度场景。
为什么这么设计?说白了,就是权衡。对称量化计算快,适合大批量权重矩阵乘法。非对称量化精度高,适合对精度敏感的激活值。
我建议:如果你在写自己的量化工具,可以先从对称量化入手。跑通了,再根据实际精度需求,局部替换成非对称量化。别一上来就搞复杂的,容易翻车。
4.8 小结
对称量化和非对称量化,没有绝对的好坏。关键看你的数据分布和硬件支持。对称量化简单高效,非对称量化灵活精准。选对了,事半功倍;选错了,精度崩盘。
嗯,这一章就到这里。记住一句话:先看数据,再选量化。
公众号:蓝海资料掘金营,微信deep3321