量化基础:定点数表示、对称/非对称量化、量化参数与误差来源
在进入 QAT(量化感知训练)的图构建与 fake quant 节点插入之前,必须先建立扎实的量化理论基础。量化本质上是将连续或高精度离散值(通常是 FP32)映射到有限离散集合(如 INT8、INT16)的过程。这一过程涉及三个核心问题:如何用定点数表示实数、如何选择映射规则(对称/非对称)、以及如何定义和量化误差。本章将逐一拆解这些概念,并明确它们对后续 fake quant 节点设计的影响。
2.1 定点数表示:从 FP32 到 Qm.f
核心原理
定点数(Fixed-point)是一种实数表示方法,它约定小数点固定在某个二进制位之后。格式通常记为 Qm.f,其中 m 表示整数位个数,f 表示小数位个数,总位宽为 m+f+1(含符号位)。例如 Q7.8 表示 16 位有符号定点数,其中 7 位整数、8 位小数。定点数的数值计算公式为:
value = (-1)^sign × (整数部分 + 小数部分 × 2^(-f))
与浮点数相比,定点数没有指数位,因此动态范围小,但硬件实现简单、计算速度快、功耗低。在神经网络推理中,INT8 定点数是最常见的格式,因为它能在精度损失可控的前提下大幅提升吞吐量。
判断方法
选择定点数格式时,需要根据张量的实际数值分布决定 Q 格式。判断步骤如下:
- 统计张量的最大绝对值 max_abs,确定整数位 m = ceil(log2(max_abs)) + 1(含符号位)。
- 根据目标位宽(如 8 位、16 位)计算小数位 f = total_bits - m - 1。
- 若 f < 0,说明动态范围超出该位宽,需要截断或缩放。
案例拆解
假设某层激活值范围为 [-6.2, 6.2],使用 INT8 表示。max_abs = 6.2,m = ceil(log2(6.2)) + 1 = 3+1 = 4。则 f = 8 - 4 - 1 = 3,即 Q4.3 格式。该格式可表示范围 [-16, 15.875],步长 0.125,能覆盖原范围且精度为 0.125。若激活值范围变为 [-20, 20],则 m=5,f=2,步长变为 0.25,精度下降。
2.2 对称量化与非对称量化
核心原理
对称量化(Symmetric Quantization)将浮点范围 [-max_abs, max_abs] 映射到量化范围 [-127, 127](INT8 有符号),zero_point 固定为 0。其映射公式为:
x_int = clamp(round(x / scale), -127, 127)
scale = max_abs / 127
非对称量化(Asymmetric Quantization)允许浮点范围 [min_val, max_val] 映射到 [0, 255](INT8 无符号),zero_point 不为 0。其映射公式为:
x_int = clamp(round(x / scale) + zero_point, 0, 255)
scale = (max_val - min_val) / 255
zero_point = round(-min_val / scale)
对比分析
| 维度 | 对称量化 | 非对称量化 |
|---|---|---|
| zero_point | 固定为 0 | 可学习或统计得到 |
| 动态范围利用 | 若分布偏斜,浪费量化区间 | 充分利用 [0,255] 区间 |
| 硬件实现 | 简单,无需零点修正 | 需额外加法运算 |
| 适用场景 | 权重(通常关于 0 对称) | 激活值(常为正或偏斜) |
| INT8 范围 | [-127, 127] | [0, 255] |
实战场景
在 QAT 中,权重通常使用对称量化,因为训练后的权重分布近似高斯且关于 0 对称;激活值则常使用非对称量化,因为 ReLU 后的激活值全为非负,对称量化会浪费一半区间。例如,某层激活值范围为 [0, 12.0],若用对称量化,scale = 12/127 ≈ 0.0945,实际有效精度为 0.0945;若用非对称量化,scale = 12/255 ≈ 0.0471,精度提升一倍。
2.3 量化参数:scale 与 zero_point 的确定
核心原理
scale(步长)和 zero_point(零点)是量化的核心参数。scale 表示量化后每个整数步长对应的浮点大小,zero_point 表示浮点 0 对应的量化整数。反量化公式为:
x_dequant = (x_int - zero_point) × scale
在 QAT 中,这些参数通常通过以下方式确定:
- 静态量化:在训练前统计校准数据集上的激活值 min/max,固定 scale 和 zero_point。
- 动态量化:每次推理时实时计算 min/max,参数随输入变化。
- QAT 中的伪量化:在 forward 中模拟量化误差,但 scale/zero_point 仍由统计得到,且梯度通过直通估计器(STE)回传。
操作流程
- 收集张量样本(权重或激活值)的统计分布。
- 确定量化范围:对称用 max_abs,非对称用 min/max。
- 计算 scale = (max - min) / (q_max - q_min)。
- 计算 zero_point = round(q_min - min / scale),并 clamp 到量化范围。
- 在 QAT 中,将 scale/zero_point 注册为 buffer,不参与梯度更新。
案例拆解
以 TensorRT 的校准过程为例,假设某层激活值分布如下:min=-2.5, max=8.5,目标 INT8 非对称量化。则 scale = (8.5 - (-2.5)) / 255 = 11/255 ≈ 0.0431,zero_point = round(0 - (-2.5)/0.0431) = round(58.0) = 58。量化后,浮点值 0 对应整数 58,浮点值 -2.5 对应整数 0,浮点值 8.5 对应整数 255。若使用 KL 散度校准,会进一步优化 min/max 的选择以最小化信息损失。
2.4 量化误差来源与影响
核心原理
量化误差主要来自四个方面:
- 舍入误差:round() 操作将连续值映射到最近整数,最大误差为 0.5×scale。
- 截断误差:超出量化范围的值被 clamp,产生饱和误差,误差大小取决于超出程度。
- 零点偏移误差:zero_point 取整导致浮点 0 无法精确映射,产生恒定偏移。
- 信息丢失:FP32 的 23 位尾数压缩到 INT8 的 8 位,必然丢失高频细节。
误差分析表
| 误差类型 | 产生原因 | 影响范围 | 缓解方法 |
|---|---|---|---|
| 舍入误差 | round 操作 | 所有值 | 增大位宽、使用随机舍入 |
| 截断误差 | 超出 min/max | 极端值 | 优化 min/max 选择、使用 KL 校准 |
| 零点偏移 | zero_point 取整 | 整体偏移 | 精确计算 zero_point、使用对称量化 |
| 信息丢失 | 位宽不足 | 小数值 | 混合精度、残差连接 |
案例拆解:误差累积对网络的影响
考虑一个 50 层的 ResNet,每层激活值量化引入 1% 的相对误差。由于误差逐层传递,最终输出误差可能达到 1.01^50 ≈ 1.64 倍,即 64% 的偏差。这就是为什么深层网络对量化更敏感。在 QAT 中,我们通过在训练中模拟这些误差,让网络自适应调整权重,从而将误差影响降到最低。例如,在 ImageNet 分类任务中,PTQ(训练后量化)可能掉点 2-3%,而 QAT 通常能控制在 0.5% 以内。
2.5 总结与复盘
本章核心要点可归纳为:
- 定点数 Qm.f 格式是量化的基础,动态范围与精度需权衡。
- 对称量化适合权重,非对称量化适合激活值,选择依据是数据分布。
- scale 和 zero_point 是量化的核心参数,其计算需结合统计分布与校准方法。
- 量化误差来源包括舍入、截断、零点偏移和信息丢失,需针对性缓解。
- 在 QAT 中,fake quant 节点通过模拟量化-反量化过程,将误差纳入训练优化,从而提升量化后模型的鲁棒性。
理解这些基础概念后,下一阶段我们将深入 fake quant 节点的具体实现细节,包括如何插入节点、如何构建训练图,以及如何设计直通估计器(STE)来保证梯度流动。