监督微调
Supervised Fine-Tuning
SFT 通常指:用一批高质量的“输入—输出”示范数据,对已经预训练好的语言模型继续做监督学习。
如果用 LLM 语境里更常见的话说,它经常就是 instruction tuning 或 chat fine-tuning:模型不再只是学“下一个 token 在互联网语料里最可能是什么”,而是开始学“面对这样的指令或对话历史,什么样的回答才是期望输出”。
所以一句话可以概括成:
SFT 是把预训练模型从“会续写文本”,推到“更会按要求回答”的那一步。
为什么需要 SFT
预训练阶段优化的是 next-token prediction。这个目标当然很重要,因为它让模型学会语言、知识、模式和推理的基础能力;但它并不天然等于“用户想要什么回答”。
例如,用户问一个问题时,真正想要的通常不是“最像互联网延续”的文本,而是:
- 能直接回答问题;
- 愿意遵循格式;
- 能区分 system / user / assistant 的角色;
- 在问答、总结、翻译、代码解释等任务上给出更像助手的输出。
SFT 的作用,就是用示范数据把这些“助手行为”显式教给模型。
回顾:它和预训练的关系
从数学上看,SFT 并没有发明一个全新的训练目标。
设输入是
对数化以后就是
所以 SFT 最常见的损失就是负对数似然,也就是 teacher-forcing cross-entropy:
这说明:
SFT 不是把语言模型从“生成模型”变成别的东西,而是继续用生成式目标训练,只不过训练数据换成了更贴近助手行为的样本。
数据
最简化的写法,SFT 数据就是一对
其中
在实际 LLM 里,
- 单轮指令,例如
(instruction, output); - 带补充上下文的样本,例如
(instruction, input, output); - 多轮对话,即过去若干轮
system / user / assistant的历史加上当前用户输入; - 某些带工具调用、结构化格式、JSON 输出约束的序列。
但不管外表怎么变,最后都会被序列化成一个因果语言模型能读的 token 序列。也就是说,工程上看起来格式很多,训练时本质上仍然是:
给定前缀,预测接下来的目标回答 token。
一个更贴近实现的写法
很多时候,训练样本不会只保留“回答部分”,而是把整段序列都拼起来。设拼接后的序列是
那么一个更一般的 SFT 损失可以写成
其中
这条式子非常重要,因为它把很多工程细节都统一了。
- 如果所有 token 都参与损失,那么
; - 如果只想让 assistant 的回答部分参与损失,而不让 system / user / prompt 部分参与,那么就在这些位置把
设成 0。
所以很多人说“只在 response tokens 上算 loss”,本质上说的就是这条 mask 公式。
为什么很多实现只在回答部分算 loss
一个很常见的做法是:
- prompt / instruction / user tokens 作为条件输入;
- assistant response tokens 才真正参与 loss。
这样做的直觉是:模型的任务是“根据前面的指令和上下文,生成回答”,而不是把用户问题也背下来。
于是常见实现会把用户侧 token 的损失 mask 掉,只保留回答侧 token 的监督信号。
不过这件事并不是铁律。最近也有工作专门研究:如果把 instruction 部分也纳入损失,会不会在某些任务上更好。所以更准确的说法是:
“只在输出 tokens 上算 loss” 是常见工程约定,但不是不可动的定义本身。
SFT 到底学到了什么
这是最值得想清楚的一点。
很多人第一次听到 SFT,会误以为它是在“往模型里灌新知识”。这不完全错,但也不够准确。
更稳妥的理解是:SFT 最擅长做的是 把预训练里已经存在的能力,组织成更可调用、更可控、更符合指令接口的形式。
它常见会学到的东西包括:
- 更稳定的回答格式;
- 更明确的任务边界;
- 更强的 instruction-following 倾向;
- 更像助手的语气、结构和拒答风格;
- 对多轮角色结构更敏感的输出方式。
这也是为什么很多工作会观察到:即使只用数量不算夸张、但质量很高的 SFT 数据,也能把模型的“可用性”明显拉上来。
一个很有代表性的现象
像 FLAN 这样的工作说明,把预训练模型在大量以自然语言指令表述的任务上做 instruction tuning,可以显著改善 unseen tasks 上的 zero-shot 表现。
而 LIMA 则进一步给出了一个非常有代表性的结论:只用 1000 条 carefully curated 的 prompt-response 样本,标准 supervised loss 也能把一个 65B 基座模型调成相当强的对话助手。这类结果常被解读为:预训练学到的大部分知识已经在底座里,SFT 更像是在教模型“怎么把这些能力用助手形式表达出来”。
这里要注意,这不是说 SFT 完全学不到新知识,而是说:
在很多通用助手场景里,SFT 的主要贡献往往不是“从零创造知识”,而是“重塑输出接口、回答风格和任务调用方式”。
SFT 为什么常常有效
SFT 有效,最核心的原因其实很朴素:
它给了模型一个更贴近真实使用方式的数据分布。
预训练语料的分布很广,里面有网页、书、代码、论坛、问答、碎片文本;而 SFT 数据通常更接近“用户提问 — 助手回答”这种使用场景。
因此,哪怕模型结构完全没变,只要训练分布从“开放文本”切到“高质量助手示范”,输出行为就会显著变化。
这也是为什么 SFT 常常先带来这些肉眼可见的变化:
- 回答更收敛;
- 更少乱续写;
- 更会遵守格式;
- 更知道什么时候该回答、什么时候该总结、什么时候该拒答。
SFT 的数据质量为什么比数量更重要
在 SFT 阶段,一个非常常见的经验规律是:
高质量数据通常比单纯堆更多低质量数据更重要。
这并不是说规模不重要,而是说在很多助手场景里,示范数据的风格、正确性、一致性、覆盖面、去重和模板质量,会非常直接地影响模型最终学到的回答习惯。
像 LIMA 和 QLoRA 这类工作,都强化了一个很强的工程直觉:高质量、精心筛选的数据往往能带来非常高的性价比。
全参数 SFT 和参数高效 SFT
从“更新多少参数”来看,SFT 大致有两条常见路线。
第一条是 full fine-tuning,也就是更新模型的大部分甚至全部参数。它的优点是表达能力足,缺点是显存、存储和训练成本都高,而且不同任务各自保存一整份模型也很重。
第二条是 PEFT,也就是参数高效微调。其中最常见的是 LoRA。LoRA 的核心思想是:冻结原模型权重,只在若干层里插入可训练的低秩矩阵,从而大幅减少需要更新的参数量。
如果再往前走一步,就是 QLoRA。它把基座模型量化到 4-bit,并在冻结的量化模型上训练 LoRA adapter,使得大模型 SFT 的门槛进一步下降。
所以今天很多开源 SFT 实践默认说“做 SFT”,实际常常是在说:
用 LoRA 或 QLoRA 对一个 base model 做监督微调。
SFT 不是万能的
虽然 SFT 非常重要,但它并不是“只要做了就什么都会变好”。
有几点最好提前讲清:
第一,SFT 不等于自动获得可靠的新知识。很多能力仍然主要来自预训练。
第二,SFT 学到的可能不只是“更会回答”,也可能是“更像训练集”。如果训练数据风格单一、答案模板化严重,模型也可能被拉得更模板化。
第三,SFT 可能改变 base model 原本更开放的输出分布。换句话说,它通常会增强“遵循性”,但有时也会牺牲一部分自由生成时的开放性和多样性。
第四,一些近期分析指出,在某些开放数据设定下,instruction tuning 的主要收益更接近风格和 response initiation,而不是显著增强知识本身;并且全参数 fine-tuning 在某些实验里可能带来知识退化或更高幻觉率。因此,讨论 SFT 的效果时,最好把“模型规模、数据质量、训练方式、是否 LoRA、是否 full FT”分开看。
总结
它说明了 SFT 的本质:
- 给定输入
; - 让模型把目标回答
的每个 token 概率都尽量拉高; - 通过大量高质量示范,把模型推向我们想要的回答方式。
更工程实现的写法:
SFT 的本质,不是发明了一种和预训练完全不同的新学习范式,而是把标准的语言模型条件似然目标,应用在更高质量、更贴近“用户 — 助手”交互的数据上。
因此,它最擅长做的事情通常不是“重新发明模型的知识”,而是把预训练中已经存在的能力重新组织起来,让模型更会遵循指令、更会按格式输出、更像一个稳定可用的助手。
SFT = 用高质量示范数据,教预训练模型学会“怎么回答”。