4. 量化核心原理
TinyML 模型量化,本质上是在精度与资源之间做一次“翻译”。深度学习模型在训练时通常使用 32 位浮点数(FP32)来存储权重和激活值,但在微控制器、边缘传感器等资源受限设备上,FP32 的存储和计算开销往往难以承受。量化就是将 FP32 的连续数值映射到低比特离散数值(如 INT8、INT16)的过程。要理解这一过程,必须先掌握三个核心概念:定点与浮点表示、量化尺度(Scale)与零点(Zero Point)、对称与非对称量化。这三者共同决定了量化误差的来源、大小以及部署后的实际表现。
上图展示了从浮点表示到定点/量化表示的完整映射关系。在 TinyML 部署中,我们通常将 FP32 模型转换为 INT8 或 INT16 模型,以换取 4 倍到 8 倍的存储压缩和更快的推理速度。但这一转换并非无损,理解量化尺度与零点的数学含义,是控制精度损失的第一步。
4.1 定点与浮点表示:从数学本质到硬件代价
浮点表示(Floating Point) 采用科学计数法的二进制形式,由符号位、指数位和尾数位组成。以 FP32 为例,其数值范围约为 ±3.4×10³⁸,精度可达 7 位有效十进制数字。这种表示方式动态范围极大,非常适合训练阶段梯度传播和参数更新的需求。然而,FP32 运算需要专门的浮点单元(FPU),在 ARM Cortex-M 系列等低功耗 MCU 上,FPU 要么不存在,要么频率受限,导致计算延迟和功耗显著上升。
定点表示(Fixed Point) 则使用整数配合固定的小数点位置来表示数值。例如 Q7.8 格式表示 1 位符号、7 位整数、8 位小数,其范围有限但精度均匀。定点运算只需要整数乘法器和移位操作,在硬件上极其高效。TinyML 中常用的 INT8 量化,本质上就是一种特殊的定点表示——将浮点数值映射到 [-128, 127] 的整数区间。
4.2 量化尺度与零点:数学映射的核心
量化过程可以抽象为一个仿射变换。给定浮点张量 r,量化后的整数值 q 满足:
r = S × (q - Z)
其中:
- S(Scale,尺度):浮点数值与整数步长的比例关系,计算公式为
S = (r_max - r_min) / (q_max - q_min)。S 是一个浮点数,决定了量化的分辨率。 - Z(Zero Point,零点):浮点数值 0 对应的量化整数值。Z 的作用是保证浮点 0 在量化后能被精确表示,避免因偏移产生误差。
实际量化时,我们首先统计张量的最小值 r_min 和最大值 r_max,然后计算 S 和 Z,最后将每个浮点值映射到最近的整数:
q = round(r / S + Z)
反量化(Dequantization)则使用 r = S × (q - Z) 恢复近似浮点值。这一过程在推理时通常被融合到算子内部,以减少额外开销。
4.3 对称与非对称量化:适用场景与精度权衡
对称量化(Symmetric Quantization) 将浮点范围映射到以 0 为中心的整数区间,即 Z = 0。此时 q = round(r / S),实现简单,无需存储零点。对称量化适合权重分布近似对称的层(如经过 BatchNorm 后的卷积层),且 INT8 的符号位天然支持负值。但若激活值分布偏向正数(如 ReLU 输出),对称量化会浪费一半的量化范围,导致精度下降。
非对称量化(Asymmetric Quantization) 允许 Z ≠ 0,将浮点范围 [r_min, r_max] 完整映射到 [q_min, q_max]。对于 ReLU 等非负激活函数,非对称量化能充分利用全部整数范围,显著降低量化误差。代价是需要额外存储和计算 Z,且推理时需多一次减法操作。
| 对比维度 | 对称量化 | 非对称量化 |
|---|---|---|
| 零点 Z | 恒为 0 | 非 0,需计算和存储 |
| 计算复杂度 | 低(无减法) | 中(多一次减法) |
| 适用张量 | 权重(分布近似对称) | 激活值(ReLU 后非负) |
| 精度表现 | 对偏态分布误差较大 | 对偏态分布更友好 |
| 硬件支持 | 多数 NPU/加速器原生支持 | 部分硬件需额外指令 |
在实际工程中,权重通常使用对称量化,激活值通常使用非对称量化。这是因为权重经过训练后分布相对稳定且近似高斯分布,而激活值受 ReLU 等非线性函数影响,往往呈现明显的单侧分布。
4.4 案例拆解:一个语音唤醒词的 INT8 量化实战
假设我们有一个基于 DS-CNN 的语音唤醒词模型,输入为 49 帧 Mel 频谱特征,模型大小 450KB,在 Cortex-M4 上 FP32 推理延迟为 320ms。目标是将模型量化到 INT8 并部署到资源更紧张的 Cortex-M0+ 上。
初始现象:直接使用 TensorFlow Lite 默认的量化配置(对称权重、非对称激活),模型精度从 96.2% 下降到 91.5%,误唤醒率上升了 3 倍。用户无法接受。
分析过程:
- 首先检查各层的权重分布。通过直方图工具发现,第一层卷积权重存在少量极端值(outliers),导致 S 值偏大,量化步长粗糙。
- 检查激活值分布。发现中间层的激活值范围在 [-0.5, 6.8] 之间,非对称量化虽然比对称量化好,但仍有部分通道的分布差异极大。
- 进一步定位到 BatchNorm 层融合后的缩放因子影响了激活分布。
优化步骤:
- 对第一层权重采用 Per-Channel 量化(每个输出通道独立计算 S 和 Z),而非默认的 Per-Tensor 量化。这一步将精度恢复到 94.8%。
- 对激活值使用 Percentile 校准(取 99.99% 分位数作为 r_max),排除极端噪声值的影响。精度提升至 95.6%。
- 将最后一层全连接层保留为 FP32(混合精度量化),因为该层参数少但对最终分类置信度影响大。最终精度达到 96.0%,仅损失 0.2%。
结果对比:
| 配置 | 模型大小 | 推理延迟 | 精度 |
|---|---|---|---|
| FP32 原始 | 450KB | 320ms | 96.2% |
| 默认 INT8 | 113KB | 85ms | 91.5% |
| 优化 INT8 | 118KB | 88ms | 96.0% |
风险与代价:Per-Channel 量化增加了约 4KB 的元数据存储,且部分底层算子(如 CMSIS-NN)对 Per-Channel 支持不完善,需要手动实现。混合精度量化导致推理流程中需要切换数据类型,增加了约 3ms 的调度开销。
4.5 常见误区与总结复盘
误区一:认为量化尺度 S 越小越好。实际上,S 过小会导致量化范围不足,大数值被截断(Clipping),产生严重溢出误差。S 的选择需要在分辨率和范围之间平衡。
误区二:忽略零点 Z 的作用。在对称量化中 Z=0 简化了计算,但若强行对非负激活值使用对称量化,会浪费一半的整数编码空间,导致有效分辨率减半。
误区三:对所有层使用相同的量化配置。不同层对量化的敏感度差异巨大。第一层和最后一层通常对精度影响最大,应优先考虑更高比特或 Per-Channel 量化。
误区四:校准数据集选择不当。校准集应覆盖真实部署场景的输入分布。若只用干净语音校准,遇到噪声环境时激活值分布偏移,量化误差会急剧增大。
总结而言,定点与浮点表示决定了硬件计算的效率边界,量化尺度与零点构成了浮点到整数的数学桥梁,对称与非对称量化则提供了针对不同张量分布的精度优化手段。掌握这三者的原理,是进行后续精度调优、误差分析和部署验证的基石。在实际项目中,建议按照“先默认配置跑通,再逐层分析分布,最后针对性优化”的流程推进,避免盲目追求低比特而牺牲模型可用性。