LoRA 适配器怎样与基础模型分离加载
来源:17golang原创
时间:2026-11-07 23:31:18 102浏览 收藏
我第一次把 LoRA 用到推理服务时,最容易混淆的是“加载适配器”和“加载一个新模型”。LoRA 目录通常只保存相对基础模型的增量参数,正确的做法是先加载兼容的基础模型,再把适配器挂到这个模型上。这样基础模型可以复用,适配器也能按任务切换;只有在准备做单体部署时,才考虑把两者合并。
官方地址:https://huggingface.co/docs/peft/en/package_reference/lora
下面的示例以 Transformers 和 PEFT 的文本模型为主,路径和模型名使用占位值,重点是加载顺序与生命周期,不把静态示意当成已经运行的输出。
先分清基础模型和 LoRA 权重
基础模型提供完整的网络结构和原始参数,LoRA 适配器只保存要插入目标层的低秩增量。适配器目录至少要能让加载器找到配置与权重,例如 adapter_config.json 和适配器权重文件。它不能脱离匹配的基础模型独立变成一个完整的语言模型。
这也是“分离加载”的核心:模型对象负责承载基础参数,适配器对象负责额外的可切换参数。两者分开存储并不代表推理时完全分成两个互不相干的网络,而是由 PEFT 在目标层建立组合关系。

用 PeftModel 把适配器挂到已有模型
如果基础模型已经由 Transformers 加载,PEFT 的显式写法最直观:先得到 base_model,再调用 PeftModel.from_pretrained。这一步不会把基础模型目录改写成适配器目录,适配器仍然可以单独替换。
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import PeftModel
# 先加载完整基础模型;它决定网络结构和词表兼容性
base_model_id = "your-org/your-base-model"
base_model = AutoModelForCausalLM.from_pretrained(
base_model_id,
device_map="auto",
)
tokenizer = AutoTokenizer.from_pretrained(base_model_id)
# 再加载 LoRA 增量权重;这里的目录不是完整基础模型
adapter_path = "./adapters/customer-service"
model = PeftModel.from_pretrained(
base_model,
adapter_path,
adapter_name="customer_service",
)
# 明确指定推理时启用的适配器,避免依赖隐含状态
model.set_adapter("customer_service")
model.eval()
这里的关键不是某个模型名,而是顺序:基础模型先存在,适配器再附着。device_map="auto" 只是大模型常见的设备分配选项;如果你的设备策略不同,应按部署环境调整。
也可以直接在 Transformers 模型上加载
较新的 Transformers 集成了适配器管理能力。若你不需要单独包装成 PeftModel,可以在已有的 Transformers 模型上直接调用 load_adapter。仓库或本地目录仍然需要包含适配器配置与权重。
from transformers import AutoModelForCausalLM
# 基础模型先加载,适配器随后附加到同一个模型对象
model = AutoModelForCausalLM.from_pretrained("your-org/your-base-model")
model.load_adapter(
"./adapters/customer-service",
adapter_name="customer_service",
)
# 只启用指定适配器;其它已加载适配器保持未激活
model.set_adapter("customer_service")
如果适配器的 adapter_config.json 中记录了基础模型信息,也可以使用支持自动检测的加载方式。但在服务端显式先加载基础模型更容易控制缓存、设备和多个适配器的生命周期。
多个 LoRA 适配器怎样切换
我在一个进程里同时放置“客服语气”和“代码解释”两个适配器时,最重要的经验是给它们稳定的名字。加载第二个适配器不会自动把第一个替换掉;真正改变当前推理行为的是 set_adapter。
# 两个适配器共用同一个基础模型,但保留各自的目录和名字
model.load_adapter("./adapters/customer-service", adapter_name="customer_service")
model.load_adapter("./adapters/code-explainer", adapter_name="code_explainer")
# 按请求或路由选择当前适配器;名称必须与加载时一致
model.set_adapter("code_explainer")
# 不需要适配器时关闭适配器,回到基础模型的行为
model.disable_adapters()
真实服务中不要把“当前适配器”藏在全局可变变量里再并发修改。可以按请求路由建立隔离的模型实例,或者在明确的串行临界区内切换;PEFT 的适配器名只解决权重选择,不自动解决你的并发状态管理。
卸载和删除不是同一件事
只想暂时去掉 LoRA 模块时,可以使用 unload();如果适配器以后不再需要,可以使用 delete_adapter 释放对应的适配器状态。unload() 返回新的模型对象,不能假设它会原地改变原变量。
# unload 返回卸载后的模型,必须接住返回值
base_like_model = model.unload()
# 如果只是不再需要某个命名适配器,可以删除它
# model.delete_adapter("customer_service")
# 后续如果还要使用另一个适配器,重新明确激活它
# model.set_adapter("code_explainer")
这里不要把 unload() 和“删除基础模型”混为一谈:基础模型仍然是模型主体,卸载的是附加的 LoRA 模块。对长期服务进程,还要结合显存引用、缓存和请求生命周期处理对象回收。

什么时候保持分离,什么时候合并
保持分离适合多个任务共享一个基础模型、按请求切换风格或任务、以及仍在试验不同适配器的场景。它的代价是加载和管理路径更复杂,服务需要明确当前适配器及其设备位置。
如果模型已经定型、服务只需要一套固定行为,可以考虑 merge_and_unload(),把 LoRA 权重合入基础模型并返回一个不再携带适配器模块的模型。合并后切换适配器的灵活性会消失,因此不要在实验阶段过早合并。
# 只在确定要做固定单体部署时合并
merged_model = model.merge_and_unload()
# 合并后的模型可以按普通 Transformers 模型保存
merged_model.save_pretrained("./export/merged-model")
tokenizer.save_pretrained("./export/merged-model")
PEFT 文档还提供了在不合并的情况下加载不同适配器、设置活动适配器的方式;Diffusers 等其他模型管线也有自己的 load_lora_weights 和 set_adapters 接口,不能把文本模型的 API 原样套到图像管线。
排查分离加载失败的三个方向
| 现象 | 优先检查 | 处理思路 |
|---|---|---|
| 找不到适配器配置 | 目录是否包含 adapter_config.json 和权重 | 确认传入的是适配器目录,而不是训练缓存的上级目录 |
| 加载后尺寸或层不匹配 | 基础模型、任务类型和 target modules | 换回训练该适配器时使用的兼容基础模型 |
| 切换后输出没有变化 | adapter_name、set_adapter 和 disable 状态 | 先确认活动适配器,再排查权重是否确实属于当前基础模型 |
从经验上看,最稳妥的排查顺序是先确认“目录结构”,再确认“基础模型身份”,最后确认“当前激活状态”。不要一遇到输出异常就把 LoRA 合并;合并会让定位和回退都更麻烦。
结论:把基础模型当底座,把适配器当可替换策略
LoRA 分离加载可以归纳成一句话:基础模型先加载,适配器后附加,推理前显式选择,生命周期结束时再卸载或删除。需要多任务切换时保持分离,需要固定单体部署时再合并。这样既能复用基础模型,又能把适配器的兼容性、激活状态和部署取舍说清楚。
相关问题
- LoRA 适配器能脱离基础模型单独推理吗?不能把它当完整模型使用,必须找到训练时兼容的基础模型。
- 加载两个适配器会自动叠加吗?不会。先用唯一名称加载,再按 API 明确设置当前适配器或组合策略。
- 什么时候使用 merge_and_unload?固定模型行为、减少运行时适配器管理时使用;需要频繁切换时保持分离更合适。
-
234 收藏
-
173 收藏
-
369 收藏
-
195 收藏
-
243 收藏
-
158 收藏
-
400 收藏
-
500 收藏
-
145 收藏
-
212 收藏
-
科技周边 · 人工智能 | 24分钟前 | 人工智能 · vLLM KV Cache gpu-memory-utilization max-num-batched-tokens max-num-seqs 批处理显存265 收藏
-
307 收藏
-
444 收藏
-
296 收藏
-
248 收藏
-
322 收藏
-
212 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习