4、后训练量化:快速部署的捷径与陷阱
后训练量化,说白了就是模型训练完之后,我们再动手把它从 FP32 压缩成 INT8 甚至更低比特。这玩意儿在嵌入式部署里太常见了,我几乎每个项目都会用到它。为什么?因为它快,真的快,不需要重新训练,几行代码就能让模型跑起来。
但我要先泼一盆冷水。这玩意儿看着简单,坑却不少。我见过太多人一上来就量化,结果模型精度直接崩了,然后跑来问我怎么回事。嗯,咱们今天就把这些坑一个个填上。
4.1 量化到底在做什么?
先说说本质。量化就是把连续的浮点数映射到离散的整数上。比如一个权重是 0.1234,量化后可能就变成了 12(假设是 INT8 的某个值)。
公式其实很简单:
Q = round( (R - zero_point) / scale )
其中 R 是原始浮点数,Q 是量化后的整数,scale 和 zero_point 就是我们要找的量化参数。
我个人习惯把 scale 理解为「步长」。你想想看,FP32 能表示的范围太大了,INT8 只有 256 个值。所以每个整数代表一个区间,scale 就是这个区间的大小。
关键点:量化不是无损的。每次量化都会引入误差,关键是怎么让这个误差不影响最终结果。
4.2 常见的量化方式
后训练量化主要有两种路子:
- 权重量化:只量化模型的权重参数。这个最简单,几乎不会掉精度。我在项目中经常用这个做快速验证。
- 全量化:权重和激活值都量化。这个麻烦一些,但压缩效果更好。
还有一种叫「量化感知训练」,但那不属于后训练量化,咱们今天不聊。
4.3 校准数据集:被忽视的关键
做全量化的时候,你需要一个校准数据集。这个数据集用来统计激活值的分布,从而确定 scale 和 zero_point。
我曾经犯过一个错误。当时图省事,随便拿了 100 张图片做校准。结果模型部署后,精度掉了 5 个点。后来换成 500 张有代表性的图片,精度只掉了 0.3 个点。
注意:校准数据集必须能代表真实场景的数据分布。不要用训练集做校准,那会过拟合。也不要只用几张图,那统计出来的分布不准。
我建议校准集至少 200-500 张,而且要覆盖各种情况。比如做目标检测,要有不同光照、不同角度、不同大小的目标。
4.4 量化粒度:逐层还是逐通道?
量化粒度是个容易被忽略的细节。说白了就是:每个层用一个 scale,还是每个通道用一个 scale?
| 粒度 | 优点 | 缺点 |
|---|---|---|
| 逐层量化 | 实现简单,计算快 | 精度损失大,尤其对分布不均匀的层 |
| 逐通道量化 | 精度更高,能适应不同通道的分布 | 实现复杂,硬件支持要求高 |
我个人习惯:能逐通道就逐通道。虽然实现起来麻烦点,但精度确实好。不过要注意,有些嵌入式芯片不支持逐通道量化,你得先查硬件手册。
4.5 常见的陷阱与避坑指南
这里我总结几个最常见的坑:
- 陷阱一:忽略异常值。激活值里偶尔会出现几个特别大的值,比如 100 以上。如果直接用这些值算 scale,那大部分值都会被压缩到很小的区间里,精度就崩了。我建议先做异常值裁剪,把 99.9% 分位以外的值截断。
- 陷阱二:对称量化 vs 非对称量化。ReLU 激活后的值都是非负的,用非对称量化更合适。但有些硬件只支持对称量化,那就得注意了。
- 陷阱三:BN 层融合。量化前一定要把 BN 层融合到卷积层里。不融合的话,量化误差会放大。这个步骤很多框架会自动做,但最好确认一下。
小技巧:量化后一定要做精度验证。我习惯在验证集上跑一遍,对比量化前后的输出差异。如果某个层的输出差异超过 5%,那这个层可能需要特殊处理。
4.6 实战:用 PyTorch 做后训练量化
来,看个实际例子。假设我们有一个训练好的模型:
import torch
import torch.quantization as quant
# 加载预训练模型
model = torch.load('model_fp32.pth')
model.eval()
# 准备量化配置
model.qconfig = quant.get_default_qconfig('fbgemm')
model = quant.prepare(model, inplace=True)
# 用校准数据集跑一遍
with torch.no_grad():
for images in calibration_loader:
model(images)
# 转换为量化模型
model = quant.convert(model, inplace=True)
# 保存量化模型
torch.save(model.state_dict(), 'model_int8.pth')
这段代码看着简单,但实际项目中往往没这么顺利。我遇到过一个问题:校准的时候数据量不够,导致某些层的 scale 算得不准。后来我加了个循环,每 50 张图重新统计一次分布,效果好了很多。
4.7 什么时候不该用后训练量化?
不是所有模型都适合后训练量化。我总结了几种情况:
- 模型本身精度就不高。比如只有 80% 的准确率,量化后可能掉到 75%,那就没法用了。
- 模型对数值非常敏感。比如一些回归任务,或者检测小目标的模型。量化后小目标的特征可能直接被抹掉了。
- 模型结构特殊。比如用了很多自定义算子,量化工具可能不支持。
遇到这些情况,我建议要么用量化感知训练,要么干脆别量化,直接用 FP16 部署。FP16 虽然压缩比不如 INT8,但精度损失小很多。
4.8 总结
后训练量化是个好东西,但别把它当万能药。我的经验是:先做权重量化试试水,如果精度没问题,再考虑全量化。全量化的时候,校准数据集和量化粒度是关键。最后一定要做精度验证,别偷懒。
嗯,今天就聊到这儿。下一章咱们聊聊量化感知训练,那个路子更稳,但代价是得重新训练模型。