PEFT 怎样分别启用和停用模型中的 LoRA 层
来源:17golang原创
时间:2026-10-29 16:53:08 483浏览 收藏
PEFT 里“启用和停用 LoRA”不是一个动作。你可能是在同一个模型上临时比较基座结果,也可能是在多个 LoRA 适配器之间切换,还可能只是想让 Transformers 直连接口暂时关闭全部适配器。对应的 API 分别是 disable_adapter()、set_adapter(),以及 disable_adapters()/enable_adapters()。
官方资料:https://huggingface.co/docs/peft/package_reference/peft_model
PeftModel适合用with model.disable_adapter():做一次临时基座推理,退出上下文后 LoRA 状态恢复。- 多个 LoRA 都已加载时,用
set_adapter("名称")选择活动适配器;切换不等于删除,未选中的权重仍在内存中。 - 如果模型使用 Transformers 的适配器混入接口,才使用
disable_adapters()和enable_adapters()这对全局方法。
先分清:你要切换的是适配器,还是整层开关
我在整理一套“同一基座、多个任务 LoRA”的推理入口时,最容易混淆的是三个概念:适配器已经加载但没有被选中、所有适配器暂时停用,以及把 LoRA 模块从模型中移除。它们的资源状态和恢复方式完全不同。
| 目标 | 推荐接口 | 结果 |
|---|---|---|
| 临时得到基座模型结果 | PeftModel.disable_adapter() | 上下文内不应用适配器,退出后恢复 |
| 在多个 LoRA 之间切换 | set_adapter(name) | 选择活动适配器,其他适配器保留 |
| 永久去掉注入层 | unload() 或删除指定适配器 | 需要重新赋值或重新加载才能恢复 |
| Transformers 直连模型全部停用 | disable_adapters() | 关闭所有已附加适配器,再用对应恢复方法启用 |
因此,target_modules 是创建 LoRA 时决定“往哪些模块注入”的配置,不是运行时逐层开关。若只是想比较有无 LoRA 的输出,不要为了这次比较卸载整个模型。

用 disable_adapter 做一次基座模型对照
如果对象是 PeftModel,最稳妥的做法是把停用范围限制在一个上下文里。官方 API 将 disable_adapter() 定义为上下文管理器,适合拿同一批输入分别得到“带 LoRA”和“仅基座”的结果,不会改变模型文件,也不要求重新加载权重。
from peft import PeftModel
def compare_base_and_lora(model: PeftModel, inputs):
# 正常路径使用当前活动的 LoRA 适配器。
lora_output = model(**inputs)
# 上下文内临时停用适配器,得到基座模型对照结果。
with model.disable_adapter():
base_output = model(**inputs)
# 离开 with 后,后续调用回到原来的适配器状态。
restored_output = model(**inputs)
return lora_output, base_output, restored_output
这个写法的重点是范围清晰:不要把停用状态散落到全局变量,也不要在上下文外假设 LoRA 仍然停用。若业务确实需要长期只运行基座模型,才考虑 unload();它会返回移除适配器模块后的模型,必须接住返回值。
多 LoRA 模型用 set_adapter 选择活动适配器
多个适配器共存时,加载只代表权重进入模型,并不等于它已经成为当前推理路径。可以给每个任务起稳定的名称,再用 set_adapter() 切换。对普通 PeftModel,官方参考接口按名称设置一个活动适配器;其他适配器不会被删除,只是不参与这次前向计算。
from peft import PeftModel
def select_task_adapter(model: PeftModel, adapter_name: str):
# adapter_name 必须是已经加载到模型中的名称。
model.set_adapter(adapter_name, inference_mode=True)
# 这里的前向调用只使用刚选中的适配器。
return model
# 例如:先加载名为“客服”和“摘要”的两个 LoRA,再按请求选择。
model.load_adapter("./adapter-summary", adapter_name="摘要")
model.set_adapter("摘要", inference_mode=True)
如果需求是“同一批输入同时组合多个适配器”,不要把普通 PeftModel.set_adapter() 当作通用列表接口。PEFT 文档对支持多适配器的方法给出了更低层的 model.base_model.set_adapter([...]) 入口,是否可组合要以具体 tuner 类型为准。只需要在“客服”和“摘要”之间二选一时,使用单个名称更容易维护。
按模型入口选择停用与恢复 API
PEFT 和 Transformers 都能管理 LoRA,但对象类型不同,方法名也不同。若模型通过 Transformers 的 PeftAdapterMixin 直接附加适配器,可以显式关闭和恢复全部适配器:
def run_base_only(model, inputs):
# 关闭当前模型上的全部适配器,保留它们在内存中的权重。
model.disable_adapters()
try:
return model(**inputs)
finally:
# 无论推理是否抛出异常,都恢复适配器,避免污染后续请求。
model.enable_adapters()
这组方法适合“整个模型暂时回到基座”的场景;而 set_adapter() 适合“只换当前活动任务”的场景。不要把 requires_grad=False 当成停用 LoRA:它主要影响梯度和训练,不等价于前向计算不使用适配器。

上线前用状态接口确认“选中了谁”
在服务化推理里,最值得记录的是当前活动适配器和启用状态,而不是仅凭配置文件猜测。PEFT 提供的状态接口可以帮助排查“权重已经加载,但输出仍像基座”这一类问题:
def adapter_snapshot(model: PeftModel):
# 读取模型级状态,便于在请求切换后记录当前配置。
model_status = model.get_model_status()
# 读取每个 LoRA 层的启用、活动和可用适配器信息。
layer_status = model.get_layer_status()
return model_status, layer_status
发布前可以按下面的清单排查:
- 临时基座对照是否被限制在
with或try/finally范围内? set_adapter使用的名称是否确实已经通过from_pretrained或load_adapter加载?- 你需要的是停用前向计算,还是只停用训练梯度?两者不要混用。
- 是否把
unload()当成可逆开关?它会返回一个移除适配器的模型,恢复需要重新加载。
常见问题
退出 disable_adapter 上下文后需要手动 enable 吗?
使用 PeftModel 的上下文写法时通常不需要。上下文结束后会恢复之前的适配器状态;如果你使用的是 Transformers 直连接口,才按对应 API 显式调用 enable_adapters()。
set_adapter 会释放未选中 LoRA 的显存吗?
不会。它主要切换活动适配器,其他已加载权重仍然保留。需要释放某个适配器时,使用 delete_adapter(),但这已经是资源管理动作,不是临时停用。
能不能只关闭某一个 LoRA 注入层?
高层 API 的常用边界是按适配器选择或全局停用,而不是在业务代码里遍历每个注入层改内部标志。若确实需要层级级别的实验,应先确认对应 tuner 的支持范围,再用 get_layer_status() 观察状态,避免把内部实现当成稳定公共接口。
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
185 收藏
-
420 收藏
-
415 收藏
-
224 收藏
-
150 收藏
-
269 收藏
-
372 收藏
-
298 收藏
-
472 收藏
-
350 收藏
-
科技周边 · 人工智能 | 1小时前 | 性能优化 · Hugging Face Datasets IterableDataset flatten_indices indices mapping Arrow222 收藏
-
326 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习