LLM Fine-tuning(LoRA / RLHF / DPO)
先把结论放前面
大模型的 Fine-tuning 不是"训一次",而是一套从预训练到对齐的完整流程:
Pretraining → 学会语言规律(大量无监督文本)
SFT(Supervised Fine-tuning) → 学会遵循指令(高质量指令-回复对)
RLHF / DPO → 学会和人类偏好对齐(比 SFT 更难表达的品质:有用、无害、诚实)
LoRA / QLoRA 是降低 Fine-tuning 显存和计算成本的方法,不是替代 RLHF 的东西。
为什么这个问题值得单独讲
LLM 的训练和 Fine-tuning 是目前工业界和学术圈最活跃的领域,但概念最容易混:
- SFT 和 RLHF 是什么关系?
- LoRA 是替代 RLHF 还是只是降低成本?
- DPO 为什么比 RLHF 简单,简化了什么?
- 什么时候该 Fine-tune,什么时候该用 Prompt Engineering?
Pre-training → SFT → RLHF 完整链路
Pretraining(预训练)
用海量无监督文本(互联网爬取),训练语言模型预测下一个 token。目标是学会语言本身。
训练数据:The Pile、RedPajama、RefinedWeb 等万亿 token 级数据集。
损失函数:标准 Language Modeling Loss(Next Token Prediction)。
# 预训练伪代码
for batch in dataloader:
tokens = tokenize(batch["text"])
logits = model(tokens)
loss = cross_entropy(logits[:, :-1], tokens[:, 1:])
loss.backward()
SFT(Supervised Fine-tuning)
用高质量的指令-回复对(Instruction-Response pairs),教模型"怎么回答问题"。
训练数据:人工标注的指令数据(如 OpenAI 的 InstructGPT 数据集)。
# SFT 伪代码
for batch in dataloader:
tokens = tokenize(batch["instruction"], batch["response"])
logits = model(tokens)
# 只在回复部分算损失
loss = cross_entropy(logits[:, :-1], tokens[:, 1:])
loss.backward()
SFT 能解决什么问题:教会模型遵循指令格式、回答问题的结构(不要自言自语、不要拒绝不存在的知识)。
SFT 不能解决什么问题:安全性(有 Toxic 输出)、对齐(符合人类偏好的回答风格)。
RLHF(Reinforcement Learning from Human Feedback)
RLHF 解决的是"SFT 能教会模型回答问题,但不能保证回答质量符合人类偏好"的问题。
核心流程:
-
Reward Model 训练:收集人类偏好数据(同一问题,两个回答,哪个更好),训练 Reward Model 预测人类偏好。
-
PPO 强化学习:用 Reward Model 的信号,通过 PPO(Proximal Policy Optimization)算法优化 SFT 模型,让它产生 Reward 更高的输出。
# RLHF Step 1: Reward Model
preference_data = [
{"question": "...", "response_a": "...", "response_b": "...", "label": "a"}
]
# 训练 Reward Model 预测"哪个回答更好"
# RLHF Step 2: PPO
for batch in ppo_iterations:
responses = sft_model.generate(question)
rewards = reward_model(question, responses)
ppo_update(sft_model, rewards) # 用 PPO 算法更新模型
RLHF 的问题:
- 需要大量人类偏好标注(成本高)
- PPO 训练不稳定(KL 散度约束需要仔细调)
- Reward Model 可能被 hacking(模型学会"骗"Reward Model)
DPO(Direct Preference Optimization)
DPO 是 2023 年提出的方法,直接用偏好数据优化语言模型,不需要训练 Reward Model,也不需要 PPO,大幅简化了 RLHF。
核心思想:把 RLHF 的 Reward Model 建模融进策略本身,直接从偏好数据里学习。
Loss 函数:
DPO Loss = - log σ( r(x,y_w) - r(x,y_l) - β × KL(π_θ(y|x) || π_ref(y|x)) )
- y_w:人类偏好的回答
- y_l:人类不偏好的回答
- π_θ:当前模型
- π_ref:参考模型(SFT 模型)
- β:KL 散度惩罚系数
为什么 DPO 更好:
| 维度 | RLHF | DPO |
|---|---|---|
| 训练稳定性 | 不稳定(PPO 难调) | 稳定(直接优化) |
| 需要 Reward Model | 需要 | 不需要 |
| 需要 PPO | 需要 | 不需要 |
| 人类偏好数据效率 | 低 | 高 |
| 工程复杂度 | 高 | 低 |
| 效果 | 好 | 在简单对齐任务上接近 RLHF |
DPO 的弱点:对于复杂的多维度偏好(如"既要有用又要有害性低"),DPO 的表现不一定比 RLHF 更好。
LoRA / QLoRA:降低 Fine-tuning 成本
全参数 Fine-tuning 的问题
GPT-3(175B 参数)的全参数 Fine-tuning 需要:8×A100(80GB)× 100+ 小时。这不是普通团队能承受的。
LoRA(Low-Rank Adaptation)
核心思想:冻结预训练模型的原始权重 W₀,在旁边额外训练两个低秩矩阵 A 和 B。推理时,原始权重 + 低秩更新的效果和全参数 Fine-tuning 接近。
原始前向: h = W₀ · x
LoRA 前向: h = W₀ · x + (B · A) · x
其中 A ∈ ℝ^(r×k),B ∈ ℝ^(k×r),r 是秩(rank),通常 r = 4, 8, 16, 64。
秩 r 的选择:
- r = 4-8:轻量,适合简单任务(如情感分类)
- r = 16-64:标准,效果和全参数 Fine-tuning 接近
- r = 128+:接近全参数 Fine-tuning
显存节省:全参数 Fine-tuning 需要保存梯度 + 优化器状态(FP32 优化器),LoRA 只需要保存 A 和 B 两个矩阵 + 优化器状态。175B 模型从 1.2TB 显存降到 350GB(8 倍压缩)。
QLoRA(Quantized LoRA)
QLoRA = LoRA + NF4(4-bit NormalFloat 量化)。
核心步骤:
- 把预训练模型量化为 NF4(4-bit 量化)
- 用 LoRA 在量化模型上 Fine-tuning
- 合并 LoRA 权重回量化模型
效果:65B 模型可以在 48GB 显存(如单张 A100)上 Fine-tuning。
LoRA 的常见配置
from peft import LoraConfig, get_peft_model
lora_config = LoraConfig(
r=16, # rank,越大越接近全参数微调
lora_alpha=32, # 缩放系数,通常 = 2×rank
target_modules=[ # 应用 LoRA 的模块
"q_proj", "k_proj", # Transformer 的 Q 和 K
"v_proj", "o_proj", # V 和 O
"gate_proj", "up_proj", "down_proj" # FFN 层
],
lora_dropout=0.05,
bias="none", # 不训练 bias
task_type="CAUSAL_LM"
)
model = get_peft_model(base_model, lora_config)
# 可训练参数从 7B × 4 bytes × 2 ≈ 56GB → 约 80MB
LoRA 的变体
DoRA(Weight-Decomposed LoRA):把 LoRA 的更新分解为幅度(magnitude)和方向(direction),效果比标准 LoRA 更好,尤其在高 rank 设置下。
QLoRA / QA-LoRA:LoRA + 量化,结合两种压缩手段。
Instruction Tuning(指令微调)
Instruction Tuning 和 SFT 本质上是同一件事,但侧重点不同:
- SFT:强调"用监督数据 Fine-tune",解决模型遵循指令的问题
- Instruction Tuning:强调"数据是格式化的指令",通常是 Instruction-Input-Output 三元组
常见数据集:
- Alpaca(Stanford):用 Self-Instruct 生成
- Vicuna:ChatGPT 对话数据
- WizardLM:用 LLM 生成复杂指令
- FLAN:Google 的大规模指令微调数据集
什么时候该 Fine-tune,什么时候该 Prompt Engineering
| 场景 | 推荐方法 |
|---|---|
| 需要模型学习新知识(新事实、新领域) | Fine-tuning(SFT) |
| 需要模型改变输出风格 | Fine-tuning(SFT) |
| 需要模型遵循复杂格式 | Fine-tuning(SFT) |
| 知识已经存在于模型里,只是没被激活 | Prompt Engineering |
| 只需要给模型更多上下文 | RAG |
| 需要实时更新的知识 | RAG(Fine-tuning 不是为此设计的) |
| 需要模型和特定行为对齐 | RLHF / DPO |
常见误区:用 Fine-tuning 来让模型学习新知识是低效的——训练数据量有限,无法覆盖所有知识边角情况。RAG 才是处理实时知识的正确工具,Fine-tuning 的价值在于改变风格和结构。
DeepSpeed + ZeRO
DeepSpeed 是微软的分布式训练库,和 LoRA 是互补的——LoRA 降低单卡显存,DeepSpeed 让训练分布到多卡。
ZeRO(Zero Redundancy Optimizer):把优化器状态、梯度、模型参数分片到不同 GPU:
- ZeRO-1:优化器状态分片(显存节省约 4 倍)
- ZeRO-2:优化器状态 + 梯度分片(显存节省约 8 倍)
- ZeRO-3:全部参数分片(显存节省约 N 倍,N = GPU 数)
# DeepSpeed 配置
ds_config = {
"zero_optimization": {
"stage": 3,
"offload_param": {"device": "cpu"}, # 显存不够时把参数放到 CPU
"offload_optimizer": {"device": "cpu"}
},
"bf16": {"enabled": True} # BF16 训练
}
如果放到面试里怎么讲
"SFT 和 RLHF 是什么关系?"
SFT 是用高质量指令数据做监督学习,让模型学会回答问题;RLHF 是用人类偏好数据做强化学习,让模型学会产生"更好的"回答。SFT 解决的是"怎么回答",RLHF 解决的是"什么算好回答"。通常的流程是先 SFT 再 RLHF。
"LoRA 为什么能省显存?"
LoRA 冻结原始权重,在旁边训练两个低秩矩阵 A 和 B。我只需要保存 A 和 B 的梯度 + 优化器状态,不需要保存整个模型的梯度。全参数 Fine-tuning 175B 模型需要 1.2TB 显存,LoRA 只需要约 350GB。
最后记几个点
- Pretraining 学语言规律,SFT 学遵循指令,RLHF/DPO 学人类偏好
- 全参数 Fine-tuning = SFT + 梯度;LoRA = 低秩矩阵 Fine-tuning,不需要梯度
- RLHF 需要 Reward Model + PPO,DPO 不需要,两者都在学习"什么算好回答"
- DPO 比 RLHF 简单稳定,但在复杂多维度对齐任务上不一定更好
- LoRA 节省显存,DeepSpeed ZeRO 分布式训练,两者可以叠加
- QLoRA = NF4 量化 + LoRA,65B 模型可在单张 A100(48GB)上 Fine-tuning
- 知识类问题用 RAG,风格/格式/行为类问题用 Fine-tuning
跨库关联
本文件是 LLM Fine-tuning 的概览视图,详细内容拆分到 大模型知识库 的各专题中:
- 预训练 → 预训练
- SFT 详解 → 监督微调SFT
- RLHF 全流程 → 人类反馈强化学习RLHF
- DPO/ORPO/KTO 对比 → 偏好优化DPO_GRPO
- LoRA/QLoRA 原理 → LoRA与QLoRA
- 训练工具链 → 训练生态工具