模型量化基础:从浮点到整数的思维转变
模型量化,说白了就是把模型里那些高精度的浮点数(FP32),用低精度的整数(INT8)甚至更低比特来表示。你想想看,一个模型动辄几百兆,塞进边缘设备里根本跑不动。量化就是帮模型「减肥」——减掉那些不必要的精度,换来更快的速度和更小的体积。
我在项目中遇到过不少同学,一听到量化就觉得是「有损压缩」,担心精度掉得没法看。其实不然。好的量化策略,能把精度损失控制在 1% 以内,甚至有些场景下还能带来微弱的正则化效果,让模型更鲁棒。嗯,这里面的门道,我们慢慢聊。
量化的本质:映射与截断
量化的数学本质,就是一个映射函数。它把浮点数的取值范围,映射到整数的取值范围上。举个例子,FP32 的取值范围大约是 ±3.4×10³⁸,而 INT8 只有 -128 到 127。我们要做的,就是找到一种方式,让这个映射损失最小。
我个人习惯把量化拆成两个步骤:
- 确定缩放因子(Scale)和零点(Zero Point)
- 执行映射计算
公式其实很简单:
Q = round( (R - Z) / S )
其中 R 是原始浮点值,Q 是量化后的整数值,S 是缩放因子,Z 是零点。反过来,反量化就是:
R ≈ S × (Q - Z)
这里有个关键点:零点 Z 的存在,是为了让浮点 0 能精确映射到整数 0。为什么重要?因为卷积、全连接层里大量用到 padding 和 ReLU,如果 0 映射不准,计算就会出偏差。
对称量化 vs 非对称量化
这是量化里最基础也最核心的选择题。我直接给你对比表:
| 对比维度 | 对称量化 | 非对称量化 |
|---|---|---|
| 零点 Z | 固定为 0 | 根据数据分布动态计算 |
| 映射范围 | [-max, max] → [-127, 127] | [min, max] → [0, 255] |
| 计算复杂度 | 低(无需零点偏移) | 高(需要零点偏移计算) |
| 适用场景 | 权重分布对称(如正态分布) | 激活值分布偏斜(如 ReLU 后) |
| 精度损失 | 对非对称分布损失较大 | 能更好适配数据分布 |
对称量化,就是假设你的数据分布是对称的。权重经过训练后,通常接近零均值对称分布,所以对称量化对权重很友好。而且零点为 0,计算时少一次加减法,硬件实现更简单。
非对称量化,则更灵活。它根据实际数据的 min 和 max 来确定映射范围。比如 ReLU 后的激活值全是非负的,用非对称量化就能把整个 INT8 的 0~255 范围都用上,精度自然更高。
我的经验: 权重用对称量化,激活值用非对称量化。这是业界最成熟的方案,TensorRT、ONNX Runtime 都这么干。别自己瞎折腾,除非你有特殊需求。
量化精度与性能的权衡
为什么量化能提速?原因有三:
- 计算更快:INT8 乘法比 FP32 快 2-4 倍,很多硬件还有专门的 INT8 指令
- 内存更小:模型体积缩小 4 倍,缓存命中率大幅提升
- 带宽更低:从 DDR 搬运的数据量减少,功耗自然下降
但代价是什么?精度。我直接给你看一组典型数据:
| 量化方案 | 模型体积 | 推理速度(FPS) | 精度(Top-1) |
|---|---|---|---|
| FP32(基线) | 100% | 1.0x | 72.5% |
| INT8 对称 | 25% | 2.8x | 71.8% |
| INT8 非对称 | 25% | 2.6x | 72.2% |
| INT4 | 12.5% | 4.5x | 68.3% |
看到没?INT8 量化只掉了 0.3%~0.7% 的精度,但速度翻了近 3 倍。这就是量化的魅力。
我曾经踩过的坑: 有一次我把一个 MobileNetV2 直接量化到 INT8,结果精度掉了 5%。排查了半天,发现是某个层的激活值分布特别宽,量化截断把大量信息丢掉了。后来加了 校准数据集 做 KL 散度优化,才把精度拉回来。
量化精度的关键:校准与截断
校准(Calibration)是量化前必须做的一步。它的目的是:找到最佳的缩放因子 S 和零点 Z。
常见的校准方法有三种:
- MinMax 校准:直接用数据的 min 和 max 确定范围。简单粗暴,但对 outlier 敏感。
- KL 散度校准:让量化后的分布尽量接近原始分布。TensorRT 默认用这个。
- 百分位校准:去掉两端 1% 的极端值,减少 outlier 影响。
我个人习惯先用 MinMax 快速验证,再用 KL 散度做最终校准。如果精度还不满意,就检查一下哪些层的量化误差大,单独给它们保留 FP16。
量化推理的完整流程
下面这张图,是我在项目中总结的量化推理流程:
量化精度的「黄金三角」
在实际项目中,我总结了一个「黄金三角」原则:
- 模型结构:深度可分离卷积、残差连接对量化更友好
- 校准数据:必须覆盖真实推理场景的分布
- 量化策略:逐层 vs 逐通道、对称 vs 非对称
这三者缺一不可。我见过有人花了两周调量化策略,结果发现是校准集选错了——用的全是白天图片,模型一到晚上就崩。嗯,这种低级错误,犯一次就够了。
实用技巧: 量化后一定要做逐层精度对比。把每一层的输出都 dump 出来,算一下 SNR(信噪比)。哪一层 SNR 低于 30dB,就重点优化那一层。这个习惯帮我省了无数排查时间。
量化精度的「隐形杀手」
最后,我分享几个容易踩的坑:
- BatchNorm 融合:量化前必须把 BN 层融合进 Conv 层,否则精度会崩
- 激活函数:ReLU6 比 ReLU 对量化更友好,因为它的输出范围固定
- 跨层连接:ResNet 的 shortcut 要注意两边的量化参数是否一致
- 量化粒度:逐通道量化比逐层量化精度高,但计算量也大