PaddleClas 模型裁剪与量化算法全解:PACT 量化与 FPGM 裁剪的部署加速实战
PaddleClas 模型裁剪与量化算法全解:PACT 量化与 FPGM 裁剪的部署加速实战
深度学习模型因其计算复杂度高、参数冗余多,在边缘设备、低功耗场景和实时推理系统中往往难以直接部署。模型压缩技术通过在保持精度的前提下降低参数量与计算量,成为打通"训练—部署"链路的关键一环。本文以 PaddleClas 官方算法文档为主线,系统讲解其在图像分类任务中主推的两类压缩算法——PACT 量化与 FPGM 裁剪:既从数学原理上剖析"为什么有效",也从配置文件、源码与自动化压缩工具三个层面给出可直接落地的操作方案。读完本文,你将掌握在 PaddleClas 中启用 PACT 量化训练、FPGM 结构化裁剪,以及通过 PaddleSlim 自动压缩(量化+蒸馏)产出 INT8 模型并加速部署的完整实战技能。
1. 为什么需要模型压缩:计算复杂度与参数冗余
深度学习在图像分类上取得卓越效果的同时,也带来了两个部署层面的瓶颈:
- 计算复杂度高:卷积、全连接等算子在前向推理时消耗大量算力,限制了在高帧率、低功耗场景下的实时性;
- 参数冗余:大规模网络参数占用大量存储与通信带宽,尤其在端侧(手机、嵌入式设备)上,模型体积直接决定了可用性。
模型压缩算法通过降低参数冗余,能够同时减少存储占用、通信带宽与计算复杂度。在众多压缩手段中,**量化(Quantization)与裁剪(Pruning)**应用最为广泛。在 PaddleClas 中,官方主推以下两种算法:
- 量化方法:PACT(PArameterized Clipping acTivation)
- 裁剪方法:FPGM(Filter Pruning via Geometric Median)
二者的具体算法参数定义与扩展能力由 PaddleSlim 提供,PaddleClas 负责将其接入分类训练/压缩流程。
2. PACT 量化:用可学习截断解决激活值量化难题
2.1 量化的两个对象:Weight 与 Activation
模型量化主要包括两个部分:
- 权重(Weight)量化:对网络参数做低比特(如 INT8)映射;
- 激活值(Activation)量化:对前向传播过程中的特征图做低比特映射。
只有对两部分同时量化,才能获得最大的计算效率收益(此时卷积/全连接算子可以在 INT8 整数运算下执行)。对于权重,可以通过网络正则化等手段让分布尽量紧凑,减少离群点与不均匀分布;但对于激活值,一直缺乏有效的分布控制手段,这正是 PACT 要解决的问题。
2.2 PACT 的动机:ReLU 造成激活值范围"无限大"
PACT 提出时的关键观察是:当使用权重量化方案去量化激活值时,激活值的量化结果与全精度结果相差较大。
根本原因在于:权重基本分布在 0 到 1 的范围内,而经过 ReLU 激活函数后,激活值取值范围是(理论上的)无限大。若直接按全局最大绝对值确定量化 scale,绝大多数数值会集中在很小的量化区间内,导致严重的舍入误差。
2.3 核心思想:截断式 ReLU 与可学习截断上界 α
为此,PACT 引入**截断式 ReLU(Clipped ReLU)**作为激活函数:在量化激活值之前,先去掉分布中的离群点,从而将量化带来的精度损失降到最低——在某些任务上甚至能达到比原模型更高的准确率。
其关键在于截断上界 α 是一个可学习的参数,它保证每一层都能通过训练学到各自不同的量化范围,从而最大程度降低量化带来的舍入误差。PACT 的量化公式如下:
从公式可以看出,PACT 的思想是用上述量化函数替代 ReLU 本身:对输入大于 0 的部分以阈值 α 进行截断,再按 α 进行对称量化映射。
2.4 PaddleSlim 中的改进:对正负两侧同时截断
在 PaddleSlim 中,上述公式被进一步改进为:
改进后的做法是:在激活值与待量化的算子(卷积、全连接等)之间插入 PACT 预处理。它不仅对大于 0 的分布进行截断,也对小于 0 的部分做同样的限制,从而更完整地圈定待量化数值范围,降低量化损失。与此同时,截断阈值保持为可训练参数——在量化训练过程中,模型会自动找到合理的截断阈值,进一步降低量化精度损失。
2.5 PaddleClas 中的落地:Slim.quant 配置节
在 PaddleClas 的模型配置体系中,量化训练通过 Slim 配置节开启。以 ResNet50_vd 量化训练配置 为例,关键片段如下:
# for quantization or prune model
Slim:
## for quantization
quant:
name: pact
Slim.quant.name: pact即指定使用 PACT 量化方法;- 其余为常规训练配置:
Arch(网络结构、类别数、是否加载预训练)、Loss(训练/评估损失,此处训练使用带 label smoothing 的 CELoss)、Optimizer(Momentum + Cosine 学习率衰减)、DataLoader(ImageNet 训练/验证数据流)、Metric(Top1/Top5 精度评估)。
PaddleClas 在 ppcls/configs/slim/ 目录下为多种模型预置了量化与裁剪配置,包括 MobileNetV3_large_x1_0_quantization.yaml、PPLCNet_x1_0_quantization.yaml、ResNet50_vehicle_cls_quantization.yaml、ResNet50_vehicle_reid_quantization.yaml、GeneralRecognition_PPLCNet_x2_5_quantization.yaml 等,覆盖通用分类、车辆分类/ReID、通用识别等场景,可直接作为修改模板。
3. FPGM 裁剪:从"范数最小"到"几何冗余"
3.1 传统范数剪枝的两大前提
模型剪枝(Pruning)是减小模型体积、提升推理效率的重要手段。传统网络剪枝方法一般将网络 filter(卷积核)的范数 作为其重要性度量:范数值越小,代表该 filter 越不重要,可以将其从网络中裁剪掉;范数越大则越重要,予以保留。
FPGM 指出,这类方法要成立,必须同时依赖两个条件:
- filter 的范数偏差应该足够大,这样重要与不重要的 filter 才能被很好地区分开;
- 不重要的 filter 的范数应该足够小,使其与重要 filter 有明显距离。
然而在真实网络中,这两个条件往往无法同时满足——所有 filter 的范数可能分布得很集中,此时按范数排序裁剪会伤及重要结构。
3.2 FPGM 的核心思想:利用几何中心的可表达性
基于上述分析,FPGM(Filter Pruning via Geometric Median)转而利用层内 filter 的几何中心特性:处于几何中心附近的 filter,可以被其他 filter 的线性组合所表达,即信息冗余度高,因此可以将其剔除。
这样一来,剪枝判断从"范数小 = 不重要"转变为"位置冗余 = 可删除",完全避开了前面提到的两点范数假设。下图直观对比了 FPGM 与基于范数的传统方法在筛选被剪 filter 时的差异(详细数学推导可参见 CVPR 2019 论文 Filter Pruning via Geometric Median for Deep Convolutional Neural Networks):
3.3 PaddleClas 中的落地:Slim.prune 配置节
FPGM 裁剪同样通过 Slim 配置节启用。以 ResNet50_vd 裁剪配置 为例:
# for quantization or prune model
Slim:
## for prune
prune:
name: fpgm
pruned_ratio: 0.3
Slim.prune.name: fpgm指定裁剪算法为 FPGM;Slim.prune.pruned_ratio: 0.3表示期望裁剪 30% 的通道/滤波器,该比例需要根据精度-速度权衡调整。
PaddleClas 同样为多种模型预置了裁剪配置:MobileNetV3_large_x1_0_prune.yaml、ResNet50_vd_prune.yaml、ResNet50_vehicle_cls_prune.yaml、ResNet50_vehicle_reid_prune.yaml 等,覆盖通用分类与车辆识别场景。
4. 自动化压缩:ACT 工具链与量化蒸馏一体化
除手工编写 Slim 配置做量化/裁剪训练外,PaddleClas 在 deploy/slim/act/ 目录下提供了图像分类模型自动压缩(ACT)示例,将"量化训练(QAT)+ 蒸馏"组合成一条命令完成,产出可直接部署的压缩模型。
4.1 自动压缩启动方式
以 ResNet50 为例,单卡启动:
export CUDA_VISIBLE_DEVICES=0
python run_ppclas.py \
--compression_config_path='./configs/ResNet50/qat_dis.yaml' \
--reader_config_path='./configs/ResNet50/data_reader.yaml' \
--save_dir='./save_quant_ResNet50/'
多卡启动(ImageNet 这类大数据集上可获得近似线性加速比,注意同步调整学习率):
export CUDA_VISIBLE_DEVICES=0,1,2,3
python -m paddle.distributed.launch run_ppclas.py \
--save_dir='./save_quant_resnet50/' \
--compression_config_path='./configs/ResNet50/qat_dis.yaml' \
--reader_config_path='./configs/ResNet50/data_reader.yaml'
该流程内部调用 paddleslim.auto_compression.AutoCompression 接口完成量化训练与蒸馏。
4.2 自动压缩配置文件详解
以 PPLCNet_x1_0 的 qat_dis.yaml 为例,一个典型的量化+蒸馏压缩配置包含四大部分:
Global:
model_dir: PPLCNet_x1_0_infer # Inference 模型目录
model_filename: inference.pdmodel # 模型结构文件
params_filename: inference.pdiparams # 权重参数文件
batch_size: 32
input_name: x # 模型输入 tensor 名称
Distillation:
alpha: 1.0 # 蒸馏损失权重
loss: l2 # 蒸馏损失类型
QuantAware:
use_pact: true # 启用 PACT 量化
activation_bits: 8 # 激活值量化位宽
is_full_quantize: false
onnx_format: True # 输出 ONNX 兼容格式
activation_quantize_type: moving_average_abs_max
weight_quantize_type: channel_wise_abs_max
not_quant_pattern: # 不参与量化的算子模式
- skip_quant
quantize_op_types: # 参与量化的算子类型
- matmul
- matmul_v2
weight_bits: 8 # 权重量化位宽
TrainConfig:
epochs: 1
eval_iter: 1000
learning_rate:
type: CosineAnnealingDecay
learning_rate: 0.015
optimizer_builder:
optimizer:
type: Momentum
weight_decay: 0.00002
origin_metric: 0.7132 # 原始模型精度,用于压缩后对比
参数含义要点:
QuantAware.use_pact: true是本仓库 ACT 示例中默认开启的 PACT 量化开关,与前述 PACT 算法一一对应;activation_bits/weight_bits控制量化位宽,默认均为 8;activation_quantize_type与weight_quantize_type决定量化 scale 的计算方式(如moving_average_abs_max、channel_wise_abs_max),直接影响量化精度与计算效率;quantize_op_types列出实际量化的算子,not_quant_pattern提供按算子名跳过量化的通道;TrainConfig.learning_rate需与 batch size 保持线性关系(如单卡 batch_size=32 对应 lr=0.015,batch size 缩小 4 倍则 lr 除以 4,多卡则按卡数倍增)。
deploy/slim/act/configs/ 下还提供了 MobileNetV3_small_x1_0、PPHGNet_small、SwinTransformer_base、CLIP_vit_base_patch16_224、ResNet50 等模型的现成 qat_dis.yaml 与 data_reader.yaml 组合,可直接替换使用。data_reader.yaml 中的数据预处理与 DataLoader 配置与 PaddleClas 主训练流程保持一致。
4.3 ACT 压缩效果参考(仓库 README 实测数据)
根据 deploy/slim/act/README.md 中记录的实测基准(GPU 为 NVIDIA Tesla V100 单卡 + TensorRT-8.0.3.4,CPU 为 Intel Xeon Gold 6271C、10 线程,测试 batch_size 均为 4),量化+蒸馏策略在保持精度基本不变的同时显著降低 GPU 推理耗时:
| 模型 | 策略 | 压缩训练评估 Top-1 Acc | GPU 耗时(ms) | CPU 耗时(ms) |
|---|---|---|---|---|
| MobileNetV3_small_x1_0 | Baseline | 68.01 | 2.4 | 27.2 |
| MobileNetV3_small_x1_0 | 量化+蒸馏 | 66.94 | 1.6 | 27.5 |
| ResNet50_vd | Baseline | 79.05 | 5.9 | 23.5 |
| ResNet50_vd | 量化+蒸馏 | 78.62 | 2.8 | 17.8 |
| PP-HGNet_small | Baseline | 81.33 | 6.5 | 22.6 |
| PP-HGNet_small | 量化+蒸馏 | 81.25 | 4.0 | 22.9 |
| SwinTransformer_base_patch4_window7_224 | Baseline | 83.26 | 18.5 | 942.7 |
| SwinTransformer_base_patch4_window7_224 | 量化+蒸馏 | 83.26 | 9.2 | 955.1 |
| PP-LCNet_x1_0 | Baseline | 71.05 | 2.3 | 45.7 |
| PP-LCNet_x1_0 | 量化+蒸馏 | 70.70 | 1.6 | 43.2 |
| CLIP_vit_base_patch16_224 | Baseline | 85.36 | 13.9 | 68.9 |
| CLIP_vit_base_patch16_224 | 量化+蒸馏 | 85.36 | 8.3 | 66.5 |
从表中可以看到,INT8 量化在 GPU + TensorRT 下通常能获得约 1.5~2 倍的推理加速,而精度损失普遍控制在 1 个百分点以内;Transformer 类模型(如 SwinTransformer)在 GPU 上的收益尤为明显。此外,deploy/slim/auto_compression/README.md 中的 MobileNetV3_large_x1_0 示例显示,量化+蒸馏在 ARM CPU(SDM865)上可将单张推理耗时从 16.62ms 降至 9.85ms,说明该方案同样适用于端侧部署。
5. 压缩模型的推理部署与加速
5.1 部署加速选型
压缩产出的 INT8 模型在不同硬件上有不同的加速手段:
- GPU:使用 TensorRT 推理引擎加速;
- CPU:使用 MKLDNN(MKL-DNN) 加速库。
以 test_ppclas.py 的调用方式为例,TensorRT + INT8 推理:
python test_ppclas.py \
--model_path=./save_quant_resnet50 \
--use_trt=True \
--use_int8=True \
--use_gpu=True \
--data_path=./dataset/ILSVRC2012/
MKLDNN + INT8 推理:
python test_ppclas.py \
--model_path=./save_quant_resnet50 \
--data_path=./dataset/ILSVRC2012/ \
--cpu_num_threads=10 \
--use_mkldnn=True \
--use_int8=True
5.2 推理参数速查表
| 参数名 | 含义 |
|---|---|
| model_path | inference 模型文件所在目录,需包含 .pdmodel 与 .pdiparams 两个文件 |
| model_filename | 模型目录下的模型文件名称 |
| params_filename | 模型目录下的参数文件名称 |
| data_path | 数据集路径 |
| batch_size | 预测一个 batch 的大小 |
| image_size | 输入图像大小(注意 InceptionV3 等模型输入为 299,需相应修改) |
| use_gpu | 是否使用 GPU 预测 |
| use_trt | 是否使用 TensorRT 预测引擎 |
| use_mkldnn | 是否启用 MKL-DNN 加速;与 use_gpu 同时为 True 时忽略该选项 |
| cpu_num_threads | CPU 预测线程数,默认 10 |
| use_fp16 | 使用 TensorRT 时是否启用 FP16 |
| use_int8 | 是否启用 INT8 推理 |
5.3 常见问题:CPU 上 MKLDNN 推理精度异常
针对 MKLDNN 推理 CLIP_vit_base_patch16_224、SwinTransformer_base_patch4_window7_224 及其压缩模型时出现的精度严重下降问题,需要在预测配置中删除两个融合 pass:
config.delete_pass("fc_mkldnn_pass")
config.delete_pass("fc_act_mkldnn_fuse_pass")
这两行代码已写入 test_ppclas.py 对应位置(默认注释状态),遇到上述模型的精度异常时取消注释即可恢复。
6. 总结:算法原理与工程落地的完整映射
| 压缩算法 | 核心原理 | PaddleClas 配置入口 | 典型配置文件 |
|---|---|---|---|
| PACT 量化 | 以可学习截断上界 α 的 Clipped ReLU 替代 ReLU,压缩激活分布、减少离群点,降低量化映射损失 | Slim.quant.name: pact;ACT 中 QuantAware.use_pact: true |
ResNet50_vd_quantization.yaml、qat_dis.yaml |
| FPGM 裁剪 | 利用 filter 的几何中心特性剔除可被其他 filter 表达的红余 filter,从信息冗余度而非范数大小出发做剪枝 | Slim.prune.name: fpgm + pruned_ratio |
ResNet50_vd_prune.yaml |
结合本仓库 ppcls/configs/slim/ 与 deploy/slim/act/ 的现成配置,开发者可以:
- 直接修改
Slim配置节,复用主训练流程(tools/train.py)完成量化/裁剪训练; - 一键 ACT 自动压缩,用
run_ppclas.py将量化训练与蒸馏结合,自动产出 INT8 部署模型; - 按部署平台选择 TensorRT / MKLDNN 加速,并在压缩后通过 Top-1 Acc 与原模型对比验证压缩收益。
PACT 与 FPGM 一"量化"一"裁剪",分别从数值映射与结构冗余两个维度切入,配合 PaddleSlim 的参数化实现与 PaddleClas 的工程化配置,为图像分类模型在 GPU、CPU 与端侧设备上的高效部署提供了一条低精度损失的完整路径。



