LoRA 与参数高效微调
全量微调的问题
最直接的微调方式是全量微调(Full Fine-tuning)——更新模型的所有参数。
但这有一个大问题:一个 7B 参数的模型,全量微调需要大约 60GB 显存(FP16)。这远超大多数消费级 GPU 的容量。70B 的模型?你可能需要一个 GPU 集群。
有没有办法用更少的资源达到接近的效果?
LoRA:低秩适配
LoRA(Low-Rank Adaptation)是目前最流行的参数高效微调方法。它的核心思想非常优雅:
不修改原始模型的权重,而是在旁边加一小组可训练的参数。
直觉理解
想象模型的权重矩阵 W 是一个巨大的矩阵(比如 4096×4096)。全量微调要更新整个矩阵的 1600 万个参数。
LoRA 的做法:把更新分解为两个小矩阵的乘积。
原始矩阵 W: 4096 × 4096 (16M 参数)
LoRA 更新 ΔW = A × B
A: 4096 × 16 (65K 参数)
B: 16 × 4096 (65K 参数)
总共: 130K 参数 ← 只有原来的 0.8%!
这里的 16 就是秩(rank)——LoRA 的关键超参数。秩越大,可训练参数越多,表达能力越强,但训练成本也越高。
为什么这能工作
研究发现,微调时权重的实际变化具有低秩特性——也就是说,虽然模型有数十亿参数,但微调时真正需要改变的"有效自由度"远小于参数总量。LoRA 正是利用了这一特性。
QLoRA:更进一步
QLoRA 结合了量化和 LoRA,进一步降低内存需求:
- 把基础模型量化到 4bit(大幅减少内存)
- 在量化模型上应用 LoRA
- 训练时只更新 LoRA 参数(用 FP16 精度)
全量微调 7B 模型: ~60 GB 显存
LoRA 微调 7B 模型: ~16 GB 显存
QLoRA 微调 7B 模型: ~6 GB 显存 ← 一块 RTX 4060 就行!
QLoRA 让你在消费级硬件上微调 7B 甚至 13B 的模型成为可能。
三种方式的对比
| 全量微调 | LoRA | QLoRA | |
|---|---|---|---|
| 可训练参数 | 100% | 0.1-1% | 0.1-1% |
| 7B 模型显存 | ~60 GB | ~16 GB | ~6 GB |
| 训练速度 | 最慢 | 快 | 快 |
| 效果 | 最好(理论上) | 接近全量 | 略低于 LoRA |
| 硬件要求 | 多 GPU | 单 GPU (16GB+) | 单 GPU (8GB+) |
| 推荐场景 | 资源充足、追求极致 | 大多数场景 | 资源有限 |
对于大多数开发者,QLoRA 是最实用的选择。
LoRA 的关键超参数
Rank (r)
秩,决定了 LoRA 的"容量"。
| Rank | 可训练参数 | 适用 |
|---|---|---|
| 8 | 最少 | 简单任务(风格调整) |
| 16 | 适中 | 大多数任务 |
| 32 | 较多 | 复杂任务 |
| 64+ | 很多 | 接近全量微调 |
推荐从 16 开始。 效果不好再提高。
Alpha (α)
缩放因子,控制 LoRA 更新的强度。通常设为 rank 的 2 倍(即 alpha = 2 × rank)。
实际更新 = ΔW × (alpha / rank)
alpha/rank = 2 意味着 LoRA 的更新会被放大 2 倍。
Target Modules
LoRA 应用到哪些模块。Transformer 中有多种权重矩阵:
target_modules = [
"q_proj", # Query 投影
"k_proj", # Key 投影
"v_proj", # Value 投影
"o_proj", # Output 投影
"gate_proj", # FFN 门控
"up_proj", # FFN 上投影
"down_proj", # FFN 下投影
]
推荐:至少包含 q_proj 和 v_proj。 对效果有显著影响的是注意力层的投影矩阵。如果资源允许,可以加上所有线性层。
Dropout
防止过拟合的正则化手段。通常设为 0.05-0.1。数据量少时可以适当提高。
一个完整的 LoRA 配置
from peft import LoraConfig
lora_config = LoraConfig(
r=16, # 秩
lora_alpha=32, # 缩放因子
target_modules=[
"q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj"
],
lora_dropout=0.05,
bias="none",
task_type="CAUSAL_LM"
)
LoRA 权重的使用
训练完成后,LoRA 会保存为一个很小的文件(通常几十 MB):
base_model/ # 原始模型(几 GB)
lora_adapter/ # LoRA 权重(几十 MB)
adapter_config.json
adapter_model.safetensors
使用时有两种方式:
1. 动态加载(推理时叠加)
from peft import PeftModel
model = load_base_model("meta-llama/Llama-3.1-8B")
model = PeftModel.from_pretrained(model, "path/to/lora_adapter")
优势:一个基础模型可以搭配多个 LoRA,按需切换。
2. 合并权重(发布前合并)
merged_model = model.merge_and_unload()
merged_model.save_pretrained("merged_model/")
优势:推理时没有额外开销,可以直接量化为 GGUF 部署。
要点总结
- LoRA 是当前最主流的微调方法——用不到 1% 的参数达到接近全量微调的效果。
- QLoRA 进一步降低门槛——一块 8GB 显卡就能微调 7B 模型。对大多数开发者最实用。
- 关键超参数:rank=16, alpha=32 是好的起点。 目标模块至少包含 q_proj 和 v_proj。
- LoRA 权重小(几十 MB)且可热切换——一个基础模型可以搭配不同任务的 LoRA。