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
非对称量化能充分利用全部整数区间,适合激活值这类分布偏移的数据,代价是零点参与运算,反量化时需额外处理。
量化粒度:从 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),是判断量化是否可用的最终依据。
一个可执行的计算示例
假设某层权重范围为 [-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,误差略大,且负半轴和正半轴分辨率相同但区间利用不充分。