ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

PEFT ShadowPEFT 完全实战指南:并行 Shadow 网络的参数高效微调、配置与独立部署

PEFT ShadowPEFT 完全实战指南:并行 Shadow 网络的参数高效微调、配置与独立部署 人工智能大模型微调LoRA【免费下载链接】peft PEFT: State-of-the-art Parameter-Efficient Fine-Tuning.项目地址https://gitcode.com/gh_mirrors/pe/peft点击查看免费下载ShadowPEFTShadow Network for Parameter-Efficient Fine-Tuning为冻结的大模型骨干网络并行接入一个轻量、可训练的shadow影子网络在每个解码器层影子网络向基座隐藏状态注入学到的修正并通过门控更新推进自身的影子状态全程仅训练影子部分基座保持冻结。本篇指南以 examples/shadow_finetuning/README.md 为骨架结合 PEFT 仓库中 ShadowConfig、ShadowModel 与 ShadowLayer / ShadowCache / DetachedShadowModel 的源码实现完整讲解 mirror 与预训练两种影子骨干的搭建方式、全部配置参数、双 KV 缓存生成、训练保存流程以及用unload_shadow()把影子网络独立出来部署的完整方案。读完本文你将能够基于 shadow_finetuning.py 跑通一次 ShadowPEFT 微调并理解其底层工作原理。一、ShadowPEFT 是什么并行影子网络与逐层轨迹注入ShadowPEFT 的核心思想是不修改冻结基座的任何权重而是训练一个与骨干并行的小型shadow网络。论文见文末 Citation 的 arXiv 编号 2604.19254与源码中的注释将其机制概括为src/peft/tuners/shadow/config.py一个小型影子骨干shadow backbone先从输入产生初始影子状态s^(0)该状态随基座解码循环逐层骑乘rides前向过程在每一个被包裹的目标块target block处计算基座隐藏状态与影子状态之间的差异discrepancy经低秩瓶颈后注入回块输入论文 Eq. 2–4影子状态再由块输出通过门控残差更新gated residual update推进到s^(l)论文 Eq. 5–7。整个过程只训练影子骨干和轻量的注入/更新适配器injection/update adapters基座权重全程冻结。官方文档用如下示意描述这一并行数据流docs/source/package_reference/shadow.mdInput ├──► Shadow backbone (small, trainable) ──► s^(0) └──► Base model (frozen, large) block_0 ◄── inject(h, s) ─► h_0 ──► update ─► s_1 block_1 ◄── inject(h, s) ─► h_1 ──► update ─► s_2 ... (the (hidden, shadow) pair rides the loop together)Shadow 模块在架构上与骨干完全解耦architecturally decoupled因此可以做到即插即用挂载/摘除无需修改基座权重集中训练影子网络作为一个整体被独立训练预训练初始化可以从一个更小的预训练模型初始化影子骨干。一个关键推论是因为这种适配是依赖输入的、位于层空间的轨迹input-dependent trajectory in layer space而非静态的权重增量ShadowPEFT无法像 LoRA 那样合并merge回基座权重。在源码中merge()、merge_and_unload()等操作都会显式抛出NotImplementedErrorsrc/peft/tuners/shadow/model.py、src/peft/tuners/shadow/layers.py。对应的替代 API 是unload_shadow()将在后文详细展开。二、快速开始两种影子骨干构建方式示例脚本 shadow_finetuning.py 是官方给出的开箱即用 Demo。它通过ShadowConfig(shadow_model...)控制影子骨干的来源支持两种模式模式shadow_model取值影子骨干来源Mirror默认mirror根据基座 config 自动构建更少的层、可选的更小 MLP/注意力Pretrained模型 id 或本地路径从一个独立的可选更小的预训练模型加载两种模式的公共依赖与设备逻辑完全一致脚本先加载 tokenizer 与基座模型构造ShadowConfig再调用get_peft_model(base_model, config)完成封装shadow_finetuning.pytokenizer AutoTokenizer.from_pretrained(args.base_model_name_or_path) if tokenizer.pad_token is None: tokenizer.pad_token tokenizer.eos_token base_model AutoModelForCausalLM.from_pretrained(args.base_model_name_or_path) config ShadowConfig( shadow_modelargs.shadow_model, rargs.r, update_hidden_sizeargs.update_hidden_size, shadow_alphaargs.shadow_alpha, shadow_dropoutargs.shadow_dropout, auxiliary_loss_weightargs.auxiliary_loss_weight, task_typeCAUSAL_LM, ) model get_peft_model(base_model, config).to(device) model.print_trainable_parameters()2.1 Mirror 影子骨干默认模式不显式指定shadow_model时脚本默认值为mirrorPEFT 会从基座模型的 config 出发深度拷贝并缩小后自动构建一个镜像骨干。从源码_build_shadow_backbonesrc/peft/tuners/shadow/model.py可以看到具体的构建逻辑对语言模型取基座骨干的 config 深拷贝默认把层数缩到1shadow_num_hidden_layers or 1并可按需覆盖隐藏宽度、前馈宽度与注意力头数对 Diffusers 架构有注册后端的架构目前 Flux2使用减配的架构相似模型其他兼容的 diffusion transformer 则退化为一个逐 token 的残差 MLP骨干_TokenShadowBackbone见 model.py为兼容 Qwen3 这类在 config 中携带按层数定长字段layer_types、max_window_layers的架构_normalize_layer_config会对这些字段做截断/补齐model.py。命令行直接运行默认模式python shadow_finetuning.py --base_model_name_or_path Qwen/Qwen3-8BShadowPEFT 支持缓存生成cached generation为冻结的基座模型与影子骨干各自维护独立的 KV 缓存。use_cacheTrue与非缓存生成两种方式都受支持机制详见第四章。2.2 预训练影子骨干显式指定将shadow_model设为独立的可选更小的预训练模型 id 或本地路径即可用其初始化影子骨干python shadow_finetuning.py \ --base_model_name_or_path Qwen/Qwen3-8B \ --shadow_model shadow-llm/Qwen3-0.6B-H8B这里的关键机制是可训练投影trainable projection当预训练骨干的隐藏宽度与基座不一致时ShadowPEFT 会自动插入一个nn.Linear(shadow_hidden, base_hidden, biasFalse)来桥接两个隐藏空间。从源码_init_shadow_backbonemodel.py看投影的三种情况是加载的是 projected 影子检查点model_type causal_lm_with_hidden_projection如shadow-llm/Qwen3-0.6B-H8B则直接复用检查点内训练好的shadow_hidden - base_hidden投影_load_projected_shadow_backbonemodel.py并校验维度匹配普通预训练模型且隐藏宽度不同新建一个可训练投影隐藏宽度相同使用nn.Identity()无需投影。示例脚本会打印投影层的具体类型便于确认命中了哪种路径projection model.base_model.shadow_projection[default] print(fshadow_projection: {type(projection).__name__})从测试用例 tests/test_shadow.pytest_smaller_shadow_hidden_size_inserts_projection/test_matching_shadow_hidden_size_uses_identity也可以印证影子隐藏尺寸小于基座时插入投影相等时使用恒等映射。三、ShadowConfig 核心参数详解ShadowConfig继承自PeftConfig全部字段定义与默认值见 src/peft/tuners/shadow/config.py。以下按功能分组给出参数说明、默认值及源码依据3.1 注入与更新机制参数默认值说明源码依据r8注入瓶颈W_downd→r与W_upr→d的低秩秩值必须为正整数layers.pyshadow_alpha0.1注入修正的强度系数alpha对应论文 Eq. 4 中加在块输入上的缩放示例脚本默认传1.0shadow_dropout0.2施加在差异信号上、进入瓶颈之前的 dropout 概率对应 Eq. 3设为0时为恒等映射示例脚本默认传0.0init_weightsTrue是否将W_up零初始化使训练开始时注入为无操作no-op镜像 LoRA 的B0约定除非清楚后果否则不要修改update_hidden_sizeNone等于r更新网络Tcandidate与Ggate两个 MLP 的隐藏宽度layers.pyauxiliary_loss_weight0.05辅助影子损失的权重lambda论文 Eq. 8–9传入labels时叠加到任务损失设为0则禁用示例脚本默认传0.053.2 影子骨干构建参数默认值说明shadow_modelmirror影子骨干来源mirror自动构建其他字符串视为模型 id/本地路径。使用显式检查点时不得再设置下面 4 个 mirror 专属覆盖项__post_init__会抛出ValueError见 config.pyshadow_num_hidden_layersNone1层mirror 影子骨干的深度Flux2 下生成指定数量的双流块与两倍数量的单流块通用 Diffusers 回退下为残差 MLP 块数shadow_hidden_sizeNone 基座mirror 影子骨干的隐藏宽度可与基座不同自动插入投影Flux2 缩减必须保持其注意力头维度shadow_num_attention_headsNone 基座mirror 影子骨干的注意力头数架构感知后端使用通用 MLP 回退不使用shadow_intermediate_sizeNonemirror 影子骨干的前馈宽度通用 MLP 回退下默认为其隐藏宽度share_embeddingsTrue是否通过inputs_embeds复用冻结的基座输入嵌入来驱动影子骨干而非使用影子骨干自己的嵌入表3.3 目标块选择与其他参数默认值说明target_modulesNone需要包裹的 transformer块整个解码器块而非线性层可以是名字列表或正则如r.*\.layers\.\d$匹配所有解码器块None时默认包裹基座全部解码器块。被包裹的块必须连续因为影子状态需要从第一个包裹块骑乘到最后一个model.pyexclude_modulesNone不包裹的模块名列表或正则layers_to_transformNone指定要变换的块索引传单个整数则只变换该索引layers_patternNone与layers_to_transform配合指定持有解码器块的nn.ModuleList名字通常为layers或h两者必须同时出现或同时不出现modules_to_saveNone需要设为可训练并随检查点保存的额外模块如lm_head或分类头task_type—任务类型示例脚本使用CAUSAL_LM序列分类为SEQ_CLS需要注意layers_to_transform不能与字符串形式的target_modules或layers_pattern混用__post_init__中有一组显式校验config.py。四、双 KV 缓存ShadowPEFT 的缓存生成机制ShadowPEFT 支持增量解码incremental decoding其 KV 缓存是双份的一份给冻结基座一份给影子骨干。原因在于自回归生成时影子状态s^(0)需要随 token 逐个推进而注入/更新是逐 token 局部的token-local——新 token 只需要它自己的影子状态因果性保证前缀的基座键值在注入下计算保持有效。源码中的实现载体是ShadowCachesrc/peft/tuners/shadow/layers.py它是 TransformersCache的子类内部持有base与shadow两个缓存实例凡影响 batch/序列布局的操作reset、reorder_cache、crop、batch_repeat_interleave、batch_select_indices都会同时作用到两个缓存注意力元数据与update等操作委托给基座缓存未知属性也通过__getattr__委托给基座缓存以兼容不同架构的缓存实现它不可编译is_compileable为False因为两份缓存的层布局与隐藏宽度可能不同也不支持 legacy tuple 转换。缓存的生命周期由ShadowModel的四组边界钩子boundary hooks管理model.py模型顶层pre_hook重置每轮前向的簿记解包ShadowCache让基座只看到自己的 past并从原始输入计算初始影子状态s^(0)模型顶层forward_hook把基座 past 与影子 past 重新打包成ShadowCache作为past_key_values传给生成循环第一个包裹块的pre_hook把块输入包装成ShadowCarrier携带hidden与shadow两个张量并预置s^(0)最后一个包裹块的forward_hook把载体解包回普通隐藏状态张量交给基座的 final norm。use_cacheTrue与use_cacheFalse均受支持out model.generate(input_ids, max_new_tokens32) # 默认启用双 KV 缓存 # 或显式指定 out model.generate(input_ids, use_cacheTrue, max_new_tokens32) # use_cacheFalse 时每步重新处理完整序列便于调试同样可用测试 tests/test_shadow.pyTestShadowKVCache系列系统验证了这一机制预填充返回ShadowCache、逐步解码的 logits 与整序列重算完全对齐、关闭缓存时不返回ShadowCache、禁用适配器时退回纯基座缓存以及reorder/crop对双缓存的一致性。示例脚本末尾的推理同样使用缓存with torch.no_grad(): generated model.generate(**prompt, max_new_tokens20, use_cacheTrue, do_sampleFalse)五、训练、保存与重载示例脚本中的训练循环是一个可运行的骨架真实场景请替换为真实数据集或transformers.Trainer将labels中的 padding 位替换为-100用AdamW只优化requires_gradTrue的参数跑若干步后打印 lossshadow_finetuning.pytexts [ A small shadow backbone can adapt a much larger base model., A projection bridges the shadow and base hidden spaces when they differ., Only the shadow backbone and the injection/update adapters are trained., ] batch tokenizer(texts, return_tensorspt, paddingTrue).to(device) labels batch[input_ids].clone() labels[labels tokenizer.pad_token_id] -100 optimizer torch.optim.AdamW([p for p in model.parameters() if p.requires_grad], lrargs.lr) model.train() for step in range(args.num_steps): optimizer.zero_grad() out model(input_idsbatch[input_ids], attention_maskbatch[attention_mask], labelslabels) out.loss.backward() optimizer.step() print(fstep {step}: loss{out.loss.item():.4f})5.1 辅助影子损失训练时如果传入了labelsShadowModel.forward会额外计算影子路径自身的任务损失CE(shadow_head(s^(0)), labels)论文 Eq. 8–9并按auxiliary_loss_weight加权叠加进总损失model.py该损失在初始影子状态s^(0)上计算——这正是独立unload_shadow()模型所计算的内容从而保证影子网络脱离基座后也能独立求解任务若在最终状态s^(L)上训练独立模型将处于未训练状态源码注释与回归测试 test_auxiliary_loss_trains_the_detached_shadow_model 均明确此点未加权的分离副本会以output.shadow_loss和tuner.last_shadow_loss形式暴露给日志/监控不保留计算图last_shadow_loss是 DDP/FSDP 场景下可靠的读取位置对因果 LM影子头直接复用基座的输出头若希望该头可训练并随检查点保存请通过 PEFT 常规机制配置modules_to_save[lm_head]。5.2 保存与重载save_pretrained只保存适配器部分影子骨干 注入/更新 投影不存储基座。重载时影子骨干架构会依据shadow_model重建再恢复微调后的权重shadow_finetuning.pymodel.save_pretrained(args.output_dir) print(fSaved adapter to {args.output_dir}) reloaded_base AutoModelForCausalLM.from_pretrained(args.base_model_name_or_path) model PeftModel.from_pretrained(reloaded_base, args.output_dir).to(device) model.eval()从测试 test_save_includes_shadow_modules_but_not_frozen_head 可以看出检查点内容包含.shadow_backbone.*、shadow_down、shadow_update_transform等键因果 LM 场景下不含.shadow_head.*因为 LM 头复用基座重载后重新解析而modules_to_save[lm_head]时 LM 头以标准 PEFT 键保存。六、独立部署unload_shadow() 与 DetachedShadowModelShadowPEFT 的部署模型与 LoRA 的merge_and_unload思路相反LoRA 把适配烘焙回基座返回基座ShadowPEFT 则把轻量影子网络单独取出来——unload_shadow()是ShadowPEFT 版的 merge_and_unloadmodel.py。调用方式# 返回影子骨干 投影 头的独立模型行为类似普通 causal LM支持 generate() 与 KV 缓存 shadow model.base_model.unload_shadow(copyTrue) shadow.eval() with torch.no_grad(): shadow_generated shadow.generate(**prompt, max_new_tokens20, use_cacheTrue, do_sampleFalse) shadow.save_pretrained(f{args.output_dir}-standalone-shadow)几个关键点计算内容独立模型运行head(projection(backbone(x)))——逐块的更新依赖基座输出因此不独立存在这正是评估影子路径自身性能与基座无关的方式copy参数默认copyFalse共享模块与 PEFT 模型共享参数改动互相影响copyTrue深拷贝出私有模块。保存检查点必须用copyTrue——mirror 影子骨干默认共享冻结的基座输入嵌入其自身embed_tokens被移除共享引用不是返回模型的子模块copyFalse的检查点会缺少嵌入表copyTrue会为骨干重新挂接一份私有嵌入拷贝生成完整检查点model.py返回类型DetachedShadowModelsrc/peft/tuners/shadow/layers.py继承PreTrainedModel与GenerationMixin因果 LM 头时返回CausalLMOutputWithPast并支持generate()与 KV 缓存序列分类头时池化最后 token 返回SequenceClassifierOutput限制Diffusers 模型不支持unload_shadow()重建完整独立去噪器是架构相关的直接抛NotImplementedError可保存可推送独立模型可像普通 HF 模型一样save_pretrained或推送适用于高效率/边缘推理。测试覆盖了独立模型的生成能力、copy的模块独立性、copyTrue才能得到完整检查点、投影被正确应用等场景tests/test_shadow.py。七、多适配器行为与限制ShadowPEFT 与常规 PEFT 方法一样支持多适配器的添加、切换、删除与启停但有两个显著约束同一时刻只能激活一个适配器因为影子状态是贯穿网络的单条轨迹set_adapter传入多个名字会抛ValueErrormodel.py不可合并merge/merge_adapter/merge_and_unload全部显式报错恢复纯基座请用unload()获取独立影子网络请用unload_shadow()。切换适配器时tuner 级别的影子模块骨干/投影/头的requires_grad会随之同步到新激活的适配器_sync_shadow_module_trainabilitymodel.py删除适配器后边界钩子会重新绑定避免悬空回调model.py。相关测试见 tests/test_shadow.py。此外序列分类SEQ_CLS场景不支持多适配器model.py。使用门槛方面_get_decoder_layers要求基座能自动定位到nn.ModuleList形式的解码器层栈layers/h等找不到时可显式设置target_modules被包裹的块必须至少两个否则影子载体没有可骑乘的循环测试test_requires_two_layerstests/test_shadow.pylayers_to_transform与字符串target_modules互斥。ShadowLayer 通过__getattr__将未知属性委托给被包裹的基座块保证 Qwen3 等架构读取attention_type等块级属性时行为不变layers.py。八、与 LoRA 类方法的定位对比按官方文档的表述docs/source/package_reference/shadow.md与 LoRA 风格方法相比ShadowPEFT 会引入更多参数与计算量并行运行一个网络并包裹整个解码器块但换来的是适配器是一个自包含网络可以集中训练、跨任务复用并可用小的预训练模型初始化。它特别适合影子路径需要独立可用/可部署的场景若目标是极致的参数效率与可合并性LoRA 类方法仍是更轻的选择。需要说明的是这类对比属于官方文档给出的定性描述本文不延伸任何未经证实的性能结论。九、引用信息如果你在研究中使用了 ShadowPEFT可引用官方 README 中给出的条目examples/shadow_finetuning/README.mdarticle{li2026shadowpeft, title{ShadowPEFT: Shadow Network for Parameter-Efficient Fine-Tuning}, author{Li, Xianming and Li, Zongxi and Lee, Tsz-fung Andrew and Li, Jing and Xie, Haoran and Li, Qing}, journal{arXiv preprint arXiv:2604.19254}, year{2026} }十、进一步阅读示例脚本examples/shadow_finetuning/shadow_finetuning.py完整可运行 Demo含 mirror/预训练两种模式、训练、保存、重载与独立部署全流程配置类src/peft/tuners/shadow/config.pyShadowConfig全部参数与校验逻辑核心实现src/peft/tuners/shadow/model.pyShadowModel骨干构建、投影、边界钩子、双缓存打包、辅助损失、unload_shadow层与数据结构src/peft/tuners/shadow/layers.pyShadowLayer注入/更新公式、ShadowCarrier、ShadowCache、DetachedShadowModel官方 API 文档docs/source/package_reference/shadow.md测试用例tests/test_shadow.py覆盖双缓存一致性、辅助损失、投影插入、独立模型、Diffusers 回退等约 40 个场景赞分享人工智能大模型微调LoRA【免费下载链接】peft PEFT: State-of-the-art Parameter-Efficient Fine-Tuning.项目地址https://gitcode.com/gh_mirrors/pe/peft点击查看免费下载相关推荐深入解析 PEFT ShadowPEFT以可分离影子网络实现参数高效微调深入解析 PEFT ShadowPEFT以可分离影子网络实现参数高效微调 ShadowPEFT 是 PEFT 中一类特殊的参数高效微调方法它在 完全冻人工智能大模型微调LoRAclaude-skills 微调实战LoRA、QLoRA 与参数高效微调PEFT完整指南claude skills 微调实战LoRA、QLoRA 与参数高效微调PEFT完整指南 在 claude skills 仓库中 fine tuningAI 技能AI 插件后端前端DevOpsPaddleNLP PEFT实践参数高效微调全集PaddleNLP PEFT实践参数高效微调全集 引言大模型微调的新范式 你是否曾面临这样的困境想要微调一个大语言模型来适应特定任务却发现显存需求巨大、人工智能大模型深度学习NLP预训练微调模型推理服务模型量化分布式训练强化学习创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表