模型量化入门:FP32 vs FP16 vs INT8

各位同学好,我是你们的老朋友。今天咱们聊聊模型量化——这个在NPU推理优化里绕不开的话题。

说实话,我刚接触量化那会儿,也觉得不就是把精度降一降嘛,有啥好讲的?后来在项目里踩了不少坑,才明白这里面门道很深。今天我就把这几年的经验掰开了揉碎了讲给你听。

为什么需要量化?

先问个问题:你想想看,一个FP32的模型跑在NPU上,跟跑在GPU上有什么区别?

其实核心就两点——带宽和算力。

NPU的片上存储很有限,一般就几MB到几十MB。你一个ResNet-50的模型,FP32权重大概98MB,根本放不下。每次推理都要从DDR搬数据,带宽就成了瓶颈。

我做过一个实验:同样的模型,FP32推理延迟是15ms,换成INT8后直接降到4ms。为什么?因为数据量小了4倍,搬运时间少了,计算单元也能跑得更快。

核心结论:量化就是用更少的比特数表示数值,换来更快的推理速度和更低的功耗。

FP32 vs FP16 vs INT8:到底差在哪?

咱们先看一张表,直观感受一下差异:

数据类型 位宽 表示范围 精度 典型场景
FP32 32位 ±3.4×10³⁸ 约7位有效数字 训练、高精度推理
FP16 16位 ±6.5×10⁴ 约3位有效数字 混合精度训练、部分推理
INT8 8位 -128~127 整数精度 NPU推理主力

你看,FP32范围最大,精度最高。但NPU上跑FP32,就像开着一辆大卡车在胡同里掉头——费劲。

FP16呢?范围小了很多,但精度还行。我有个项目做语音识别,FP16推理精度只掉了0.1%,速度却快了1.8倍。嗯,这个性价比挺划算。

INT8就更狠了。数据量直接压缩到原来的1/4,NPU的乘累加单元跑得飞起。但代价是——精度损失需要仔细处理。

我的经验:如果模型对精度不敏感(比如分类任务),直接上INT8。如果是检测或分割,建议先做FP16,再逐步压到INT8。

量化原理:到底是怎么压缩的?

量化说白了,就是找一个映射关系,把浮点数映射到整数上。

数学上很简单:

Q = round(r / S) + Z

其中:

  • r 是原始浮点数
  • Q 是量化后的整数
  • S 是缩放因子(scale)
  • Z 是零点偏移(zero point)

反量化就是反过来:

r = (Q - Z) × S

你看,就这么简单。但实际工程里,麻烦事全在怎么选S和Z上。

我曾经在一个项目里,直接用了全局的min/max来算S,结果模型精度掉了5%。后来改成逐通道量化,精度只掉了0.3%。

注意:量化不是简单的四舍五入。你想想看,如果原始数据分布不均匀,直接量化会导致大量信息丢失。

对称量化 vs 非对称量化

这两个概念,我建议你从零点位置来理解。

对称量化

对称量化里,零点Z=0。也就是说,浮点数的0映射到整数的0。

公式变成:

Q = round(r / S)

好处是计算简单,硬件实现方便。坏处是——如果数据分布不对称,比如ReLU后的激活值全是正数,那负数那半边就浪费了。

我记得有一次做MobileNet的量化,激活值全是0到6之间。用对称量化,量化步长S=6/127≈0.047,精度损失很小。但如果是权重,分布可能正负对称,对称量化就很合适。

非对称量化

非对称量化允许零点Z不为0。这样就能把浮点数的min/max完整映射到整数的min/max。

公式就是前面那个:

Q = round(r / S) + Z

好处是数据利用率高,精度损失小。坏处是计算稍微复杂一点,硬件上要多算一个偏移。

我建议你记住这个原则:

经验法则:

  • 权重:用对称量化(分布通常对称)
  • 激活值:用非对称量化(分布通常偏斜)
  • 如果硬件支持,优先用非对称量化

一张图看懂量化流程

下面这张图是我自己画的,把整个量化流程串起来了:

模型量化核心流程 FP32 原始模型 收集校准数据 (几百张图片/样本) 统计min/max 计算S和Z 执行量化 Q = round(r/S) + Z INT8 量化模型 权重+激活值 精度验证 对比FP32精度 部署到NPU 享受加速! 图:模型量化从FP32到INT8的完整流程

实际项目中的避坑指南

讲完理论,咱们聊聊实战中容易踩的坑。

我曾经踩过的坑:

  • 校准数据太少:有一次我只用了50张图片做校准,结果模型在测试集上精度掉了3%。后来改成500张,精度只掉了0.5%。建议至少用几百张有代表性的数据。
  • 忽略异常值:数据里偶尔会有几个特别大或特别小的值,直接取min/max会导致量化步长过大。我习惯用百分位法,比如取1%和99%分位点。
  • 逐层量化 vs 逐通道量化:逐层量化省事但精度差,逐通道量化精度好但计算量大。我的建议是——权重用逐通道,激活值用逐层。

一个小技巧:量化后一定要做精度验证。我一般会跑完整验证集,对比FP32和INT8的精度差异。如果差异超过1%,就要调整量化参数了。

总结一下

量化这件事,说白了就是用精度换速度。但怎么换、换多少,需要你根据实际场景来权衡。

我个人习惯的做法是:

  1. 先用FP32跑一遍,拿到精度基线
  2. 转FP16,看看精度损失
  3. 如果没问题,再压到INT8
  4. INT8精度不够?试试逐通道量化或混合精度

嗯,今天就先聊到这儿。量化这块内容很多,后面咱们还会讲到量化感知训练、混合精度量化这些进阶话题。你先把基础打牢,后面学起来就轻松了。

想要更多资料,联系可可