【Bug已解决】Only one `target_parameters` adapter per model 解决方案 【Bug已解决】Only onetarget_parametersadapter per model 解决方案一、现象长什么样在使用 PEFT 的某些 tuner如PromptTuning、PrefixTuning、P-Tuning时你可以通过target_parameters指定 adapter 作用在模型的哪一组参数上而不是默认全部。但当你尝试给同一个模型挂第二个也用target_parameters的 adapter 时报ValueError: Only one target_parameters adapter is allowed per model.或者激活多个 adapter 时只有第一个带target_parameters的生效第二个被静默忽略。根因是 PEFT 内部约定一个模型同时只能有一个 adapter 使用target_parameters机制。本文讲清为什么以及如何在不违背约束下实现“多组参数分别微调”。二、背景target_parameters是 PEFT 里一个特殊机制用于只把 adapter 的参数挂到模型里你指定的那几个 nn.Parameter 上常见于 Prompt/Prefix 类需要把虚拟 token 的 embedding 精确插入到特定层。它的实现方式是在inject阶段adapter 记录“我要替换/附加到哪些具名参数”并在 forward 时局部改写这些参数。问题在于PEFT 为了在前向时正确还原“被 target 的参数”在模型上维护了一份targeted_module之类的全局映射。如果允许两个 adapter 都用target_parameters指向重叠或不同的模块这份映射会冲突到底哪个 adapter 的虚拟参数在该位置生效。所以 PEFT 直接限制每个模型至多一个target_parametersadapter。注意这和“多 adapter 共存”是两回事普通 LoRA 可以挂很多个用add_adapterset_adapter切换但带target_parameters的只能有一个。三、根因根因 APEFT 全局targeted_module映射不允许多写最直接。模型上保存“哪几个参数被 target adapter 接管”的映射是单份的。第二个target_parametersadapter 写入时会和第一个冲突触发ValueError。根因 B把target_parameters当成“多组独立微调”的工具误以为可以像 LoRA 那样挂 N 个分别 target 不同模块。实际上target_parameters是给 Prompt/Prefix 这类“局部插入虚拟参数”设计的不是给“分组独立训练”设计的。根因 C试图用不同 adapter_name 绕过有人想add_adapter(a, cfg_a)、add_adapter(b, cfg_b)两个都用target_parameters以为名字不同就行。但限制是按“机制”不是按“名字”仍报同一个错。根因小结一个模型只能有一个target_parametersadapter是 PEFT 的硬约束target_parameters用于 Prompt/Prefix 的局部虚拟参数插入不是分组训练工具想“多组参数分别微调”应用 LoRA 的多 adapter 或分别训练后合并。四、最小可运行复现下面脚本演示“挂第二个 target_parameters adapter 触发 ValueError”以及如何用普通 LoRA 多 adapter 绕过import torch import torch.nn as nn from peft import (PrefixTuningConfig, LoRAConfig, get_peft_model, PromptTuningConfig) class Tiny(nn.Module): def __init__(self): super().__init__() self.lin nn.Linear(16, 8) def forward(self, x): return self.lin(x) def demo(): base Tiny() # 第一个 target_parameters adapterPrefix—— 合法 cfg1 PrefixTuningConfig(num_virtual_tokens4, token_dim16) m get_peft_model(base, cfg1) print(第一个 target_parameters adapter 挂载成功) # 尝试挂第二个 target_parameters adapter —— 触发限制 try: cfg2 PromptTuningConfig(prompt_tuning_initRANDOM, num_virtual_tokens4, tokenizer_name_or_pathgpt2) m.add_adapter(p2, cfg2) print(第二个也成功你的版本未限制) except ValueError as e: print(触发限制:, e) # 正确绕过用普通 LoRA 多 adapter不带 target_parameters base2 Tiny() lm get_peft_model(base2, LoRAConfig(r4, target_modules[lin])) lm.add_adapter(lora_b, LoRAConfig(r4, target_modules[lin])) lm.set_adapter(default) print(LoRA 多 adapter 共存成功可 set_adapter 切换) if __name__ __main__: demo()运行结果印证第二个target_parametersadapter 报Only one ... allowed而 LoRA 多 adapter 正常共存。五、解决方案第一层最小直接修复一个模型只挂一个target_parametersadapter。如果你需要对“不同参数组”分别微调分两种场景处理场景1你真正想要 Prompt/Prefix 效果只需要一个。直接保留那一个即可不要尝试加第二个。场景2你想要“多组参数各自独立训练”。用LoRA 的多 adapter 机制替代target_parametersfrom peft import get_peft_model, LoRAConfig model get_peft_model(base, LoRAConfig(r4, target_modules[lin], adapter_nameg1)) model.add_adapter(g2, LoRAConfig(r4, target_modules[lin])) # 训练时切换 model.set_adapter(g1) # 只激活 g1 的 LoRA model.set_adapter(g2) # 切到 g2 # 推理合并两者若需要 model.set_adapter([g1, g2]) # 部分版本支持多激活LoRA 的多 adapter 不依赖target_parameters不受“一个模型一个”的限制。六、解决方案第二层结构性改进6.1 需要“不同模块不同 adapter”时用 LoRA 的 target_modules 区分# 组A 只训 attention组B 只训 mlp —— 两个 LoRA adapter 用不同 target model get_peft_model(base, LoRAConfig(r4, target_modules[q_proj, v_proj], adapter_nameattn)) model.add_adapter(mlp, LoRAConfig(r4, target_modules[up_proj, down_proj]))两个都是普通 LoRA互不冲突分别 target 不同模块效果等价于“分组微调”。6.2 序列任务用 Prompt 单一 adapter 切换如果一定要 Prompt/Prefix把不同任务做成同一 adapter 的不同虚拟 token 前缀靠输入区分而不是多个 target_parameters adapter# 不同任务用不同 prefix 文本但同一个 PromptTuning adapter model.set_adapter(prompt_taskA) # 若必须多也需非 target_parameters 方案6.3 序列化训练避免冲突for name, cfg in adapters.items(): if uses_target_parameters(cfg): assert not any(uses_target_parameters(c) for c in active), 已有 target_parameters adapter在加 adapter 前做断言提前暴露冲突。七、解决方案第三层断言 / CI 守护加测试守护“至多一个 target_parameters adapter”import pytest from peft import get_peft_model, PrefixTuningConfig def count_target_adapters(model) - int: n 0 for name, cfg in model.peft_config.items(): if getattr(cfg, target_parameters, None) or cfg.peft_type in (PROMPT_TUNING, PREFIX_TUNING): n 1 return n def test_at_most_one_target_adapter(base): m get_peft_model(base, PrefixTuningConfig(num_virtual_tokens4, token_dim16)) assert count_target_adapters(m) 1 # 再想加会失败 with pytest.raises(ValueError): m.add_adapter(p2, PrefixTuningConfig(num_virtual_tokens4, token_dim16)) def test_lora_multi_adapter_ok(base): m get_peft_model(base, LoRAConfig(r4, target_modules[lin])) m.add_adapter(b, LoRAConfig(r4, target_modules[lin])) assert count_target_adapters(m) 0 # LoRA 不占 target_parameters 名额CI 跑这两条任何“误加第二个 target_parameters adapter”都会被拦下。八、排查清单遇到Only one target_parameters adapter per model时查是不是挂了第二个 Prompt/Prefix 类 adapter它们用 target_parameters至多一个。是否误把 target_parameters 当分组训练工具它不是用 LoRA 多 adapter 替代。是不是用不同 adapter_name 想绕过限制按机制不按名字仍报错。普通 LoRA 多 adapter 能用吗能且不占 target_parameters 名额。不同模块分组微调怎么办两个 LoRA 用不同target_modules。加 adapter 前有没有断言count_target_adapters1时禁止再加。真的需要多个 Prompt 效果用同一 adapter 不同前缀输入区分。九、小结“Only onetarget_parametersadapter per model” 是 PEFT 的硬约束一个模型同时只能有一个使用target_parameters机制的 adapter主要是 Prompt/Prefix/P-Tuning 类因为模型上维护的“被 target 的参数”全局映射是单份的多写会冲突。真正想要 Prompt/Prefix 效果保留那一个即可不要加第二个想要“多组参数分别微调”用LoRA 的多 adapteradd_adapterset_adapter它不依赖target_parameters不受此限不同模块分组可用两个 LoRA 各自target_modules区分加 adapter 前用count_target_adapters1断言守护提前暴露冲突。一句话target_parameters 一个模型只能有一个要分组微调请用 LoRA 多 adapter别往 Prompt/Prefix 上叠加。