2、量化基础:模型量化的基本概念、Int8量化的原理、对称与非对称量化、量化参数(scale、zero-point)
在嵌入式系统与边缘计算场景中,STM32 等微控制器(MCU)的算力与存储资源远不及云端 GPU,却需要运行实时神经网络推理任务。模型量化(Quantization)正是解决这一矛盾的核心技术手段。它通过将神经网络中的高精度浮点参数与激活值映射到低比特整数表示,在极小精度损失的前提下,显著压缩模型体积并加速推理。本章将系统梳理量化的基本概念、Int8 量化数学原理、对称与非对称量化策略,以及 scale 与 zero-point 两个核心参数的推导与使用方法,为后续在 STM32 平台上的实际部署打下坚实的理论基础。
上图展示了 Int8 量化的整体框架:左侧是原始浮点数据域,中间是量化参数,右侧是量化后的整数域。整个量化过程本质上是一个带参数的线性映射,而 scale 与 zero-point 就是连接两个数据域的桥梁。下面我们将逐一拆解这些概念。
2.1 模型量化的基本概念与动机
核心原理:模型量化是指将神经网络中存储和计算的数值从高精度浮点(如 FP32)转换为低精度整数(如 Int8、Int16)或低比特浮点(如 FP16)的过程。在 STM32 这类资源受限的 MCU 上,量化带来的收益是巨大的:首先,模型体积可压缩至原来的 1/4(FP32 占 4 字节,Int8 占 1 字节),这使得原本无法放入片内 Flash 的模型变得可行;其次,整数运算在 Cortex-M 系列内核上通常比浮点运算快 2-4 倍,且许多 STM32 型号(如 H7 系列)具备 DSP 指令集,可进一步加速 Int8 矩阵乘加运算;最后,整数运算功耗更低,对电池供电的物联网设备尤为重要。
量化粒度:根据 scale 和 zero-point 的共享范围,量化可分为逐张量(per-tensor)、逐通道(per-channel)和逐组(per-group)量化。逐张量量化对整个张量使用一组参数,实现简单但精度损失较大;逐通道量化对卷积核的每个输出通道分别统计参数,精度更高,是 STM32 部署中常用的折中方案。
| 量化粒度 | 参数共享范围 | 精度表现 | 硬件开销 | 适用场景 |
|---|---|---|---|---|
| 逐张量 | 整个张量一组 (s, z) | 较低 | 极小 | 激活值量化、简单模型 |
| 逐通道 | 每个输出通道一组 (s, z) | 较高 | 中等 | 权重量化、CNN 模型 |
| 逐组 | 按固定大小分组 | 最高 | 较大 | 极端压缩场景 |
2.2 Int8 量化的数学原理与参数推导
核心原理:Int8 量化将浮点实数 r 映射到 8 位整数 q,映射关系由公式 q = round(r / s) + z 决定,其中 s 是缩放因子(scale),z 是零点(zero-point)。反量化公式为 r = s * (q - z)。s 必须是正浮点数,z 必须是整数且与 q 同类型。这个映射的本质是寻找一个线性变换,使得浮点区间 [r_min, r_max] 能够被整数区间 [q_min, q_max] 完整覆盖。
scale 的计算:对于对称量化,s = max(|r_min|, |r_max|) / 127,因为 Int8 对称范围是 [-127, 127](保留 -128 用于特殊处理)。对于非对称量化,s = (r_max - r_min) / 255,利用完整的 [0, 255] 无符号范围。
zero-point 的计算:对称量化中 z 恒为 0;非对称量化中 z = round(-r_min / s) - q_min,其中 q_min 通常为 0。zero-point 的作用是确保浮点中的 0 在量化后仍然精确对应整数 0(或指定整数),这对于卷积神经网络中大量存在的 padding 操作和 ReLU 激活函数至关重要——如果 0 不能被精确表示,padding 和 ReLU 截断会产生系统性误差。
// 非对称量化参数计算示例(C 语言伪代码)
float r_min = -1.5f, r_max = 3.5f;
float s = (r_max - r_min) / 255.0f; // s = 5.0 / 255 ≈ 0.0196
int z = (int)round(-r_min / s) + 0; // z = round(1.5/0.0196) ≈ 77
// 验证:浮点 0.0f 对应整数 q = round(0/s) + 77 = 77
// 反量化:r = 0.0196 * (77 - 77) = 0.0f ✓
2.3 对称量化与非对称量化对比
判断方法:选择对称还是非对称量化,主要取决于数据的分布特征。如果浮点数据的分布关于 0 对称(如经过 tanh 激活的权重),对称量化是自然选择;如果数据分布明显偏向一侧(如 ReLU 后的激活值,全为非负数),非对称量化能更充分地利用整数表示范围,降低量化误差。
| 对比维度 | 对称量化 | 非对称量化 |
|---|---|---|
| 整数范围 | [-127, 127] | [0, 255] 或 [-128, 127] |
| zero-point | 恒为 0 | 非零整数 |
| 计算复杂度 | 低(无需处理 z) | 较高(需额外加减 z) |
| 精度表现 | 对非对称分布数据误差较大 | 对任意分布均能较好适配 |
| 硬件友好度 | 极高(SIMD 优化简单) | 中等(需额外指令处理) |
| 典型应用 | 权重、偏置 | 激活值、特征图 |
实战场景:在 STM32 上部署 MobileNet 时,第一层卷积的输入是 RGB 图像(0-255 范围),使用非对称量化可以精确覆盖整个输入空间;而中间层的权重经过训练后通常呈近似高斯分布,使用对称量化即可获得良好效果。混合使用两种策略,往往比统一使用一种策略的精度高 1-3%。
2.4 量化参数校准与实操案例
操作流程:确定 scale 和 zero-point 的过程称为校准(Calibration)。常用的校准方法有三种:
- MinMax 校准:直接统计训练集或验证集上激活值的全局最小值和最大值,计算 s 和 z。实现简单,但对异常值敏感。
- 百分位校准:使用 99.99% 或 99.999% 分位数替代最大值,避免个别离群点拉大量化范围。
- KL 散度校准:通过最小化量化前后数据分布的 KL 散度来确定最优截断阈值,精度最高但计算量较大。
案例拆解:假设我们在 STM32F746 上部署一个手势识别 CNN,模型第一层卷积的权重分布范围为 [-0.85, 0.92],激活值(ReLU 后)范围为 [0.0, 6.4]。我们采用逐通道对称量化权重、逐张量非对称量化激活值的策略。
| 数据对象 | 分布范围 | 量化策略 | scale | zero-point |
|---|---|---|---|---|
| 权重(通道 0) | [-0.85, 0.92] | 对称 | 0.92/127 ≈ 0.00724 | 0 |
| 权重(通道 1) | [-0.72, 0.68] | 对称 | 0.72/127 ≈ 0.00567 | 0 |
| 激活值 | [0.0, 6.4] | 非对称 | 6.4/255 ≈ 0.0251 | 0 |
校准完成后,我们将 FP32 权重转换为 Int8 存储,并在推理时使用 CMSIS-NN 的 arm_convolve_s8() 函数执行整数卷积。实测结果显示:模型体积从 1.2MB 压缩至 310KB,单次推理时间从 85ms 降至 23ms,精度从 96.2% 降至 95.1%,损失在可接受范围内。
2.5 常见误区与总结复盘
常见误区一:认为量化就是简单的类型转换。实际上,量化需要精心设计参数,且不同层可能需要不同的量化策略。直接使用 (int8_t)float_value 进行强制转换会完全破坏模型精度。
常见误区二:忽略 zero-point 的作用。在非对称量化中,zero-point 的微小误差会在多层累加后被放大。尤其在残差网络(ResNet)中,跳跃连接的加法操作要求两个分支的 zero-point 必须一致,否则会产生偏移。
常见误区三:对所有层使用相同的量化参数。不同层的激活值分布差异巨大,必须逐层统计。经验法则是:权重逐通道量化,激活值逐张量量化,且每层独立校准。