SFT 是什么?搞懂监督微调:从数据集到训练自己的模型
目录
先给结论:SFT 是什么
SFT(Supervised Fine-Tuning,监督微调)就是:拿一批「输入 → 理想输出」的样本,去调整一个已经会说话的模型,让它按你要的方式回答。
如果说预训练是让模型”学会语言”,那 SFT 就是教它”听懂指令、扮演角色、输出你想要的样子”。它是训练自己模型的第一步,也是投入产出比最高的一步。
你对流程的理解基本正确,只差一个重点:
选基座 → 准备数据集 → SFT
真正的门槛不在训练本身(现在的工具几行配置就能跑),而在数据集。可以说,SFT 的成败,90% 在数据。
SFT 在整个训练流程里的位置
回到大模型训练的三阶段:
| 阶段 | 做什么 | 你的使用场景 |
|---|---|---|
| 预训练 | 学语言与世界知识 | 一般不自己做 |
| SFT | 学指令、风格、行为 | 你要做的第一步 |
| 对齐(DPO/RLHF) | 让输出更符合偏好 | SFT 之后的增强 |
- 预训练决定了模型”知道什么”;
- SFT决定了模型”怎么说话、怎么做事”;
- 对齐决定了它”说得让人多满意”。
顺序不能乱:先 SFT,再对齐。 基座没调好就直接上 DPO,等于在歪地基上盖楼。
第一步:选一个基础模型
默认选 Instruct / Chat 版,而不是纯 Base 版。
- 纯 Base 模型只会”续写”,不会对话;
- Instruct 版已经过通用指令微调,能正常聊天,你是在它基础上做二次微调(领域/风格 SFT)。
常见选择:
| 基座 | 特点 |
|---|---|
| Qwen2.5-1.5B / 7B / 14B-Instruct | 中文强、生态好、可商用,最推荐 |
| Llama 3.1/3.2 8B / 3B-Instruct | 英文强、社区大 |
| GLM、Yi、DeepSeek 系列 | 视语言和数据而定 |
选多大?从 7B 起步,先用 LoRA 跑通;效果不够再考虑 14B,或改用全量微调。
第二步:准备数据集(核心)
数据长什么样
SFT 数据就是一条条”示例对话”。主流有三种格式:
① Alpaca 格式(单轮)
{
"instruction": "给出一段角色扮演的回复",
"input": "今天工作好累",
"output": "听起来你今天真的辛苦了,要不要跟我说说发生了什么?"
}
② 多轮对话格式(ShareGPT / messages)——微调助手类模型更常用
{
"messages": [
{ "role": "system", "content": "你是小雅,温柔、会倾听的虚拟伴侣。" },
{ "role": "user", "content": "今天工作好累" },
{ "role": "assistant", "content": "听起来你今天真的辛苦了,要不要跟我说说?" },
{ "role": "user", "content": "老板又临时加需求" },
{ "role": "assistant", "content": "又是这样……你当时是不是特别想翻白眼?" }
]
}
③ ShareGPT 格式
{
"conversations": [
{ "from": "human", "value": "今天工作好累" },
{ "from": "gpt", "value": "听起来你今天真的辛苦了……" }
]
}
三种只是外壳不同,本质都是「上下文 → 期望回复」。
一个必须搞懂的关键点:只对 assistant 算 loss
训练时,只有 assistant(模型要生成的部分)参与 loss 计算,user 和 system 部分要 mask 掉(label 设为 -100)。
为什么?因为你要教的是”模型该怎么回答”,而不是”用户会怎么说话”。如果不 mask,模型会连用户的口吻一起学,甚至学成自己问自己答。
好消息是:主流框架(TRL、LLaMA-Factory)用多轮格式时会自动完成 masking,你只要用对的数据格式就行。
数据从哪来
- 人工标注:质量最高,成本最高,适合少量精品
- 真实业务日志:量大、真实,但必须清洗(去重、脱敏、去低质、按会话重建)
- 强模型合成(蒸馏):用效果好的大模型批量生成,再人工/规则筛选,性价比高
- 开源数据集:直接可用,但通用,通常要混入自己的数据
数据量要多少
- 从几百到几万条都能显著见效;
- 有研究证明,约 1000 条高质量数据就能让模型学会一个明确的任务;
- 质量远比数量重要:几万条噪声数据,效果常常不如几千条精挑细选的。
清洗要点:去重、去乱码/短废句、统一角色设定、平衡不同类型、剔除评测集(数据泄漏会让你误判)。
第三步:开跑——全量还是 LoRA?
| 方式 | 说明 | 适合 |
|---|---|---|
| 全量微调 | 更新所有参数,效果上限高 | 数据多、算力足 |
| LoRA / QLoRA | 只训少量附加参数,显存省 | 个人/小团队首选 |
工具上,基本轮不到你手写训练循环:
- LLaMA-Factory:配置即用,最省心;
- Unsloth:单卡提速省显存;
- Hugging Face TRL:
SFTTrainer,灵活; - Axolotl:配置化,社区活跃。
一个 LLaMA-Factory 的 LoRA SFT 配置大概长这样:
model_name_or_path: Qwen/Qwen2.5-7B-Instruct
stage: sft
finetuning_type: lora
lora_rank: 8
lora_alpha: 16
dataset: my_sft_dataset
template: qwen # 必须匹配基座的对话模板
cutoff_len: 2048
per_device_train_batch_size: 2
gradient_accumulation_steps: 8
learning_rate: 1.0e-4
num_train_epochs: 3.0
lr_scheduler_type: cosine
warmup_ratio: 0.1
bf16: true
几个要盯的超参:
- learning rate:LoRA 常用
1e-4量级,全量微调要小得多(1e-5量级); - epoch:2~3 轮通常够,太多容易过拟合;
- chat template:必须和基座一致(Qwen 用 ChatML 格式),否则训练全白费;
- cutoff_len / packing:长样本截断策略要合理。
训练时最常见的坑
- 数据格式或模板不匹配 → loss 不降、模型学坏
- 灾难性遗忘:全量微调 + 小数据 + 高学习率,会把原有能力冲掉;可混入少量通用指令数据缓解
- 过拟合:学会”背答案”,换个问法就不会了;减少 epoch、加数据
- 只学了格式,没学内容:数据同质化太严重
- 训练/推理时的 system prompt 不一致:训练写”你是小雅”,推理换个设定,效果对不上
- EOS / 截断问题:回复停不下来,或没加结束符
怎么判断 SFT 成功了
- 建一套固定的评测集(别用训练数据);
- 用 LLM-as-judge + 人工打分,对比 SFT 前后的输出:
- 是否符合目标风格/人设?
- 指令遵循是否变好?
- 通用能力是否退化(灾难性遗忘)?
- 只看 loss 曲线是不够的——loss 低不等于输出好。
SFT 的边界:它能做什么,不能做什么
- ✅ SFT 擅长:改变行为、风格、输出格式、角色扮演
- ❌ SFT 不擅长:注入新知识(用继续预训练或 RAG)
- ❌ SFT 不负责:优化偏好、减少不喜欢的回答(用 DPO 等对齐方法)
一句话:SFT 教”怎么回答”,不教”知道什么”。
最小可跑通流程
- 选基座:Qwen2.5-7B-Instruct
- 准备数据:JSONL,多轮 messages 格式,只对 assistant 算 loss
- 选工具:LLaMA-Factory 或 TRL
- 先用 QLoRA 小规模跑通,看 loss 和输出
- 建评测集,对比 SFT 前后
- 合并 LoRA、部署(vLLM / Ollama)
流程就这么短——难的是每一步背后的数据质量和评测。把这两件事做好,SFT 本身反而最简单。