3. 数值表示与量化基础

量化部署的第一步,是把训练好的浮点权重和激活值映射到低比特整数域。这个映射不是简单的“四舍五入”,而是一套由数值表示方式、映射策略、粒度选择和误差度量共同决定的工程体系。理解这套体系,才能在后续部署中判断“为什么掉点”“该调哪里”。

定点与浮点:两种数值表示的本质差异

浮点数(如 FP32、FP16、BF16)用“符号位 + 指数位 + 尾数位”表示,指数位让数值可以覆盖极大和极小的动态范围,代价是位宽开销大、乘加运算复杂。定点数(如 INT8、INT4)则约定小数点位置固定,所有数值共享同一个缩放尺度,用整数运算即可完成乘加,硬件效率高、功耗低。

以 INT8 为例,它只有 256 个离散取值。量化的核心任务就是:给定一段浮点数值区间,找到合适的缩放因子和零点,把连续值映射到这 256 个整数上,并保证反量化后误差可控。这里需要先明确一个约定:本文所有量化公式均采用“浮点值 = 缩放因子 × (整数值 − 零点)”的表示,即零点对应浮点 0 的整数编码。

对称与非对称量化

对称量化强制浮点 0 映射到整数 0,即零点为 0,缩放因子由绝对值最大的数决定:

scale = max(|x|) / (2^(b-1) - 1)
q = round(x / scale)
x_deq = q * scale

对称量化实现简单,适合权重这类近似零均值分布的数据,但若数据分布明显偏斜(如 ReLU 后的激活值全为非负),会浪费一半整数区间。

非对称量化允许零点不为 0,用最小值和最大值共同确定映射:

scale = (max(x) - min(x)) / (2^b - 1)
zero_point = round(-min(x) / scale)
q = round(x / scale) + zero_point
x_deq = (q - zero_point) * scale

非对称量化能充分利用全部整数区间,适合激活值这类分布偏移的数据,代价是零点参与运算,反量化时需额外处理。

对称量化 vs 非对称量化:映射区间对比 对称量化(零点 = 0) 浮点 0 负半轴 正半轴 scale = max(|x|) / 127 整数区间 [-127, 127] 对称使用 偏斜数据会浪费一半区间 非对称量化(零点 ≠ 0) 浮点 0 全部整数区间用于非负数据 scale = (max − min) / 255 整数区间 [0, 255] 完整利用 零点参与反量化运算

量化粒度:从 per-tensor 到 per-channel

缩放因子和零点可以按不同粒度共享。per-tensor 整张张量共用一个 scale,实现最简单,但若各通道数值范围差异大,小范围通道会被大范围通道“淹没”,误差显著。per-channel 为每个输出通道单独计算 scale,能显著降低权重误差,是卷积层权重量化的常用选择。per-group 进一步把通道内元素分组,每组独立 scale,常见于 INT4 权重量化,组大小通常取 32、64 或 128。

粒度越细,精度越好,但元数据(scale/zero_point)存储开销和反量化计算量也越大。工程上需要在精度和效率之间权衡:权重常用 per-channel 或 per-group,激活值因动态范围随输入变化,通常用 per-tensor 并配合校准统计。

零点与缩放因子:映射的两个自由度

缩放因子决定“一个整数步长代表多少浮点值”,零点决定“哪个整数编码对应浮点 0”。两者共同定义了仿射映射。对于对称量化,零点固定为 0,只剩 scale 一个自由度;对于非对称量化,两者都需要计算并存储。

反量化时,若零点不为 0,必须先减去零点再乘 scale。这个细节在算子融合和硬件实现中非常关键:卷积的偏置项、ReLU 的截断点都需要根据零点做相应偏移,否则会出现系统性偏差。

量化误差来源与度量

量化误差主要来自三方面:舍入误差,即浮点值到最近整数的取整偏差,理论上限为半个 scale;截断误差,当数值超出校准得到的 [min, max] 区间时被裁剪,产生较大误差,常见于激活值分布尾部;粒度误差,同一 scale 覆盖的数值范围过宽,导致小数值分辨率不足。

常用度量指标包括:

  • MSE(均方误差):量化前后逐元素差值的平方均值,反映整体偏差能量。
  • 余弦相似度:衡量量化前后向量方向一致性,对权重量化尤其敏感。
  • SQNR(信噪量化比):信号功率与量化噪声功率之比,单位为 dB,数值越高表示量化越保真。
  • 端到端精度:最终任务指标(如 Top-1 准确率、mAP),是判断量化是否可用的最终依据。
校准阶段建议同时观察逐层 SQNR 和端到端指标:若某层 SQNR 明显偏低但端到端掉点不大,可优先保留该层高精度;若端到端掉点显著而逐层指标尚可,则需检查是否存在离群通道或激活截断问题。

一个可执行的计算示例

假设某层权重范围为 [-1.2, 0.8],采用 INT8 非对称量化:

scale = (0.8 - (-1.2)) / 255 = 2.0 / 255 ≈ 0.007843
zero_point = round(-(-1.2) / 0.007843) = round(153.0) = 153

浮点值 0.5 量化:
q = round(0.5 / 0.007843) + 153 = round(63.75) + 153 = 64 + 153 = 217
反量化:(217 - 153) × 0.007843 = 64 × 0.007843 ≈ 0.502

浮点值 -1.2 量化:
q = round(-1.2 / 0.007843) + 153 = round(-153.0) + 153 = 0
反量化:(0 - 153) × 0.007843 ≈ -1.200

可以看到,边界值被精确映射到整数端点,中间值存在约 0.002 的舍入偏差,这正是半个 scale 量级的典型误差。若改用对称量化,scale = 1.2 / 127 ≈ 0.009449,同样的 0.5 会映射到 round(0.5 / 0.009449) = 53,反量化约 0.501,误差略大,且负半轴和正半轴分辨率相同但区间利用不充分。

实际部署中不要只盯着权重误差。激活值的动态范围随输入样本变化,校准集选择不当会导致截断误差急剧上升。建议用 100~500 张有代表性的校准样本统计激活分布,并对比 min-max、百分位截断(如 99.9%)和 KL 散度三种校准策略的端到端表现。