2. 模型量化基础

各位同学,咱们今天聊聊模型量化。说实话,这是端侧推理里最“实在”的一环。你模型设计得再花哨,到了手机、边缘设备上跑不动,一切都是白搭。量化,就是让模型“瘦身”并“提速”的关键手段。

我个人习惯把量化看作一种“有损压缩”。就像你把一张高清照片转成 JPEG,画质会损失一点,但文件小了好几倍。模型量化也是这个道理——把模型里的权重和激活值,从高精度的浮点数(比如 FP32)映射到低精度的整数(比如 INT8)。

为什么能这么做?因为神经网络对噪声有一定的容忍度。你想想看,人眼对 JPEG 的压缩 artifacts 都能接受,神经网络对数值精度的“小误差”自然也能扛得住。当然,前提是你得掌握好那个“度”。

核心思想: 用更少的比特数来表示数值,从而减少模型体积、降低内存带宽需求、加速计算(尤其是整数运算)。

量化的数学原理:对称 vs 非对称

量化说白了就是一个数学映射。我们要把浮点数范围 [r_min, r_max] 映射到整数范围 [q_min, q_max]。这里有两个流派:对称量化和非对称量化。

1. 对称量化

对称量化,我理解就是“以零为中心”。浮点数的 0 映射到整数的 0。它的公式很简单:

q = round(r / scale)
scale = max(|r_max|, |r_min|) / (q_max - q_min)  // 通常 q_max - q_min = 127 - (-128) = 255

你看,这里只有一个参数 scale(缩放因子)。没有零点偏移。实现起来非常干净。

优点: 计算简单,硬件实现友好。很多硬件加速器(比如 NVIDIA 的 Tensor Core)对对称量化有专门优化。

缺点: 如果数据分布不是对称的(比如 ReLU 后的激活值全是正数),那就会浪费一半的整数表示范围。举个例子,如果浮点数值域是 [0, 10.0],对称量化会把范围映射到 [-128, 127],但 [-128, 0] 这一段全浪费了,精度自然就差了。

我的经验: 我在项目中遇到过,对权重做对称量化效果通常不错,因为训练好的权重分布往往接近对称。但对激活值,尤其是 ReLU 后的激活值,对称量化经常“翻车”。这时候就该非对称量化上场了。

2. 非对称量化

非对称量化更灵活。它引入了“零点(zero point)”的概念,让浮点数的 0 可以映射到任意整数。公式如下:

q = round(r / scale) + zero_point
scale = (r_max - r_min) / (q_max - q_min)
zero_point = round(q_min - r_min / scale)

这里有两个参数:scale 和 zero_point。你可以把整个浮点数范围“塞”进整数范围,不浪费任何比特。

优点: 能充分利用整数表示范围,精度通常优于对称量化,尤其对分布不均匀的数据。

缺点: 计算稍微复杂一点,因为每次运算都要考虑 zero_point 的偏移。不过现代推理框架都帮你处理好了。

特性 对称量化 非对称量化
参数数量 1 个 (scale) 2 个 (scale, zero_point)
零点映射 浮点 0 = 整数 0 浮点 0 = 任意整数
计算复杂度 低 中
适用场景 权重、分布对称的数据 激活值、分布不对称的数据
硬件友好度 高 中

注意: 非对称量化虽然精度好,但如果你要部署到某些“古老”的硬件上,它可能不支持 zero_point 的运算。这时候你就得退而求其次,用对称量化了。我曾经在一款 IoT 芯片上踩过这个坑,折腾了两天才发现是硬件不支持非对称量化。

量化精度与性能的权衡

这其实是个永恒的话题。精度和性能,就像鱼和熊掌。量化得越狠(比如从 INT8 降到 INT4),性能提升越明显,但精度损失也越大。

我给大家画个图,直观感受一下:

量化精度与性能权衡图 精度曲线(越高越好) FP32 精度: 100% INT8 精度: ~98% INT4 精度: ~95% INT2 精度: ~85% 性能曲线(越高越好) FP32 性能: 1x INT8 性能: ~3x INT4 性能: ~6x INT2 性能: ~10x 说明:从 FP32 到 INT8,精度损失很小(~2%),但性能提升 3 倍,这是最“划算”的区间。 再往下量化(INT4/INT2),性能提升边际递减,精度损失却急剧增加。

从图上可以清楚看到,INT8 是当前工业界的“甜点”。精度损失在 1-2% 以内,但推理速度能快 2-4 倍。我个人的建议是:除非你的硬件对 INT4 有原生支持,否则优先考虑 INT8 量化。

那什么时候用 INT4 呢?当你的模型对精度不敏感,或者你的硬件带宽是瓶颈时。比如一些简单的分类任务,或者语音唤醒词检测,INT4 完全够用。

避坑指南: 我曾经在一个目标检测项目里,为了追求极致性能,强行把模型量化到 INT4。结果呢?mAP 直接掉了 8 个点,模型基本废了。后来我改用混合精度量化——对敏感层(比如检测头)保持 INT8,对不敏感层(比如 backbone 的前几层)用 INT4。最终精度只掉了 2%,性能提升了 4.5 倍。所以,不要一刀切,要“因层施策”。

量化工具链介绍

理论说完了,咱们聊聊实战工具。目前业界最主流的两个量化工具链是 TensorRT 和 ONNX Runtime。我两个都用过,各有千秋。

1. TensorRT

TensorRT 是 NVIDIA 的亲儿子。如果你用的是 NVIDIA 的 GPU(包括 Jetson 系列),那 TensorRT 几乎是必选项。

它的量化流程大概是这样的:

  1. 导入模型: 支持从 ONNX、TensorFlow、PyTorch 等框架导入。
  2. 构建引擎: 指定精度(FP32、FP16、INT8)。如果选 INT8,需要提供校准数据集(calibration dataset)。
  3. 校准: TensorRT 会跑一遍校准数据,统计每层激活值的分布,然后计算出最优的 scale 和 zero_point。
  4. 序列化: 把优化后的引擎保存为 .plan 文件,部署时直接加载。
// 伪代码示例:TensorRT INT8 量化
import tensorrt as trt

TRT_LOGGER = trt.Logger(trt.Logger.WARNING)
builder = trt.Builder(TRT_LOGGER)
network = builder.create_network()
parser = trt.OnnxParser(network, TRT_LOGGER)

// 加载 ONNX 模型
with open("model.onnx", "rb") as f:
    parser.parse(f.read())

// 配置 INT8 量化
config = builder.create_builder_config()
config.set_flag(trt.BuilderFlag.INT8)
config.int8_calibrator = MyCalibrator()  // 自定义校准器

// 构建引擎
engine = builder.build_engine(network, config)

关键点: 校准数据集的质量直接决定量化精度。我建议校准集至少包含 500-1000 张有代表性的图片,覆盖各种光照、角度、场景。千万别用训练集做校准,那会导致过拟合,部署后精度反而下降。

2. ONNX Runtime

ONNX Runtime 是微软开源的跨平台推理引擎。它的优势在于“通用性”——支持 CPU、GPU、NPU、甚至 WebAssembly。

它的量化方式更灵活,支持两种模式:

  • 动态量化(Dynamic Quantization): 运行时动态计算 scale 和 zero_point。好处是无需校准数据,坏处是推理时多了计算开销。
  • 静态量化(Static Quantization): 和 TensorRT 类似,需要校准数据提前计算好量化参数。推理时直接使用,没有额外开销。
// 伪代码示例:ONNX Runtime 静态量化
import onnx
from onnxruntime.quantization import quantize_static, QuantType

// 加载 ONNX 模型
model_fp32 = "model.onnx"
model_int8 = "model_int8.onnx"

// 执行静态量化
quantize_static(
    model_input=model_fp32,
    model_output=model_int8,
    calibration_data_reader=MyCalibrationDataReader(),  // 校准数据读取器
    quant_format=QuantType.QInt8,  // 使用 INT8
    per_channel=True  // 按通道量化,精度更好
)

我的选择: 如果目标平台是 NVIDIA GPU,我无脑选 TensorRT。它的算子融合和内存优化做得太出色了。但如果要部署到 CPU 或者混合架构(比如 ARM + GPU),ONNX Runtime 是更稳妥的选择。它支持的量化格式更多,而且社区活跃,遇到问题容易找到解决方案。

量化知识体系总览

最后,我用一张图把本章的核心内容串起来,方便大家记忆:

模型量化知识体系 模型量化 数学原理 精度与性能权衡 工具链 对称量化 非对称量化 INT8 是当前甜点 TensorRT / ONNX Runtime TensorRT ONNX Runtime 精度损失 < 2% 性能提升 2-4x 核心要点: 1. 对称量化适合权重,非对称量化适合激活值。 2. INT8 是当前性价比最高的量化精度。 3. TensorRT 适合 NVIDIA 平台,ONNX Runtime 适合跨平台部署。

好了,这一章的内容就到这里。量化是个“实践出真知”的领域,光看理论是不够的。我建议大家找个开源模型(比如 MobileNet 或 ResNet),用 TensorRT 或 ONNX Runtime 实际跑一遍量化流程,看看精度变化和性能提升。遇到问题很正常,多试几次就有感觉了。