Transformers用LoRA做参数高效微调
来源:17golang原创
时间:2026-11-15 12:33:26 460浏览 收藏
全量微调需要为每个模型参数保存梯度和优化器状态,显存与检查点都会迅速变大。Transformers 配合 PEFT 使用 LoRA 时,可以冻结预训练底座,只在指定线性层旁训练低秩适配器;训练结束后保存的是一套轻量权重,而不是再复制一份完整模型。
官方文档:https://huggingface.co/docs/transformers/peft
r决定低秩更新的容量,target_modules决定把适配器挂在哪里。get_peft_model会把底座改造成带适配器的模型,Trainer 只更新可训练参数。- 适配器要和兼容的底座一起加载;是否合并权重取决于部署时是否还要切换适配器。
先把训练边界定清楚:底座冻结,LoRA只改适配器
LoRA 的核心不是缩小原模型,而是在目标模块上增加两个低秩矩阵,用它们表达训练产生的增量。原始权重保持冻结,优化器只跟踪适配器参数,因此训练状态更轻,也便于为同一个底座保存多个领域适配器。

| 参数 | 作用 | 判断思路 |
|---|---|---|
r | 低秩矩阵的秩 | 越大容量越高,也会增加可训练参数 |
lora_alpha | 适配器缩放因子 | 与 rank 一起观察更新幅度,不要脱离任务调参 |
lora_dropout | 适配器分支的 dropout | 小数据集可用来缓和过拟合 |
target_modules | 注入适配器的模块名 | 必须匹配具体模型的层命名,不能照抄别的架构 |
用LoraConfig把训练范围写成代码
先以因果语言模型为例。下面的配置使用常见的 query/value 投影名;实际模型应先查看模块命名,再决定目标模块。get_peft_model 会原地改造模型对象,重复调用前要确认没有再次注入同一适配器。
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import LoraConfig, TaskType, get_peft_model
model_id = "facebook/opt-350m" # 示例底座;生产环境固定可复现的模型版本
tokenizer = AutoTokenizer.from_pretrained(model_id) # 分词器必须与底座保持一致
model = AutoModelForCausalLM.from_pretrained(model_id) # 先加载完整但尚未训练的底座
lora_config = LoraConfig(
r=16, # 用较小秩控制适配器容量
lora_alpha=32, # 控制 LoRA 更新的缩放
lora_dropout=0.05, # 小数据集上给适配器分支保留正则化
target_modules=["q_proj", "v_proj"], # 只在模型真实存在的投影层注入
task_type=TaskType.CAUSAL_LM, # 告诉 PEFT 当前任务是因果语言建模
bias="none", # 不额外训练底座 bias,减少更新范围
)
model = get_peft_model(model, lora_config) # 注入低秩适配器并冻结底座
model.print_trainable_parameters() # 用参数比例检查配置是否生效
这里最容易出错的是 target_modules。不同架构可能使用不同的投影命名;如果名称不存在,配置并没有覆盖你以为的注意力层。打印可训练参数只是第一层检查,还要在小批量数据上观察 loss 是否能正常下降。
交给Trainer训练,并只保存适配器
带适配器的模型可以像普通 Transformers 模型一样交给 Trainer。由于底座参数的 requires_grad 为关闭状态,Trainer 只会更新 LoRA 分支;检查点通常包含 adapter_model.safetensors 和 adapter_config.json,底座权重仍由部署侧单独提供。

from transformers import Trainer, TrainingArguments
training_args = TrainingArguments(
output_dir="./lora-output", # 只把适配器检查点写入这个目录
num_train_epochs=3, # 训练轮数仍需结合数据规模和验证集调整
per_device_train_batch_size=4, # 显存不足时先降低单卡 batch
save_strategy="steps", # 保留可恢复训练的检查点
save_steps=200, # 生产任务应配合磁盘空间设置间隔
)
trainer = Trainer(
model=model, # 这里传入的是已经注入 LoRA 的模型
args=training_args,
train_dataset=dataset, # dataset 需提前完成分词和标签整理
)
trainer.train() # Trainer 只对可训练的适配器参数反向传播
model.save_pretrained("./lora-output/final-adapter") # 保存最终适配器及配置
加载与合并的选择
恢复时必须使用兼容的底座,再从适配器目录加载参数。保留适配器的好处是可以在同一个底座上切换多个领域版本;只有部署链路不再需要切换、并且希望减少运行时组合逻辑时,才考虑合并权重。合并会改变交付物形态,不能把它当成训练成功的必要步骤。
from transformers import AutoModelForCausalLM
from peft import PeftModel
base = AutoModelForCausalLM.from_pretrained("facebook/opt-350m") # 先恢复同一底座
model = PeftModel.from_pretrained(base, "./lora-output/final-adapter") # 再加载适配器
# 只有部署不再切换适配器时才合并;合并后不便于继续管理独立适配器
# merged = model.merge_and_unload()
常见问题
LoRA 的 rank 越大效果一定越好吗?
不一定。rank 增大只代表更新容量和显存开销上升,数据规模、目标模块和训练步数同样影响结果。应从较小配置开始,用验证集比较。
为什么训练后的目录没有完整模型文件?
这是参数高效微调的预期行为。适配器目录记录增量权重和配置,推理时需要先准备对应底座,再加载适配器。
什么时候应该改用 QLoRA?
当底座模型本身难以放入显存时,可以把量化底座与 LoRA 结合,但量化 dtype、训练器和硬件约束需要单独核对,不能只替换一个参数。
判断这套方案是否合适,可以回到三个问题:目标层名称是否真实存在,训练数据是否足以区分领域增量,部署时是否需要同时保留多个适配器。三点都明确后,再调 rank 和缩放,通常比盲目扩大 LoRA 容量更稳。
-
234 收藏
-
173 收藏
-
369 收藏
-
284 收藏
-
387 收藏
-
340 收藏
-
210 收藏
-
211 收藏
-
124 收藏
-
268 收藏
-
261 收藏
-
212 收藏
-
科技周边 · 人工智能 | 15小时前 | python · 人工智能 · 并行处理 index Hugging Face Datasets Datasets shard num_shards contiguous417 收藏
-
280 收藏
-
科技周边 · 人工智能 | 15小时前 | python · Transformers TextIteratorStreamer 流式生成 AsyncTextIteratorStreamer StoppingCriteria198 收藏
-
279 收藏
-
161 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习