一、SFT 到底是什么?—— 让预训练模型学会“说人话”

各位同学好,我是你们的老朋友。今天咱们聊聊 SFT,也就是监督微调。

说实话,我刚接触这个领域时,也觉得 SFT 不就是“拿标注数据再训一训”嘛,有啥好讲的?但后来踩了不少坑才发现,这里面的门道比想象中深得多。

先问大家一个问题:预训练模型已经很强了,为什么还要做 SFT?

你想想看,像 LLaMA、ChatGLM 这些大模型,预训练阶段学的是“海量文本的统计规律”。它能续写句子,能填空,但你要它“像个助手一样回答问题”——嗯,它还真不会。

举个例子:

  • 预训练模型看到“中国的首都是”,它会接“北京”。这没问题。
  • 但如果你问“请用三句话介绍北京”,它可能给你写一篇论文出来。

说白了,预训练模型是个“知识渊博但不懂规矩”的天才。SFT 要做的,就是教会它“对话的规矩”。

SFT 的核心目标:让模型从“续写模式”切换到“对话模式”。

具体来说,就是让模型学会:

  • 理解指令的意图(是问答、总结还是翻译?)
  • 遵循输出格式(列表、段落、JSON?)
  • 保持角色一致性(你是助手,不是用户)

二、SFT 的原理:其实就是在做“条件概率对齐”

从数学角度看,SFT 的原理并不复杂。

预训练阶段,模型学的是 P(x)——也就是文本本身的概率分布。而 SFT 阶段,我们要学的是 P(y|x)——给定输入 x(比如用户问题),输出 y(比如助手回答)的条件概率。

我习惯用一个比喻来理解:

  • 预训练 = 让模型读完了整个图书馆的书
  • SFT = 告诉模型“当别人问你问题时,你应该这样回答”

具体实现上,SFT 就是拿一批 (指令, 回答) 对,让模型去拟合这些回答。损失函数用的是交叉熵,后面会细讲。

一个小经验:我在项目中遇到过,SFT 数据量不是越多越好。有时候 1 万条高质量数据,效果比 10 万条噪声数据好得多。质量 > 数量,这句话在 SFT 里是铁律。

三、预训练模型怎么选?—— LLaMA vs ChatGLM 的实战对比

选基座模型,是 SFT 的第一步。我见过不少团队,模型选错了,后面怎么调都白搭。

目前主流的选择就两个方向:LLaMA 系列ChatGLM 系列。我分别说说我的看法。

3.1 LLaMA:开源社区的“标准答案”

LLaMA 是 Meta 开源的模型,现在已经是事实上的行业标准了。为什么大家都爱用?

  • 生态好:HuggingFace 上几乎所有的工具、微调框架都优先支持 LLaMA
  • 可扩展性强:从 7B 到 70B,参数量选择多
  • 社区活跃:遇到问题,搜一下基本都有解决方案

但 LLaMA 有个硬伤——中文能力偏弱。毕竟它的预训练数据里英文占了绝大多数。如果你要做中文对话系统,直接用 LLaMA 效果会打折扣。

避坑指南:我曾经直接用 LLaMA-7B 做中文 SFT,结果模型连“你好”都回不利索。后来加了中文继续预训练,才勉强能用。所以,中文场景慎用原生 LLaMA

3.2 ChatGLM:中文场景的“本土选手”

ChatGLM 是智谱 AI 开源的模型,中文能力天然强。我个人的经验是:

  • 中文理解力好:成语、俗语、古诗词,基本不在话下
  • 部署友好:6B 的模型,一张 3090 就能跑推理
  • 对话风格自然:预训练阶段就做了对话优化

但 ChatGLM 也有缺点:英文能力一般,且社区生态不如 LLaMA 丰富。有些最新的微调工具,可能不支持 ChatGLM。

3.3 我的选择建议

场景 推荐模型 理由
纯中文对话 ChatGLM-6B 中文能力强,开箱即用
中英混合 LLaMA-2-7B + 中文继续预训练 平衡中英文能力
需要高可控性 LLaMA-2-13B 参数量大,微调后效果上限高
资源有限 ChatGLM-6B 或 Qwen-7B 显存占用小,训练成本低

补充一句:现在阿里开源的 Qwen 系列也值得关注。它在中文和英文上表现都不错,而且支持 8K 上下文。我最近几个项目都在用 Qwen,效果挺稳的。

四、SFT 的损失函数:交叉熵到底在算什么?

好,到了最核心的部分——损失函数。

SFT 用的损失函数就是 交叉熵损失(Cross-Entropy Loss)。公式长这样:

L = - Σ y_true * log(y_pred)

别被公式吓到,我用人话解释一下:

  • y_true 是真实答案中每个 token 的 one-hot 编码
  • y_pred 是模型预测的每个 token 的概率分布
  • 交叉熵衡量的是“模型预测分布”和“真实分布”之间的差距

说白了,损失函数就是在惩罚“模型猜错”的行为。模型预测的概率越接近真实答案,损失就越小。

4.1 为什么用交叉熵,不用 MSE?

这个问题我面试时经常问。答案是:分类问题天然适合交叉熵

  • MSE(均方误差)对概率值的差异不敏感
  • 交叉熵对“低概率高损失”非常敏感——模型一旦把正确答案预测成低概率,损失会飙升

举个例子:假设正确答案是 token ID 100,模型预测它的概率是 0.1。交叉熵会给出一个很大的损失,逼着模型调整参数。而 MSE 可能觉得“0.1 也不算太差”,更新力度就弱很多。

4.2 实际训练时的注意事项

我在项目中踩过这个坑:损失计算时,要不要忽略 padding token?

答案是:必须忽略

因为我们在 batch 训练时,不同样本的长度不一样。短的样本会 padding 到和长的样本一样长。这些 padding token 没有实际意义,如果把它们也算进损失里,模型会学到“预测 padding 位置”这种无用的能力。

代码实现上,PyTorch 的 CrossEntropyLoss 有个 ignore_index 参数,设成 padding token 的 ID 就行:

loss_fn = nn.CrossEntropyLoss(ignore_index=tokenizer.pad_token_id)

另一个坑:有些同学会把“输入部分”也参与损失计算。比如用户问题“你好吗?”和助手回答“我很好”,如果连“你好吗?”也计算损失,模型会学到“预测用户问题”这种错误行为。记住:只计算“回答部分”的损失

五、一张图看懂 SFT 全流程

说了这么多,我画了一张流程图,帮你把整个 SFT 的脉络理清楚:

SFT 监督微调核心流程 预训练模型 LLaMA / ChatGLM / Qwen SFT 监督微调训练 输入:指令数据对 (instruction, response) 损失函数:交叉熵(仅计算回答部分) 数据准备 清洗 / 格式化 模型选择 参数量 / 架构 SFT 微调后模型 具备对话能力 评估 & 迭代 迭代优化

这张图展示了 SFT 的完整闭环:从预训练模型出发,经过数据准备和模型选择,进入 SFT 训练,得到具备对话能力的模型,最后评估效果并迭代优化。

核心要点回顾:

  • SFT 的目标是让模型学会“对话的规矩”
  • 预训练模型选型要看场景:中文选 ChatGLM,中英混合选 LLaMA 或 Qwen
  • 损失函数用交叉熵,只计算回答部分的损失,忽略 padding token
  • 数据质量比数量更重要

好了,这一章的内容就到这里。SFT 是整个 RLHF 流程的基石,打好这个基础,后面学 RLHF 的奖励模型和强化学习阶段才会更顺畅。下一章我们聊聊 SFT 的数据构建——这可是个技术活,也是我踩坑最多的地方。


专注资料整理