4. 模型量化技术:INT8/FP16 量化原理、PTQ 与 QAT、校准数据集、精度损失评估

模型量化,说白了就是把模型里那些又大又慢的 FP32 浮点数,换成更小的 INT8 或 FP16。为什么要这么干?因为边缘设备上,算力和带宽都是稀缺资源。我刚开始接触量化时,总觉得这是“降级”,精度肯定要掉一大截。后来才发现,只要方法得当,INT8 推理速度能翻 2-4 倍,而精度损失可以控制在 0.5% 以内。

这一章,我们就来拆解量化的底层逻辑,以及如何在工业视觉场景下落地。

4.1 量化原理:从 FP32 到 INT8 的映射

量化的核心公式其实很简单:

Q = round( (R - zero_point) / scale )

其中 R 是原始浮点数,Q 是量化后的整数,scale 和 zero_point 就是我们要找的量化参数。scale 决定了步长,zero_point 负责对齐零点。

举个例子,假设一个权重张量的范围是 [-1.0, 2.0],要量化到 INT8(范围 -128 到 127):

  • scale = (2.0 - (-1.0)) / (127 - (-128)) ≈ 0.0118
  • zero_point = round(-(-1.0) / 0.0118) + (-128) ≈ -43

这样,浮点数 0.5 量化后就是:round(0.5 / 0.0118 - 43) ≈ 85。

关键点:量化不是简单的截断,而是带参数的线性映射。参数选得好,精度损失就小。

4.2 FP16 与 INT8:两种主流量化格式

FP16 和 INT8 是边缘部署中最常见的两种格式。它们各有优劣,我习惯根据硬件和精度要求来选。

特性 FP16 INT8
位宽 16 位 8 位
模型体积缩减 约 50% 约 75%
推理加速比 1.5x - 2x 2x - 4x
精度损失 几乎无损 通常 < 1%
硬件支持 NVIDIA Jetson、大部分 GPU Jetson、RK3588、部分 FPGA

FP16 量化,说白了就是“半精度”。它保留了指数位和尾数位,所以动态范围很大。我在 Jetson Xavier 上跑过 FP16 的 YOLOv5,精度和 FP32 几乎一模一样,但帧率从 30 提到了 45。

INT8 量化就激进多了。它把数值范围压缩到 256 个离散值。对于激活值分布比较均匀的网络,效果很好。但遇到某些层(比如检测头的输出),数值范围特别大,就容易出问题。

我的建议:如果硬件支持 FP16,优先用 FP16,省心。如果必须用 INT8,一定要做校准和精度验证。

4.3 PTQ 与 QAT:两种量化路径

量化有两种主流方法:训练后量化(PTQ)和量化感知训练(QAT)。

4.3.1 PTQ(Post-Training Quantization)

PTQ 是最简单的方法。模型训练完后,直接拿一批数据跑一遍,统计出每层的 scale 和 zero_point,然后量化。整个过程不需要重新训练。

优点很明显:快,几分钟搞定。缺点呢?精度损失可能比较大,尤其是对敏感层。

我曾经在一个缺陷检测项目里用 PTQ 量化 ResNet-50,结果 mAP 从 0.92 掉到了 0.85。后来发现是某个卷积层的激活值分布太宽,scale 选得不好。

4.3.2 QAT(Quantization-Aware Training)

QAT 就聪明多了。它在训练过程中模拟量化误差,让模型自己去适应。具体做法是在前向传播时插入伪量化节点(FakeQuant),反向传播时用直通估计器(STE)近似梯度。

QAT 的流程一般是:

  1. 加载预训练 FP32 模型
  2. 在关键层插入 FakeQuant 节点
  3. 用较小的学习率(比如 1e-5)微调几个 epoch
  4. 导出 INT8 模型

QAT 的精度通常比 PTQ 高 1-2 个百分点。代价是训练时间增加了,而且需要原始训练数据。

注意:QAT 微调时,学习率不能太大,否则模型会“忘记”之前学到的特征。我一般用 1e-5 到 1e-6,微调 5-10 个 epoch。

4.4 校准数据集:选对数据,事半功倍

PTQ 需要一组校准数据来统计激活值的分布。校准数据集的质量,直接决定了量化效果。

选校准数据时,有几个原则:

  • 代表性:数据要覆盖真实场景中的各种情况。比如工业检测,要包含不同光照、不同角度的样本。
  • 多样性:不要只用一类样本。我见过有人只用“良品”做校准,结果“缺陷品”的激活值分布完全没覆盖到,量化后漏检率飙升。
  • 数量适中:一般 100-500 张就够了。太多反而增加校准时间,效果提升有限。

校准过程其实很简单:把校准数据喂给模型,记录每层激活值的 min 和 max,然后算出 scale 和 zero_point。

避坑指南:我曾经用 1000 张图片做校准,结果发现某些层的激活值范围被极端值拉宽了。后来改用百分位法(比如取 99.9% 的 min/max),效果好了很多。

4.5 精度损失评估:量化后的“体检报告”

量化完,必须做精度评估。不能只看整体指标,要逐层、逐类地分析。

我一般会做这几件事:

  1. 整体指标对比:在验证集上跑 FP32 和 INT8 模型,对比 mAP、F1-score 等指标。
  2. 逐层误差分析:用余弦相似度或 MSE 对比每层输出的差异。如果某层的误差特别大,就要重点关注。
  3. 可视化检查:随机挑几张图,对比 FP32 和 INT8 的检测结果。有时候指标没掉,但个别样本的检测框偏移了。

下面是一个典型的精度损失评估表格:

模型 mAP@0.5 mAP@0.5:0.95 推理时间 (ms)
FP32 0.923 0.671 45.2
INT8 (PTQ) 0.908 0.652 18.7
INT8 (QAT) 0.919 0.665 18.5

你看,QAT 的精度明显比 PTQ 高,推理时间几乎一样。所以,如果时间允许,我建议用 QAT。

核心原则:精度损失 < 1% 是可接受的。如果超过 2%,就要检查校准数据或量化参数了。

4.6 量化流程总览

为了让你更直观地理解整个量化流程,我画了一张图:

模型量化流程总览 模型量化流程总览 FP32 预训练模型 选择量化路径 PTQ 训练后量化 QAT 量化感知训练 校准数据集 微调训练 INT8 量化模型 PTQ 速度快但精度可能损失大;QAT 精度高但需要微调训练

从图中可以看到,PTQ 和 QAT 最终都输出 INT8 模型,但中间路径不同。PTQ 依赖校准数据集,QAT 则多了一步微调训练。

4.7 实战中的避坑指南

最后,分享几个我在项目中踩过的坑:

  • 校准数据太少:有一次我只用了 50 张图做校准,结果量化后模型在复杂场景下完全失效。后来加到 200 张,问题解决。
  • 忽略敏感层:某些层(比如检测头的输出层)对量化特别敏感。我习惯对这些层单独做 FP16 或跳过量化。
  • 不做逐层验证:只看整体指标容易掩盖问题。我建议至少对比 3-5 个关键层的输出分布。

重要提醒:量化不是“一键优化”。每次量化后,都要在真实场景下做充分测试。尤其是工业视觉,漏检和误检的代价可能很高。

好了,这一章的内容就到这里。量化技术是边缘部署的核心技能,掌握了它,你就能在算力受限的设备上跑出接近原生的精度和速度。