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 知识结构图:量化选择决策流程

下面这张图是我自己总结的决策流程,帮你快速判断该用哪种量化:

量化类型选择决策流程 开始:选择量化类型 数据分布是否关于0对称? 对称量化 权重、正态分布数据 非对称量化 激活值、偏斜分布 硬件支持zero_point? 硬件支持zero_point? 支持 支持 ✅ 直接使用对称量化 ✅ 使用非对称量化 不支持 不支持 折中:尝试对称量化

2.7 实战建议:我踩过的坑和总结

最后,分享几个我实际项目中的经验:

  1. 权重用对称,激活用非对称——这是最稳妥的默认配置。权重分布通常对称,激活值通常偏斜。
  2. 先跑一遍校准数据——看看实际分布再决定。我习惯用 100-500 张图片做校准,统计 min/max。
  3. 注意硬件限制——有些 NPU 只支持对称量化,这时候就别纠结了,用对称量化然后做精度补偿。
  4. 混合精度量化——不同层可以用不同量化方式。比如敏感层用非对称,非敏感层用对称。

一个小技巧:

如果你不确定该用哪种,可以先用对称量化跑一遍,看精度。如果精度掉得厉害(超过 1%),再换成非对称。我做过统计,大约 70% 的模型用对称量化就够了,剩下 30% 需要非对称来救场。

好了,对称量化和非对称量化的核心内容就这些。记住一句话:对称量化省计算,非对称量化保精度。具体选哪个,看你的硬件和精度要求。


专注资料整理