SFT 指令微调
从“会续写”到“会回答”
M3 给了我们一个懂语言但不懂对话的模型。这一节把它变成助手。
预训练模型的问题不是笨,而是不知道该干嘛。它只学过“预测下一个词”,所以你写“今天天气”,它接“真好”;你问“今天天气怎么样?”,它可能接“这个问题问得好呀”——因为在它见过的语料里,问句后面经常跟着这种话。
SFT 用一批人写的“问-答”示范,通过和 M3 完全一样的“预测下一个词”训练方式,让模型学会:看到问题,就该给出回答。
上游: M3 的预训练模型(只会续写)。
本节: 用“指令-回答”数据做监督微调,教它对话的格式和“回答问题”这个行为。
下游: M5 用强化学习,突破 SFT 教不了的东西(更符合人类偏好、更会推理)。
SFT 到底在教什么?
一个反直觉但极其重要的结论,决定了后面所有的做法。
最容易的误解是:SFT 在给模型“灌新知识”。错。
有一篇叫 LIMA 的研究把这件事推到了极致:只用 1000 条精心挑选的问答示范做 SFT(不用任何强化学习),效果就能逼近顶尖模型;而另一个用了 52 倍数据的模型反而更差。
结论:模型的知识几乎全部在预训练(M3)就学好了。SFT 只是在教“表层行为”——用什么格式、以什么角色、回答还是续写。 因为知识早就有了,重塑行为不需要很多数据。这一条同时解释了三件事:为什么预训练模型只会续写、为什么 1000 条就够、以及为什么 SFT 有天花板(改不了知识和推理能力,所以才需要 M5 的 RL)。
两件必须做对的事:模板对齐 + loss mask
SFT 的训练方式和 M3 一模一样,但有两个“不报错却会毁掉结果”的细节。
一、对话模板(chat template)
预训练数据是纯文本,但对话有结构:谁是系统提示、谁是用户、谁是助手。模型靠一套特殊 token来区分这些角色,比如 Qwen 用 <|im_start|>user ... <|im_end|>。
麻烦在于:每个模型的特殊 token 都不一样,且没有统一标准。用错模板,模型不会报错,但会“静默变笨”——这是 SFT 最容易踩的坑。下面的工具让你切换不同模型,看同一段对话被套上多不一样的模板。
二、loss mask(−100)
SFT 数据里既有用户的话,也有助手的话。但训练时只对助手的回复算 loss,用户那部分的 label 全设成 −100(忽略)。
为什么?因为模型的学习容量有限。让它去学“预测用户会问什么”是浪费——用户问什么是用户的事。只教它该怎么回答。写成公式,SFT 和 M3 预训练的差别只有一个求和范围:
下面的工具打开“显示 loss mask”,绿底的就是真正参与训练(进入上面那个 Σ)的部分。
上面是模板的示意。下面加载真实的 Qwen 词表(离线版改用站内自带的 Qwen3.8 词表,与 Qwen2.5 一样用 ChatML 模板)验证一件关键事实:<|im_start|> 这一整串 12 个字符,在 Qwen 的词表里是一个特殊 token(单一 id)——而在没学过这个模板的 GPT-2 词表里,它会被拆成一堆碎片。这就是”模板必须和模型配套”在词表层面的物理原因。
看什么: ① Qwen 里 <|im_start|> 是单个 token(一个 id);② 同一串字符 GPT-2 拆成 6~8 块——它根本不认识这个模板;③ 对照”普通文本”预设:去掉 <| |> 包装后,Qwen 也把它当普通词拆——特殊 token 是词表里显式注册的,不是模型”猜”出来的。
🔍 一个经典陷阱:base 模型停不下来
拿 Qwen 这类 base 模型做 SFT 时,如果不把结束符 EOS 对齐成模板里的 <|im_end|>,模型就不知道什么时候该停,会无限生成下去。这是“模板不匹配”杀伤力的典型例子——TRL 文档专门拿它当教学案例。
怎么省着教:LoRA
既然只是重塑行为、数据也不多,那能不能不动整个模型?能——LoRA。
全量微调要更新模型所有参数,显存和存储都很贵。LoRA 的洞察是:微调时的权重更新其实是低秩的——不需要动整个 d×d 的大矩阵,用两个瘦长矩阵 B、A 的乘积去逼近就够了。它的前向计算就一行:
冻结原权重,只训 B 和 A,可训练参数能降几个数量级。
下面这个计算器让你调模型维度、LoRA 秩 r、层数,实时看可训练参数从“全量”掉到“LoRA”是多大的差距——这就是初中数学,比任何黑盒工具都可靠。
d×d
❄️ 冻结
关于 rank r 的取舍,有一段值得看的认知演进:2024 年的结论是“LoRA 学得少、也忘得少”(换新知识不如全量微调,但更能保住原能力);2025 年 John Schulman 团队复现后修正为“配置对了,LoRA 能追平全量微调”——关键是要用在所有权重矩阵上、而不只是注意力层,且该用更高的学习率。同一个问题的认知在两年里演进,比背一个静态答案有价值得多。
把我们的模型微调成助手
记住分工:代码 AI 来写,关键决策你来做。
本模块的项目任务单
| 步骤 | 你的决策 / 动作 | 说明 |
|---|---|---|
| 1. 准备数据 | 找/造几千条“指令-回答”,重质不重量 | LIMA 的教训:质量 > 数量 |
| 2. 定对话模板 | 用 M1 分词器配套的 chat template | 对齐 EOS token,否则停不下来 |
| 3. 开 loss mask | assistant_only_loss=True | 只对助手回复算 loss |
| 4. 选微调方式 | LoRA(省显存)或全量 | 小模型全量也扛得住;大模型用 LoRA |
| 5. 让 AI 写训练 | 用 TRL 的 SFTTrainer | 核心是看懂它的 loss 计算,不是当黑盒 |
| 6. 验收 | 问它问题,看它回答而不是续写 | 从“续写机”变“助手”就成功了 |
SFT 的天花板: 它能教格式和行为,但改不了模型的知识和推理上限。你会发现微调后的模型“会好好回答了”,但遇到需要多步推理、或需要更贴合人类偏好的场景,它还是差口气。这正是 M5 强化学习要解决的——也是为什么 InstructGPT 在 SFT 之后还要加一整套 RLHF。
常见的坑 + 该带走的
| 坑 | 症状 | 怎么办 |
|---|---|---|
| 用错 chat 模板 | 不报错,模型静默变笨 | 用模型配套的模板 |
| base 模型没对齐 EOS | 模型无限生成停不下来 | 设 eos_token 对齐模板结束符 |
| 没开 loss mask | 浪费容量学“预测用户输入” | assistant_only_loss=True(并确认模板含 generation 关键字) |
| 以为 SFT 灌知识 | 拼命堆数据量 | 知识在预训练就有了,SFT 重质不重量 |
| LoRA 只用在注意力层 | 效果明显不如全量 | LoRA 要用在所有权重矩阵上 |
| SFT 多轮次猛训 | 过拟合,性能反降 | Raschka 实测:多轮次弊大于利 |
这一模块你应该带走的
- SFT 教的是行为不是知识:LIMA 用 1000 条打赢 52 倍数据——重质不重量;
- chat template 没有统一标准,用错不报错、模型静默变笨(silent failure);
- 特殊 token 是词表里显式注册的——你在真实验里亲眼看过
<|im_start|>在 Qwen 是一个 id; - loss mask = 把 user token 的 label 设 −100:只教”怎么回答”,不浪费容量学”用户会问什么”;
- base 模型必须对齐 EOS,否则停不下来;
- LoRA 的地基是低秩假设:只训 2rd 而非 d²;要用在所有权重矩阵上;
- SFT 有天花板:改不了知识和推理上限——这是 M5 存在的理由。
概念索引(本模块登场): SFT 监督微调 · 指令数据 · chat template · 特殊 token · silent failure · loss mask · −100 ignore · EOS 对齐 · LIMA · 表层行为 vs 知识 · LoRA · 低秩 · 秩 r · QLoRA · NF4 · SFT 天花板
有不明白的? 随时在对话里问我,我会记到 05-问答记录/M4-SFT-问答.md。
想往下钻,按你愿意花的时间选
坦率提醒:这个主题中文深度资源稀缺,下面以英文一手资料为主。
🎮 想更直观 10–30 分钟
🔬 想吃透原理 1–3 小时
📄 想读原文 按需
我替你排除了什么: B站 12 分钟速通微调 · CSDN 同质化转载 · 知乎结论罗列 · 各类 LoRA 显存计算器(来源不可信,且不少是给 Stable Diffusion 图像 LoRA 的,不是 LLM)。
另注:B站「LoRA 发明者亲自解读」其实是 Edward Hu 的 YouTube 搬运,中文标题有误导;这个主题没找到能通过筛选的中文深度视频——所以本页的模板/mask/LoRA 三个概念,中文深度内容基本是课程自己产出的。