高效微调方法
课程简介
LoRA、Adapter、Prefix Tuning 等参数高效微调技术。
🎬 本课程视频:Finetuning LLMs — 大模型微调
参数高效微调:LoRA、Adapter 与 QLoRA
一、全量微调的挑战
全量微调(Full Fine-tuning)需要更新模型的所有参数。对于一个 70B 参数的模型,即使只使用 16 位精度,也需要约 140GB 的显存来加载模型参数,加上优化器状态和梯度,总显存需求超过 300GB。这需要多张 A100 或 H100 显卡,成本极高。
二、LoRA(Low-Rank Adaptation)
2.1 核心思想
LoRA 是目前最流行的参数高效微调方法。它的核心洞察是:预训练模型具有较低的「内在维度」——也就是说,模型适应新任务时所需的参数变化可以用一个低秩矩阵来近似。
2.2 工作原理
LoRA 冻结原始模型的全部权重,在注意力层的权重矩阵旁边插入两个低秩矩阵 A 和 B 进行训练。
原始模型权重 W(冻结):
W ∈ ℝ^(d×k)
LoRA 低秩分解:
原始更新 ΔW = W_new - W(全量微调需要学习 d×k 个参数)
LoRA 近似 ΔW = BA(学习 B∈ℝ^(d×r) 和 A∈ℝ^(r×k) 共 (d+k)×r 个参数)
其中 r << min(d, k)
推理时,LoRA 的输出与原始权重输出相加:
h = Wx + BAx
2.3 关键参数:秩(Rank)
秩 r 是 LoRA 的核心超参数,控制着可训练参数的数量和模型的表达能力。
| r 值 | 可训练参数量 | 表现力 | 推荐场景 |
|---|---|---|---|
| 1-4 | 极少 | 有限 | 简单任务、资源受限 |
| 8-16 | 适中 | 良好 | 大多数任务 |
| 32-64 | 较多 | 接近全量 | 复杂任务、追求最佳效果 |
Andrew Ng 推荐:大多数任务从 r=16 开始,效果不够再增加到 r=32 或 64。
2.4 实现代码
from peft import LoraConfig, get_peft_model
from transformers import AutoModelForCausalLM
# 加载模型
model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-3-8B")
# LoRA 配置
lora_config = LoraConfig(
r=16, # 秩
lora_alpha=32, # 缩放因子(通常设为 r 的 2 倍)
target_modules=[ # 应用 LoRA 的模块
"q_proj",
"k_proj",
"v_proj",
"o_proj"
],
lora_dropout=0.05, # dropout 率
bias="none", # 是否训练偏置
task_type="CAUSAL_LM" # 任务类型
)
# 应用 LoRA
peft_model = get_peft_model(model, lora_config)
# 检查可训练参数数量
trainable_params = sum(p.numel() for p in peft_model.parameters() if p.requires_grad)
total_params = sum(p.numel() for p in peft_model.parameters())
print(f"可训练参数:{trainable_params}/{total_params} ({100 * trainable_params / total_params:.2f}%)")
# 训练方式与全量微调相同
trainer = Trainer(
model=peft_model,
args=training_args,
train_dataset=train_dataset,
eval_dataset=eval_dataset
)
trainer.train()
# 保存 LoRA 权重(只需保存少量参数)
peft_model.save_pretrained("./lora_weights")
2.5 LoRA 的数学分析
为什么 LoRA 有效?考虑一个预训练好的权重矩阵 W₀。全量微调需要学习更新量 ΔW,使得:
W = W₀ + ΔW
LoRA 假设 ΔW 具有低秩特性,即:
ΔW = BA, 其中 B ∈ ℝ^(d×r), A ∈ ℝ^(r×k), r << min(d,k)
对于一个 4096×4096 的权重矩阵(常见于 Transformer),全量微调需要学习约 1600 万个参数。使用 LoRA(r=16)只需要学习约 13 万个参数——减少了约 120 倍。
三、其他 PEFT 方法
3.1 Adapter
在 Transformer 的每一层中插入小型前馈网络。
原始层:LayerNorm → Attention → LayerNorm → FFN
Adapter 层:LayerNorm → Attention → LayerNorm → FFN → Adapter → Residual
Adapter 的参数量通常设为主网络的 1-5%。
3.2 Prefix Tuning
在注意力机制的 Key 和 Value 前添加可学习的虚拟 Token。
# Prefix Tuning 在 attention 前加虚拟 token
prefix_length = 10 # 虚拟 token 数量
prefix_embedding = nn.Parameter(torch.randn(prefix_length, hidden_dim))
3.3 Prompt Tuning
在模型的输入嵌入前添加 soft prompt(可学习的嵌入向量)。
[soft_prompt_1] [soft_prompt_2] ... [soft_prompt_k] [原始输入]
3.4 方法对比
| 方法 | 参数效率 | 推理开销 | 实现复杂度 | 效果 |
|---|---|---|---|---|
| LoRA | 高 | 无 | 低 | 优秀 |
| Adapter | 中 | 略增 | 中 | 良好 |
| Prefix Tuning | 高 | 略增 | 中 | 中等 |
| Prompt Tuning | 最高 | 无 | 低 | 中等(依赖任务) |
四、QLoRA:量化 LoRA
4.1 核心思想
QLoRA 在 LoRA 的基础上进一步引入了 4-bit 量化,使微调超大模型成为可能。
4.2 工作原理
- 4-bit NormalFloat 量化:将模型权重量化为 4-bit,显存需求降低约 4 倍
- 双重量化:对量化常数再进行一次量化,进一步节省显存
- 分页优化器:利用 CPU 内存作为显存的扩展,处理偶尔的显存溢出
- LoRA 训练:在量化的模型上应用 LoRA
4.3 实现
from transformers import BitsAndBytesConfig
import torch
# 4-bit 量化配置
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4", # NormalFloat 4-bit
bnb_4bit_compute_dtype=torch.bfloat16,
bnb_4bit_use_double_quant=True # 双重量化
)
# 加载量化模型
model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-3-70B",
quantization_config=bnb_config,
device_map="auto"
)
# 应用 LoRA(配置不变)
peft_model = get_peft_model(model, lora_config)
# 训练(注意:量化模型不能训练量化参数,只能训练 LoRA 参数)
4.4 QLoRA 的显存优势
| 配置 | 7B 模型 | 13B 模型 | 70B 模型 |
|---|---|---|---|
| 全量微调(16-bit) | 56GB | 104GB | 560GB |
| LoRA(16-bit) | 28GB | 52GB | 280GB |
| QLoRA(4-bit) | 7GB | 13GB | 70GB |
单张 RTX 4090(24GB 显存)即可使用 QLoRA 微调 70B 模型。
五、PEFT 的最佳实践
5.1 如何选择 PEFT 方法?
- 首选 LoRA:通用性最强,效果稳定,推理无额外开销
- 需要极致参数效率:QLoRA(显存受限时)
- 自然语言理解任务:Adapter 有时表现更好
- 文本生成任务:LoRA 是主流选择
5.2 LoRA 配置建议
- r = 16 开始,不够调大
- lora_alpha = 2 * r
- 目标模块:至少包含 q_proj 和 v_proj
- 训练 2-4 个 epoch
5.3 多任务 LoRA
可以为不同任务训练不同的 LoRA 适配器,推理时根据需要加载:
任务 A 的 LoRA 权重 → path/to/lora_A
任务 B 的 LoRA 权重 → path/to/lora_B
推理时:
加载基础模型 + 任务 A 的 LoRA → 执行任务 A
加载基础模型 + 任务 B 的 LoRA → 执行任务 B
六、总结
参数高效微调(PEFT)技术大幅降低了微调大语言模型的门槛。LoRA 通过低秩分解实现与全量微调接近的效果,同时只更新极少量参数。QLoRA 通过 4-bit 量化进一步将显存需求降低 4 倍,单张消费级显卡即可微调 70B 模型。选择合适的 PEFT 方法和配置,可以在有限资源下实现高质量的领域适配。
七、LoRA 的优势与局限
7.1 LoRA 的主要优势
- 显存需求低:4GB 显存即可微调 7B 模型
- 训练速度快:参数量少了几个数量级
- 模型质量高:在多数任务上接近全量微调
- 便于切换:不同任务的 LoRA 权重可以随时切换
- 低存储成本:一个 LoRA 适配器通常只需 5-50MB
7.2 LoRA 的局限
- 并非所有任务都适合,极简单的任务可能不需要微调
- 极端复杂的任务可能需要全量微调
- 需要选择合适的 rank 值
八、QLoRA:量化 LoRA
8.1 QLoRA 的核心思想
QLoRA = 4-bit 量化 + LoRA。将预训练模型量化为 4-bit(NormalFloat4),然后在这个量化模型上应用 LoRA 微调。
8.2 QLoRA 的显存节省
| 方法 | 7B 模型 | 13B 模型 | 70B 模型 |
|---|---|---|---|
| 全量微调 | 56GB | 104GB | 560GB |
| LoRA | 14GB | 26GB | 140GB |
| QLoRA | 4GB | 8GB | 48GB |
8.3 QLoRA 的实现
from transformers import BitsAndBytesConfig
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.bfloat16
)
model = AutoModelForCausalLM.from_pretrained(
model_name,
quantization_config=bnb_config
)
九、总结
关键要点回顾:
- PEFT 是大模型微调的实用方案
- LoRA 通过低秩矩阵分解大幅减少可训练参数
- Adapter 在 Transformer 层中插入小型神经网络
- Prefix Tuning 在输入前缀中学习连续向量
- QLoRA 结合 4-bit 量化进一步降低硬件门槛
七、LoRA 的优势与局限
7.1 LoRA 的主要优势
- 显存需求低:4GB 显存即可微调 7B 模型
- 训练速度快:参数量少了几个数量级
- 模型质量高:在多数任务上接近全量微调
- 便于切换:不同任务的 LoRA 权重可以随时切换
- 低存储成本:一个 LoRA 适配器通常只需 5-50MB
7.2 LoRA 的局限
- 并非所有任务都适合,极简单的任务可能不需要微调
- 极端复杂的任务可能需要全量微调
- 需要选择合适的 rank 值
八、QLoRA:量化 LoRA
8.1 QLoRA 的核心思想
QLoRA = 4-bit 量化 + LoRA。将预训练模型量化为 4-bit(NormalFloat4),然后在这个量化模型上应用 LoRA 微调。
8.2 QLoRA 的显存节省
| 方法 | 7B 模型 | 13B 模型 | 70B 模型 |
|---|---|---|---|
| 全量微调 | 56GB | 104GB | 560GB |
| LoRA | 14GB | 26GB | 140GB |
| QLoRA | 4GB | 8GB | 48GB |
8.3 QLoRA 的实现
from transformers import BitsAndBytesConfig
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.bfloat16
)
model = AutoModelForCausalLM.from_pretrained(
model_name,
quantization_config=bnb_config
)
九、总结
关键要点回顾:
- PEFT 是大模型微调的实用方案
- LoRA 通过低秩矩阵分解大幅减少可训练参数
- Adapter 在 Transformer 层中插入小型神经网络
- Prefix Tuning 在输入前缀中学习连续向量
- QLoRA 结合 4-bit 量化进一步降低硬件门槛
七、LoRA 的优势与局限
7.1 LoRA 的主要优势
- 显存需求低:4GB 显存即可微调 7B 模型
- 训练速度快:参数量少了几个数量级
- 模型质量高:在多数任务上接近全量微调
- 便于切换:不同任务的 LoRA 权重可以随时切换
- 低存储成本:一个 LoRA 适配器通常只需 5-50MB
7.2 LoRA 的局限
- 并非所有任务都适合,极简单的任务可能不需要微调
- 极端复杂的任务可能需要全量微调
- 需要选择合适的 rank 值
八、QLoRA:量化 LoRA
8.1 QLoRA 的核心思想
QLoRA = 4-bit 量化 + LoRA。将预训练模型量化为 4-bit(NormalFloat4),然后在这个量化模型上应用 LoRA 微调。
8.2 QLoRA 的显存节省
| 方法 | 7B 模型 | 13B 模型 | 70B 模型 |
|---|---|---|---|
| 全量微调 | 56GB | 104GB | 560GB |
| LoRA | 14GB | 26GB | 140GB |
| QLoRA | 4GB | 8GB | 48GB |
8.3 QLoRA 的实现
from transformers import BitsAndBytesConfig
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.bfloat16
)
model = AutoModelForCausalLM.from_pretrained(
model_name,
quantization_config=bnb_config
)
九、总结
关键要点回顾:
- PEFT 是大模型微调的实用方案
- LoRA 通过低秩矩阵分解大幅减少可训练参数
- Adapter 在 Transformer 层中插入小型神经网络
- Prefix Tuning 在输入前缀中学习连续向量
- QLoRA 结合 4-bit 量化进一步降低硬件门槛
延伸阅读
- 📺 B 站播放列表:Finetuning LLMs — 大模型微调
- 📚 更多学习资源,请访问 deeplearning.ai 官网