ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

AMCT 结构化剪枝实战指南:基于 amct_pytorch.pruning 的 Dense FFN / CNN / MoE 通道与专家剪枝

AMCT 结构化剪枝实战指南:基于 amct_pytorch.pruning 的 Dense FFN / CNN / MoE 通道与专家剪枝 AMCT 结构化剪枝实战指南基于 amct_pytorch.pruning 的 Dense FFN / CNN / MoE 通道与专家剪枝【免费下载链接】amctAMCT是CANN提供的昇腾AI处理器亲和的模型压缩工具仓。项目地址: https://gitcode.com/cann/amct导读本文基于 CANN AMCT 开源仓库中amct_pytorch.pruning模块使用文档编写系统讲解如何对一个已实例化、已加载权重的torch.nn.Module进行结构化剪枝包括 Dense FFN 中间维度、CNN 通道、MoE 专家三个可剪枝域容差驱动的自动搜索剪枝、固定剪枝率剪枝、CNN 最小二乘重建、MoE 专家剪枝菜单、剪枝后恢复recovery菜单、与量化组合使用以及剪枝后的config维度回写。读完本文你将能够直接调用amct.prune()完成打分 → 剪枝 → 恢复 → 可选量化的完整压缩流水线并正确理解各配置项与内存/精度权衡。一、模块定位与核心工作机制amct_pytorch.pruning是对一个已经实例化且权重已加载的torch.nn.Module执行结构化剪枝的工具。它的核心设计取向有三个原地修改in-place剪枝直接改写模型结构并通过可选的reportPruneReport()接收统计信息不依赖进程级全局状态config 同步剪枝会同时改写模型的config维度字段如intermediate_size/num_experts保证剪枝后的模型能够被save_pretrained/ 加载直接还原无需额外转换步骤不自带模型下载库本身从不下载模型模型由调用方自行实例化。从入口实现看api.pyprune()会根据参数自动路由到四种模式触发条件模式行为tolerance容差驱动的精度搜索在ratio_grid上二分搜索满足精度损失的最大剪枝率size_budget参数量预算模式剪到目标保留参数比例config 中携带方法级menu菜单选择模式一次校准从多个候选方案中挑选最优以上皆无默认固定剪枝率模式按 config 中的prune_ratio直接剪其中tolerance与size_budget互斥同时传入会抛出ValueErrorapi.py。剪枝四步score → prune → recover → (optional) quantize工具的运行流程可以概括为四步score打分在少量校准数据数个 forward batch上跑一次前向为每个可剪枝结构FFN 中间通道 / CNN 通道 / MoE 专家计算重要性分数prune剪除移除分数最低的部分recover恢复可选对幸存权重做轻量补偿如最小二乘重建、bias 折叠quantize量化可选与量化流水线衔接。以自动剪枝方法为例LowVarianceDensePruningMethoddense_low_variance.py的实现细节是先给每个目标模块注册 forward hook用RunningVariance在整轮校准数据上累计输出的激活方差剪枝结束后再通过record_prune_size/record_prune_width把新宽度记录到模型元数据中。校准数据为空时该方法会告警并跳过不改动模型。二、三个可剪枝域Dense FFN / CNN 通道 / MoE 专家工具只剪那些生产者 → 消费者接口可以被验证的维度对不确定的结构一律保守跳过从而保证张量形状始终自洽Dense FFN只收缩中间维度——gate/up_proj的out_features与down_proj的in_features同步收缩hidden / residual 宽度不动attention 的 q/k/v/o 投影被自动排除。CNN 通道沿生产者 conv out-channels →可选 BatchNorm→ 消费者 in-channels链路同步缩放喂给残差add的 conv、ConcatInception消费者以及 grouped / depthwise conv 不会被剪。MoE 专家整体移除被路由的专家并同步收缩 router共享常开专家保留hidden 输入输出不变。从源码看 Dense 域的目标发现Dense 域的目标发现逻辑domains/dense.py按优先级依次尝试三种模式规范命名gate_projup_projdown_proj三线性层要求gate.out_features up.out_features down.in_features融合 gate_upgate_up_proj单个 Linear前半是 gate、后半是 up要求out_features 2 * down.in_features典型如 Phi-3 / GLM-4 风格形状推断对无规范命名的模块从形状关系推断出两个同 hidden 宽度的 Linear → 一个 down Linear的模式从而兼容 Bloom 风格等相邻双线性层 / Conv1D。attention 投影通过名称特征自动排除dense.py 中维护了q_proj/k_proj/v_proj/o_proj/wq/wk/wv/wo/qkv等提示词列表_looks_like_attention_proj命中即跳过min_neurons默认 16以下的维度也不会作为候选。从源码看 MoE 域的目标发现MoE 域domains/moe.py会遍历named_modules查找三类专家容器传统nn.ModuleList如experts/expert_layers/moe_experts专家数取len(experts)融合 batched 专家三维批权重如MixtralExperts/Qwen3MoeExperts*TopKRouter通过参数shape[0]推断专家数兜底探测在 router 兄弟模块存在的前提下查找带三维权重的模块。router 的识别moe.py同样兼容nn.Linearout_features num_experts、裸权重持有者以及包裹内部 Linear 的 router wrapper。剪枝时若 router 是nn.Linear则直接裁剪out_features否则递归裁剪 router 子树中所有专家维等于原专家数的参数与 buffer避免 router 继续为已不存在的专家输出 logits 导致越界。top_k每 token 路由专家数的解析也很关键moe.py按 router → MoE block →model.config的顺序在所有拼写形式top_k/num_experts_per_tok/moe_top_k/num_selected_experts中读取读不到时回退到DEFAULT_TOP_K 8并告警。这一点对 mass / merge 类判据的专家激活计数准确性很重要——Mixtral 每 token 只路由 2 个专家硬编码 8 会显著扭曲打分结果。三、容差驱动的自动剪枝Tolerance-driven Auto Pruning当只给出可接受的精度损失上限tolerance时工具在ratio_grid上执行二分搜索对每个候选比例r尝试裁剪根据方法不同在模型上掩码试算或复制试算可选地先做微调然后测量质量下降若在容差内则向更大的r推进否则回退到更小的r最终应用满足容差的最大比例。搜索过程中任何一次剪枝 / 前向失败都被视为不可接受不抛异常因此在精度非单调的场景下搜索会倾向于少剪。最简单的用法import amct_pytorch as amct amct.prune(model, datacalib, tolerance0.02) # 搜索并应用容差内最大比例原地剪枝默认的保真度指标是无标签的在校准数据上剪枝前后模型 top-1 预测一致率。也可以通过evaluator传入自定义评估器callable(model)-float或暴露.evaluate(model) - float的对象。内存占用注意是否需要在搜索时为每个候选比例复制一份模型取决于方法本身README 与 accuracy_based_auto_prune.py 的搜索流程一致仅做选择保留哪些的方法low_variance/variance_channel/activation_count/mass_variance通过掩码试算把裁剪掩码进模型 → 测量 → 回滚全程只驻留一份模型会重写权重的方法reconstruct 的最小二乘、output_merge的专家合并没有掩码等价实现每个候选比例都需要在完整副本上试算峰值内存约为模型的两倍以上传入finetune_fn/quant_fn时同理这些回调会修改模型allocation.strategysensitivity的逐层敏感度探测也在完整模型副本上进行固定剪枝率模式从不复制模型。参数说明参数必填默认值说明model是-待剪枝原地的torch.nn.Moduledata视方法而定None校准数据方差类方法必需默认评估集tolerance否None可接受精度损失上限与evaluator同尺度传入即进入容差搜索evaluator否top-1 保真度callable(model)-float或暴露.evaluate(model) - float的对象eval_data否回退到data默认保真度指标的评估批次ratio_grid否0.1..0.8候选剪枝率升序report否None传入PruneReport()作为 sink 以取回统计信息attention 投影默认跳过由skip_layers配置驱动见下文高级配置。evaluator/eval_data/ratio_grid/finetune_fn/quant_fn仅在搜索模式下生效在固定剪枝率模式下传入它们会抛出ValueError而不是被静默忽略——这一点在 api.py 的_reject_search_args中有明确实现。微调回调参与搜索传入finetune_fn时每个候选比例在评估前都会先做微调因此最终选出的比例是剪枝 恢复之后可用的比例from amct_pytorch.pruning import prune_finetune amct.prune(model, cfg, datacalib, tolerance0.05, evaluatortest_acc, finetune_fnlambda m: prune_finetune(m, train_data, steps300))prune_finetune由 finetune.py 提供是剪枝后轻量恢复的默认实现。四、固定剪枝率模式与 PruneReport固定剪枝率from amct_pytorch.pruning import PruneReport cfg {methods: {dense: {name: low_variance, kwargs: {prune_ratio: 0.5}}}} rep PruneReport() amct.prune(model, cfg, datacalib, reportrep) print(rep.as_dict())methods中列出的域是唯一被剪的域。任何未被列出的域都会被钉在prune_ratio: 0.0而不是按默认比例裁剪——这一规则对固定剪枝率、容差搜索、size budget、菜单选择和诊断diagnose一视同仁。只有configNone完全不指定任何域时才回退到三个域的默认比例cnn 0.30 / dense 0.50 / moe 0.50。该默认逻辑在 config.py 的resolved_methods()中有明确实现。kwargs只接受方法实际读取的键。拼写错误如把prune_ratio写成prune_rate会抛出ValueError并列出该方法可接受的键而不是被忽略后让默认剪枝率继续生效——这防止了本意只剪 30% 结果剪了 50%这类静默事故。config.py 中的_validate_method_kwargs通过accepted_kwargs白名单机制实现校验每个内建方法都在其类定义中声明了accepted_kwargs例如LowVarianceDensePruningMethod只接受{prune_ratio}。PruneReport 结构prune(..., reportrep)会原地填充rep无进程级全局状态通过rep.as_dict()读取report.py字段含义backend检测到的模型后端huggingface/modelscope/pretrained-module/torchparams_before/params_after剪枝前后参数量prunable_fraction位于可剪枝结构中的参数占比仅size_budget模式填充per_layer_sparsity{module_path: sparsity}——每个被剪层的移除比例warnings非致命提示跳过的融合专家、非均匀宽度等budget_unreachablesize_budget目标无法达成时为Trueallocation_choice采用的跨层分配方式uniform / sensitivityevents逐 (domain, method, module) 的剪枝日志后端检测在 compat.py 实现按模块名是否含transformers/modelscope以及是否具备save_pretrainedconfig来判定。五、CNN 通道剪枝CNN 域提供两种方法预设见 presets.pyvariance_channel按激活方差切片通道同父级兄弟 conv 启发式reconstruct先移除低显著性通道再用im2col 最小二乘重建消费者 conv 权重以保持输出无需微调。from amct_pytorch.pruning import CNN_RECONSTRUCT_PRUNE_CFG amct.prune(model, CNN_RECONSTRUCT_PRUNE_CFG, datacalib) # 自定义{methods: {cnn: {name: reconstruct, # kwargs: {prune_ratio: 0.3, ridge: 1e-2}}}}ridge是最小二乘的岭正则项默认1e-2用于缓解校准数据不足时的欠定问题。使用要点输出头最后一个 Linear与skip_layers匹配的层会被自动忽略校准数据必须提供足够的行数 keep x k x k才能求解最小二乘当方程欠定或消费者不是 Conv2d 时会发出告警并回退为朴素切片在残差ResNet块中内部 conv→conv 耦合被剪喂给残差add的 conv 自动排除。ConcatInception消费者与 grouped/depthwise conv 不剪。六、MoE 专家剪枝方差判据菜单高级用法不在__all__中需通过from amct_pytorch.pruning import ...显式导入注意MOE_VARIANCE_MENU_CFG与DENSE_RECOVERY_MENU_CFG、CNN_RECOVERY_MENU_CFG实际已从init.py 导出。传入MOE_VARIANCE_MENU_CFG可以执行一次校准、按菜单中每个判据各剪一份副本、在小验证集上挑选最优、应用胜者的流程。prune只要看到 config 携带menu就切换到菜单选择模式因此不需要tolerancefrom amct_pytorch.pruning import MOE_VARIANCE_MENU_CFG amct.prune( model, MOE_VARIANCE_MENU_CFG, datacalib, eval_dataval, evaluatorev) # 保持 val ! calib所有菜单型配置共享同一个模式一次校准从多个候选中挑最优。具体机制是共享一次校准前向 → 每个菜单候选在模型副本上各剪一次 → 在独立的小验证集eval_data上分别测量 → 只有严格胜过安全兜底的候选才会被采纳平局或失利一律保留兜底。这样仅在校准集上表现好、在验证集上不稳定的候选不会被误选。MoE 方差菜单中的候选是不同重要性打分判据mass/cond_var/peak/cvxpeak其中mass是安全兜底。各判据与实现对应关系见 presets.pymassactivation_count兜底cond_var/peak/cvxpeakmass_variance方法variance_score分别取cond默认/peak/cvxpeak深度切分boundaryboundary层以内用 mass、以上用方差。默认10-1表示全方差auto表示逐层list[int]表示指定层。MOE_VARIANCE_MENU_CFG默认boundary-1传入自定义boundaryK的菜单可搜索深度切分。注意方差判据只有在验证集上严格胜过mass时才会替换掉mass否则回退到mass。测试用例 test_pruning_auto_prune.py 中的test_never_worse_than_fallback_prunes_and_forwards、test_non_fallback_criterion_can_strictly_win、test_default_is_cond_backward_compatible等用例覆盖了这一严格获胜才替换的行为。七、剪枝后恢复菜单Dense FFN / CNN 通道传入DENSE_RECOVERY_MENU_CFG可以搜索剪枝后的恢复方案。恢复菜单复用与上一节完全相同的 best-of-menu 机制只是候选从重要性判据换成了剪后补偿策略——仍然是一次校准、在留出验证集上 best-of-menu、只在严格获胜时替换兜底from amct_pytorch.pruning import DENSE_RECOVERY_MENU_CFG amct.prune( model, DENSE_RECOVERY_MENU_CFG, datacalib, eval_dataval, evaluatorev)CNN 通道剪枝通过CNN_RECOVERY_MENU_CFG使用同一菜单菜单模式只剪菜单所锚定的域from amct_pytorch.pruning import CNN_RECOVERY_MENU_CFG amct.prune( model, CNN_RECOVERY_MENU_CFG, datacalib, eval_dataval, evaluatorev)菜单候选presets.pynone朴素切片兜底bias把均值折叠进消费者 biasls最小二乘重建默认recovery参数的默认值就是ls。这与reconstruct方法的recoverykwargls默认/bias/none对应。使用建议README 明确给出的经验规则也被test_dense_recovery_quality_ladder_ls_best、test_dense_ls_underdetermined_warns_and_falls_back等测试印证校准数据充足时倾向ls校准行数 intermediate 宽度时ls欠定bias更稳健bias折叠可能在校准均值与测试集偏移时过拟合想在测试侧保留底线可把bias从cfg[methods][dense][menu]中移除CNN 的 im2col 行数通常充足ls在 CNN 域很少欠定适用范围无微调场景若剪后有微调朴素切片可能追平。八、高级配置跨层敏感度分配与 MoE 输出空间合并import amct_pytorch as amct from amct_pytorch.pruning import ( SENSITIVITY_ALLOC_PRUNE_CFG, MOE_OUTPUT_MERGE_PRUNE_CFG, ) # 跨层敏感度分配默认 uniform amct.prune(model, SENSITIVITY_ALLOC_PRUNE_CFG, datacalib) # config[allocation] {strategy: sensitivity, ref_ratio: 0.5, # min_ratio: 0.05, max_ratio: 0.9, guard: calib_nll} # 注意敏感度分配会让各层宽度不同而 config 中对应的计数字段是单一标量无法描述 # 因此这些计数字段不会回写save 后的模型无法直接 from_pretrained 还原 # 需要自己保存每层尺寸并在加载时重建结构。需要标准 save/load 时请对所有层用同一剪枝率。 # MoE 输出空间专家合并LS 残差配对 drop 兜底 amct.prune(model, MOE_OUTPUT_MERGE_PRUNE_CFG, datacalib) # moe kwargs: keep_ratio0.5, selectorcalib_nll|noneSENSITIVITY_ALLOC_PRUNE_CFG的完整定义见 presets.py其allocation校验规则strategy只能取uniform/sensitivityguard只能取calib_nll/none各 ratio 必须落在[0.0, 1.0)且min_ratio max_ratio在 config.py 中实现。MOE_OUTPUT_MERGE_PRUNE_CFG对应output_merge方法presets.py通过最小二乘残差配对把专家合并到输出空间selector决定用calib_nll还是none来选择保留专家。skip_layers 与量化感知显著性cfg {methods: {dense: {name: reconstruct, kwargs: {prune_ratio: 0.5}}}} cfg[skip_layers] [self_attn, lm_head, shared_expert] # 量化感知显著性 cfg[methods][dense][kwargs][quant_cfg] { weights_cfg: {strategy: channel, symmetric: True, dtype: int8}} # size budget保留 70% 参数量 amct.prune(model, cfg, datacalib, size_budget0.7)skip_layers名字包含其中任一子串的层完全不碰。搜索模式tolerance / size_budget / menu会自动并入self_attn/attention/attn固定剪枝率模式不会需要自行列出。在 pruner.py 中_is_skipped会对目标的 producer/consumer/gate/router 等路径做子串匹配过滤。quant_cfg只被reconstruct方法读取low_variance忽略它。size_budget按目标保留比例搜索剪枝方案prunable_fraction与budget_unreachable会反映在 PruneReport 中。内存受限环境下的手动循环用reconstruct/output_merge搜索、或传入finetune_fn/quant_fn时工具会整模型复制。如果设备放不下两份可以把干净权重留在主机内存自行循环固定剪枝率——固定剪枝率从不复制设备上始终只有一份工作模型import copy import torch import amct_pytorch as amct pristine model.cpu() # 基线留在主机内存 best None for prune_ratio in (0.3, 0.4, 0.5): trial copy.deepcopy(pristine).to(npu:0) # 设备上唯一的模型 cfg {methods: {dense: {name: low_variance, kwargs: {prune_ratio: prune_ratio}}}} amct.prune(trial, cfg, datacalib) # 固定剪枝率无复制 if my_evaluator(trial) threshold: # 保留通过阈值的最大比例 best prune_ratio del trial torch.npu.empty_cache()阶段容错策略PruneConfig还提供两个与容错相关的顶层字段config.py字段默认值可选值含义min_channels41通道剪枝的最小保留通道数min_neurons161Dense 剪枝的最小保留神经元数min_experts11专家剪枝的最小保留专家数missing_data_policywarn_skipwarn_skip/raise方法需要数据但未提供时的行为stage_error_policyraiseraise/warn_skip单个域剪枝失败时的行为warn_skip会回滚该阶段的部分改动并继续后续阶段pruner.py九、与量化组合使用先剪枝、再量化、最后转换——因为剪枝改变了张量形状量化校正在剪枝后的权重上才正确import amct_pytorch as amct amct.prune(model, datacalib, tolerance0.02) # 1) 结构化剪枝 amct.quantize(model, quant_cfg) # 2) 在剪枝后的模型上量化 amct.convert(model) # 3) 转换部署模型恢复与量化回调finetune_fn / quant_fn两者都是可选回调在容差搜索期间每次评估前作用于每个被剪副本因此选出的比例反映的是剪枝 恢复 / 量化之后的质量finetune_fn(model)对剪后副本做轻量恢复如若干优化器步quant_fn(model)对剪后副本做量化使搜索计入剪枝 量化的联合损失它永远不会让搜索剪得更多。from amct_pytorch.pruning import prune_finetune # 仅恢复每个候选在测量前先微调 amct.prune(model, cfg, datacalib, tolerance0.05, evaluatorev, finetune_fnlambda m: prune_finetune(m, train_data, steps300)) # 在一个容差下联合剪枝 量化搜索看到的是量化后的质量 amct.prune(model, cfg, datacalib, tolerance0.03, evaluatorev, quant_fnlambda m: amct.quantize(m, quant_cfg))自定义评估器与量化校准复用剪枝的evaluator只要求一个协议暴露evaluate(model)并返回精度指标越高越好的对象不涉及任何基类因此同一个评估器也可以交给量化的accuracy_based_auto_calibration使用class MyEvaluator: def evaluate(self, model): return my_top1_accuracy(model) ev MyEvaluator() amct.prune(model, datacalib, tolerance0.02, evaluatorev) amct.accuracy_based_auto_calibration(model, ev, quant_cfg, ...)一个需要留意的差异内置的amct.ModelEvaluator是量化校准的数据供给器其evaluate(model, iterations)返回 None不能用于精度搜索精度搜索必须使用返回指标值的评估器。剪枝侧两种签名evaluate(model)与evaluate(model, iterations)都能接受。十、支持的剪枝结构总览只有生产者 ↔ 消费者接口能被验证的维度才会被剪其余一律跳过Dense FFN只剪中间维度gate/up.out_featuresdown.in_featureshidden / residual 宽度保持attention 投影q/k/v/o自动排除。CNN 通道生产者Conv2dgroups1→ 可选BatchNorm2d→ 通道匹配的消费者Conv2d/Linear协同缩放。喂残差add的 conv 自动排除Concat 消费者与 grouped/depthwise conv 不剪。MoE 专家整体移除被路由专家hidden 输入输出不变共享常开专家排除。域支持说明dense是三线性gate/up/down_proj、融合gate_up_projPhi-3/GLM-4、相邻双 Linear/Conv1D含 Bloom 风格。Llama/Qwen2/Mistral/Qwen3 无需手工skip_layers即可剪。cnn是variance_channel启发式切片reconstructim2col 最小二乘。ResNet 风格独立块不被同级检测识别。moe是传统nn.ModuleListnn.Lineargate、融合 batched 专家MixtralExperts/Qwen3MoeExperts*TopKRouter、分组 routern_group/topk_group、共享专家 sigmoid 路由noaux_tc、兄弟双张量融合专家GraniteMoE、嵌套 router-biasErnie4.5。结构可剪性在常见架构家族的 2 层微型模型上有自动化覆盖Llama/Qwen/Mixtral/GLM/Phi/GPT/GraniteMoE/Ernie4.5 等可参考 test_pruning_real_hf_models.py 与 test_pruning_auto_prune.py。此外prune_diagnoseprune_diagnose可用于在正式剪枝前诊断模型结构是否可被识别。十一、剪枝后的 config 同步剪枝后的尺寸会回写到model.config使save_pretrained保存的 config 与剪枝后的权重一致实现位于 compat.py 与patch_common_configDense FFN 中间维度 →intermediate_size/ffn_hidden_size/n_inner专家数 →num_local_experts/num_experts/n_routed_experts/n_experts每 token 专家数 →num_experts_per_tok/moe_top_k/top_k/num_selected_experts会下调到不超过幸存专家数否则 router 会选中已不存在的专家第一次 forward 即失败。对于多模态包装模型compat.py 采用白名单方式处理子 configtext_config/llm_config/language_config只改写语言模型所在子 config 的维度——避免误写视觉塔自己的intermediate_size。当各层专家数不一致时单一标量无法描述非均匀剪枝此时计数字段保持不写只记录一条警告——写入任意一层的值都会与其他层矛盾。但top_k仍会下调到最薄一层的专家数以保证每一层都能运行。这类模型在save_pretrained后无法通过普通from_pretrained还原需要自行保存每层尺寸并在加载时重建结构。要避免这种情况请对所有层使用相同的prune_ratio而不是使用会产生非均匀结果的敏感度分配SENSITIVITY_ALLOC_PRUNE_CFG。非均匀 Dense FFN 宽度同理。模拟模式simulate.py下试算不会改写model.config因为_clamp_int_attrs只会下调num_experts_per_tok激进的候选比例会留下错误值且后续无法抬高pruner.py 中的注释说明了这一设计取舍。延伸阅读结构化剪枝 API 与配置详解、PruneConfig 数据类、预设配置PruneReport 统计结构、AutoPruner 剪枝流水线Dense 域目标发现、MoE 域目标发现、config 维度回写低方差剪枝方法实现测试验证test_pruning_auto_prune.py、test_pruning_real_hf_models.py剪枝示例examples/algorithms/pruning/README.md含 CNN / Dense / MoE 剪枝运行样例相关文档自动通道剪枝搜索配置、剪枝诊断、剪枝微调、恢复剪枝重训模型【免费下载链接】amctAMCT是CANN提供的昇腾AI处理器亲和的模型压缩工具仓。项目地址: https://gitcode.com/cann/amct创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表