监督微调 SFT(Supervised Fine-Tuning)
所属:01-fundamentals / 02-post-training
面试权重:★★★
来源:通用领域知识(B站「大模型面试八股」合集高频);未做一手考证
相关项目:Own — HKGAI LLM(SFT+DPO 两阶段)、QueWI(Qwen2.5-4B SFT 做意图识别)→ 见02-interview/projects/hkgai-llm.md
一句话#
SFT 是在预训练基座上,用「指令 → 期望回答」的成对数据继续做下一 token 预测,把「会续写」的基座变成「会听话」的助手。它是 post-training 的第一步,也是所有对齐流程的底座。
为什么重要(面试角度)#
这道题几乎必问,而且答得浅会立刻暴露。面试官想看的不是「SFT 就是拿数据微调」这句废话,而是你是否知道:
- loss 到底算在哪些 token 上(只算 response,不算 prompt)
- 为什么 SFT 数据要少而精而不是多而杂
- SFT 和预训练的数据分布匹配问题
- SFT 之后模型会变笨吗(灾难性遗忘,见
catastrophic-forgetting.md)
因为你在 HKGAI 和 QueWI 都亲手做过 SFT,这题必须答到能反向教育面试官的程度。
核心内容#
训练目标#
标准做法是只在 response token 上计算 loss,prompt 部分做 mask(通常置为 -100,被 CrossEntropyLoss 忽略)。原因很直接:你希望模型学会「给定指令该产出什么」,而不是学会「复述指令」。
如果误把 prompt 也算进 loss,模型会浪费容量去建模指令本身的分布,且在短 prompt / 长回复的数据上会过度拟合指令措辞。
数据:质量压倒数量#
LIMA 论文的核心结论是:约 1,000 条高质量指令数据就能让基座获得可用的指令遵循能力。SFT 的瓶颈从来不是数据量,而是:
| 维度 | 要求 |
|---|---|
| 多样性 | 覆盖任务类型、长度、语言、难度。同质数据会让模型只会在一个模式里打转 |
| 正确性 | 这是模仿学习,错的示范会被原样学走。数据里一个错误的推理链,模型会一并内化 |
| 格式一致 | 训练时的 chat template 必须和推理时逐字符一致,否则性能断崖式下跌 |
| 难度分布 | 全放简单样本 → 模型学不到推理;全放难题 → 学不动 |
关键超参#
- 学习率:比预训练低 1–2 个数量级(典型
1e-5~2e-5)。用预训练的学习率会把权重打飞。 - epoch:通常 2–3。SFT 数据量小,epoch 一多立刻过拟合(表现为训练 loss 降、评测不升、回复变得模板化)。
- packing:把多条短样本拼进同一个序列以提高 GPU 利用率。必须配合正确的 attention mask,否则不同样本会互相「看见」,是隐蔽的性能杀手。
- 序列长度:太短会截断长回复,让模型学不会长输出;太长则浪费算力。
数据分布匹配#
一个容易被忽略但很关键的工程点:SFT 数据的分布应当拟合预训练分布,而不是偏离它。如果 SFT 数据的语言、领域、长度分布与预训练数据差异过大,模型会在学习新格式时破坏已有的知识表示 —— 这正是灾难性遗忘的机制之一。
你在 HKGAI 的做法就是在训练语料里**策略性混入 10% 通用数据(General Data)**来锚住通用能力,这是标准且有效的缓解手段。
SFT 在整体流程里的位置#
预训练基座
↓ SFT ← 学会遵循指令(本文件)
↓ 偏好对齐 ← DPO / GRPO / PPO,学会「哪种回答更好」
↓ 就绪SFT 负责能力与格式,偏好对齐负责偏好与价值。
⚠️ 「必须先 SFT 才能 RL」是条件性结论,不是普适规律 —— 本文此前写「跳过 SFT 直接做 RLHF 几乎不可行」,说得太绝对,会被一个高频追问点打穿。
准确的边界是:「必须先 SFT」只在输出格式或基本行为尚未建立时成立。 足够强、已经有非零成功率的基座可以跳过 SFT 直接 RL —— DeepSeek-R1-Zero 就是这种情形。它后来加入冷启动 SFT,主要是改善可读性与语言一致性,而不是为 RL 注入任务知识(这一点很关键:冷启动 SFT 常被误读成「RL 之前必须教它知识」)。
两个方向都有实验证据:一端是小模型 + 严格结构化输出(如 11B 级基座要求严格 JSON)不经 SFT 直接端到端 RL 完全失败,因为基础模型产不出结构化输出、奖励根本算不出来;另一端是足够强的基座直接 RL 成功。所以判据不是「要不要 SFT」,而是「基座现在能不能产出可被奖励函数评分的输出」 —— 能,就跳过;不能,就先 SFT 把格式立起来。
常见面试问法#
Q:SFT 的 loss 为什么只算在 response 上? A:目标是学「给定指令产出什么」,而非「复述指令」。prompt 上算 loss 会浪费容量建模指令分布的措辞,且在指令短、回复长的数据上放大对措辞的过拟合。
Q:SFT 数据是不是越多越好? A:不是。LIMA 显示约 1k 条高质量数据即可。SFT 是模仿学习,边际收益在质量上而非数量上;同质数据堆量反而会让输出模式僵化。
Q:SFT 之后模型变笨了,为什么? A:灾难性遗忘。SFT 数据分布与预训练分布偏离,加上小数据 + 多 epoch 的过拟合,会覆盖原有能力。缓解:混入通用数据、降低 epoch、LoRA 冻结部分权重、更小的学习率。
Q:chat template 不一致会怎样? A:性能显著下降。训练与推理的特殊 token、role 标记、空格必须完全一致;很多「模型微调后反而更差」的案例根因就在这里。
Q:SFT 和指令微调(Instruction Tuning)是一回事吗? A:基本同义。Instruction Tuning 强调数据是多样化指令这一形态,SFT 强调监督信号形式。实际语境中可互换。
易错点#
- ❌ 说「SFT 就是拿数据微调一下」—— 没有信息量,等于没答。
- ❌ 认为 SFT 数据越多越好。
- ❌ 忘记 mask prompt token。
- ❌ 把 SFT 当成对齐价值的手段 —— 那是 DPO/GRPO/RLHF 的活。
- ❌ 忽略 chat template 一致性这个最常见的事故根因。
- ❌ epoch 设太大,把过拟合当成「学得更充分」。
自测#
1. 为什么 SFT 的 loss 只在 response token 上计算?prompt 上算 loss 会带来什么具体问题?
答案
目标是建模 p(response | instruction),prompt 是条件不是目标。在 prompt 上算 loss 会让模型花容量去建模指令分布的措辞,且在「短指令 + 长回复」的数据上过度拟合指令写法,泛化变差。工程上通常把 prompt 位置的 label 置为 -100 让损失函数忽略。
2. 你的 SFT 训练 loss 一路下降,但评测集不升反降。最可能的原因和三个具体动作是什么?
答案
最可能:过拟合 + 灾难性遗忘。动作:① 降低 epoch 到 2–3 以内并加早停;② 在训练语料中混入通用数据(如 10%)锚住通用能力;③ 降学习率或改用 LoRA 冻结主干。另需检查 chat template 是否与推理一致。
3. 「SFT 学能力,偏好对齐学偏好」——请各举一个只有前者能解决、只有后者能解决的例子。
答案
只有 SFT 能解决:模型不会按指定 JSON schema 输出工具调用参数(这是格式与能力问题,SFT 给示范即可)。只有偏好对齐能解决:模型能输出正确答案,但语气啰嗦/过度拒答/风格不符合要求(这是「两个都合理的回答之间选哪个」的偏好问题,SFT 没有负样本可学)。
4. packing 提高吞吐,但可能带来什么隐蔽问题?
答案
若 attention mask 没按样本边界正确设置,不同样本会互相 attend,模型学到跨样本的虚假依赖,训练看似正常但效果受损。此外跨样本拼接会改变位置编码的连续性,若未重置位置 id 也会引入噪声。
5. 为什么说 SFT 数据的分布应拟合预训练分布?偏离会付出什么代价?
答案
偏离会让模型在适配新格式/领域时改写已有知识表示,导致通用能力退化(灾难性遗忘)。SFT 数据量远小于预训练数据,大步长的分布偏移足以覆盖原有权重;因此在分布上贴近预训练、并在语料中保留通用数据,能显著降低退化。