3、量化类型:对称量化与非对称量化、逐张量与逐通道量化的区别与适用场景
TinyML 模型量化的核心目标,是在尽可能保留精度的前提下,将浮点权重与激活值映射到低比特整数空间。然而,“量化”并非单一操作,它包含多种类型与粒度选择。理解对称量化与非对称量化、逐张量与逐通道量化的本质区别,是工程师在部署 Int8 模型时做出正确取舍的前提。错误的量化类型选择,轻则导致精度损失超标,重则引发推理结果完全错误。本节将系统拆解这两组关键概念,并给出面向实际硬件(如 Cortex-M 系列 MCU)的选型建议。
上图展示了量化类型与粒度的核心决策路径。左侧分支解决“数值映射范围”问题,右侧分支解决“统计粒度”问题。实际部署时,两者需要组合使用:例如,权重常用“对称+逐通道”,激活常用“非对称+逐张量”。下面逐一深入剖析。
3.1 核心原理:从数学映射到硬件指令
量化本质上是将浮点实数域映射到有限整数域。设浮点值为 \( r \),量化后的整数为 \( q \),则标准仿射映射关系为:
r = scale * (q - zero_point)
其中 scale(缩放因子)是浮点数,zero_point(零点)是整数。对称量化强制 zero_point = 0,非对称则允许其非零。从信息论角度看,对称量化假设数据分布关于原点对称,非对称量化则能适应偏置分布(如 ReLU 后的激活值全为非负)。
在硬件层面,Cortex-M4/M7 等内核的 DSP 指令(如 SMMUL、SMLAD)对对称量化支持更佳,因为无需额外的零点减法操作。而 Cortex-M55 等带有 Ethos-U55 NPU 的芯片,其硬件加速器通常原生支持非对称量化,但逐通道量化需要额外的内存访问来加载每个通道的 scale。
- 对称量化: \( r = scale \times q \),其中 \( scale = \frac{max(|r|)}{127} \)
- 非对称量化: \( r = scale \times (q - zero\_point) \),其中 \( scale = \frac{max(r) - min(r)}{255} \),\( zero\_point = round(-\frac{min(r)}{scale}) \)
逐张量与逐通道的区别在于 scale 的统计维度。逐张量为整个 4D 张量(N, H, W, C)计算一个 scale;逐通道则为每个输出通道(C 维度)分别计算 scale。后者能捕捉不同通道间数值范围的巨大差异,这在深度可分离卷积(如 MobileNet)中尤为明显——不同通道的权重分布可能相差数个数量级。
3.2 判断方法:四步选型流程
面对一个具体的层或张量,可按以下流程快速决策:
- 判断张量类型:是权重还是激活值?权重通常用对称量化,激活值用非对称量化。
- 分析数值分布:统计权重的 min/max 和直方图。若分布近似对称(如正态分布),选对称;若明显偏置(如所有值大于0),选非对称。
- 评估通道差异:计算每个输出通道的权重范围。若最大/最小通道的 scale 比值超过 10 倍,强烈建议逐通道量化。
- 检查硬件约束:查阅目标 MCU 的指令集文档。若硬件不支持逐通道的 scale 加载,则退化为逐张量,但需通过裁剪或正则化控制通道差异。
| 维度 | 对称量化 | 非对称量化 | 逐张量 | 逐通道 |
|---|---|---|---|---|
| 零点 | 固定为 0 | 可偏移 | 单一值 | 每通道独立 |
| 计算开销 | 低(无偏移) | 中(需偏移) | 最低 | 中(需查表) |
| 精度表现 | 权重佳,激活差 | 激活佳 | 通道差异大时差 | 通道差异大时优 |
| 典型应用 | 权重、BN 参数 | 激活值、Embedding | 小模型、激活 | 卷积权重、全连接 |
| 内存占用 | 1 个 scale | 1 个 scale + 1 个 zp | 1 组参数 | C 组参数(C为通道数) |
3.3 案例拆解:MobileNetV2 在 Cortex-M7 上的量化实战
背景与约束:某智能门锁产品需在 STM32H743(Cortex-M7, 480MHz)上部署 MobileNetV2 进行人脸检测。模型原始大小为 13.5MB,Flash 剩余 2MB,RAM 剩余 512KB。目标帧率 ≥ 5 FPS,精度损失 ≤ 2%。
初始现象:直接使用 TensorFlow Lite 默认的“对称+逐张量”量化后,模型大小降至 1.7MB,但精度损失高达 7.3%,且推理时间 320ms,未达帧率要求。
关键数据分析:通过 TFLite 的量化调试工具,导出每层权重的 min/max。发现第 3、5、7 个深度可分离卷积层的权重通道范围差异极大——最小通道范围 0.002,最大通道范围 0.85,比值达 425 倍。同时,激活值经 ReLU6 后分布集中在 [0, 6] 区间,但存在少量负值(来自残差连接)。
分析判断:逐张量量化用一个 scale 覆盖 0.002~0.85 的范围,导致小数值通道被严重截断。激活值使用对称量化则浪费了一半的整数表示范围(负半轴几乎未使用)。
实际操作步骤:
- 将权重改为“对称+逐通道”量化,激活保持“非对称+逐张量”。
- 对残差连接层,手动将激活量化范围从 [-6, 6] 调整为 [-0.1, 6.2],以捕捉微小负值。
- 使用 TFLite 的 MLIR 量化器,设置
--post_training_quantize=True --quantize_per_channel=True。 - 在 CMSIS-NN 中启用
ARM_NN_TRUNCATE宏,匹配逐通道 scale 的加载方式。
结果对比:
| 方案 | 模型大小 | Top-1 精度 | 推理时间 |
|---|---|---|---|
| 浮点基线 | 13.5 MB | 91.2% | 980 ms |
| 对称+逐张量 | 1.7 MB | 83.9% | 320 ms |
| 对称逐通道权重 + 非对称逐张量激活 | 1.7 MB | 89.8% | 285 ms |
风险与代价:逐通道量化使 Flash 中多存储了 32 个 scale 值(每个通道 4 字节),仅增加 128 字节,可忽略。但 CMSIS-NN 的矩阵乘法需要额外循环加载 scale,导致推理时间仅提升 12%,而非预期的 20%。复盘发现,瓶颈在于内存访问模式而非计算量。
3.4 常见误区与总结复盘
误区一:对称量化一定比非对称好。实际上,对于分布严重偏置的激活值,非对称量化能提供更精细的表示。例如,ReLU 后的激活值全为非负,对称量化会浪费一半的整数范围。
误区二:逐通道量化总是优于逐张量。逐通道量化增加了计算复杂度和内存访问。对于通道差异小的层(如全连接层),逐张量量化完全足够,强行使用逐通道反而降低推理速度。
误区三:忽略 zero_point 的硬件代价。部分低端 MCU 的 DSP 指令不支持带零点的乘法,需要软件模拟,导致推理时间翻倍。选型前务必查阅指令集手册。
误区四:量化类型与粒度混为一谈。两者是正交的维度。可以组合出“对称+逐张量”、“非对称+逐通道”等四种组合,需根据张量类型分别选择。
- 权重:优先“对称+逐通道”,若硬件不支持则退化为“对称+逐张量”,但需检查通道差异。
- 激活:优先“非对称+逐张量”,若激活分布极端(如长尾),可考虑逐通道。
- 偏置:通常不量化,保持 int32 或 float32。
- 硬件适配:先查 CMSIS-NN 或厂商 SDK 支持的量化格式,再决定方案。