2. 量化精度与性能权衡:INT4/INT8/FP16 量化对比与误差分析
量化,说白了就是用更少的比特数去表示模型的权重和激活值。很多刚入行的朋友觉得量化就是简单地把 float32 转成 int8,跑起来就完事了。嗯,要是真这么简单,我就不用花一整章来讲它了。
我个人的习惯是,在动手量化之前,先想清楚一个问题:你到底要省什么? 省内存?省带宽?还是省计算时间?不同的目标,对应的量化策略完全不同。这一章,我们就来把这笔账算清楚。
2.1 三种主流量化格式:INT8、INT4、FP16
先看一张对比表,心里有个底:
| 格式 | 位宽 | 动态范围 | 精度特点 | 典型场景 |
|---|---|---|---|---|
| FP16 | 16-bit | ±65,504 | 接近 FP32,几乎无精度损失 | GPU/部分 MCU 加速器 |
| INT8 | 8-bit | [-128, 127] | 精度损失可控,推理加速明显 | MCU 主力量化格式 |
| INT4 | 4-bit | [-8, 7] | 精度损失大,需特殊校准 | 极端内存受限场景 |
你想想看,FP16 其实不算严格意义上的「量化」,它只是把 float 的指数和尾数砍了一半。在支持 FP16 的硬件上,它几乎是零成本的精度保留方案。但大多数 MCU 没有 FPU,或者 FPU 只支持 FP32,这时候 FP16 反而要软件模拟,得不偿失。
INT8 才是 MCU 上的主力。我做过一个项目,把 MobileNetV2 从 FP32 量化到 INT8,模型体积从 14MB 直接降到 3.5MB,推理速度提升了 3 倍,而 Top-1 准确率只掉了 0.7%。这个 trade-off,绝大多数应用都能接受。
INT4 就比较激进了。我曾经在一个只有 256KB Flash 的 Cortex-M4 上跑关键词唤醒模型,FP32 根本塞不下,INT8 勉强能放但没空间放中间缓存。最后硬着头皮上了 INT4,配合混合精度,才把模型塞进去。代价是精度掉了 2.3%,但至少能跑了。
2.2 量化误差从哪来?
量化误差不是玄学,它有三个主要来源。我习惯把它们叫做「三把刀」:
- 截断误差: 数值超出量化范围,直接砍掉。比如 INT8 最大只能表示 127,权重里有个 128.3,对不起,截断成 127。
- 舍入误差: 数值在量化步长之间,四舍五入带来的偏差。比如步长是 0.5,实际值 1.2 量化成 1.0,误差 0.2。
- 异常值放大: 激活值里偶尔出现几个特别大的值,为了覆盖它们,量化步长被拉大,导致大部分正常值的精度反而变差。
为什么会这样?我举个例子你就明白了。假设你有一组激活值,99% 都在 [-1, 1] 之间,但有 1% 的值跑到了 10。如果用 INT8 量化,为了覆盖那个 10,步长必须设成 10/127 ≈ 0.0787。结果 [-1, 1] 区间只用了不到 26 个量化等级,精度损失惨重。这就是异常值在作祟。
2.3 精度损失评估方法
量化完怎么知道模型还行不行?不能光靠感觉。我一般用下面这套流程:
2.3.1 逐层误差分析
不要只看最终准确率。我习惯把每一层的输出都 dump 出来,对比 FP32 和量化后的余弦相似度。如果某一层的相似度突然掉到 0.95 以下,那这一层就是瓶颈。
# 伪代码:逐层余弦相似度检查
for layer in model.layers:
fp32_out = layer.forward(fp32_input)
int8_out = layer.forward(int8_input)
cos_sim = cosine_similarity(fp32_out.flatten(), int8_out.flatten())
print(f"Layer {layer.name}: cos_sim = {cos_sim:.4f}")
if cos_sim < 0.95:
print(" ⚠️ 需要关注!")
2.3.2 最终指标对比
对于分类任务,看 Top-1/Top-5 准确率。对于回归任务,看 MSE 或 MAE。但要注意,量化后的精度波动在 ±0.5% 以内通常是可以接受的。如果掉了 1% 以上,就要回去找原因了。
| 评估指标 | 适用场景 | 可接受下降范围 |
|---|---|---|
| Top-1 准确率 | 分类 | ≤ 0.5% |
| MSE | 回归 | ≤ 1% |
| 余弦相似度 | 逐层分析 | ≥ 0.95 |
| PSNR | 图像/音频 | ≥ 30dB |
2.3.3 校准数据集的重要性
量化需要「校准数据集」来确定缩放因子。很多人随便拿几张图就跑,结果上线后精度崩了。我建议:校准集至少要覆盖真实场景中 80% 的数据分布。比如你做的是户外摄像头的人脸检测,校准集里就不能全是室内自拍。
2.4 量化精度与性能的权衡决策树
下面这张图是我自己总结的决策流程,每次做量化项目我都会过一遍:
2.5 实战中的量化策略选择
最后,我分享几个实战中的经验法则:
- 先跑 INT8 校准,看精度。 如果掉点 < 0.5%,直接上 INT8,别折腾。
- 如果 INT8 掉点 > 1%, 先检查是不是异常值问题。用逐层余弦相似度定位问题层,考虑对该层使用 FP16 混合精度。
- 如果 Flash 实在不够, 才考虑 INT4。但要做好精度下降 2-5% 的心理准备。
- FP16 在 MCU 上要谨慎。 除非你的芯片有硬件 FP16 支持,否则软件模拟 FP16 比 INT8 慢得多。