1. 量化基础回顾:从原理到精度损失
各位同学好,我是老张。做模型部署这些年,我踩过最多的坑就是量化。明明在 GPU 上跑得好好的模型,一量化就掉点,有时候掉得你怀疑人生。今天咱们先把基础打牢——量化到底是什么,它背后的数学原理,以及精度损失从哪来。
说白了,量化就是把模型里的浮点数(FP32)用更小的整数(INT8)来表示。为什么要这么干?因为 INT8 的推理速度能快 2-4 倍,模型体积缩小 4 倍,功耗也大幅降低。我最早在手机端做人脸检测时,一个 200MB 的模型量化到 50MB,推理时间从 120ms 降到 35ms,效果立竿见影。
1.1 量化的数学原理
量化的核心公式其实就两个:缩放因子(Scale)和零点(Zero Point)。
对称量化:假设数据分布关于零点对称。公式很简单:
// 对称量化
scale = max(|x|) / 127
x_int8 = round(x / scale)
// 反量化
x_fp32 = x_int8 * scale
我刚开始做量化时,习惯用对称量化。为什么?因为它实现简单,不需要零点偏移。但后来发现一个问题——如果模型权重分布不对称,比如 ReLU 后的激活值全是正数,对称量化会浪费一半的量化范围。
非对称量化:允许数据分布偏移,用零点来补偿。
// 非对称量化
scale = (max - min) / 255
zero_point = round(-min / scale)
x_int8 = round(x / scale + zero_point)
// 反量化
x_fp32 = (x_int8 - zero_point) * scale
非对称量化更灵活,但多了一个零点参数。我在做 NLP 模型量化时,发现 BERT 的激活值分布往往不对称,用非对称量化能多保住 0.5-1% 的精度。
核心区别总结:对称量化适合权重(分布接近对称),非对称量化适合激活值(分布可能偏移)。
1.2 量化精度损失的根源
为什么量化会掉精度?我把它归结为三个根源:
- 截断误差:超出量化范围的数值被直接截断。比如 INT8 范围是 [-128, 127],如果某个权重是 200,量化后变成 127,信息就丢了。
- 舍入误差:浮点数到整数的四舍五入。比如 3.6 量化成 4,0.3 量化成 0,每次舍入都有误差。
- 梯度误差:量化操作不可导,反向传播时梯度近似不准确。训练后量化尤其明显。
我记得有一次做 YOLOv5 量化,mAP 从 0.72 掉到 0.58。排查后发现是某个层的权重分布特别宽,截断误差太大。后来改用逐通道量化,mAP 回升到 0.68。
避坑指南:我曾经在量化 MobileNetV3 时,发现精度直接崩了。后来才意识到,MobileNet 的深度可分离卷积对量化特别敏感——每个通道的权重分布差异很大,逐层量化会放大误差。解决方案是改用逐通道量化,或者做量化感知训练。
1.3 量化精度损失的影响因素
| 因素 | 影响程度 | 典型场景 |
|---|---|---|
| 权重分布宽度 | 高 | 分布越宽,截断误差越大 |
| 激活值分布对称性 | 中 | 不对称分布浪费量化范围 |
| 网络深度 | 中 | 误差逐层累积 |
| 量化粒度 | 高 | 逐层 vs 逐通道,差异明显 |
| 校准数据集 | 高 | 数据分布不匹配,校准不准 |
你想想看,量化就像用一把粗尺子去量精细的零件。尺子刻度越粗(量化位宽越小),误差越大。但如果我们知道零件的大致尺寸范围(校准数据),就能把尺子调得更准。
1.4 量化精度损失的可视化
下面这张图展示了量化过程中数据分布的变化。我习惯用这种图来快速定位精度损失来源。
实战技巧:我习惯在量化前先打印每层的权重和激活值分布直方图。如果发现某个层的分布特别宽(比如超过量化范围的 3 倍),我会优先处理这个层——要么做逐通道量化,要么用 KL 散度校准法找到最优截断点。
1.5 量化精度损失的评估方法
怎么量化精度损失?我一般用三个指标:
- 精度差:量化前后准确率的差值。比如从 92.3% 掉到 91.1%,损失 1.2%。
- 相对精度损失:(原始精度 - 量化精度) / 原始精度。更公平地比较不同模型。
- 余弦相似度:量化前后每层输出的余弦相似度。低于 0.99 就要警惕。
嗯,这里要注意:精度差在 1% 以内通常可以接受,但具体看业务场景。我做金融风控模型时,精度损失超过 0.5% 就会被驳回。而做图像分类时,1-2% 的损失往往可以接受。