2、量化基础:定点与浮点表示、量化参数(scale/zero-point)、对称与非对称量化
TinyML 模型在部署到 MCU、DSP 或 NPU 等资源受限设备时,几乎无一例外地需要将训练好的 32 位浮点(FP32)权重和激活值转换为低比特整数表示(如 INT8、INT16)。这一转换过程称为量化(Quantization),而 PTQ(训练后量化)则是其中工程代价最低、落地最广的路径。要正确实施 PTQ 并完成功能验证,首先必须透彻理解量化背后的数学本质:浮点与定点如何映射、scale 与 zero-point 如何决定映射关系、对称与非对称量化各自适用何种场景。本章将围绕这三个核心问题展开,为后续的校准、误差分析和功能验证打下坚实的理论基础。
2.1 定点与浮点表示:为什么 TinyML 必须转向整数运算
浮点数(FP32)由符号位、指数位和尾数位组成,能够以极高的动态范围表达实数,但其硬件实现需要专门的 FPU(浮点运算单元),且单次乘加运算的功耗和面积远高于整数运算。在 Cortex-M 系列 MCU 上,FP32 乘法通常需要 3-5 个时钟周期,而 INT8 乘法仅需 1 个周期,且功耗降低约 10 倍。定点数则通过固定的小数点位置,用整数表示实数,其运算完全由 ALU 完成,无需额外硬件支持。
在 TinyML 场景中,模型推理的瓶颈往往不是算力而是内存带宽和功耗。一个 100 万参数的模型,FP32 存储需要 4MB,而 INT8 仅需 1MB,这意味着 Flash 占用减少 75%,SRAM 占用同样大幅降低。更重要的是,绝大多数 MCU 不具备 FPU(如 Cortex-M0+),若强行运行浮点推理,只能通过软件模拟,速度慢 20-50 倍。因此,将模型转换为定点或整数表示,是 TinyML 落地的先决条件。
定点表示的核心思想是:用整数配合缩放因子(scale)来表达实数。例如,定点数 Q7.8 表示 7 位整数位、8 位小数位,其精度为 2⁻⁸ = 0.00390625。但现代量化框架(如 TFLite Micro、CMSIS-NN)更倾向于使用统一的整数表示 + 浮点 scale 的组合,即"伪定点"方式——存储和计算用整数,但 scale 以浮点形式保存,在反量化或融合运算时使用。
2.2 量化参数:scale 与 zero-point 的数学定义与计算
量化映射的数学表达式为:
量化(浮点→整数): q = round(r / scale) + zero_point
反量化(整数→浮点): r = (q - zero_point) × scale
其中,scale(缩放因子)是一个正浮点数,表示整数每变化 1 个单位对应的浮点步长;zero_point(零点)是一个整数,表示浮点值 0.0 对应的量化值。这两个参数的计算方法如下:
- 确定浮点范围:统计张量(权重或激活)的最小值
r_min和最大值r_max。对于权重,通常直接取训练后的实际 min/max;对于激活,则需要通过校准数据集(Calibration Dataset)统计得出。 - 计算 scale:
scale = (r_max - r_min) / (q_max - q_min),其中q_max和q_min是量化后的整数范围。对于 INT8 非对称量化,q_min=0, q_max=255;对于对称量化,q_min=-127, q_max=127(或 -128~127,取决于实现)。 - 计算 zero_point:
zero_point = round(q_min - r_min / scale),并需要裁剪到[q_min, q_max]范围内。
以实际案例说明:假设某层激活值经校准后统计得到 r_min = -2.5,r_max = 5.5,采用非对称 INT8 量化(0~255):
scale = (5.5 - (-2.5)) / (255 - 0) = 8.0 / 255 ≈ 0.0313725
zero_point = round(0 - (-2.5) / 0.0313725) = round(79.69) = 80
验证:浮点值 0.0 对应的量化值为 80,反量化时 (80 - 80) × 0.0313725 = 0.0,映射正确。浮点值 5.5 对应 round(5.5/0.0313725) + 80 = round(175.3) + 80 = 255,达到最大值边界。
| 参数 | 符号 | 作用 | 典型值/范围 | 注意事项 |
|---|---|---|---|---|
| 缩放因子 | scale | 确定量化步长 | 正浮点数,通常为 2⁻¹⁰ ~ 2⁻³ | 过小导致溢出,过大量化误差增大 |
| 零点 | zero_point | 对齐浮点 0 值 | INT8 范围 [-128, 127] 或 [0, 255] | 非对称量化时通常非零 |
| 位宽 | bit-width | 决定量化精度 | 8/16/4 位 | 位宽越低,精度损失越大 |
| 量化范围 | [q_min, q_max] | 整数表示边界 | INT8: [-128,127] 或 [0,255] | 对称量化通常用 [-127,127] 避免溢出 |
2.3 对称量化与非对称量化:原理、对比与选型
对称量化强制 zero_point = 0,即浮点 0 映射到整数 0。此时映射简化为 q = round(r / scale),反量化为 r = q × scale。对称量化的优势在于:
- 计算路径更短,无需额外的零点减法操作,在硬件上可减少一次加法运算。
- 对于权重张量(其分布通常近似关于 0 对称),对称量化不会浪费量化范围。
- 卷积运算中的乘加累加可以完全使用整数运算,无需处理零点偏移。
但对称量化的缺点是:若浮点分布明显不对称(如 ReLU 后的激活值全为非负),则量化范围会有一半被浪费。例如,激活值范围 [0, 6.0],若采用对称量化,则实际映射范围是 [-6.0, 6.0],但负半轴完全未使用,导致有效精度减半。
非对称量化允许 zero_point ≠ 0,能够将浮点范围 [r_min, r_max] 完整映射到整数范围 [q_min, q_max],充分利用所有量化级别。对于激活值(尤其是经过 ReLU 后的非负分布),非对称量化通常能获得更低的量化误差。其代价是:
- 推理时需要额外处理 zero_point 的偏移,增加少量计算开销。
- 在卷积层融合时,zero_point 需要被纳入偏置项,增加了实现复杂度。
工程实践中的选型原则:权重优先使用对称量化,激活优先使用非对称量化。这是因为权重分布通常对称,而激活分布往往偏置。TFLite Micro 默认采用这种混合策略,在精度和计算效率之间取得最佳平衡。
2.4 案例拆解:一个 Conv2D 层的量化参数计算与验证
假设我们有一个 3×3 的卷积层,权重张量(4 个输出通道,每个通道 3×3×3)的统计值如下:w_min = -0.85,w_max = 0.92。激活值(输入特征图)经校准统计为 a_min = 0.0,a_max = 7.5。我们采用权重对称 INT8、激活非对称 INT8 的混合方案。
步骤 1:计算权重量化参数(对称)
scale_w = max(|w_min|, |w_max|) / 127 = 0.92 / 127 ≈ 0.007244
zero_point_w = 0
量化权重: q_w = round(w / 0.007244)
步骤 2:计算激活量化参数(非对称)
scale_a = (7.5 - 0.0) / 255 = 0.029412
zero_point_a = round(0 - 0.0 / 0.029412) = 0
量化激活: q_a = round(a / 0.029412) + 0
注意:由于激活最小值为 0,zero_point 恰好为 0,此时非对称退化为对称。但若激活范围为 [1.2, 7.5],则 zero_point_a = round(0 - 1.2/0.029412) = round(-40.8) = -41,非对称特性显现。
步骤 3:卷积计算的整数实现
浮点卷积:y = Σ (w × a) + b。量化后,整数卷积为:
q_y = zero_point_y + scale_w * scale_a / scale_y × (Σ (q_w × q_a) - zero_point_a × Σ q_w + q_b)
其中 q_b 是偏置的量化值,scale_y 是输出激活的 scale。实际部署时,scale_w * scale_a / scale_y 会被预先计算为一个浮点乘数,并在累加后一次性缩放。
步骤 4:功能验证要点
- 验证
zero_point是否在合法范围内(INT8 为 [-128, 127]),若超出则裁剪。 - 验证反量化后的浮点值与原始浮点值的最大绝对误差(MAE)和均方根误差(RMSE)。
- 使用随机输入数据,对比量化模型与浮点模型的输出差异,确认误差在可接受范围(通常 < 1% 相对误差)。
r_min / scale 恰好接近整数边界,round 操作可能产生 1 的偏差。这种偏差在深层网络中会被逐层放大。建议在验证时检查每一层的 zero_point 是否与理论值一致,并观察激活值是否出现系统性偏移。
2.5 常见误区与总结复盘
误区 1:认为对称量化一定比非对称量化精度差。实际上,对于权重这种对称分布,对称量化反而更优,因为它避免了 zero_point 引入的额外噪声。选型应基于数据分布,而非一概而论。
误区 2:忽略 scale 的溢出风险。当浮点范围过大而位宽较小时,scale 会变得很大,导致量化步长粗糙,小数值被截断为 0。例如,若权重范围 [-100, 100] 用 INT8 对称量化,scale = 100/127 ≈ 0.787,则小于 0.39 的权重全部变为 0,精度严重受损。此时应考虑使用 INT16 或进行权重裁剪。
误区 3:zero_point 计算后不检查范围。在极端情况下(如 r_min 远大于 0),zero_point 可能超出 [q_min, q_max]。例如,r_min = 10.0,r_max = 20.0,scale = 10/255 ≈ 0.0392,zero_point = round(0 - 10/0.0392) = round(-255.1) = -255,超出 INT8 范围。此时必须裁剪到 -128,但会导致部分浮点值无法映射,需要重新调整 r_min 或使用更大的位宽。
总结复盘:量化参数的正确性是 PTQ 功能验证的第一道关卡。在编写验证脚本时,应至少包含以下检查项:
- 所有 scale 必须为正浮点数,且非 NaN/Inf。
- 所有 zero_point 必须在量化范围内。
- 反量化后的张量与原始张量的形状、数值范围一致。
- 对每个量化层,计算量化误差(MAE/RMSE),并设定阈值(如 MAE < 0.01 × 原始范围)。
- 端到端验证:使用至少 100 张校准图片,对比量化模型与浮点模型的输出 logits 或 softmax 概率分布。
只有通过上述验证,才能确保量化后的模型在目标硬件上具备可靠的功能正确性。下一阶段将进入校准数据集的选择与 PTQ 流程设计,但在此之前,请务必确保对 scale 和 zero_point 的理解无任何偏差。