- 教程
- 人工智能
- 大模型
- NLP
- 微调
【免费下载链接】smol-course
A course on aligning smol models.
本文是 smol-course 项目「指令微调(Instruction Tuning)」模块的技术指南,系统讲解两条核心技术主线:以 ChatML 为代表的对话模板(Chat Templates)与基于 TRLSFTTrainer的监督微调(Supervised Fine-Tuning)。读完本文,你将掌握如何把基础模型(如SmolLM2-135M)格式化为可对话的指令模型、如何将任意数据集转换为 ChatML 格式,以及如何配置SFTConfig完成一次完整的微调、评估与发布流程。
模块概览:指令微调在 smol-course 中的位置
指令微调(Instruction Tuning)是指:为了把预训练模型适配到特定任务,使用与该任务相关的数据集对模型进行额外训练的过程,从而让模型在目标任务上取得更优表现。smol-course 的韩文版模块(v1/ko/1_instruction_tuning/README.md)将这一主题拆分为两大核心内容:
- 对话模板(Chat Templates)——结构化用户与 AI 模型之间的交互,保证响应的一致性与上下文相关性,核心组件包括系统提示词与基于角色的消息;
- 监督微调(SFT)——使用带标签的任务数据对预训练语言模型进行适配,是让模型真正"学会干活"的关键步骤。
模块同时提供了两张实战练习表(v1/ko/1_instruction_tuning/README.md):
| 标题 | 说明 | 实战内容 | 仓库链接 |
|---|---|---|---|
| Chat Templates | 使用 SmolLM2 掌握对话模板,并将数据集转换为 ChatML 格式 | 🐢 将HuggingFaceTB/smoltalk数据集转为 chatml 格式;🐕 将openai/gsm8k数据集转为 chatml 格式 | chat_templates_example.ipynb |
| Supervised Fine-Tuning | 使用SFTTrainer对 SmolLM2 进行微调 | 🐢 使用HuggingFaceTB/smoltalk数据集;🐕 使用bigcode/the-stack-smol数据集;🦁 为真实使用场景挑选数据集 | sft_finetuning_example.ipynb |
注:本模块的完整理论文档为 v1/ko/1_instruction_tuning/chat_templates.md 与 v1/ko/1_instruction_tuning/supervised_fine_tuning.md,以下章节分别展开。
一、对话模板(Chat Templates)
1.1 基础模型 vs 指令模型:为什么需要模板
**基础模型(Base Model)**在大量原始文本上以"预测下一个 token"为目标进行训练;**指令模型(Instruct Model)**则是专门经过微调、能够遵循指令并参与对话的变体。以仓库实战使用的模型为例:HuggingFaceTB/SmolLM2-135M是基础模型,而SmolLM2-135M-Instruct是其指令微调版本。
要让基础模型表现得像指令模型,必须以模型能理解的方式一致地格式化提示词——这正是对话模板的用武之地。ChatML是其中一种被广泛使用的模板格式,通过明确的角色指示符(system、user、assistant)来结构化对话:
<|im_start|>user 안녕하세요!<|im_end|> <|im_start|>assistant 만나서 반갑습니다!<|im_end|> <|im_start|>user 질문을 해도 될까요?<|im_end|> <|im_start|>assistant关键事实:基础模型可能在不同的对话模板上被微调过,因此使用指令模型时,必须使用与之一致(匹配)的对话模板,否则模型无法正确解析角色与消息边界。从源码结构看,模板的核心作用就是定义"与语言模型通信时对话应以何种格式呈现"——包括系统级指令、用户消息、助手响应三部分,从而在交互中维持格式一致性并引导模型对不同输入做出恰当响应。
1.2 消息结构:role 与 content
transformers库会根据模型的 tokenizer 自动处理对话模板。我们只需把消息结构化为包含role与content键的字典列表,剩下的格式化工作交给 tokenizer:
messages = [ {"role": "system", "content": "You are a helpful assistant focused on technical topics."}, {"role": "user", "content": "Can you explain what a chat template is?"}, {"role": "assistant", "content": "A chat template structures conversations between users and AI models..."} ]其中**系统消息(System Message)**奠定模型的基础行为方式,是影响后续所有交互的持久指令。例如:
system_message = { "role": "system", "content": "You are a professional customer service agent. Always be polite, clear, and helpful." }而**对话历史(Conversation)**则让模板通过记录用户与助手之间的多轮往来维持上下文,从而实现更连贯的多轮对话:
conversation = [ {"role": "user", "content": "I need help with my order"}, {"role": "assistant", "content": "I'd be happy to help. Could you provide your order number?"}, {"role": "user", "content": "It's ORDER-123"}, ]1.3 Transformers 实现:apply_chat_template 的核心用法
transformers库为对话模板提供了内建支持,核心 API 是AutoTokenizer.apply_chat_template。仓库文档 v1/ko/1_instruction_tuning/chat_templates.md 给出的标准用法如下:
from transformers import AutoTokenizer tokenizer = AutoTokenizer.from_pretrained("HuggingFaceTB/SmolLM2-135M-Instruct") messages = [ {"role": "system", "content": "You are a helpful coding assistant."}, {"role": "user", "content": "Write a Python function to sort a list"}, ] # 应用对话模板 formatted_chat = tokenizer.apply_chat_template( messages, tokenize=False, add_generation_prompt=True )三个关键参数说明:
tokenize=False:返回纯文本字符串(而非 token id),便于直接查看模板化后的对话内容;tokenize=True(默认):返回 token id 列表,可直接喂给模型;add_generation_prompt=True:在末尾追加assistant角色的起始标记(如<|im_start|>assistant),提示模型开始生成响应,这在推理/生成场景中尤其重要。
1.4 自定义格式与多轮支持
不同消息类型可以定制不同的格式,例如按角色追加特殊 token 或自定义排版:
template = """ <|system|>{system_message} <|user|>{user_message} <|assistant|>{assistant_message} """.lstrip()模板同样能处理复杂多轮对话并在其中维持上下文,例如下面这个数学辅导场景:
messages = [ {"role": "system", "content": "You are a math tutor."}, {"role": "user", "content": "What is calculus?"}, {"role": "assistant", "content": "Calculus is a branch of mathematics..."}, {"role": "user", "content": "Can you give me an example?"}, ]1.5 实战:从 notebook 看模板的完整调用链
chat_templates_example.ipynb 给出了可复现的完整链路,首先动态选择设备并加载模型:
from transformers import AutoModelForCausalLM, AutoTokenizer from trl import setup_chat_format import torch device = ( "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu" ) model_name = "HuggingFaceTB/SmolLM2-135M" model = AutoModelForCausalLM.from_pretrained(pretrained_model_name_or_path=model_name).to(device) tokenizer = AutoTokenizer.from_pretrained(pretrained_model_name_or_path=model_name) model, tokenizer = setup_chat_format(model=model, tokenizer=tokenizer)这里的trl.setup_chat_format会为没有内建对话模板的基础模型自动装配一套 ChatML 模板并补充对应的特殊 token,是"把基础模型变成可对话模型"的关键一步(这也解释了为何后续apply_chat_template能直接输出<|im_start|>系列标记)。
随后定义一条简单对话并观察三种输出形态(对应 notebook 中的三组实验):
messages = [ {"role": "user", "content": "Hello, how are you?"}, {"role": "assistant", "content": "I'm doing well, thank you! How can I assist you today?"}, ] # 1) 不 tokenize,直接查看模板化后的对话字符串 input_text = tokenizer.apply_chat_template(messages, tokenize=False) print("Conversation with template:", input_text) # => <|im_start|>user\nHello, how are you?<|im_end|>\n<|im_start|>assistant\n... # 2) tokenize 并添加生成提示,解码后可见末尾多出 assistant 引导标记 input_text = tokenizer.apply_chat_template(messages, tokenize=True, add_generation_prompt=True) print("Conversation decoded:", tokenizer.decode(token_ids=input_text)) # 3) 默认 tokenize,得到与模型词表对应的 token id 序列 input_text = tokenizer.apply_chat_template(messages, add_generation_prompt=True) print("Conversation tokenized:", input_text)三组实验分别验证了:模板如何插入特殊 token 形成结构化文本、生成提示(generation prompt)如何在结尾追加assistant引导、以及整个对话+特殊 token 如何被映射为模型词表中的 id 序列。notebook 还提供了两档练习题:
- 🐢 使用
datasets.load_dataset("HuggingFaceTB/smoltalk", "everyday-conversations")加载对话数据,通过ds.map(process_dataset)将每条样本转换为包含role/content的消息列表并应用对话模板; - 🐕 将
openai/gsm8k(数学推理数据集,含question与answer字段)转换为 ChatML 格式,需要自行构造用户消息与助手消息再套用模板。
这两项练习的意义在于:虽然 TRL 在训练时会自动套用模型对话模板,但理解内部格式转换机制(特别是不同字段如何映射为 role/content)对排查数据问题、适配自定义数据集至关重要。
二、监督微调(Supervised Fine-Tuning)
2.1 什么是 SFT:原理与适用场景
监督微调(SFT)是让预训练模型适配特定任务或领域的关键过程。预训练模型虽有出色的通用能力,但往往需要针对具体使用场景做定制。SFT 通过在人验证过的、精心筛选的数据集上继续训练来弥合这一差距。
其核心机制是:通过带标签的 token 示例教会预训练模型执行特定任务——向模型展示大量期望的"输入-输出"行为样例,使其学习到针对你的使用场景的特定模式。SFT 之所以有效,是因为它既利用了预训练阶段获得的基础知识,又能把模型行为调整到符合你的具体需求。
是否使用 SFT,主要取决于"模型当前能力"与"具体需求"之间的差距。以下场景尤其适合:
- 需要精细控制模型输出时,例如开发客户服务应用,希望模型始终遵循公司准则、以标准化方式处理技术咨询;
- 专业领域(如医疗、法律)中,准确性与领域术语遵循至关重要;
- 在以上情形中,SFT 能帮助模型响应符合专业标准并贴合领域知识。
2.2 微调流程:数据、训练与持续评估
SFT 的过程包含三个环节:
- 数据准备:选择或构建能代表目标任务的数据集,应覆盖模型将遇到的各种场景。数据质量至关重要——每条样本都要清晰示范你期望模型产出的输出类型;
- 实际训练:使用 Hugging Face 的
transformers与trl等框架,基于数据集训练模型权重; - 持续评估:全过程都要用验证集监控模型性能,确保模型学到期望行为的同时不损失通用能力。关于如何评估模型,将在本仓库的模块 4(Evaluation)中展开。
2.3 SFT 在偏好对齐中的角色
SFT 是让语言模型与人类偏好对齐的基础环节:**基于人类反馈的强化学习(RLHF)与直接偏好优化(DPO)**等技术,都先依靠 SFT 建立基础层面的任务理解,再进一步把模型响应与期望结果对齐。预训练模型尽管语言能力普遍,却不一定总能产出符合人类偏好的输出;SFT 通过引入领域数据与指令来填补这一差距,使模型生成更贴近人类期望的响应。这也是本仓库后续偏好对齐模块(如 v1/ko/2_preference_alignment)的地基。
2.4 核心工具:TRL 与 SFTTrainer
监督微调的关键软件包是Transformer Reinforcement Learning(TRL)——一套用强化学习(RL)训练 transformer 语言模型的工具包。它构建于 Hugging Face Transformers 之上,允许直接加载预训练语言模型,支持大部分 decoder 与 encoder-decoder 架构,并覆盖语言建模中的主要 RL 流程:SFT、奖励建模(RM)、近端策略优化(PPO)、直接偏好优化(DPO)。仓库的多个模块都会使用 TRL。
2.5 实战:SFTConfig 关键参数逐项解析
sft_finetuning_example.ipynb 展示了用SFTTrainer微调HuggingFaceTB/SmolLM2-135M的完整流程。数据准备阶段强调一个要点:TRL 会根据模型对话模板自动格式化输入消息,因此数据只需以含role/content键的字典列表形式组织:
from transformers import AutoModelForCausalLM, AutoTokenizer from datasets import load_dataset from trl import SFTConfig, SFTTrainer, setup_chat_format import torch device = ( "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu" ) model_name = "HuggingFaceTB/SmolLM2-135M" model = AutoModelForCausalLM.from_pretrained(pretrained_model_name_or_path=model_name).to(device) tokenizer = AutoTokenizer.from_pretrained(pretrained_model_name_or_path=model_name) model, tokenizer = setup_chat_format(model=model, tokenizer=tokenizer) finetune_name = "SmolLM2-FT-MyDataset" finetune_tags = ["smol-course", "module_1"] # 加载对话数据集(path 与 name 分别指定数据集与子集配置) ds = load_dataset(path="HuggingFaceTB/smoltalk", name="everyday-conversations")随后通过SFTConfig配置训练过程。该配置控制训练步数、批大小、学习率、评估方式等,notebook 中的核心参数及含义如下:
| 参数 | 示例值 | 作用说明 |
|---|---|---|
output_dir | "./sft_output" | 训练输出(checkpoint、日志等)保存目录 |
max_steps | 1000 | 最大训练步数,按期望训练时长与数据集规模调整 |
per_device_train_batch_size | 4 | 每设备训练批大小,受 GPU 显存容量约束 |
learning_rate | 5e-5 | 学习率,微调场景的常用取值 |
logging_steps | 10 | 训练指标(loss 等)的日志记录频率 |
save_steps | 100 | 模型 checkpoint 的保存频率 |
evaluation_strategy | "steps" | 周期性评估设置(按步数评估) |
eval_steps | 50 | 评估频率(步数间隔) |
use_mps_device | device == "mps" | 是否在 Apple MPS 上启用(混合精度训练相关) |
hub_model_id | finetune_name | 上传 Hugging Face Hub 时使用的模型名称 |
sft_config = SFTConfig( output_dir="./sft_output", max_steps=1000, per_device_train_batch_size=4, learning_rate=5e-5, logging_steps=10, save_steps=100, evaluation_strategy="steps", eval_steps=50, use_mps_device=(True if device == "mps" else False), hub_model_id=finetune_name, ) trainer = SFTTrainer( model=model, args=sft_config, train_dataset=ds["train"], eval_dataset=ds["test"], )实战提示(notebook 标注):若改用
bigcode/the-stack-smol这类代码数据集,需通过参数指定content列(字段名与对话数据集不同);若数据集本身不是 TRL 可直接转换的对话格式,则需先按 chat_templates.md 的方法自行预处理。
2.6 训练、保存与发布:一次完整的微调闭环
配置完成即可启动训练并保存、发布模型(对应 notebook 三连):
# 训练:反复遍历数据集、计算损失并通过反向传播更新参数以最小化损失 trainer.train() # 保存模型到本地目录 trainer.save_model(f"./{finetune_name}") # 上传到 Hugging Face Hub(需先 login 并配置 hub_model_id) trainer.push_to_hub(tags=finetune_tags)训练前后对比是验证微调效果的标准做法:notebook 在训练前先用同一 prompt 测试基础模型——
prompt = "Write a haiku about programming" messages = [{"role": "user", "content": prompt}] formatted_prompt = tokenizer.apply_chat_template(messages, tokenize=False) inputs = tokenizer(formatted_prompt, return_tensors="pt").to(device) outputs = model.generate(**inputs, max_new_tokens=100) print("Before training:") print(tokenizer.decode(outputs[0], skip_special_tokens=True))训练完成后,用相同 prompt 对微调后模型再次生成(使用save_model保存的权重),对比输出质量即可直观看到 SFT 带来的行为改变。完整的微调流程是:加载基础模型 →setup_chat_format装配对话模板 → 加载/预处理数据集 → 配置SFTConfig→ 初始化SFTTrainer→train()→save_model/push_to_hub→ 训练前后生成对比。
三、下一步学习路径
完成本模块后,建议按以下路径继续深入(均位于本仓库内):
- 动手跑通两个 notebook:chat_templates_example.ipynb(先掌握模板与数据集转换)、sft_finetuning_example.ipynb(完成一次完整微调),可尝试升级难度(如代码数据集、自选真实场景数据集);
- 进阶偏好对齐:在 SFT 打底后,进入模块 2 偏好对齐了解 DPO 等后续对齐技术(本模块 SFT 正是其基础);
- 评估闭环:微调效果需要通过模块 4 评估中的验证集与评估工具来客观衡量,防止灾难性遗忘与过拟合。
掌握对话模板的格式化规则与SFTTrainer的参数语义,是后续所有对齐类微调(DPO、PPO 等)的共同地基——这也是 smol-course 将本模块置于课程起点、并在各语言版本(如 v1/1_instruction_tuning/README.md)中保持一致编排的原因。
- 教程
- 人工智能
- 大模型
- NLP
- 微调
【免费下载链接】smol-course
A course on aligning smol models.
相关推荐
从 v0.1 到 v1.66:Bottlerocket 版本演进全解读(以 CHANGELOG 为主线)
从 v0.1 到 v1.66:Bottlerocket 版本演进全解读(以 CHANGELOG 为主线) Bottlerocket 是一款专为托管容器设计的开源
教程人工智能大模型NLP微调smol-course 指令微调入门指南:对话模板与监督式微调实战
smol course 指令微调入门指南:对话模板与监督式微调实战 本指南基于 smol course 仓库韩语版模块 units/ko/unit1/1.md
教程人工智能大模型NLP微调smol-course 指令微调入门:从 Chat 模板到监督微调(SFT)的完整指南
smol course 指令微调入门:从 Chat 模板到监督微调(SFT)的完整指南 本文是 smol course 仓库中「Ajuste por Instr
教程人工智能大模型NLP微调
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考