原文出处:Supervised Fine-Tuning with SmolLM3 原作者:Hugging Face · 许可证:Apache-2.0 License 中文译本由诸葛AI学院整理,仅供学习参考,版权归原作者与 Hugging Face 所有。
用 SmolLM3 做监督微调
监督微调(supervised fine-tuning,SFT)是指令微调(instruction tuning)的基石:它把基座语言模型(base language model)变成听得懂指令、按指令干活的助手。这一节里,你会用真实世界的数据集(dataset)和生产级工具,动手微调 SmolLM3。
什么是监督微调?
SFT 就是在预训练模型(pre-trained model)的基础上,拿带标注样例的任务数据集继续训练。可以把它想成专业化教育:
- 预训练教的是通用语言理解(相当于学会读书认字)。
- 监督微调教的是具体技能和行为习惯(相当于学会干某一项具体的活)。
SFT 背后的关键认识是:我们不是在从零教模型新知识,而是在重塑它运用已有知识的方式。预训练模型已经理解语言、掌握语法,也吸收了海量事实信息。SFT 做的,是把这种通用能力引导到具体的应用模式、回答风格和任务要求上。
这条路走得通,是因为它复用了预训练阶段学到的深层语言表示(representation),算力开销又比从零训练小得多。经过 SFT,模型学会识别指令模式、维持对话上下文、遵守安全准则,并按期望的格式生成回答。
提示:动手做 SFT 之前,先想想:拿一个现成的指令微调模型,配上写得好的提示词(prompt),够不够用?SFT 要投入大量算力和工程精力,只有当提示词搞不定时才值得做。这个取舍过程可参考 Hugging Face LLM Course。
SmolLM3 的 SFT 之路
SmolLM3 的指令跟随能力,来自一套讲究的多阶段流程:
- 基座模型(
SmolLM3-3B-Base):在 11T 令牌(token)的通用文本上完成预训练 - SFT 训练:在精选的指令数据集上微调,其中包含 SmolTalk2
- 偏好对齐(preference alignment):再用 APO(Anchored Preference Optimization,锚定偏好优化)等技术打磨
这套多阶段流程做出来的模型,既知识扎实,又乐于配合。
SFT 为什么有效:背后的机理
SFT 有效,是因为它一边复用预训练学到的深层语言表示,一边调整模型的行为模式。训练时,模型参数通过梯度下降(gradient descent)在任务样例上更新,模型处理和生成文本的方式随之发生细微但重要的变化。
具体来说,这个过程靠几个机制运转:
行为适应:模型学会识别指令模式并做出恰当回应。这需要更新注意力机制(attention mechanism),让它盯住语言里的指令线索,同时调整输出分布,让期望的回答更容易出现。有研究表明,指令微调主要改变模型的表层行为,并不动它的底层知识(Wei et al., 2021)。
任务专业化:模型学的不是全新概念,而是把已有知识用到具体场景里。这也是 SFT 比预训练高效得多的原因:我们在精炼现成的能力,而不是从头搭建。研究显示,事实知识主要来自预训练,SFT 教的是怎么把这些知识排版、呈现得体面(Ouyang et al., 2022)。
安全对齐:通过接触精心筛选的样例,模型学会更有帮助、更安全无害、更诚实。这既包括学会该说什么,也包括学会在什么场合不该说什么。InstructGPT(Ouyang et al., 2022)和 Constitutional AI(Bai et al., 2022)都验证过这条路的有效性。
提示:SFT 教的不是新事实,而是新行为。模型在预训练里已经认识了世界;SFT 教它怎么用这些知识当一个称职的助手。
数学上,这一步做的是最小化交叉熵损失(cross-entropy loss):让模型的预测和训练数据里的目标回答尽量接近。随着训练推进,模型的概率分布会慢慢偏向你在样例中演示的那类回答。
什么时候该用监督微调
核心问题是:"我的场景需要的行为,和通用对话差别大吗?"如果答案是肯定的,SFT 大概率有帮助。
决策框架:用下面这份清单判断你的项目适不适合上 SFT:
- 试过对现成的指令微调模型做提示词工程吗?
- 需要稳定统一的输出格式,而提示词给不到吗?
- 你的领域是不是专到通用模型普遍吃力的程度?
- 有高质量的训练数据吗(至少 1,000 条样例)?
- 有训练和评估所需的算力吗?
大部分问题答"是",SFT 就值得投入。
SFT 的流程
下面进入 SFT 本身。整套流程有固定的章法,照着走才能出高质量的结果:
1. 数据集准备与选择
训练数据的质量是 SFT 成败的头号因素。预训练拼数量,SFT 拼质量和相关性。数据集里的输入-输出对,要能精确演示你希望模型学会的行为。
选对数据集:
- SmolTalk2:训练 SmolLM3 用的数据集,包含高质量的指令-回答对。
- 领域数据集:用于医疗、法律、技术等专业应用。
- 自建数据集:针对你自己的用例整理的样例。
每条训练样例应包含:
- 输入提示:用户的指令或问题
- 期望回答:理想的助手回复
- 上下文(可选):所需的附加信息
提示:数据集规模参考: - 下限:基础微调至少 1,000 条高质量样例。 - 建议:10,000 条以上,性能更稳。 - 质量优先:1,000 条精挑细选的样例,往往打得过 10,000 条平庸的。
记住:模型会学着复刻训练数据里的模式,花在数据整理上的时间不浪费。
2. 环境搭建与配置
搭 SFT 环境需要像样的算力。原文说"三个主要选项",实际列了四个:
- 本地 GPU:如果你手头有一张至少 16GB 显存(VRAM)的 GPU,恭喜,直接本地训练。
- Hugging Face Jobs:没有 GPU、又不想用云厂商,可以用 Hugging Face Jobs。细节放在下一节展开。
- Notebook GPU:习惯用 Google Colab 这类 notebook 平台的,也能借它们的 GPU。
- 云 GPU:想把算力攥在自己手里,可以选 AWS、GCP、Azure 这类云厂商。
硬件门槛:一张至少 16GB 显存的 GPU,比如 Nvidia RTX 4080 或 A10G。
3. 训练配置
超参数(hyperparameter)选得好坏直接决定 SFT 成败。目标是找到平衡点:模型学得动,又不过拟合(overfitting)、不训崩。下面逐个讲这些参数怎么选:
关键超参数:
学习率(learning rate)(5e-5 到 1e-4):控制每次更新时模型权重变动的幅度
- SmolLM3 从 5e-5 起步;这个值保守、稳定。
- 太大:模型训不稳,损失震荡甚至爆炸。
- 太小:学得太慢,可能迟迟不收敛。
批大小(batch size)(4-16):一次并行处理的样例数
- 大批次:梯度更稳,但更吃显存。
- 小批次:省显存,但梯度噪声大。
- 用梯度累积(gradient accumulation)可以得到更大的等效批次。
最大序列长度(max sequence length)(2048-4096):单条训练样例的令牌上限
- 序列长:能处理更复杂的对话。
- 序列短:训练更快,省显存。
- 对表你的场景:按目标对话的典型长度来定。
训练步数(training steps)(1000-5000):参数更新的总次数
- 取决于数据集大小:数据越多,步数通常越多。
- 盯验证损失:它不再改善就该停。
- 经验法则:把整个数据集过 3 到 5 轮(epoch)。
预热步数(warmup steps)(总步数的 10%):训练初期把学习率逐步抬上去
- 防止开局不稳:让模型循序渐进进入状态。
- 常见范围:多数 SFT 任务 100-500 步。
提示:SmolLM3 超参数起步参考:
冷启动训练时,可以直接抄下面这组值:
学习率:
```python
保守(稳定,偏慢)
learning_rate = 5e-5
均衡(推荐)
learning_rate = 1e-4
激进(更快,不太稳)
learning_rate = 2e-4 ```
批大小:
借助梯度累积,可以压低单卡批次,省下显存。
```python
显存紧张
per_device_train_batch_size = 2 gradient_accumulation_steps = 8
显存均衡
per_device_train_batch_size = 4 gradient_accumulation_steps = 4
显存充裕
per_device_train_batch_size = 8 gradient_accumulation_steps = 2 ```
最大序列长度:
```python
很短的序列
max_length = 512
短序列
max_length = 1024
长序列
max_length = 2048
超长序列
max_length = 4096 ```
4. 监控与评估
想训得好,盯得紧很重要。预训练主要看损失往下走;SFT 还得同时关注定量指标和模型的实际输出,确认模型学到了想要的行为,又没过拟合、没染上坏毛病。
要盯的关键指标:
训练损失:应该稳步下降,但别降得太猛
- 健康形态:平滑、渐进地下降。
- 危险信号:突然尖峰、来回震荡、长期平台。
- 典型范围:起步在 2-4 左右,应降到 0.5-1.5。
验证损失:防过拟合最重要的指标
- 应贴着训练损失走:两者差距小,说明泛化好。
- 差距拉大:过拟合的信号,模型可能在背训练数据。
- 用它做早停(early stopping):验证损失不再改善就停训。
样例输出:定期做定性检查不可少
- 生成回答:训练中拿模型没见过的提示词测一测。
- 检查格式一致性:确认模型按期望的样式回答。
- 留意退化:警惕重复、胡言乱语的输出。
资源占用:跟踪显存和训练速度
- 显存尖峰:可能批次开大了。
- 训练变慢:可能是数据加载或处理低效。
看懂 SFT 的损失曲线
训练损失通常会经历三个明显阶段。原文此处有一张图(例子来自 Hugging Face LLM Course),画的正是这样一条损失曲线:
- 开局陡降:模型快速适应新的数据分布
- 逐渐趋稳:模型进入精修状态,损失下降放缓
- 收敛:损失稳定下来,训练接近完成
健康的训练形态:训练成功与否的关键信号,是训练损失和验证损失之间保持小差距。这说明模型学的是可泛化的模式,而不是在背具体样例。
要警惕的几种信号
损失曲线里有几种形态预示着问题:
过拟合形态
原文此处有一张图,画的是典型过拟合曲线:训练损失一路走低,验证损失先降后升,两条线越拉越开。
如果验证损失上升、训练损失还在下降,模型就是过拟合了。可以考虑:
- 减少训练步数或轮次
- 增大数据集的规模或多样性
- 加入正则化(regularization)手段
- 基于验证损失做早停
欠拟合形态
原文此处有一张图,画的是损失几乎不见下降的曲线。
如果损失看不到明显改善,可能是:
- 学得太慢(试着把学习率调大)
- 任务对模型来说太难(检查数据质量)
- 撞上了架构限制(考虑换别的模型规模)
疑似死记硬背
原文此处有一张图,画的是损失低得不正常的曲线。
损失值低得离谱,往往说明模型在背答案,而不是在学习。如果还伴随以下迹象就要警惕:
- 换成相似的新样例,模型表现明显变差
- 输出缺乏多样性或创造性
- 回答和训练样例雷同得过分
提示:想更深入地解读损失曲线,可看 Hugging Face LLM Course。
用 Trackio 做实验追踪:要做完整的实验追踪,推荐 Trackio。这是一个轻量、免费的实验追踪库,建在 Hugging Face 基础设施上。它的特点:
- 无缝替换:API 兼容
wandb.init、wandb.log、wandb.finish。 - 本地优先:面板默认在本地跑,也可选择托管到 Hugging Face Spaces。
- 免费托管:包括放到 Hugging Face Spaces 上托管,全部免费。
- 轻量:Python 代码不到 3,000 行,容易扩展。
训练中想记录什么指标都行,比如:
```python
简单的 Trackio 集成
import trackio
初始化追踪
trackio.init(project="smollm3-sft")
训练过程中记录指标
trackio.log({"train_in_loss": 0.5, "learning_rate": 5e-5})
结束追踪
trackio.finish() ```
追踪训练最省事的办法,是用 trackio 的 transformers 集成。通过环境变量指定 Trackio 的项目名和 space ID:
bash
export TRACKIO_PROJECT_NAME="my-project"
export TRACKIO_SPACE_ID="username/space_id"
也可以写在代码里:
```python import os
os.environ["TRACKIO_PROJECT_NAME"] = "my-project" os.environ["TRACKIO_SPACE_ID"] = "username/space_id" ```
之后用 TRL 的 SFTTrainer 类,把追踪这件事整个交给它:
```python from trl import SFTTrainer
trainer = SFTTrainer( model=model, train_dataset=dataset["train"], args=config, ) ```
Trackio 会起一个应用,展示训练中的各项指标。原文此处嵌了一个在线演示面板(train/loss、train/mean_token_accuracy、train/num_tokens 等指标的实时曲线),这里删掉了,可以访问 Trackio 文档 看效果。
记录的指标
训练和评估过程中,会记录以下指标:
global_step:目前累计的优化器步数。epoch:当前轮次,按数据集迭代计算。num_tokens:累计处理的令牌数。loss:当前记录区间内,未掩码(non-masked)令牌上的平均交叉熵损失。entropy:未掩码令牌上,模型预测令牌分布的平均熵。mean_token_accuracy:未掩码令牌中,模型 top-1 预测与真实令牌一致的比例。learning_rate:当前的学习率;用了调度器的话,它会动态变化。grad_norm:梯度的 L2 范数,在梯度裁剪(gradient clipping)之前计算。
期望的数据集类型与格式
SFT 同时支持语言建模和提示-补全两类数据集。SFTTrainer 既认标准格式,也认对话格式。拿到对话格式的数据集时,训练器会自动给数据套用聊天模板(chat template)。
```python
标准语言建模
{"text": "The sky is blue."}
对话式语言建模
{"messages": [{"role": "user", "content": "What color is the sky?"}, {"role": "assistant", "content": "It is blue."}]}
标准提示-补全
{"prompt": "The sky is", "completion": " blue."}
对话式提示-补全
{"prompt": [{"role": "user", "content": "What color is the sky?"}], "completion": [{"role": "assistant", "content": "It is blue."}]} ```
如果你的数据集不是这几种格式,可以先做预处理,转成期望的格式。下面以对 FreedomIntelligence/medical-o1-reasoning-SFT 数据集的处理为例:
```python from datasets import load_dataset
dataset = load_dataset("FreedomIntelligence/medical-o1-reasoning-SFT", "en")
def preprocess_function(example):
return {
"prompt": [{"role": "user", "content": example["Question"]}],
"completion": [
{"role": "assistant", "content": f"
dataset = dataset.map(preprocess_function, remove_columns=["Question", "Response", "Complex_CoT"]) print(next(iter(dataset["train"]))) ```
转换结果:
json
{
"prompt": [
{
"content": "Given the symptoms of sudden weakness in the left arm and leg, recent long-distance travel, and the presence of swollen and tender right lower leg, what specific cardiac abnormality is most likely to be found upon further evaluation that could explain these findings?",
"role": "user",
}
],
"completion": [
{
"content": "<think>Okay, let's see what's going on here. We've got sudden weakness [...] clicks into place!</think>The specific cardiac abnormality most likely to be found in [...] the presence of a PFO facilitating a paradoxical embolism.",
"role": "assistant",
}
],
}
训练中的聊天模板
回到聊天模板这个话题,看看它在训练里怎么用。训练时用对模板,对模型性能影响很大。几个关键点和最佳实践如下:
预处理与分词
训练时,每条样例要么带 text 字段,要么带 (prompt, completion) 这一对,取决于数据集格式。期望格式的更多细节见 Dataset formats。SFTTrainer 会用模型自带的分词器(tokenizer)逐条分词;如果 prompt 和 completion 是分开提供的,会先拼接、再分词。
损失的计算
原文此处有一张图,配合公式示意按令牌逐项计算损失的过程。
SFT 使用的损失是令牌级交叉熵损失(token-level cross-entropy loss),定义为:
$$ \mathcal{L}{\text{SFT}}(\theta) = - \sum{t=1}^{T} \log p_\theta(y_t \mid y_{<t}), $$
其中 \( y_t \) 是第 \( t \) 个时间步的目标令牌,模型的训练目标是:给定前面的令牌,预测下一个令牌。实际计算损失时,padding 令牌会被掩码排除在外。
用 TRL 做监督微调
TRL(Transformer Reinforcement Learning)是训练语言模型的首选工具箱,专为指令微调和对齐打造。这门课全程都用它。
为什么选 TRL?
- 生产可用:大机构和研究实验室都在用。
- 覆盖面全:支持 SFT、DPO、ORPO、PPO 以及更进阶的技术。
- 高效:针对显存占用和训练速度做过优化。
- 灵活:任何 Hugging Face 模型都能配。
- 命令行支持:CLI 工具撑得起规模化的训练流程。
核心组件
- SFTTrainer:监督微调的核心类
- SFTConfig:训练参数的配置管理
- CLI Tools:面向生产流程的命令行工具
- Integration:与 Hugging Face Hub、Trackio、Weights & Biases 等无缝集成
TRL 的架构
TRL 长在 Hugging Face 生态之上:
- Transformers:模型加载与推理。
- Datasets:数据处理与管理。
- Accelerate:分布式训练与优化。
- PEFT:参数高效微调(LoRA、QLoRA)。
这种一体化设计意味着:你在用上最先进训练技术的同时,Hugging Face 生态的好处一样不落。
提示:TRL 和其他训练库的对比: - TRL:专为 LLM 训练而生,冲着指令微调去的。 - Transformers Trainer:通用型,适合基础微调。 - DeepSpeed:重心在大规模分布式训练。 - Accelerate:提供底层的分布式训练原语。
做 SFT,TRL 在易用性和高级功能之间取得了最好的平衡。想全面了解各种训练路线,见 Hugging Face LLM Course。
实操:第一次微调 SmolLM3
理论讲完,上手练。下面预告你在练习里会做出来的东西。Python 和 CLI 两条路任选:
Python 方式:
```python from transformers import AutoModelForCausalLM, AutoTokenizer from trl import SFTTrainer, SFTConfig from datasets import load_dataset import trackio as wandb
初始化实验追踪
wandb.init(project="smollm3-sft", name="my-first-sft-run")
加载 SmolLM3 基座模型
model = AutoModelForCausalLM.from_pretrained("HuggingFaceTB/SmolLM3-3B-Base") tokenizer = AutoTokenizer.from_pretrained("HuggingFaceTB/SmolLM3-3B-Base")
加载 SmolTalk2 数据集
dataset = load_dataset("HuggingFaceTB/smoltalk2_everyday_convs_think")
配置训练,接入 Trackio
config = SFTConfig( output_dir="./smollm3-finetuned", per_device_train_batch_size=4, learning_rate=5e-5, max_steps=1000, report_to="trackio", # 开启 Trackio 记录 )
开训!
trainer = SFTTrainer( model=model, train_dataset=dataset["train"], args=config, ) trainer.train() ```
CLI 方式:
```bash
用 TRL CLI 微调 SmolLM3,接入 Trackio 追踪
trl sft \ --model_name_or_path HuggingFaceTB/SmolLM3-3B-Base \ --dataset_name HuggingFaceTB/smoltalk2_everyday_convs_think \ --output_dir ./smollm3-sft-model \ --per_device_train_batch_size 4 \ --learning_rate 5e-5 \ --max_steps 1000 \ --logging_steps 50 \ --save_steps 200 \ --report_to trackio \ --push_to_hub \ --hub_model_id your-username/smollm3-custom ```
无服务器(serverless)训练选项
本地能训,但云基础设施对 SFT 帮助很大。不想自己折腾 GPU 和环境管理的用户,Hugging Face Jobs 是一条省心路线。
全托管的云端高端 GPU、自动扩缩和集成监控,详见 Training with Hugging Face Jobs。
本节要点
- SFT 是必经一步:它是基座模型通往指令跟随助手的桥梁
- 数据质量是命门:高质量数据集才有高质量的微调模型,花在整理数据上的时间不白花
- 盯紧过程:损失曲线和实际输出都要看,问题越早发现越好
- TRL 省事:从研究到生产,它把工具都备齐了
- SmolLM3 适合学习:能力够强,体积又小到人人玩得起
- 两条路都通:写代码和敲命令两种方式,按场景选
提示:继续学习:这一节只讲了基本面,SFT 这个话题还很深。更进阶的技术、评估方法、排错经验,可以去 Hugging Face LLM Course 从头看到尾,它对现代 LLM 训练技术的讲解很完整。
下一步
理论到手,接下来选你的训练路线:
- Training with Hugging Face Jobs:用云基础设施训练
- Hands-On Exercises:本地或云端微调你自己的 SmolLM3
资源与延伸阅读
- Training with Hugging Face Jobs:全托管云基础设施训练
- Trackio Documentation:免费、轻量的实验追踪
- TRL Documentation:TRL 全功能指南
- SFTTrainer API Reference:参数详解
- SmolTalk2 Dataset:训练出 SmolLM3 的数据集
- SmolLM3 Model Card:官方模型文档
- TRL CLI Documentation:命令行工具指南