量化(Quantization)详解

1. 量化的本质:降低数据精度

量化就是把高精度的浮点数(float32)转换成低精度的整数(int8/int16)
最直观的例子:

# 原始数据(float32,32位,4字节)
float32: 3.14159265  # 可以表示很精细的数值
         ↓
# 量化后(int8,8位,1字节)
int8: 3  # 只能表示整数

存储空间减少:4 bytes → 1 byte = 75% 压缩!

2. 为什么需要量化?

实际需求:

# 训练阶段:float32
模型大小: 280 MB
推理速度: 30 ms/frame
功耗: 高
硬件需求: GPU (高算力)

# 部署阶段(量化后int8)
模型大小: 70 MB  (75%)
推理速度: 8 ms/frame  (3.75x)
功耗: 低
硬件需求: Horizon BPU (嵌入式芯片)

核心驱动力:

  • ✅ 车载硬件算力有限(Horizon BPU不是GPU)
  • ✅ 实时性要求(30FPS,每帧<33ms)
  • ✅ 功耗限制(车载不能像数据中心那样散热)
  • ✅ 成本控制(边缘芯片比GPU便宜很多)

3. 量化的数学原理

基本公式:

# 量化过程(float → int)
x_float = 原始浮点数值  # 例如: 3.7854
scale = 缩放因子        # 例如: 0.05
zero_point = 零点       # 例如: 0

x_int8 = round(x_float / scale) + zero_point
       = round(3.7854 / 0.05) + 0
       = round(75.708) + 0
       = 76

# 反量化过程(int → float)
x_float_recovered = (x_int8 - zero_point) * scale
                  = (76 - 0) * 0.05
                  = 3.8

误差 = |3.7854 - 3.8| = 0.0146  (可接受)

可视化量化过程:

原始float32范围: [-10.0, 10.0]
量化到int8范围: [-128, 127]

计算scale:
scale = (max - min) / (127 - (-128))
      = (10.0 - (-10.0)) / 255
      = 20.0 / 255
      = 0.0784

映射关系:
Float32          Int8
───────────────────────
 10.0      →     127
  5.0      →      64
  0.0      →       0
 -5.0      →     -64
-10.0      →    -128

可视化:
Float32: |----●----●----●----●----| (连续的)
         -10  -5   0    5   10

Int8:    |●|●|●|●|●|●|●|●|●|●|●|●| (离散的256个值)
        -128      0           127

4. 量化的两种方式

PTQ (Post-Training Quantization) - 训练后量化

# PTQ流程
--quant_method ptq  # 指定使用PTQ
--calib_num 150     # 使用150张图片校准

步骤1: 加载训练好的float32模型
     model = load_checkpoint("mapformer.pth")
     
步骤2: 插入量化节点(FakeQuantize)
     calib_model = prepare_calibration_fx(model)
     # FakeQuantize: 模拟量化但仍用float32计算
     
步骤3: 校准(Calibration)- 统计数据分布
     for i, data in enumerate(calib_dataloader):
         if i >= 150:  # calib_num
             break
         with torch.no_grad():
             calib_model(data)  # 前向传播,收集统计信息
     
     # 收集什么?
     # - 每层激活值的min/max
     # - 权重的min/max
     # - 计算最佳scale和zero_point
     
步骤4: 确定量化参数
     scale = (max_val - min_val) / 255
     
步骤5: 转换成真正的int8模型
     quantized_model = convert_fx(calib_model)

PTQ的特点:

  • ✅ 简单快速:不需要重新训练
  • ✅ 只需少量数据:150张图片校准即可
  • ❌ 精度损失较大:直接量化可能掉点2-5%
  • 适合:快速验证、原型开发

QAT (Quantization-Aware Training) - 量化感知训练

# QAT训练
bash run_dist.sh --config <cfg> --work-dir <dir> --mode train --qat_v2

步骤1: 从float32模型开始
     model = BEVRoadGeometry()
     
步骤2: 插入FakeQuantize节点
     qat_model = prepare_qat_fx(model)
     
步骤3: 完整训练过程(模拟量化)
     for epoch in range(100):
         for data in train_dataloader:
             # 前向传播
             output = qat_model(data)
             
             # FakeQuantize的工作:
             # 1. 把激活值量化到int8再反量化回float32
             # 2. 梯度可以正常回传
             fake_quant(x):
                 x_int8 = quantize(x, scale)
                 x_float = dequantize(x_int8, scale)
                 return x_float  # 仍然是float,但模拟了int8的精度损失
             
             # 反向传播 - 网络学会适应量化误差
             loss.backward()
             optimizer.step()
     
步骤4: 转换成真正的int8模型
     quantized_model = convert_fx(qat_model)

QAT的特点:

  • ✅ 精度损失小:网络学会适应量化,通常<1%掉点
  • ✅ 鲁棒性好:对量化参数不敏感
  • ❌ 训练成本高:需要完整训练流程(几天到几周)
  • 适合:生产部署、对精度要求高

5. 量化对不同层的影响

# 卷积层(权重 + 激活都量化)
Conv2d: float32 → int8

权重量化:
  原始: weight (128, 64, 3, 3) float32 = 294,912 bytes
  量化: weight (128, 64, 3, 3) int8   = 73,728 bytes  (↓75%)
  
激活量化:
  原始: activation (B, 128, 64, 128) float32
  量化: activation (B, 128, 64, 128) int8
  
计算:
  原始: float32 × float32 = float32 ()
  量化: int8 × int8 = int32 → rescale to int8 (快4-8倍)

# BatchNorm层(通常融合到卷积)
BN参数:
  γ, β → 融合到Conv的权重和bias中
  不需要单独量化
  
# ReLU层(量化友好)
ReLU: max(0, x)
  int8下: max(0, x_int8)  # 仍然很简单

# Sigmoid/Softmax(量化不友好)
需要查找表(LUT):
  Sigmoid(x) → 用分段线性近似
  在BPU上用SegmentLUT实现

6. 量化精度损失分析

# 精度对比(从实际项目经验)
                Float32   PTQ(int8)   QAT(int8)
─────────────────────────────────────────────
Lane mAP          0.79      0.74        0.78
Inference(ms)      30        10           8
Model Size(MB)    280        70          70
BPU Support        ❌        ✅          ✅

精度损失来源:
1. 权重量化: ±0.5% - 1%
2. 激活量化: ±1% - 2%  
3. 非线性操作(Sigmoid/Softmax): ±0.5% - 1.5%
4. 累积误差: ±0.5%

总损失: PTQ ≈ 3-5%, QAT ≈ 0.5-1.5%

7. 总结

量化 = 用更少的比特表示数值

  1. 原理: Float32 → Int8
    • 32位浮点 → 8位整数
    • 通过scale和zero_point映射
    • 保留重要的数值范围
    • 通过scale和zero_point映射
    • 保留重要的数值范围
  2. 收益:
    • 模型大小: ↓ 75%
    • 推理速度: ↑ 3-8x
    • 功耗: ↓ 60-80%
    • 支持嵌入式部署
  3. 代价:
    • 精度损失: PTQ 3-5%, QAT 0.5-1.5%
    • 需要校准数据
    • QAT需要重新训练
  4. 方法选择:
    • PTQ: 快速验证、原型
    • QAT: 生产部署、高精度要求

核心理解:

  • 量化是用精度换速度和效率的技术
  • 对于自动驾驶等边缘部署场景必不可少
  • PTQ简单但掉点多,QAT慢但效果好
  • Horizon这样的专用芯片需要量化才能发挥最大性能
Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐