SFT 微调指南
🍋🍋AI学习🍋🍋🔥系列专栏:
👑哲学语录: 用力所能及,改变世界。
💖如果觉得博主的文章还不错的话,请点赞👍+收藏⭐️+留言📝支持一下博主哦🤞
如果你用过 ChatGPT 或任何大模型产品,可能会有一种错觉:模型什么都会。但把一个基座模型变成能听懂指令、按格式输出、在特定领域靠谱的助手,中间隔着最关键的一步——监督微调(Supervised Fine-Tuning,SFT)。
这篇文章从零开始,逐层深入:先讲 SFT 在做什么,再讲数据怎么准备,然后讲 LoRA 为什么成了标配,最后聊几个容易被忽略的深层问题。无论你是刚接触微调,还是已经跑过几次训练脚本,应该都能找到有用的部分。
SFT 到底在干什么
基座模型是在海量文本上训练出来的。它学会了预测下一个词,但不知道“用户提问时应该怎么回答”。你给它一段“法国的首都是”,它会续写“巴黎,一座历史悠久的城市……”;你给它“帮我写一封请假邮件”,它可能会接着续写出更多类似的句子,而不是真的写一封邮件。
SFT 做的事情,就是用成对的“指令-理想回答”数据,把基座模型“续写文本”的习惯,扭转成“回应指令”的习惯。数据长这样:
{"messages": [
{"role": "system", "content": "你是一个简洁的客服助手。"},
{"role": "user", "content": "我的订单显示已签收但我没收到。"},
{"role": "assistant", "content": "抱歉给您带来不便。请提供订单号,我帮您核查物流详情。"}
]}
训练时,模型看到 system 和 user 的内容,被要求生成 assistant 的内容。Loss 计算只针对 assistant 部分。反复看几千到几万条这样的例子后,模型就学会了“看到这类输入,应该输出这类回答”。
这里有一个容易被忽略的点:SFT 教的是“格式和风格”,不是“知识”。模型在 SFT 中学会的是“回答客服问题时应该先道歉再询问订单号”,而不是“订单号应该怎么查”。知识在预训练阶段就已经存在了,SFT 只是把它引导出来。如果你的领域知识是模型从未见过的(比如公司内部产品文档),单靠 SFT 效果有限,可能需要继续预训练(CPT)来补充知识。
数据质量
个人认为SFT最重要的部分
跑通 SFT 训练脚本只需要十分钟。做出一个真正有用的模型,大部分时间花在数据上。
微软的文档给出了 SFT 数据的五个质量标准,值得逐条对照:
一致性。每个示例都演示你要强化的那个行为。如果你的客服助手有时先道歉再问订单号,有时直接问订单号,有时又先解释政策——训练出来的模型也会随机切换风格。
准确性。一条错误示例的破坏力远超你的想象。在冬季装备推荐数据里混入一条“推荐夏季帐篷用于雪地露营”,模型可能在相关场景中持续犯类似的错。
多样性。覆盖用户可能问到的各种变体和边缘情况。如果实际流量中 40% 的咨询涉及退款,而你的训练数据里退款示例只占 5%,模型在这类高频场景上的表现会明显偏弱。
清晰。每个示例只演示一种明确的行为。避免“正确回答需要主观解释”的样本。
代表性。训练数据的分布要匹配真实使用模式。一个只包含正式书面语的数据集,训出来的模型可能不会处理口语化的用户输入。
还有一个实操层面的建议:100 条高质量多样化示例,好过 500 条平庸示例。从 50 到 100 条开始,微调、评估、分析失败案例,再决定是加数据还是改数据。
LoRA,让微调从“买不起”变成“用得起”
理解了 SFT 在做什么之后,下一个问题是:怎么训?
全量微调要更新模型的所有参数。一个 70 亿参数的模型,全量微调至少需要 80GB 以上的显存,千亿参数模型则需要多卡集群。而且每个任务都要存一份完整的模型副本,存储成本随任务数量线性增长。更麻烦的是灾难性遗忘——模型学会了法律文书,可能连日常对话都变得生硬。
LoRA(Low-Rank Adaptation)的思路很聪明:不改动基座模型的任何参数,只在旁边挂小矩阵。研究发现在适配新任务时,权重的更新量具有“低秩特性”,不需要完整的高维矩阵就能近似表达。具体做法是冻结原始权重,在注意力层等关键位置注入两个小矩阵 A 和 B,训练时只更新这两个矩阵。
效果差异是数量级的。一个用 LoRA 微调的 Qwen2-0.5B 示例中,可训练参数只占总量的一小部分,显存需求从“需要专业卡”降到“消费级显卡也能跑”。训练完成后,你可以把 LoRA 权重单独保存(通常只有几十 MB),部署时按需加载不同任务的 LoRA,基座模型始终只有一份。
参数配置上,常见的起点是:秩(r)取 8 到 16,alpha 取秩的 2 到 4 倍,dropout 设 0.1 防止过拟合,目标模块覆盖注意力的 q/k/v/o 和 MLP 的 gate/up/down。学习率通常比全量微调高一些(LoRA 训练时会自动提升),epoch 数从 1 开始,观察验证集表现再调整。
参数配置
参数分三层:先调什么,后调什么
很多教程一上来就列十几行配置,容易让人迷失。实际调参有优先级:学习率和 LoRA alpha 的影响远大于 rank,先把前两个调对,再考虑其他。
第一层:必须认真设的
学习率。LoRA 微调的典型起点是 2e-4。如果训练不稳定(loss 剧烈震荡),降到 1e-4;如果 loss 几乎不动,可以尝试 3e-4 但不要更高。全量微调的学习率要低一个数量级,常用 2e-5 左右。一个实用的判断方法:跑几百步的 LR range test,画 loss 对学习率的曲线,选 loss 开始飙升之前的那个值。
LoRA alpha。常见做法是设成 rank 的 1 到 2 倍。先固定 rank=16,试 alpha=16 和 alpha=32。如果欠拟合(验证 loss 高、输出过于泛化),优先把 alpha 提到 32,而不是急着加 rank。alpha 的作用是缩放 LoRA 更新量,调它比调 rank 更直接。
warmup 比例。SFT 的 warmup 通常占训练总步数的 5% 到 10%。比如总共 2000 步,warmup 设 100 到 200 步。作用是让 Adam 优化器的二阶矩估计在初期积累足够样本,避免前几十步的梯度尖峰破坏模型。不设 warmup 的短训练经常在前 100 步就崩了。
第二层:用默认值起步,有问题再动
rank(r)。从 16 开始。经验上 r=8 到 16 覆盖了大多数任务,r=32 以上收益递减,且更容易过拟合。只有在 alpha 调到 32 仍然欠拟合时,才考虑把 r 提到 32。
LoRA dropout。默认 0。只有观察到过拟合(训练 loss 继续降但验证指标掉头向下)时,才加到 0.05 到 0.1。
weight decay。通常设 0.01,配合 AdamW 优化器。对 LoRA 来说影响不大,但设一个小的值没有坏处。
第三层:按硬件条件取舍
batch size 与梯度累积。单卡显存放得下就用最大 batch,放不下就用梯度累积凑等效 batch。LoRA SFT 常用的等效 batch size 是 8 到 32。比如单卡 batch=2,梯度累积=8,等效就是 16。小 batch 配合梯度累积在低资源场景下泛化往往更好。
epoch 数。从 1 到 3 开始。几千条数据跑 2 到 3 个 epoch 是常见起点。数据量极少(几百条)时可以适当增加,但必须配合早停。
Step 到底怎么算
这是最容易混淆的地方。训练框架里显示的 “step” 有两种含义,看错了会误判训练进度。
优化器 step(optimizer step):参数真正更新的次数。计算方式是:
总 step 数 = (样本数 × epoch 数) ÷ 等效 batch size
等效 batch size = 单卡 batch size × 梯度累积步数 × 卡数。举例:1000 条数据,跑 2 个 epoch,等效 batch=16,总 step = 2000 ÷ 16 = 125 步。这个数字告诉你模型总共更新了多少次权重。
训练 step(training step / global step):有些框架把每个 micro-batch 的前向传播也算一步。如果单卡 batch=2、梯度累积=8,那么每 8 个 micro-step 才对应 1 个 optimizer step。看 loss 曲线时确认横轴是哪个,否则会觉得 “跑了 1000 步怎么还没收敛”——实际只更新了 125 次。
一个直观的参考:LoRA SFT 通常在几百到两千个 optimizer step 内就能看出趋势。如果 2000 步之后验证指标还在明显提升,说明数据量或任务复杂度超出预期,可以继续;如果 500 步内就 plateau 了,先检查数据质量,而不是加步数。
什么时候该停:不看 loss,看验证
训练 loss 降到很低但不代表模型学会了。上一篇提到的“不完全学习”现象意味着,loss 是全局平均值,掩盖了个别样本的问题。
实操上设两个停止条件:
早停(early stopping)。每半个或一个 epoch 在验证集上评一次,如果验证指标连续 1 到 2 次没有改善,就停。这是最可靠的止损方式。
训练集回测。训练结束后,用训练集本身的样本重新让模型回答,找出那些 loss 收敛但仍然答错的样本。如果这类样本集中在某个类别(比如全是退款场景),说明那个类别的数据或知识有缺口,回去改数据比继续训更有用。
Loss下降
这是最容易被忽视、也最值得警惕的一点。
腾讯混元团队在 ACL 2026 的一项研究中做了一个系统性排查:对 Qwen、LLaMA、OLMo2 等多个模型家族和 10 个数据集做 SFT 后,回头用训练集本身测试模型,发现平均 15.3% 的训练样本,模型在训练中见过、loss 也降了,但重新提问时就是答不对。
他们把这个现象命名为不完全学习(Incomplete Learning Phenomenon)。原因是 loss 是全局平均值,掩盖了样本间的差异。loss 收敛只代表“大部分样本学会了”,那些始终学不会的样本被淹没了。
根因可以归为几类:有些样本本身存在标注错误或歧义;有些需要模型不具备的背景知识;有些是数据分布中过于罕见的边缘情况。论文的干预实验发现了一个关键结论:对于知识缺失导致的“学不会”,增加 epoch 几乎无效,补充继续预训练(CPT)数据才有效。而另一些根因(如标注噪声)则无法通过 SFT 本身解决,必须在数据层面处理。
这对实践的含义是:不要只看 loss 曲线来判断训练是否成功。在训练集上做回测,找出那些“反复训练仍然答不对”的样本,逐个分析原因。如果问题出在知识缺口,加 epoch 是浪费时间;如果问题出在数据噪声,改数据才是正解。
SFT 的边界
SFT 能让模型学会“怎么回答”,但它有两个天然局限。
第一,它教不了模型“什么回答更好”。SFT 的数据是“这个输入,这个回答是对的”,但真实场景中往往存在多个合理回答,有的更简洁,有的更详细,有的语气更合适。SFT 无法表达这种偏好排序。这就是为什么 SFT 之后通常还有 RLHF 或 DPO 阶段,用偏好数据进一步对齐。
第二,SFT 与灾难性遗忘的张力始终存在。即使使用 LoRA 冻结了基座,过度训练仍然会让模型在目标任务上过拟合,损失通用能力。ACL 2026 的一项研究进一步发现,参数重要性在训练过程中是动态变化的——训练早期关键的参数,到后期可能不再关键,反之亦然。静态地“保护”某一组参数并不是最优解,动态调整隔离策略才能更好地平衡学习与遗忘。
更多推荐

所有评论(0)