SFT 看起来像最普通的语言模型微调:给定 prompt 和 response,继续做 next-token prediction。 真正容易出错的地方不在损失函数名字,而在聊天模板、特殊 token、loss mask、packing 和数据质量。
这篇文章把 SFT 当作后训练系统的策略初始化来讲。 它既要让模型学会像助手一样回答,也要给后续奖励模型、DPO 或 PPO 留出稳定起点。
一、SFT 的目标函数
监督微调(Supervised Fine-Tuning)把每条样本写成指令与回答对。 模型看到指令、系统消息、历史对话和角色标记后,只在助手回答部分计算 next-token loss。
\[ \mathcal{L}_{SFT}(\theta)=-\sum_{t\in \mathcal{M}}\log \pi_\theta(y_t|x,y_{<t}) \]
这里 \(\mathcal{M}\) 是 loss mask 选中的 token 集合。 对话 prompt、system message、用户输入通常不参与 loss;assistant response 才是被监督的目标。
二、聊天模板决定模型看到的任务
同一段对话用不同模板展开,会变成不同 token 序列。 角色标记、开始结束符、换行、工具调用标签都会进入模型上下文。
| 元素 | 作用 | 常见错误 |
|---|---|---|
| system | 定义助手行为边界 | 训练有 system,推理没有 system |
| user | 承载指令与上下文 | 把 user token 计入 loss |
| assistant | 标记需要生成的回答 | 忘记 assistant 起始标记 |
| special tokens | 区分轮次和终止 | EOS 不一致导致生成不停 |
| tool markers | 表达工具调用结构 | 把工具返回当成助手自然语言 |
模板不是格式问题,而是任务定义的一部分。 SFT、RM、DPO、PPO 和评测最好共享同一 tokenizer 与 chat template,否则后续阶段会优化另一个分布。
三、loss mask:只训练助手 token
note = "示意:构造 SFT loss mask,真实代码需按 tokenizer 和 chat template 调整"
tokens = tokenizer.apply_chat_template(messages, add_generation_prompt=False)
labels = tokens.input_ids.copy()
loss_mask = [0] * len(labels)
for span in assistant_response_spans(tokens):
for i in range(span.start, span.end):
loss_mask[i] = 1
for i, keep in enumerate(loss_mask):
if not keep:
labels[i] = -100 # PyTorch CrossEntropyLoss 忽略该位置
outputs = model(input_ids=tokens.input_ids, labels=labels)
loss = outputs.loss这段代码只是示意。 真实实现要确保 span 边界来自模板解析,而不是用字符串搜索硬猜。 多轮对话、工具调用和截断都会改变助手 token 的位置。
四、packing 与截断
SFT 数据长度差异很大。 packing 会把多条短样本拼到同一个 sequence 里,提高 GPU 利用率。
packing 的前提是 attention mask 和 loss mask 正确隔离样本。 若两条样本之间没有边界,后一条样本会看见前一条样本的答案,训练目标被污染。
- 短样本多时,packing 能减少 padding 浪费。
- 长样本多时,packing 收益有限,截断策略更重要。
- 截断应优先保留完整回答边界,避免只留下 prompt 或半句答案。
- 评测模板必须和训练模板兼容,否则 packing 带来的效率收益会变成分布错位。
五、学习率、epoch 与过拟合
SFT 通常只跑少量 epoch,常见范围是 1 到 3 个 epoch,但这不是定律。 数据规模、模型大小、学习率、是否 LoRA、是否混入通用数据都会改变合适轮数。
过拟合不一定表现为 validation loss 立刻恶化。 更常见的信号是回答模板化、复读训练语料风格、拒答边界僵硬,或者后续 RL 的 KL 起点很差。
六、数据质量比数量更硬
LIMA 论文用“Less Is More for Alignment”强调少量高质量示范也能明显影响模型交互行为。 这个结论不应被误读成数据越少越好,而是说明 SFT 对示范质量、覆盖范围和风格一致性非常敏感。
Self-Instruct 和 Alpaca 展示了用模型生成指令数据、再清洗微调的路线。 它降低了构造指令数据的门槛,也带来蒸馏偏差和合成数据污染风险。
七、SFT 与后续 RL 的关系
在 RLHF 中,SFT 模型通常同时扮演两个角色:它是 PPO policy 的初始化,也是 KL reference model 的来源。 初始化太弱,RL 要花大量步数学习基本格式;初始化太窄,RL 探索空间不足。
DPO 也依赖 SFT 起点。 偏好损失会围绕 reference 分布移动策略,若 SFT 已经把某些正确行为排除在高概率区域外,离线偏好数据很难凭空恢复。
八、SFT 训练核对清单
1. 样本去重
- 核对点:对 prompt 和 response 做近重复检查,避免模型背诵高频模板。
- 常见失败:训练 loss 很低但泛化差。
- 观测信号:dedup ratio、near-duplicate clusters。
- 边界条件:去重不能删掉有意保留的多风格答案。
2. 来源分层
- 核对点:区分人工、蒸馏、自指令、线上回流和安全样本。
- 常见失败:不同来源质量混在一起,坏数据被高质量数据掩盖。
- 观测信号:source tag、per-source loss。
- 边界条件:来源标签本身可能含敏感信息,需脱敏。
3. 模板单测
- 核对点:给固定 messages 检查 token、role、EOS 和 assistant span。
- 常见失败:升级 tokenizer 后所有 mask 边界错位。
- 观测信号:golden tokenization tests。
- 边界条件:不同模型族需要不同 golden case。
4. prompt mask
- 核对点:用户输入和 system token 不参与监督。
- 常见失败:模型学习复述用户问题或 system policy。
- 观测信号:masked token count。
- 边界条件:某些任务可能有 deliberate echo,需要单独标注。
5. assistant mask
- 核对点:只在目标回答上计算 loss。
- 常见失败:多轮对话只训练最后一轮,遗忘前面 assistant 风格。
- 观测信号:assistant span count。
- 边界条件:多轮样本要决定训练全部 assistant 还是最后一轮。
6. EOS 处理
- 核对点:回答结束应有一致终止符。
- 常见失败:模型不停生成或过早停止。
- 观测信号:EOS rate、avg generation length。
- 边界条件:某些 chat template 使用多个结束标记。
7. packing 隔离
- 核对点:拼接样本之间要正确重置 attention 或插入边界。
- 常见失败:样本间信息泄露。
- 观测信号:cross-sample attention test。
- 边界条件:FlashAttention 变长实现要看框架支持。
8. 截断策略
- 核对点:记录被截断的是 prompt、response 还是中间历史。
- 常见失败:训练大量半截答案。
- 观测信号:truncation side、truncated response rate。
- 边界条件:长上下文任务可选择保留尾部指令。
9. 学习率
- 核对点:从小范围搜索,不把预训练 LR 直接照搬。
- 常见失败:模型快速学会固定话术但能力回退。
- 观测信号:train/val loss、benchmark regression。
- 边界条件:LoRA 和全参微调尺度不同。
10. epoch 数
- 核对点:少量 epoch 起步,观察验证集和人工样本。
- 常见失败:多轮后输出越来越同质化。
- 观测信号:epoch-wise eval、distinct n-gram。
- 边界条件:高质量小数据可更快过拟合。
11. 数据混比
- 核对点:通用能力数据、安全数据、领域数据要有明确比例。
- 常见失败:领域数据压过通用指令能力。
- 观测信号:mixture weights、per-domain eval。
- 边界条件:比例是产品选择,不是普适常数。
12. 蒸馏偏差
- 核对点:教师模型风格会被学生复制。
- 常见失败:学生学会教师口癖和拒答习惯。
- 观测信号:style classifier、manual review。
- 边界条件:蒸馏不等于获得教师真实能力。
13. 安全样本
- 核对点:有害请求的拒答和安全替代建议需单独设计。
- 常见失败:模型把所有敏感词都拒绝。
- 观测信号:refusal precision/recall。
- 边界条件:安全策略要和法律与产品规则一致。
14. 代码数据
- 核对点:代码 SFT 要保留缩进、fence 和语言标签。
- 常见失败:生成代码缺少闭合块或错误缩进。
- 观测信号:syntax pass rate。
- 边界条件:不要把不可授权代码混入训练。
15. 评测集污染
- 核对点:训练数据不能包含后续报告的评测题答案。
- 常见失败:benchmark 分数虚高。
- 观测信号:contamination scan。
- 边界条件:公开数据很难完全排除污染。
九、常见误区
- 把 SFT 当成知识注入。SFT 主要改变行为分布,事实知识更多来自预训练和检索。
- 把模板当成可有可无。模板变化会改变 token 序列,也会改变模型学到的条件分布。
- 把更多数据等同于更好。低质量合成数据会把模型拉向教师偏差和格式噪声。
- 只看 loss。SFT loss 下降不能保证指令遵循、安全或推理能力提升。
十、数据审计与调参清单
1. 角色边界
- 观察:system、user、assistant 的 token span 可追踪。
- 风险:模型学习预测用户输入。
- 处置:模板解析返回显式 span。
2. mask 单测
- 观察:固定样本的 labels 中 prompt 全为 -100。
- 风险:loss 看似下降但监督对象错了。
- 处置:为每种模板写 golden case。
3. EOS 策略
- 观察:训练和推理使用同一终止符。
- 风险:回答不停或提前截断。
- 处置:统计 EOS 命中率。
4. 样本质量
- 观察:人工抽样看事实性、结构和安全性。
- 风险:高噪声数据把模型拉向平均话术。
- 处置:设定数据准入清单。
5. 蒸馏来源
- 观察:记录教师模型和生成参数。
- 风险:无法解释风格偏差来源。
- 处置:把 teacher/version 写入 metadata。
6. 自指令过滤
- 观察:去除无意义、重复或不可回答指令。
- 风险:模型学会空洞泛化。
- 处置:用规则与人工抽检结合。
7. Alpaca 风格
- 观察:识别合成指令里的固定口吻。
- 风险:模型回答同质化。
- 处置:混入多来源风格。
8. LIMA 启示
- 观察:优先提高示范质量和覆盖。
- 风险:把论文误读成越少越好。
- 处置:用小高质集做 ablation。
9. 学习率搜索
- 观察:至少比较几个数量级附近的配置。
- 风险:单次失败被误判为数据问题。
- 处置:保留小规模 pilot。
10. epoch 选择
- 观察:按验证集和人工样例决定停止。
- 风险:训练越久越模板化。
- 处置:每 epoch 保存 checkpoint。
11. packing 边界
- 观察:不同样本之间不共享监督上下文。
- 风险:模型利用上一条答案预测下一条。
- 处置:检查 attention block。
12. 截断审计
- 观察:记录 response 被截断比例。
- 风险:训练大量残缺答案。
- 处置:调整 max length 或过滤长样本。
13. 领域混比
- 观察:按产品场景设置数学、代码、写作、安全比例。
- 风险:某领域数据压制通用能力。
- 处置:分桶评测。
14. 安全拒答
- 观察:拒答应给安全替代信息。
- 风险:模型只会生硬拒绝。
- 处置:评测拒答质量而非仅拒答率。
15. 代码格式
- 观察:保留代码块语言标签和缩进。
- 风险:生成代码难以复制运行。
- 处置:语法检查抽样。
16. 事实样本
- 观察:对含事实断言的示范做来源审核。
- 风险:模型学到过期或错误事实。
- 处置:保留引用或生成时限说明。
17. 多轮对话
- 观察:决定训练全部 assistant 轮还是最后一轮。
- 风险:上下文行为不稳定。
- 处置:记录轮数分布。
18. 工具样本
- 观察:action、observation、final answer 分开标记。
- 风险:模型把观察结果当成可生成文本。
- 处置:工具模板单测。
19. LoRA 配置
- 观察:rank、alpha、target modules 影响容量。
- 风险:容量不足只学表层格式。
- 处置:比较全参或更高 rank pilot。
20. 评测污染
- 观察:训练样本近似 benchmark 题。
- 风险:离线分数虚高。
- 处置:做 n-gram 和 embedding 去重。
21. 验证样本
- 观察:保留人工高质量验证集,不参与训练。
- 风险:只看训练 loss 误判质量。
- 处置:每轮微调后固定抽检。
22. 回答风格
- 观察:明确简洁、详细、学术或产品语气。
- 风险:多来源数据风格互相拉扯。
- 处置:按风格标签采样或过滤。
23. 拒答模板
- 观察:拒答不能只复制固定句式。
- 风险:安全回答机械且无帮助。
- 处置:加入多样化安全替代答案。
24. 数学数据
- 观察:推理步骤和最终答案都要检查。
- 风险:模型学到漂亮但错误的推导。
- 处置:用 verifier 或专家抽样。
25. 摘要数据
- 观察:控制摘要长度和事实覆盖。
- 风险:模型学会遗漏关键信息。
- 处置:用源文档一致性评估。
26. 写作数据
- 观察:区分润色、改写、续写和创作。
- 风险:模型混淆任务边界。
- 处置:在 instruction 中写清任务类型。
27. 工具调用
- 观察:训练 action 时 mask 只覆盖应由模型生成的字段。
- 风险:模型生成 tool result。
- 处置:把 tool result 作为上下文而非标签。
28. 多轮记忆
- 观察:检查模型是否正确引用前文。
- 风险:多轮 SFT 只学最后一句格式。
- 处置:构造跨轮依赖样本。
29. 负样本缺口
- 观察:SFT 没有直接告诉模型什么更差。
- 风险:后续偏好阶段必须补齐比较信号。
- 处置:把 SFT 定位为初始化。
30. checkpoint 选择
- 观察:不要只选最低 loss checkpoint。
- 风险:低 loss 可能对应模板过拟合。
- 处置:结合人工评测与下游任务。
31. 混合精度
- 观察:bf16/fp16 设置影响稳定性。
- 风险:溢出导致 loss spike。
- 处置:记录 scaler、grad norm 和 NaN。
32. 可复现性
- 观察:保存 tokenizer、模板、数据顺序和 seed。
- 风险:无法复刻 SFT 初始化。
- 处置:把训练配置视为模型资产。
十一、参考资料
- Chunting Zhou et al. “LIMA: Less Is More for Alignment”. NeurIPS 2023.
- Yizhong Wang et al. “Self-Instruct: Aligning Language Models with Self-Generated Instructions”. ACL 2023.
- Rohan Taori et al. “Alpaca: A Strong, Replicable Instruction-Following Model”. Stanford CRFM 2023.
- Long Ouyang et al. “Training language models to follow instructions with human feedback”. NeurIPS 2022.
← 上一篇:06|后训练全景 | 下一篇:08|奖励模型 →
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【强化学习与大模型后训练】06|后训练全景:SFT → RM → RLHF → 评测
把现代后训练拆成数据、目标函数、采样、奖励和评测组成的系统流水线,说明每一阶段改变模型的哪一部分。
【强化学习与大模型后训练】01|系列总览:从 RL 到 LLM 后训练的地图
把强化学习到大模型后训练的主线压成一张可阅读地图,区分风格对齐与能力激发,并说明 20 篇文章的依赖关系。
【强化学习与大模型后训练】02|MDP、回报与贝尔曼方程
用面向语言模型的最小强化学习集合定义 MDP、回报、价值、优势和贝尔曼方程,并解释 token 级与序列级建模的差异。
【强化学习与大模型后训练】03|策略梯度与 REINFORCE
从期望回报出发推导策略梯度与 REINFORCE,解释 log-derivative trick、基线降方差,以及它们在语言模型后训练中的含义。