LoRA 微调实战:在自己电脑上给大模型”打补丁”
上篇文章我们用手写200行代码,搭了一个本地 RAG 知识库问答系统。RAG 解决了”让模型知道你的私有数据”这个问题——把文档切片、向量化、检索,再丢给大模型回答。
但 RAG 有一个限制:它只能给模型提供”上下文”,不能改变模型的行为方式。
举个例子:你想让模型输出特定 JSON 格式的 API 响应、学会你团队的代码风格、或者用你品牌的语气跟客户对话——这些 RAG 做不到。因为模型本身的参数是固定的,它只能”参考”你给的资料,但改不了自己的输出习惯。
这时候就需要微调(Fine-tuning)。但传统微调要更新整个模型的所有参数——一个 7B 模型,全量微调光显存就要 60GB 以上,普通人根本玩不起。
LoRA(Low-Rank Adaptation)的出现,把门槛从”天价”打到了”亲民”。这篇我们就用 HuggingFace PEFT 库,手把手在你的电脑上微调一个 Qwen2.5 模型。
一、LoRA 是什么?用三句话说清
原始论文是微软研究团队 2021 年发表的 LoRA: Low-Rank Adaptation of Large Language Models(Hu 等)。核心思想极简单:
- 冻住原来的大模型——预训练权重完全不动
- 在旁边加两个小矩阵——只训练这两个小矩阵,参数数量减少 10,000 倍
- 训练完合并回去——推理时把训练好的小矩阵合并回原权重,零额外延迟
具体来说,假设原权重矩阵 W 的维度是 d×k,LoRA 用两个小矩阵 B(d×r)和 A(r×k)来近似它的变化量 ΔW = BA。这里的 r(rank)远小于 d 和 k(通常 8~64),所以参数量爆炸缩小。
用生活中的例子:全量微调就像给一栋大楼重新装修——拆墙改水电,成本巨大。LoRA 就像在墙上挂一幅画——大楼不动,只加一个小装饰,但效果能达到重新装修的 90% 以上。
二、实操:在本地微调 Qwen2.5-3B
以下代码经 HuggingFace PEFT 官方仓库验证可运行。我们需要三样东西:
- Python 3.10+
- 一张 8GB+ 显存的 GPU(如 RTX 3070/4060)
- 约 10GB 磁盘空间
第一步:安装依赖
pip install transformers peft accelerate datasets torch
第二步:加载模型并配置 LoRA
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import LoraConfig, get_peft_model, TaskType
import torch
model_id = "Qwen/Qwen2.5-3B-Instruct"
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(
model_id,
torch_dtype=torch.bfloat16,
device_map="auto"
)
lora_config = LoraConfig(
r=16, # 秩(rank)
lora_alpha=32, # 缩放系数
target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],
lora_dropout=0.05,
bias="none",
task_type=TaskType.CAUSAL_LM
)
model = get_peft_model(model, lora_config)
model.print_trainable_parameters()
# 输出: trainable params: 3.7M / 3,089M = 0.12%
看到没?3B 参数的模型,我们只训练 370 万个参数,占比仅 0.12%。
第三步:准备训练数据
微调数据格式通常是 Q&A 对。比如你想让模型学会用中文回答技术问题:
from datasets import Dataset
data = [
{"input": "什么是 Python 的 GIL?", "output": "GIL(全局解释器锁)是 CPython 的一个机制,确保同一时刻只有一个线程执行 Python 字节码。它简化了内存管理,但限制了多线程 CPU 密集型任务的并行性。"},
{"input": "解释一下 Git rebase 和 merge 的区别", "output": "Merge 创建一个新的合并提交,保留完整的历史分支结构。Rebase 将当前分支的提交"放"到目标分支之后,历史更线性整洁,但会改写提交哈希。"},
]
def format_func(example):
return {"text": f"用户:{example['input']}\n助手:{example['output']}"}
dataset = Dataset.from_list(data).map(format_func)
第四步:开始训练
from transformers import Trainer, TrainingArguments
training_args = TrainingArguments(
output_dir="./qwen-lora",
per_device_train_batch_size=4,
gradient_accumulation_steps=4,
num_train_epochs=3,
learning_rate=2e-4,
logging_steps=10,
save_strategy="epoch",
bf16=True,
)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=dataset,
)
trainer.train()
model.save_pretrained("./qwen-lora-final")
在 8GB 显存的显卡上,这个配置跑 1000 条数据大约需要 20~30 分钟。
第五步:加载 LoRA 做推理
from peft import PeftModel
base_model = AutoModelForCausalLM.from_pretrained(
model_id, torch_dtype=torch.bfloat16, device_map="auto"
)
lora_model = PeftModel.from_pretrained(base_model, "./qwen-lora-final")
inputs = tokenizer("用户:什么是 Python 的 GIL?\n助手:", return_tensors="pt").to("cuda")
outputs = lora_model.generate(**inputs, max_new_tokens=200)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))
三、关键参数怎么调?
很多新手第一次跑 LoRA 会困惑参数怎么设。其实核心就四个:
r(秩):LoRA 最关键的参数。r 越大,小矩阵能”记住”的信息越多,但显存和耗时也线性增加。对 7B 以下模型,r=8 已经能适配大多数任务。如果效果不够再加到 16,一般不用超过 32。
lora_alpha:控制 LoRA 权重的影响力。推荐设置为 r 的 2 倍,即 r=16 时 alpha=32。这个比例在实践中效果最稳。
target_modules:默认对 q_proj 和 v_proj 做 LoRA,这是论文的原始设定。如果想提升效果,可以扩展到所有 attention 层(加 k_proj、o_proj)。但注意不是越多越好——加多了训练变慢,收益边际递减。
数据质量比数量重要:这是最容易被忽视的一点。1000 条精心标注的高质量数据,效果远好于 10000 条爬来的脏数据。每条数据保证输入输出对应清晰,格式统一。
| 参数 | 推荐值 | 调大效果 | 调小效果 |
|---|---|---|---|
| r(rank) | 8~32 | 更强拟合能力,更吃显存 | 更快更省,可能欠拟合 |
| lora_alpha | 16~64 | LoRA 权重影响更大 | 原模型保持更多 |
| target_modules | q_proj, v_proj | 覆盖更多层,更占资源 | 只改部分层,更快 |
| learning_rate | 1e-4 ~ 3e-4 | 容易过拟合 | 训练更慢 |
实战建议:
- 第一次尝试用 r=8,跑通了再加到 16 或 32
- 数据量不足 500 条时,优先用 r=8、epoch=5
- 数据量 2000+ 条,推荐 r=16、epoch=3
- LoRA 微调首选 Qwen2.5 或 LLaMA-3.1 系列,社区生态最成熟
总结
LoRA 让大模型微调从”天方夜谭”变成了”周末项目”——一张民用显卡、几百条数据、几十分钟,就能让模型学会你想要的输出风格。相比全量微调,参数减少 10,000 倍,显存需求降低 3 倍,效果却几乎不掉。
这是”从零学大模型”系列的第 3 篇。下一篇我们聊 QLoRA——在 LoRA 基础上加量化,让 4GB 显存的旧显卡也能微调 7B 模型。也就是说,你的笔记本也能跑了。
参考文献:
- Hu, E. J., et al. “LoRA: Low-Rank Adaptation of Large Language Models.” arXiv:2106.09685, 2021. https://arxiv.org/abs/2106.09685
- HuggingFace PEFT 官方文档与代码示例. https://github.com/huggingface/peft
- HuggingFace PEFT LoRA 开发指南. https://huggingface.co/docs/peft/en/developer_guides/lora
- Qwen2.5 官方模型仓库. https://huggingface.co/Qwen/Qwen2.5-3B-Instruct
转载请注明:Falost的小窝 » LoRA 微调实战:在自己电脑上给大模型”打补丁”

