1、模型量化基础:什么是模型量化、量化的数学原理、对称量化与非对称量化、量化粒度
大家好,我是你们的老朋友。今天咱们来聊聊模型量化这个硬核话题。说实话,我刚入行那会儿,觉得量化就是个「把float转成int」的简单操作,结果第一次在项目里踩了坑,模型精度直接掉了5个点,被老板叫去喝茶……嗯,从那以后,我再也不敢小看量化了。
1.1 什么是模型量化?
模型量化,说白了就是给模型「减减肥」。你想想看,一个FP32的模型,每个参数占4个字节;如果转成INT8,每个参数只占1个字节。模型体积直接缩到原来的四分之一,推理速度也能翻倍。这在边缘设备上简直是救命稻草。
我在一个自动驾驶项目里遇到过,模型太大,车载芯片根本跑不动。量化之后,模型从200MB缩到50MB,帧率从15fps飙到了45fps。虽然精度掉了0.3%,但客户完全能接受。这就是量化的魅力——用一点点精度换巨大的性能提升。
核心思想:用更少的比特数来表示模型的权重和激活值,同时尽量保持原始精度。
1.2 量化的数学原理
量化的数学原理其实不复杂。核心就是找到一个映射关系,把浮点数范围映射到整数范围。公式长这样:
Q = round(r / S) + Z
其中:
- r 是原始的浮点数值
- Q 是量化后的整数值
- S 是缩放因子(scale)
- Z 是零点偏移(zero point)
反量化公式就是:
r = (Q - Z) * S
这里有个关键点:S 和 Z 怎么算?
S 的计算公式:
S = (r_max - r_min) / (Q_max - Q_min)
Z 的计算公式:
Z = Q_max - r_max / S
我个人习惯把 Z 四舍五入取整,因为零点偏移必须是整数。曾经有一次我忘了取整,结果量化后的模型推理结果全是乱码,排查了半天才发现是这个问题。
小技巧:实际工程中,我们通常用校准数据集来统计 r_max 和 r_min,而不是直接用整个训练集。这样能避免异常值对量化范围的干扰。
1.3 对称量化 vs 非对称量化
这两种量化方式,区别就在于零点偏移 Z 的处理。
对称量化
对称量化把零点固定在0。也就是说,Z = 0。公式简化成:
Q = round(r / S)
对称量化的好处是实现简单,计算快。但缺点也很明显——如果数据分布不对称,比如ReLU后的激活值全是正数,那对称量化会浪费一半的量化范围。
我记得在量化一个MobileNet模型时,用了对称量化,结果精度掉了2%。后来换成非对称量化,精度只掉了0.5%。原因就是激活值全是正的,对称量化把负半轴全浪费了。
非对称量化
非对称量化允许零点偏移 Z 不为0。公式就是我们前面看到的:
Q = round(r / S) + Z
非对称量化能更好地适配数据分布,精度损失更小。但代价是实现稍微复杂一点,计算量也大一些。
| 特性 | 对称量化 | 非对称量化 |
|---|---|---|
| 零点偏移 | 固定为0 | 可调节 |
| 实现复杂度 | 低 | 中 |
| 精度损失 | 较大(数据不对称时) | 较小 |
| 适用场景 | 权重量化(权重通常对称分布) | 激活值量化(激活值常偏正) |
避坑指南:我曾经在量化一个BERT模型时,对权重用了非对称量化,结果精度反而更差了。后来发现,BERT的权重分布近似正态分布,对称量化反而更合适。所以,没有绝对的好坏,一定要根据实际数据分布来选择。
1.4 量化粒度:per-tensor vs per-channel
量化粒度,说白了就是「量化范围」的粗细程度。你想想看,是整个张量共用一个缩放因子,还是每个通道各用各的?
Per-tensor 量化
整个张量(比如一个卷积层的权重)只用一个 S 和一个 Z。实现简单,计算量小。但问题在于,如果张量内部数值差异很大,量化误差就会很大。
举个例子,一个卷积层有64个输出通道,其中几个通道的数值范围特别大,其他通道范围很小。per-tensor量化会按照最大的那个通道来定范围,导致其他通道的量化精度严重浪费。
Per-channel 量化
每个通道独立计算自己的 S 和 Z。精度更高,但计算量也更大,硬件实现也更复杂。
我在一个图像分类项目里做过对比:per-tensor量化后精度掉了1.2%,per-channel量化只掉了0.3%。但推理速度上,per-channel比per-tensor慢了约5%。这就是典型的「用时间换精度」。
| 量化粒度 | 精度 | 计算量 | 硬件友好度 |
|---|---|---|---|
| Per-tensor | 较低 | 低 | 高 |
| Per-channel | 较高 | 中 | 中 |
我的建议:对于权重,优先用per-channel量化,因为权重对精度影响更大。对于激活值,如果硬件不支持per-channel,用per-tensor也问题不大。我在TensorRT里就是这么配置的——权重用per-channel,激活值用per-tensor,效果不错。
小结
好了,这一章的内容就到这里。我们讲了量化的基本概念、数学原理、对称与非对称的区别,还有量化粒度的选择。这些都是后续章节的基础,一定要理解透。
下一章,我们会深入实战,讲讲如何在TensorRT里配置量化参数。到时候我会分享一些我在实际项目中踩过的坑,保证让你少走弯路。
公众号:蓝海资料掘金营,微信deep3321