3、模型量化基础:FP32与INT8的差异、量化原理(对称/非对称)、量化感知训练(QAT)与训练后量化(PTQ)的适用场景
聊到嵌入式平台部署,量化是绕不开的话题。我刚开始接触这玩意儿时,也觉得不就是把32位浮点数转成8位整数嘛,能有多复杂?结果第一次在STM32上跑模型,精度直接掉了5个点,当时就懵了。后来才明白,量化这事儿,门道深着呢。
3.1 FP32与INT8:到底差在哪?
先说说最直观的差异。FP32,也就是单精度浮点数,用32位表示一个数。INT8呢,只用8位。你想想看,数据量直接缩到四分之一。这意味着什么?
- 存储空间:模型体积变小,Flash压力骤减。我有个项目,模型原本50MB,量化后12.5MB,直接塞进了原本放不下的芯片里。
- 计算速度:INT8的乘加运算比FP32快得多。很多芯片还有专门的INT8加速单元,比如ARM的NEON指令集、NVIDIA的Tensor Core。
- 带宽占用:内存带宽是嵌入式系统的稀缺资源。数据量小了,搬运速度自然就快了。
但代价也很明显——精度损失。FP32能表示约7位有效数字,INT8只能表示256个离散值。说白了,就是把一个连续的空间硬生生压缩成256个格子。你想想,原本精细的数值,现在只能落在某个格子里,误差就这么来了。
核心差异总结:FP32是“精细但昂贵”,INT8是“粗糙但高效”。选哪个,取决于你的精度底线和硬件资源。
3.2 量化原理:对称 vs 非对称
量化说白了就是找一个映射关系,把浮点数映射到整数。这个映射怎么找?主要有两种思路。
3.2.1 对称量化
对称量化,顾名思义,零点对齐。浮点数的0,映射到整数的0。映射公式很简单:
int8_value = round(float_value / scale)
这里的scale是缩放因子。举个例子,如果浮点数范围是[-1.0, 1.0],INT8范围是[-128, 127],那scale就是1.0/128 ≈ 0.0078。
我习惯用对称量化,因为它实现简单,硬件支持也最广泛。但有个坑——如果数据分布不对称,比如全是正数,那负半轴的量化区间就浪费了。我曾经在某个语音模型上踩过这个坑,模型输出全是0到1之间的概率值,用对称量化,负半轴的128个值全浪费了,精度损失特别大。
3.2.2 非对称量化
非对称量化引入了零点偏移,公式变成:
int8_value = round(float_value / scale) + zero_point
zero_point就是零点偏移。这样,浮点数的0可以映射到任意整数,不再强制对齐。好处是能充分利用INT8的256个值,适合数据分布不对称的场景。
但代价是计算更复杂。每次运算都要考虑zero_point,硬件实现也更麻烦。我建议,除非你的数据分布明显不对称,否则优先用对称量化。
| 特性 | 对称量化 | 非对称量化 |
|---|---|---|
| 零点对齐 | 是 | 否 |
| 实现复杂度 | 低 | 高 |
| 硬件支持 | 广泛 | 部分支持 |
| 适用场景 | 数据分布对称 | 数据分布不对称 |
3.3 量化感知训练(QAT)与训练后量化(PTQ)
确定了量化方式,接下来就是怎么做了。两种主流方法:QAT和PTQ。嗯,这里要注意,选错了方法,项目周期可能差好几倍。
3.3.1 训练后量化(PTQ)
PTQ,顾名思义,模型训练完了再量化。你只需要准备一小部分校准数据,跑一遍前向推理,统计出每层激活值的范围,然后算出scale和zero_point。
优点很明显:快!不需要重新训练,几十分钟就能搞定。我有个项目,客户要求三天内出Demo,我直接用PTQ,一天就搞定了。
但缺点也致命——精度损失可能比较大。尤其是对量化敏感的模型,比如MobileNet、EfficientNet这类轻量网络,PTQ后精度可能掉3-5个点。
我的建议:如果你的模型比较大(比如ResNet50以上),或者精度要求不高,PTQ是首选。省时省力,效果还行。
3.3.2 量化感知训练(QAT)
QAT就不一样了。它在训练过程中就模拟量化效果,让模型自己去适应量化误差。具体做法是在前向传播时插入伪量化节点(Fake Quantize),把浮点权重和激活值量化后再反量化,反向传播时还是用浮点梯度更新。
这样做的好处是,模型学会了“如何在量化条件下表现更好”。精度损失通常能控制在1%以内,甚至无损。
但代价是训练时间变长,而且需要修改训练代码。我记得第一次用QAT时,光调参就花了两周。不过效果确实好,那个模型PTQ后精度掉了4个点,QAT后只掉了0.3个点。
避坑指南:我曾经在某个项目里,直接用QAT从头训练,结果模型不收敛。后来才发现,QAT最好在预训练模型基础上做微调,而不是从头训。这个坑,我替你们踩过了。
3.4 如何选择?
说到底,选PTQ还是QAT,取决于你的项目约束:
- 时间紧、任务重:选PTQ。先跑起来,再优化。
- 精度要求极高:选QAT。多花点时间训练,换来精度保障。
- 硬件资源极度受限:选QAT。因为量化误差会被放大,PTQ可能直接崩掉。
- 模型本身很大:PTQ通常够用。大模型对量化不敏感。
我个人习惯是,先跑PTQ看看效果。如果精度损失在可接受范围内,就直接用PTQ。如果不行,再上QAT。毕竟,QAT的训练成本摆在那里,能省则省。
好了,这一章就聊到这儿。量化这东西,纸上谈兵容易,真正上手才会遇到各种奇奇怪怪的问题。下一章我们聊聊具体的量化工具和实操流程,到时候我会分享一些实际项目中的踩坑经验。