NNI 模型剪枝 Pruner 全指南:9 种剪枝算法的原理、配置与实战

发布时间:2026/9/23 3:28:54
NNI 模型剪枝 Pruner 全指南:9 种剪枝算法的原理、配置与实战
NNI 模型剪枝 Pruner 全指南9 种剪枝算法的原理、配置与实战【免费下载链接】nniAn open source AutoML toolkit for automate machine learning lifecycle, including feature engineering, neural architecture search, model compression and hyper-parameter tuning.项目地址: https://gitcode.com/gh_mirrors/nn/nni模型剪枝Pruning是 NNINeural Network Intelligence模型压缩套件的核心能力之一。本指南以 NNI 官方剪枝器参考文档docs/source/reference/compression/pruner.rst为主线系统讲解当前版本 NNI 提供的 9 种 PrunerLevel、L1Norm、L2Norm、FPGM、Slim、Taylor、Linear、AGP 与 Movement。读完本文你将掌握每种剪枝算法的核心思想、适用场景、config_list 配置方法以及训练—剪枝—加速的完整实战流程可直接在自有 PyTorch 模型上复现。一、NNI 剪枝框架概览从旧框架到新框架NNI 的模型剪枝目标是利用模型权重中的冗余将不重要的参数置零并确保其不参与反向传播从而在尽量不损失精度的前提下压缩模型体积、加速推理。NNI 官方在 docs/source/compression/pruning.rst 中给出了这一基础定义。需要注意的是并非所有历史版本的剪枝器都已迁移到新框架。官方在 docs/source/compression/pruner.rst 中明确说明目前仍有计划将 NNI 3.2 中实现的所有 Pruner 逐步迁移过来。也就是说本文列出的 9 种 Pruner 是当前新框架nni.compression.pruning中已经可用的剪枝算法全集若你需要的旧算法尚未迁移可以反馈给 NNI 团队优先支持。从源码结构看新框架的剪枝实现集中存放在 nni/compression/pruning 目录下包含以下文件basic_pruner.py基础剪枝器含 Level、L1Norm、L2Norm、FPGM均继承自_NormPruner基类slim_pruner.pySlim PrunerBN 缩放因子剪枝taylor_pruner.pyTaylor FO 剪枝器scheduled_pruner.py调度型剪枝器含ScheduledPruner、_ComboPruner、Linear、AGPmovement_pruner.pyMovement Pruner基于微调的自适应稀疏tools/共享的指标计算、掩码生成工具函数。所有这些类都通过 nni/compression/pruning/init.py 对外统一导出。下面的速查表来自官方文档概括了各算法的核心思路完整原理见后文各节名称算法简介参考论文Level Pruner按权重元素绝对值对每个元素剪掉指定比例—L1 Norm Pruner剪掉权重 L1 范数最小的输出通道Pruning Filters for Efficient ConvnetsL2 Norm Pruner剪掉权重 L2 范数最小的输出通道同 L1 范数剪枝思路FPGM Pruner基于几何中位数Geometric Median的滤波器剪枝Filter Pruning via Geometric Median for Deep CNNs AccelerationSlim Pruner剪掉 BN 层中缩放因子小的通道Learning Efficient Convolutional Networks through Network SlimmingTaylor Pruner基于权重一阶泰勒展开的重要性估计剪枝Importance Estimation for Neural Network PruningLinear Pruner稀疏率在每轮剪枝中线性增长每轮调用基础剪枝器—AGP Pruner自动渐进式剪枝Automated Gradual PruningTo prune, or not to pruneMovement Pruner通过微调实现自适应稀疏的 Movement PruningMovement Pruning: Adaptive Sparsity by Fine-Tuning二、通用剪枝配置config_list 详解所有 Pruner 的第一个参数都是model第二个参数是config_list。config_list是一个 dict 列表每个 dict 描述哪些模块要被压缩、如何压缩。完整规范见 docs/source/compression/config_list.rst这里给出剪枝最常用的键。2.1 模块选择键通用op_names模块全限定名列表如[backbone.layers.0.ffn]不存在的模块会被忽略op_names_re用 Python 标准库re正则匹配模块名op_typestorch.nn.Module子类类型名列表如[Conv2d, Linear]。若未设置则所有模块类型都可被选中若op_names与op_names_re均未设置则选中满足op_types的所有模块exclude_op_names/exclude_op_names_re/exclude_op_types显式排除某些模块名、正则、类型target_names合法的压缩目标名通常支持_input_、weight、bias、_output_。输入/输出目标可用_input_{index}、_input_{arg_name}、_output_{index}、_output_{dict_key}精确定位参数/缓冲区直接用属性名如weight、biastarget_settings{target_name: setting}形式的 dict按目标精细配置。除上述通用键外config 中的其他键会被视为目标设置的快捷方式作用于该 config 选中的所有目标。例如下面两份配置等价以有两个Linear模块fc1、fc2的模型为例shorthand_config { op_types: [Linear], sparse_ratio: 0.8 } standard_config { op_names: [fc1, fc2], target_names: [weight, bias], target_settings: { weight: { sparse_ratio: 0.8, max_sparse_ratio: None, min_sparse_ratio: None, sparse_threshold: None, global_group_id: None, dependency_group_id: None, granularity: default, internal_metric_block: None, apply_method: mul, }, bias: { align: { target_name: weight, dims: [0], }, apply_method: mul, } } }注意每个压缩目标只能配置一次重复配置不会生效。2.2 剪枝专用键sparse_ratio0~1 之间的浮点数表示剪枝目标的稀疏率或其所属组的总体稀疏率。例如稀疏率 0.8 意味着剪完后 80% 的权重值被掩码max_sparse_ratio/min_sparse_ratio限制每个目标稀疏率的上/下限通常与sparse_threshold、global_group_id搭配使用sparse_threshold直接将剪枝指标与阈值比较低于阈值的位点被掩码。不同算法阈值取值范围不同详见各 Pruner 文档一般阈值越高最终稀疏度越高global_group_id需与sparse_ratio联合使用。具有相同global_group_id的所有目标被视为一个整体sparse_ratio在组内按指标自适应分配——组内每个目标最终稀疏率可以不同但组总稀疏率等于配置值且同组内sparse_ratio必须一致。官方示例config_list [{ op_names: [fc1, fc2], sparse_ratio: 0.5, global_group_id: linear_group_1 }, { op_names: [fc3], sparse_ratio: 0.5, global_group_id: linear_group_1 }]dependency_group_id具有相同dependency_group_id的目标被视为整体被剪的位置如输出通道索引保持一致。典型场景是带有 add/mul 结构如残差连接的模块。若你不熟悉模型结构可使用auto_set_denpendency_group_ids(model, config_list, dummy_input)自动检测依赖关系并自动设置该 id见 nni/compression/utils 与官方示例 examples/compression/pruning/norm_pruning.pygranularity控制生成掩码的粒度。支持default、in_channel权重第 1 维、out_channel权重第 0 维、per_channel输入/输出最后一维以及整数列表块稀疏如[4, 4]表示对权重后两维做 4×4 块稀疏。例如输出通道剪枝config { op_types: [Conv2d], sparse_ratio: 0.5, granularity: out_channel # 等价于 [1, -1, -1, -1] }align目标掩码不由剪枝算法生成而是与另一个目标的掩码对齐。典型场景是weight与bias的关系Linear层中若weight第i行全部被掩码则bias第i位也对应掩码。也可用于生成激活掩码例如conv-bn-relu结构中让 BN 输出对齐卷积权重config { op_types: [BatchNorm2d], target_names: [weight], target_settings: { weight: { align: { module_name: conv, target_name: weight, dims: [0], } } } }apply_method默认mul乘以含 0/1 的掩码矩阵0 表示被掩码位add表示加一个含 -1000/0 的掩码矩阵通常用于 Softmax 这类激活模块。从掩码生成的源码实现看nni/compression/pruning/tools/sparse_gen.pygenerate_sparsity会按固定顺序依次执行多条规则并叠加掩码Threshold → Dependency → Global → Ratio → Align若一个目标已有掩码新掩码会与旧掩码相乘意味着越来越稀疏。其中 Ratio 规则的核心是_ratio_mask按sparse_ratio对指标做 topklargestFalse取最小的一批置 0 生成掩码Threshold 规则是metric sparse_threshold置 1并受min/max_sparse_ratio约束回退到比例掩码。三、基础剪枝器Basic Pruner基础剪枝器一次性完成剪枝决策在 basic_pruner.py 中实现可再细分为单步剪枝compress()生成掩码后立即结束和训练感知剪枝通过 Evaluator 在训练过程中间步骤生成掩码。_NormPruner基类定义了统一的流水线_collect_data收集目标数据 →_calculate_metrics计算重要度指标 →_generate_sparsity生成掩码 →update_masks更新模型掩码。3.1 Level Pruner层级/幅度剪枝核心思想最基础的剪枝器在论文中常被称为 magnitude pruning 或 fine-grained pruning。它对每个指定层的权重按绝对值大小掩码掉最小的一部分掩码比例由sparse_ratio决定。实现要点LevelPruner继承自_NormPruner并令p 1即指标为权重的绝对值basic_pruner.py其_set_default_sparse_granularity返回None表示使用逐元素fine-grained稀疏粒度。适用场景无结构剪枝稀疏度高但需要硬件/框架支持稀疏计算才能获得实际加速常用于验证性实验或与其他剪枝方法对比。3.2 L1 Norm Pruner核心思想计算层权重第一个维度上的 L1 范数然后剪掉该维度上 L1 范数较小的权重块——即卷积层按滤波器filter的 L1 范数剪枝线性层按权重行的 L1 范数剪枝。算法细节对应论文Pruning Filters for Efficient Convnets。实现要点p 1通过norm_metricstools/calculate_metrics.py计算每个块在最后一维上的范数t.norm(pp, dim-1)再用_scaler.shrink将指标缩回目标形状随后generate_sparsity按sparse_ratio掩码掉指标最小的块。3.3 L2 Norm Pruner核心思想L1 Norm Pruner 的变体唯一区别是指标换成权重块的L2 范数剪掉 L2 范数最小的块。实现要点p 2basic_pruner.py其余流水线与 L1 完全一致。3.4 FPGM Pruner核心思想FPGMFilter Pruning via Geometric Median认为与其他滤波器在几何上**最接近最可替代**的滤波器对网络贡献最小应被优先剪掉。它基于几何中位数选择最具可替代性的权重块对应论文Filter Pruning via Geometric Median for Deep Convolutional Neural Networks Acceleration。实现要点p 2但指标计算使用专门的fpgm_metricstools/calculate_metrics.py对每个滤波器计算它到其他所有滤波器的范数距离之和距离和最小的滤波器最居中、最可替代因而被剪。源码中显式断言FPGM metric do not support finegrained sparse pattern即 FPGM不支持细粒度稀疏模式只支持结构化通道级剪枝。3.5 Slim Pruner核心思想在训练过程中对BN 层缩放因子施加稀疏正则训练结束后缩放因子趋于 0 的通道被视为不重要而剪掉对应论文Learning Efficient Convolutional Networks through Network Slimming。实现位于 slim_pruner.py。构造参数在model、config_list之外evaluatorTorchEvaluator等评估器用于驱动训练training_steps整数控制模型与缩放因子的训练步数掩码将在training_steps后生成regular_scale默认 1.0控制缩放因子的惩罚强度。实现细节SlimPruner会在每个目标上注册名为{target_name}_slim_factor的缩放因子参数SLIM_SCALING_FACTOR_PNAME用一个独立 Adam 优化器lr1e-2通过patch_optimizer_step挂钩到每一步优化slim_pruner.py同时通过patch_loss在原始损失上叠加缩放因子的 L1 正则项regular_scale * sum(|factor|) / countslim_pruner.py。指标计算时取缩放因子绝对值再走统一的generate_sparsity生成掩码。3.6 Taylor FO Weight Pruner核心思想基于权重的一阶泰勒展开估计每个滤波器的重要性剪掉重要性最低的滤波器以达成预设稀疏度对应论文Importance Estimation for Neural Network Pruning。实现位于 taylor_pruner.py。重要性估计公式来自类文档字符串I_S^(1)(W) Σ_{s∈S} (g_s · w_s)²即对每个权重元素用梯度 × 权重的平方累加作为重要性信号。构造参数evaluator用于提供梯度与训练流程training_steps收集梯度的训练步数掩码在training_steps步后生成。实现细节TaylorPruner通过TensorHook为每个目标参数注册梯度钩子taylor_pruner.py在training_steps步内逐步累加(weight * grad)²最终除以training_steps取均值作为指标_collect_data中hook.buffer[0] / self.training_steps指标按norm_metrics(p1)归约到通道粒度后生成掩码。四、调度型剪枝器Scheduled Pruner调度型剪枝器本身不直接计算指标而是包装一个基础剪枝器按照预定的调度策略线性或 AGP 曲线逐步提高稀疏目标实现边训练边剪枝的渐进式稀疏。基类ScheduledPruner与包装类_ComboPruner位于 scheduled_pruner.py。调度机制的核心是_scheduled_keys [sparse_ratio, sparse_threshold, max_sparse_ratio, min_sparse_ratio]在初始化时把被包装剪枝器各目标空间上的这些目标值保存为sparse_goals然后每隔interval_steps步调用update_sparse_goals(current_times)按比例回写目标值从而让稀疏目标从 0 逐步逼近最终值。sub_pruner TaylorPruner(model, config_list, evaluator, training_steps100) scheduled_pruner AGPPruner(sub_pruner, interval_steps100, total_times10) _, masks scheduled_pruner.compress(max_steps100 * 10, max_epochsNone)注意LinearPruner 与 AGPPruner 不能用from_compressor(...)类方法初始化源码中_ComboPruner.from_compressor直接抛NotImplementedError只能像上面这样包装一个已构造好的基础 Pruner。官方声明其兼容性经过测试的基础剪枝器包括LevelPruner、L1NormPruner、L2NormPruner、FPGMPruner、SlimPruner、TaylorPruner包装其他类型时会打印兼容性未测试的警告scheduled_pruner.py。4.1 Linear Pruner核心思想被包装剪枝器的稀疏率/稀疏阈值从 0 线性增长到最终值。若同时设置了min/max_sparse_ratio它们也随线性调度同步增长。调度公式类文档字符串current_sparse (1 - initial_ratio) * current_times / total_times * final_sparse其中initial_ratio固定为 0.0源码_ComboPruner.__init__中self._initial_ratio 0.0。interval_steps表示每隔多少训练步更新一次稀疏目标total_times表示总共更新多少次。4.2 AGP Pruner核心思想自动渐进式剪枝Automated Gradual Pruning对应论文To prune, or not to prune: exploring the efficacy of pruning for model compression。稀疏目标早期快速增长、后期趋于平缓比线性调度更符合训练收敛规律。调度公式current_sparse (1 - (1 - initial_ratio) * (1 - current_times / total_times) ** 3) * final_sparse与 Linear 相同min/max_sparse_ratio也会按 AGP 曲线同步增长。两种调度器在compress(max_steps, max_epochs)时都要求训练总步数足够若传入max_steps会断言max_steps total_times * interval_steps若只传 epochs则只打印警告提醒用户确保总步数足够scheduled_pruner.py。五、Movement Pruner微调驱动的自适应稀疏Movement Pruner 是 Movement PruningAdaptive Sparsity by Fine-Tuning的实现属于细粒度剪枝fine-pruning掩码在每次微调步骤中都可以变化。其核心思想是为每个权重元素维护一个移动分数分数等于每一步权重 × 梯度之和的相反数——向 0 移动的权重累积负分远离 0 的权重累积正分推理时分数低的权重被掩码。实现位于 movement_pruner.py。构造参数evaluator驱动微调训练warmup_step开始剪枝前的预热步数optimizer.step()次数必须满足0 warmup_step cooldown_begin_step源码中有断言cooldown_begin_step稀疏度停止增长的步数。注意稀疏度停止增长不代表掩码不再变化regular_scale默认 1.0控制移动分数正则损失的缩放因子。该因子只作用于由sparse_threshold控制的目标由sparse_ratio控制的目标不会被正则化。稀疏调度公式final_sparse * (1 - (1 - (current_step - warmup_step) / (cooldown_begin_step - warmup_step)) ** 3)实现细节MovementPruner继承ScheduledPruner但把interval_steps设为 1、total_times设为(cooldown_begin_step - warmup_step)即每个训练步都更新一次稀疏目标movement_pruner.py。它为目标注册名为{target_name}_mvp_score的分数参数MOVEMENT_SCORE_PNAME用独立 Adamlr1e-2在每步更新损失钩子会对sparse_threshold控制的目标叠加regular_scale * ratio * sum(sigmoid(score)) / numel正则项其中ratio随剩余步数立方衰减。掩码的 apply_method 被改为专用的movement_mul/movement_add。在compress(max_steps, ...)时同样断言max_steps cooldown_begin_step。六、完整实战流程从剪枝到加速6.1 一次性剪枝以 Norm 系列为例官方示例 examples/compression/pruning/norm_pruning.py 展示了在 ResNet18/CIFAR10 上用 L1/L2/FPGM 剪枝的完整流程from nni.compression.pruning import L1NormPruner, L2NormPruner, FPGMPruner from nni.compression.utils import auto_set_denpendency_group_ids from nni.compression.speedup import ModelSpeedup model build_resnet18() # 预训练好的模型 config_list [{ op_types: [Conv2d], sparse_ratio: 0.5 }] dummy_input torch.rand(8, 3, 224, 224).to(device) config_list auto_set_denpendency_group_ids(model, config_list, dummy_input) pruner L1NormPruner(model, config_list) # 也可换 L2NormPruner / FPGMPruner _, masks pruner.compress() # 一次性生成掩码 pruner.unwrap_model() # 解包被包装的模型 model ModelSpeedup(model, dummy_input, masks).speedup_model() # 真正移除被剪通道流程要点依赖组自动检测对 ResNet 这类带残差连接的模型先用auto_set_denpendency_group_ids自动补齐dependency_group_id保证残差分支与主分支被剪相同通道pruner.compress()返回(model, masks)剪枝器在模型上套一层 wrapper 并挂载掩码pruner.unwrap_model()剪枝完成后解包恢复为普通模块掩码被固化ModelSpeedup(model, dummy_input, masks).speedup_model()剪枝只是置零掩码真正获得加速还需要这一步——基于掩码和 dummy input 做结构分析把被剪通道从模型中物理移除得到参数量显著下降的紧凑模型示例中剪枝前后都会打印参数量与精度对比。6.2 训练感知剪枝与渐进式调度需要边训练边剪枝的算法Slim、Taylor、Linear、AGP、Movement都要传入TorchEvaluator。官方示例 examples/compression/pruning/scheduled_pruning.py 展示了 Taylor AGP/Linear 的用法from nni.compression import TorchEvaluator from nni.compression.pruning import TaylorPruner, LinearPruner, AGPPruner evaluator TorchEvaluator(train, optimizer, training_step) sub_pruner TaylorPruner(model, config_list, evaluator, training_steps100) scheduled_pruner AGPPruner(sub_pruner, interval_steps100, total_times10) _, masks scheduled_pruner.compress(max_steps100 * 10, max_epochsNone)Slim 的用法类似examples/compression/pruning/slim_pruning.py只需额外指定training_steps1000Taylor 单独使用examples/compression/pruning/taylor_pruning.py时指定training_steps300。Movement Pruner 的参考示例是 examples/tutorials/new_pruning_bert_glue.pyBERT GLUE 微调剪枝。七、如何选择 Pruner追求稀疏度上限、不关心结构选LevelPruner逐元素幅度剪枝配合sparse_ratio使用结构化通道剪枝、模型含大量 Conv/LinearL1NormPruner/L2NormPruner简单高效是默认首选若滤波器分布存在明显几何冗余FPGMPruner往往更稳带 BN 的 CNN如 ResNet 系列SlimPruner通过训练期 L1 正则自动找到可剪通道精度恢复通常更好但需要额外训练步数希望用梯度信息指导剪枝TaylorPruner基于一阶泰勒展开的重要性估计适合已有训练流程、可接受收集梯度的开销大模型微调如 Transformer/BERTMovementPruner专为 fine-tuning 场景设计每个微调步动态更新掩码渐进式稀疏、减少一次性剪枝的精度冲击用LinearPruner或AGPPruner包装上述任一基础剪枝器AGP 的立方衰减曲线在训练后期更平缓通常比线性更友好。结语本文以 NNI 官方 Pruner 参考文档为骨架结合 nni/compression/pruning 下的源码实现与 examples/compression/pruning 中的官方示例完整梳理了当前 NNI 新框架可用的 9 种剪枝器6 种基础剪枝器Level / L1 / L2 / FPGM / Slim / Taylor、2 种调度剪枝器Linear / AGP与 1 种微调型剪枝器Movement。掌握config_list的模块选择、稀疏目标、粒度、依赖组与对齐配置理解指标计算 → 掩码生成 → 模型加速的流水线即可在自有模型上快速落地剪枝并量化其收益。关于掩码规则、剪枝精度对比与调参建议可进一步阅读 docs/source/compression/pruning.rst、docs/source/compression/config_list.rst 与 docs/source/compression/best_practices.rst。【免费下载链接】nniAn open source AutoML toolkit for automate machine learning lifecycle, including feature engineering, neural architecture search, model compression and hyper-parameter tuning.项目地址: https://gitcode.com/gh_mirrors/nn/nni创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考