2、对称量化 vs 非对称量化:原理、公式推导与适用场景对比
聊到量化,绕不开的一个核心选择题就是:用对称量化还是非对称量化?
我记得刚入行那会儿,看到这两个概念总觉得差不多。反正都是把 float 转成 int 嘛,有啥区别?后来在部署一个 MobileNet 模型时吃了大亏——用对称量化精度掉得厉害,换成非对称立马好了。嗯,从那以后我才真正去抠这两个东西的数学本质。
今天咱们就把这事彻底讲透。我会从原理、公式到实战场景,一步步拆解。
2.1 量化的本质:一个映射问题
说白了,量化就是找一个映射函数,把浮点数范围映射到整数范围。
假设我们有一组浮点数 r,要映射到 q(比如 int8 的 [-128, 127])。这个映射可以写成:
q = round(r / scale + zero_point)
其中:
- scale:缩放因子,决定每个整数步长代表多少浮点数
- zero_point:零点偏移,决定浮点 0 对应哪个整数
对称量化和非对称量化的区别,就在 zero_point 上。
核心区别一句话:
- 对称量化:zero_point = 0,浮点 0 精确映射到整数 0
- 非对称量化:zero_point ≠ 0,浮点 0 可以映射到任意整数
2.2 对称量化:简单但浪费
对称量化的公式很干净:
q = round(r / scale)
scale = max(|r_max|, |r_min|) / (Q_max - Q_min) * 2
为什么叫「对称」?因为它的量化范围关于 0 对称。比如 int8 的 [-128, 127],float 的 [-a, a]。
我个人的习惯是:如果模型权重分布接近正态分布且均值接近 0,我会优先尝试对称量化。比如 Conv 层的权重,大部分时候对称量化效果就不错。
但这里有个坑——浪费了精度。
你想想看,如果浮点数的实际范围是 [-0.1, 100],对称量化会把它映射到 [-128, 127] 的对称范围。但实际数据根本用不到负半轴那么多格子,相当于把一半的整数精度浪费了。
我曾经踩过的坑:
有一次量化一个激活值分布严重偏斜的模型,对称量化后精度掉了 5%。排查了半天才发现,是因为激活值全是正数,对称量化把一半的整数范围浪费在了负数上。换成非对称量化后,精度直接恢复。
2.3 非对称量化:灵活但多一个参数
非对称量化的公式多了一个 zero_point:
q = round(r / scale + zero_point)
scale = (r_max - r_min) / (Q_max - Q_min)
zero_point = round(Q_min - r_min / scale)
注意看,这里的 scale 计算用的是 实际范围,而不是对称范围。所以它能充分利用整个整数区间。
举个例子:
假设 float 数据范围是 [0.0, 100.0],映射到 int8 [0, 255]:
- scale = (100 - 0) / (255 - 0) ≈ 0.392
- zero_point = round(0 - 0 / 0.392) = 0
你看,这种情况下 zero_point 恰好是 0,其实退化成对称量化了。但如果是 [-0.1, 100.0]:
- scale = (100 - (-0.1)) / 255 ≈ 0.3925
- zero_point = round(0 - (-0.1) / 0.3925) ≈ 0
嗯,这里 zero_point 还是接近 0。真正体现非对称优势的场景是数据分布严重偏斜时。
我的经验:
非对称量化在量化激活值时特别有用。因为很多激活函数(如 ReLU)的输出全是非负数,用非对称量化可以充分利用整数范围。我做过一个实验,同样的模型,激活值用非对称量化比对称量化精度高 1-2%。
2.4 公式推导:从浮点到整数的完整映射
咱们把公式完整推导一遍,这样你以后遇到问题可以自己算。
对称量化:
已知:
r ∈ [r_min, r_max]
q ∈ [-Q_max, Q_max] (int8: [-128, 127])
推导:
scale = max(|r_max|, |r_min|) / Q_max
q = round(r / scale)
反量化:
r_approx = q * scale
非对称量化:
已知:
r ∈ [r_min, r_max]
q ∈ [Q_min, Q_max] (uint8: [0, 255])
推导:
scale = (r_max - r_min) / (Q_max - Q_min)
zero_point = round(Q_min - r_min / scale)
q = round(r / scale + zero_point)
反量化:
r_approx = (q - zero_point) * scale
注意看,非对称量化多了一个 zero_point 的加减操作。这在硬件实现上会多一次加法,但换来的是精度提升。
2.5 适用场景对比:一张表说清楚
| 对比维度 | 对称量化 | 非对称量化 |
|---|---|---|
| zero_point | 固定为 0 | 可调,非 0 |
| 整数范围利用率 | 低(数据偏斜时浪费一半) | 高(完全利用) |
| 硬件实现 | 简单(少一次加法) | 稍复杂(多一次加法) |
| 权重量化 | 推荐(权重分布通常对称) | 可用,但没必要 |
| 激活值量化 | 不推荐(分布偏斜) | 推荐(灵活适配) |
| 精度损失 | 数据对称时小,偏斜时大 | 整体更稳定 |
2.6 知识结构图:量化选择决策流程
下面这张图是我自己总结的决策流程,帮你快速判断该用哪种量化:
2.7 实战建议:我踩过的坑和总结
最后,分享几个我实际项目中的经验:
- 权重用对称,激活用非对称——这是最稳妥的默认配置。权重分布通常对称,激活值通常偏斜。
- 先跑一遍校准数据——看看实际分布再决定。我习惯用 100-500 张图片做校准,统计 min/max。
- 注意硬件限制——有些 NPU 只支持对称量化,这时候就别纠结了,用对称量化然后做精度补偿。
- 混合精度量化——不同层可以用不同量化方式。比如敏感层用非对称,非敏感层用对称。
一个小技巧:
如果你不确定该用哪种,可以先用对称量化跑一遍,看精度。如果精度掉得厉害(超过 1%),再换成非对称。我做过统计,大约 70% 的模型用对称量化就够了,剩下 30% 需要非对称来救场。
好了,对称量化和非对称量化的核心内容就这些。记住一句话:对称量化省计算,非对称量化保精度。具体选哪个,看你的硬件和精度要求。