训练后量化 PTQ:无需重训练的快速模型压缩
FreeGuideOnline
最新
2026-06-29
r = S * (q - Z)
其中:
- **r**:实数值(FP32)
- **q**:量化后的整数值
- **S**:缩放因子(scale,浮点数)
- **Z**:零点(zero-point,整数,用于非对称量化)
量化又可分为:
- **对称量化**:Z = 0,数值范围对称,如 [-127, 127]。
- **非对称量化**:Z ≠ 0,可更好地利用表示范围,常用于激活值。
PTQ 需要在**没有训练**的条件下确定合适的 S 和 Z 参数,这一过程称为**校准**。
## 两种主要的 PTQ 类型
### 1. 动态量化(Dynamic Quantization)
- **量化对象**:仅将权重预先量化为 INT8。
- **激活值处理**:激活值在推理时动态计算其范围,并即时量化。
- **优点**:无需校准数据,实现简单,适合 RNN、Transformer 等层。
- **缺点**:激活值的量化/反量化开销可能降低加速效果,适合内存受限场景而非极致延迟优化。
- **典型应用**:PyTorch 的 `torch.quantization.quantize_dynamic`。
### 2. 静态量化(Static Quantization)
- **量化对象**:权重和激活值都事先量化为 INT8。
- **激活值范围**:通过使用一小部分代表性的校准数据(通常几百张图片或文本样本)提前统计激活值的分布,从而固定量化参数。
- **优点**:推理速度最快,内存占用最低,能充分利用整数运算单元。
- **缺点**:需要校准数据,对激活值分布敏感。
- **典型应用**:TensorFlow Lite 的整数量化,PyTorch 的 Static Quantization。
### 3. 仅权重量化(Weight-Only Quantization)
部分算法如 GPTQ、AWQ 等专为大型语言模型设计,将权重量化为 INT4、INT8 甚至 FP8,而激活保持较高精度。这可以大幅降低显存占用,但对推理加速依赖专门内核。
## PTQ 的工作流程
以最常见的**静态量化**为例,典型流程如下:
1. **准备浮点模型**:已训练好的 FP32 模型。
2. **插入量化-反量化节点**:在需要量化的层(如卷积、全连接)前后添加观察器和伪量化节点(FakeQuantization)。
3. **校准**:运行若干批次的校准数据,统计各层激活值的 min/max 或使用更高级的统计方法(如直方图、KL 散度)来确定最优的量化参数。
4. **转换与优化**:将伪量化节点转换为真正的整数量化操作,移除不适合的算子并可能融合层(如卷积+BN+ReLU)。
5. **导出与部署**:生成纯整数的模型文件(如 TFLite、ONNX、TorchScript),在目标设备上运行。
## PTQ 校准技术详解
校准数据的数量和质量直接影响量化精度。常用校准算法包括:
- **MinMax**:直接取校准数据中的最小/最大值,简单但易受离群点影响。
- **MovingAverageMinMax**:指数移动平均统计 min/max。
- **Histogram**:基于直方图的截断,选取一个能覆盖主要分布的阈值。
- **KL 散度校准**:相比 FP32 分布与量化后分布之间的 KL 散度,找到最佳截断值,效果较好。
- **MSE(均方误差)**:最小化量化前后激活值的均方误差。
选择校准算法时,优先尝试 KL 散度或 MSE,尤其当模型包含大量离群值时。
## 主流框架下的 PTQ 实践
### 1. PyTorch 实现静态量化(示例)
```python
import torch
from torch.quantization import quantize_fx, get_default_qconfig
# 加载预训练模型
model_fp32 = torchvision.models.resnet18(pretrained=True)
model_fp32.eval()
# 设置量化配置(默认对称量化,激活用MinMax观察器)
model_fp32.qconfig = get_default_qconfig('fbgemm') # x86 CPU
# 准备模型,插入观察器
model_prepared = quantize_fx.prepare_fx(model_fp32, qconfig_dict)
# 校准(需要几百张真实图像)
with torch.no_grad():
for data in calibration_dataloader:
model_prepared(data)
# 转换为量化模型
model_quantized = quantize_fx.convert_fx(model_prepared)
# 推理
output = model_quantized(data)
2. TensorFlow Lite 整数量化
import tensorflow as tf
# 转换为 TFLite 模型并选择量化
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
# 提供代表性数据集用于校准
def representative_dataset():
for data in calibration_images:
yield [data]
converter.representative_dataset = representative_dataset
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]
converter.inference_input_type = tf.uint8 # 也可以是 tf.int8
converter.inference_output_type = tf.uint8
tflite_quant_model = converter.convert()
3. ONNX Runtime 量化
可以使用 onnxruntime-tools 或 olive 进行量化:
# 使用 Python API
from onnxruntime.quantization import quantize_static, QuantType
quantize_static(
model_input="model_fp32.onnx",
model_output="model_int8.onnx",
calibration_data_reader=calibration_data_reader,
quant_format=QuantType.QInt8
)