量化
模型量化 (Model Quantization)
模型量化是指将神经网络的浮点算法(通常为 FP32)转换为低精度算法(如 INT8, FP16, BF16)的过程,旨在减少模型大小、降低内存占用并加速推理,同时尽量保持模型精度。
1. 基本概念
1.1 为什么要量化?
- 加速计算:低精度运算(如 INT8)在特定硬件(如 CPU 的 VNNI 指令集,GPU 的 Tensor Cores)上比 FP32 快得多。
- 减少内存带宽压力:模型权重和激活值变小,减少了数据搬运的时间。
- 减小模型体积:便于在移动端或边缘设备部署。
- 降低功耗:低精度运算能耗更低。
1.2 对称量化 vs 非对称量化 (Symmetric vs Asymmetric)
量化公式通常表示为:$Q = \text{clamp}(\text{round}(R / S + Z))$ 其中 $R$ 是实数值,$Q$ 是量化后的整数,$S$ 是缩放因子 (Scale),$Z$ 是零点 (Zero Point)。
对称量化 (Symmetric):
- 假设数据分布关于 0 对称。
- $Z = 0$。
- 映射范围:$[-127, 127]$ (INT8)。
- 优点:计算简单(因为 $Z=0$),推理速度快。
- 缺点:如果数据分布严重不对称(如 ReLU 后的激活值),会浪费一半的量化范围。
非对称量化 (Asymmetric):
- 数据分布不要求对称。
- $Z \neq 0$。
- 映射范围:$[0, 255]$ (UINT8) 或 $[-128, 127]$。
- 优点:能充分利用量化范围,对非对称分布数据(如 ReLU 输出)更友好。
- 缺点:计算稍微复杂,因为需要处理 Zero Point。
1.3 量化粒度 (Granularity)
- Per-Tensor (Layer-wise):整个 Tensor 使用同一个 Scale 和 Zero Point。计算简单,但如果 Tensor 数值范围差异大,精度损失较大。
- Per-Channel (Channel-wise):对于卷积权重,每个 Channel 使用独立的 Scale 和 Zero Point。精度通常更高,是目前主流的权重量化方式。
2. 量化方法
2.1 Post-Training Quantization (PTQ, 训练后量化)
- 特点:不需要重新训练,只需要少量校准数据 (Calibration Data) 来统计激活值的分布。
- 流程:
- 准备预训练好的 FP32 模型。
- 使用校准数据集进行推理,收集各层的激活值统计信息(如 Min, Max, Histogram)。
- 计算 Scale 和 Zero Point。
- 将权重和激活值量化为整数。
- 适用场景:快速部署,无法获取全量训练数据时。
2.2 Quantization-Aware Training (QAT, 量化感知训练)
- 特点:在训练过程中模拟量化误差,让网络学习适应量化带来的噪声。
- 流程:
- 在 FP32 模型中插入“伪量化”节点 (Fake Quantization Nodes)。
- 前向传播时模拟量化(截断、取整),反向传播时使用 STE (Straight-Through Estimator) 估算梯度。
- 微调 (Fine-tune) 模型。
- 适用场景:PTQ 精度下降严重,追求极致精度时。
3. 常用统计/校准算法
在 PTQ 中,如何确定 Scale 是关键。
- MinMax:直接使用数据的最大值和最小值确定范围。对离群点 (Outliers) 非常敏感。
- Moving Average MinMax:在训练/校准过程中,使用移动平均更新 Min/Max。
- KL Divergence (Entropy Calibration):寻找一个阈值,使得量化后的分布与原始分布的 KL 散度(相对熵)最小。TensorRT 默认使用此方法,适合激活值量化。
- Percentile:取数据的 99.9% 或 99.99% 分位点作为阈值,去除极端的离群点。
4. 硬件支持与指令集
- CPU (x86): AVX-512 VNNI (DL Boost) 专门优化 INT8 计算。
- CPU (ARM): NEON 指令集,Dot Product 指令。
- GPU (NVIDIA): Tensor Cores 支持 INT8, INT4, FP16, BF16 加速。
- NPU/TPU: 专为低精度矩阵乘法设计的 ASIC。
5. 常见问题与挑战
- 精度下降:特别是 MobileNet 等轻量级网络,参数冗余少,量化后容易掉点。
- Outliers:某些层(如 Transformer 的 LayerNorm 后)可能出现极端大值,导致量化范围被拉大,大部分数值分辨率降低。解决方法包括 SmoothQuant 等。
- 混合精度 (Mixed Precision):对敏感层使用 FP16,不敏感层使用 INT8,以平衡速度和精度。