A pedagogical primer · 2026-05

SFT 到底在「修」什么?

你大概听过这样的故事:一个"什么都懂"的大模型,被训练成"什么都会答"的聊天助手。 中间发生了什么?最关键的一步,叫 SFT — Supervised Fine-Tuning,有监督微调

很多教程上来就丢公式、丢代码。我们换一种讲法——先让你亲眼看到它修好的东西, 再一点点往下挖,看看到底是怎么修的。

8 章 · 9 个交互演示 · 阅读约 25 分钟 · 最后更新 2026-05-19

预设读者

会基本的机器学习(知道 loss、梯度下降、神经网络的样子)、 基本的微积分(知道导数是什么)、用过几次 ChatGPT。 不需要懂大模型——我们从直觉讲起,公式只在它真正帮助理解时才出现。

阅读路径建议

完全新手:从 §1 顺序读到 §5,把 §5(掩码)那个交互玩透—— 这一章是整个 SFT 跟普通语言模型训练的全部区别所在。 已经会跑 LoRA:直接跳 §5 验证你的理解, 然后看 §7 关于 LoRA 的几个常见误区。 想看全景:直接跳 §8

§1同一个模型,差一步 SFT,行为天差地别

下面这个对话框,请你随便问点什么——比如"如何做番茄炒蛋?"或者"写一首关于猫的诗"。 左边是没经过 SFT 的"基础模型",右边是经过 SFT 的同一个模型。 它们的权重几乎一样,差别只在于后者多看了几万条"问-答"示范。

Demo 1 · 双子终端:基础模型 vs SFT 模型
Base Model · 未微调
SFT Model · 微调后
两边都是 Llama-2-7B 量级的模型,差别只有「是否经过 SFT」这一步训练。 注意基础模型把你的问题当成了"上文"继续写下去——这正是它被预训练的方式。
关键认知

SFT 给模型添加新知识。"番茄炒蛋"该怎么做、"猫"是什么, 基础模型其实已经全部知道。SFT 只做一件事—— 教模型「在被问问题时,应该给出回答,而不是继续延展问题」。 它教的是交互的格式,而不是世界的知识。

一句话总结

预训练让模型"博览群书",SFT 让模型"学会回话"。这一份讲解,会一步步告诉你后者是怎么做到的。

§2预训练 vs 微调:从汪洋到航道

把一个大语言模型的"全部可能行为"想象成一片权重空间—— 每一个点都是一种"会说话的方式"。 随机初始化的模型像是漂在角落里的一条小船,连句子都说不通顺。

预训练 (Pre-training) 让小船在数万亿 token 的海洋上漂流数月, 最终停在"流畅说话"的大陆上——它能写出语法正确、逻辑连贯的文本。但它不知道自己应该 回答 什么、什么时候 停下。

SFT 让它从这片大陆出发,沿着几千条"问-答"路标,走到一片很小、但很有用 的山头上——那里的模型会"听话"。

Demo 2 · 权重空间地图
预训练步数0
SFT 步数0
移动距离比1 : 1
海拔颜色越深 → 模型"语言能力"越强。橙色山头是"听话区"——只有附近的模型会回答问题。 注意 SFT 的移动距离比预训练小几个数量级。
数量级对比

预训练通常耗费 ~104 GPU·天 + 数万亿 token; SFT 通常只需 ~100 GPU·天 + 几万条样本。 SFT 的成本不到预训练的 1%, 但它带来的"行为改变"对终端用户来说远比"知识增加"明显。 正因为 SFT 这么便宜,2023 年之后,开源社区才能"人手一个 Alpaca"。

"微调"具体在改什么?

最直接的答案:权重。模型里有几十亿个浮点数参数 $\theta$, SFT 通过梯度下降把它们沿着"让训练样本变得更可能"的方向轻轻推一推。 "轻轻"两个字很关键:SFT 的学习率通常只有预训练的 1/10 到 1/100 (典型值 lr ≈ 2e-5),目的是不把预训练学到的语言能力推丢

直觉

预训练塑造能力,微调塑造行为。

§3"监督"从哪来?看一眼真正的训练数据

SFT 全名是 Supervised Fine-Tuning——"有监督的微调"。 "监督" 来自人类(或一个更强的模型)写好的标准答案。 每条训练样本都是一对:(问题, 理想回答)

下面是来自著名的 Stanford Alpaca 数据集的真实样本。点上方按钮切换样本,下方三个标签页给你三种角度看同一条数据

Demo 3 · 数据三视图
第 ③ 个视图最重要——所谓"对话",其实只是一长串字符。橙色高亮的特殊 token 像戏剧的舞台标识,告诉模型"现在该谁说话"。
关键认知

模型本质上只会处理一长串 token——没有"消息"、"角色"或"对话"这些概念。 所谓"chat 模型",只是模型见过足够多 <|im_start|>user...<|im_end|><|im_start|>assistant... 这种模板, 于是学会了"看到 assistant 这个 token,接下来该我说话"。 模板是人为约定,不是模型架构的一部分。换一个模板,重新 SFT,模型就会换种说话方式。

数据格式总览

格式结构适用场景
Alpaca(instruction, input?, output)单轮问答,最简单
ShareGPTconversations: [{from, value}, ...]多轮聊天
ChatML / OpenAI messagesrole: system/user/assistant现代主流,工具调用
一句话总结

数据决定模型学到什么。SFT 的全部"监督信号",都藏在这些 (问, 答) 对里。

§4训练的最小单位:预测下一个 token

无论是预训练还是 SFT,大模型的"学习"全部归结为一件事: 给定前面已经出现的 token,预测下一个 token 是什么。

每一步,模型对词表里 每个 token 都会输出一个"概率"。 我们希望"正确那个 token"的概率尽可能高。差距用 交叉熵损失 (cross-entropy loss) 来度量:

$$ \mathcal{L} = -\log P_\theta(\text{正确 token} \mid \text{前文}) $$

这个公式直白得令人意外:"惊讶度"就是损失。 模型给"对的答案"分配的概率越低 → 它越"没想到" → 损失越大 → 梯度越大 → 参数被推得越狠。 点击下方按钮,一步步看:

Demo 4 · 逐 token 显微镜
模型对下一个 token 的概率分布(简化为 8 个候选词)
本步损失
每个 token 的损失加起来 / 平均一下,就是一条样本的整体损失。 一个 batch 的损失再平均,就是优化器看到的最终数字。
关键认知

"训练"听起来很神秘,但放到最小单位,就只是一遍又一遍地"猜下一个 token + 看错多少 + 调一下参数"。 预训练这么干、SFT 也这么干、RLHF 之前的所有阶段都这么干。 唯一的区别是谁来决定"正确答案"——预训练用网上抓来的原文,SFT 用人类写的回答。

§5SFT 的灵魂:只对"回答"算损失

到现在我们说的"训练",对预训练和 SFT 都成立。那 SFT 究竟特殊在哪?

答案藏在一个不起眼的技术细节里:训练时,只对"回答"部分计算损失, 而忽略"问题"部分。在代码里,这通过把问题对应 token 的 label 设为 -100 (PyTorch 默认的 ignore_index)实现。

这个"小技巧"决定了 SFT 的全部精神气质。下面让你亲眼看到差别:

Demo 5 · 掩码 vs 不掩码:训练信号去向
绿色 = 参与损失(label 是真实 token);灰色 = 被忽略(label = -100);橙色 = 模板特殊 token。
为什么这是 SFT 的灵魂

如果不掩码,模型会努力"也学会生成问题"——浪费一半学习容量在你不想要的能力上。 更糟的是,被训练去"预测问题"的模型,在推理时会倾向于继续延展用户输入, 而不是回答它。这就是为什么 §1 里基础模型把"如何做番茄炒蛋"当成上文继续写下去的根因—— 它从没学过"问题之后应该有回答"。

把整个 SFT 压缩成一句话

同样的损失函数、同样的优化器、同样的数据,只是 label 上多了一层 -100 的掩码—— 就把"语言模型"变成了"对话助手"。这就是 SFT。

§6把一切串起来:训练循环与超参数

现在你已经知道损失怎么算了。剩下的就是把它最小化。 SFT 的训练循环用伪代码看是这样:

for epoch in range(num_epochs):
  for batch in dataloader:           # 一批 (prompt, response)
    logits = model(batch.input_ids)
    loss   = cross_entropy(
      logits[:, :-1], batch.labels[:, 1:],
      ignore_index=-100           # ← 这就是掩码!
    )
    loss.backward()                     # 反向传播算梯度
    optimizer.step()                    # AdamW 更新权重
    scheduler.step()                    # 学习率衰减
    optimizer.zero_grad()

剩下的就是调超参数。下面这个模拟器让你亲手"调坏"训练—— 通过失败学习什么样的超参数才合理:

Demo 6 · Loss 曲线模拟器
2e-5
16
3
10K
一键尝试常见错误:
调一下左侧滑块,观察 loss 曲线变化。
青绿线 = 训练 loss;橙线 = 验证 loss。验证集是训练时不让模型看到的样本,用来检测过拟合。
实战取值(社区共识,7B 模型)
  • 全参数 SFT:lr ≈ 2e-5,cosine 衰减 + 3% warmup
  • LoRA 微调:lr ≈ 1e-4 ~ 2e-4(因为只动很少参数,可以激进点)
  • Epochs:3 次是默认起点,少于 1 通常欠拟合,多于 5 易过拟合
  • Batch size:尽可能大(用 gradient accumulation 凑),有效 batch 32~128 常见

§7显存救星:LoRA & QLoRA

一个 7B 模型的全参数 SFT,至少需要 ~110 GB 显存 (权重 + 梯度 + 优化器状态都是 fp32 时)。消费级 GPU(24 GB)想都别想。怎么办?

LoRA(Low-Rank Adaptation,2021 年微软提出)的核心赌注是: 微调时的权重变化 $\Delta W$ 本身是"低秩"的—— 它的大部分信息可以用一个非常小的子空间表达。

$$ W_{\text{new}} = W_0 + \Delta W \approx W_0 + B \cdot A $$

其中 $W_0$ 是冻结的原始权重(不动),$A \in \mathbb{R}^{r \times k}$、$B \in \mathbb{R}^{d \times r}$ 是要训练的"小矩阵",秩 $r \ll \min(d,k)$。我们只训练 $A$ 和 $B$ —— 参数量瞬间锐减。 拖动下方滑块感受这个"省了多少":

Demo 7 · 矩阵分解工坊
$W_0$   $100 \times 100$
(冻结)
+
$B$   $100 \times r$
·
$A$   $r \times 100$
8
全参数微调
10,000
个可训练参数
LoRA 微调
1,600
个可训练参数
节省 84.0%
真实模型里 $W_0$ 是 $4096 \times 4096$ 量级,LoRA($r=16$) 把 1700 万参数压成 13 万个—— 但 $B \cdot A$ 仍然能影响整个 $4096 \times 4096$ 矩阵。(图中用 $20\times 20$ 网格代理 $100\times 100$)
QLoRA 更狠

2023 年的 QLoRA 论文 把 $W_0$ 4-bit 量化后冻结,只用 fp16 训练 LoRA 适配器。 最终:一块 48 GB 的 GPU 能 SFT 一个 65B 的模型。 个人/学生也能玩得起的大模型微调,几乎全靠 LoRA / QLoRA 撑起来。

常见超参数

参数典型值说明
rank $r$8 / 16 / 32 / 64风格微调 8;通用 SFT 16~32;代码/复杂任务 64+
alpha $\alpha$α = 2r前向时贡献缩放为 $\frac{\alpha}{r} BAx$
target_modulesall-linear最低 q/v 即可,现代实践全连接层都加
lr1e-4 ~ 2e-4比全参 SFT 高一个量级

§8SFT 在大模型训练流水线里的位置

你已经懂 SFT 是怎么回事了。最后把它放回大图景里——它是对齐的第一步, 但远不是最后一步。

Demo 8 · LLM 训练流水线(点击查看详情)

点击上方任一阶段

每个阶段在数据量、算力、目标上都有数量级差异。
这条流水线由 InstructGPT (2022) 确立、ChatGPT 大规模验证。 所有现代对话模型(GPT-4、Claude、ChatGLM、Llama-Chat、Qwen-Chat)都是这套流水线的变种。
SFT 是基石

没有一个好的 SFT 模型,后面的 RLHF / DPO 都救不回来—— 因为它们都用 SFT 模型作为初始化参考分布(KL 散度的 anchor)。 工业界一句通行说法:"SFT 决定模型能力的上限,RLHF 决定下限"。

SFT 名人堂时间线

2023 年的"开源大模型寒武纪大爆发",几乎完全由 SFT 数据集驱动。下面这些工作每一个都值得了解:

Demo 9 · SFT 名人堂
y 轴是数据量(对数刻度)。注意 LIMA——它只有 1000 条手写样本, 却逼近百万级数据训练的模型。这是 SFT 圈最知名的"少即是多"案例。

带着 SFT 视角看新闻

读到下面这些说法时,你现在应该能"看穿"它们在说什么:

  • "我们用 1 万条高质量数据微调出了一个客服机器人" → 在做 SFT,大概率用了 LoRA。
  • "模型出现幻觉/输出不稳定" → SFT 数据里有低质样本,或 epoch 太多过拟合。
  • "我们的模型是某基础模型的 chat 版本" → 在基础模型上做了 SFT(+ 可能的 RLHF)。
  • "灾难性遗忘" → SFT 数据太偏,把预训练的通用能力"覆盖"掉了。
最后一句

SFT 不教模型新知识,它教模型如何调用已有的知识。 短短一句话总结了为什么它便宜、为什么它有效、也为什么它需要后续的 RLHF 来更进一步。 —— 这就是 SFT。

§A阅读清单