首页 / 资料库 / Hugging Face · 小模型课

资料库30 分钟读完Apache-2.0微调动手练习Hugging Face

动手练习:微调 SmolLM3(下)

译自《Hands-On Exercises: Fine-Tuning SmolLM3》 · 查看英文原文

原文出处Hands-On Exercises: Fine-Tuning SmolLM3 原作者:Hugging Face · 许可证:Apache-2.0 License 中文译本由诸葛AI学院翻译整理,仅供学习参考,版权归原作者与 Hugging Face 所有。

(接上篇)

练习 3:用 SFTTrainer 对 SmolLM3 做监督微调

目标:用 TRL 库的 SFTTrainer,在真实数据集上对 SmolLM3 做监督微调(supervised fine-tuning,简称 SFT)。

注意:你需要一块至少 8GB 显存(VRAM)的 GPU。

第 1 步:环境准备与加载模型

我们加载基座模型(base model)和分词器(tokenizer),设置填充(padding)行为,把模型放到合适的设备上,为微调做好准备。

```python

导入微调所需的库

from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments from trl import SFTTrainer, SFTConfig, DataCollatorForCompletionOnlyLM from datasets import load_dataset import torch import wandb # 可选:用于实验跟踪

初始化 Weights & Biases(可选)

wandb.init(project="smollm3-finetuning")

加载用于微调的 SmolLM3 基座模型

model_name = "HuggingFaceTB/SmolLM3-3B-Base" new_model_name = "SmolLM3-Custom-SFT"

print(f"Loading {model_name}...") model = AutoModelForCausalLM.from_pretrained( model_name, dtype=torch.bfloat16, device_map="auto", trust_remote_code=True )

tokenizer = AutoTokenizer.from_pretrained(model_name) tokenizer.pad_token = tokenizer.eos_token # 设置填充令牌 tokenizer.padding_side = "right" # 生成时在右侧填充

print(f"Model loaded! Parameters: {model.num_parameters():,}") ```

python output Loading HuggingFaceTB/SmolLM3-3B-Base... Model loaded! Parameters: 3,075,098,624

准备数据集

这里我们选一个规模可控的子集来加快训练,然后用聊天模板把每条样本映射成一个 text 字符串——训练器读的就是这个字段。

```python

加载并准备训练数据集

print("=== PREPARING DATASET ===\n")

方案一:用 SmolTalk2(新手推荐)

dataset = load_dataset("HuggingFaceTB/smoltalk2", "SFT") train_dataset = dataset["smoltalk_everyday_convs_reasoning_Qwen3_32B_think"].select(range(1000)) # 取子集,训练更快

方案二:用你在练习 2 里处理好的数据集

train_dataset = gsm8k_formatted.select(range(500))

print(f"Training examples: {len(train_dataset)}") print(f"Example: {train_dataset[0]}")

准备 SFT 用的数据集

def format_chat_template(example): """用聊天模板把 messages 格式化成文本""" if "messages" in example: # SmolTalk2 的格式 messages = example["messages"] else: # 自定义格式——按需调整 messages = [ {"role": "user", "content": example["instruction"]}, {"role": "assistant", "content": example["response"]} ]

# 套用聊天模板
text = instruct_tokenizer.apply_chat_template(
    messages, 
    tokenize=False,
    add_generation_prompt=False
)
return {"text": text}

应用格式化

formatted_dataset = train_dataset.map(format_chat_template) formatted_dataset = formatted_dataset.remove_columns( [col for col in formatted_dataset.column_names if col != "text"] ) print(f"Formatted example: {formatted_dataset[0]['text'][:200]}...") ```

输出 ```python output === PREPARING DATASET === Training examples: 1000 Example: {'messages': [{'content': 'Solve the problem step by step.', 'role': 'system'}, {'content': 'Natalia sold clips to 48 of her friends in April, and then she sold half as many clips in May. How many clips did Natalia sell altogether in April and May?', 'role': 'user'}]} Formatted example: You are a math tutor. Solve problems step by step. Natalia sold clips to 48 of her friends in April, and then she sold half as many clips in May. How many clips did Natalia sell altogether in April and May?... ```

训练配置

我们配置 SFT 的几个关键参数:批大小(batch size)、序列长度、学习率(learning rate)、日志与保存频率,同时打开可选的实验跟踪和 Hub 集成。

```python

配置训练参数

training_config = SFTConfig( # 模型与数据 output_dir=f"./{new_model_name}", dataset_text_field="text", max_length=2048,

# 训练超参数
per_device_train_batch_size=2,  # 按你的显卡显存调整
gradient_accumulation_steps=2,
learning_rate=5e-5,
num_train_epochs=1,  # 先从 1 轮(epoch)开始
max_steps=500,  # 演示用,限制步数

# 优化
warmup_steps=50,
weight_decay=0.01,
optim="adamw_torch",

# 日志与保存
logging_steps=10,
save_steps=100,
eval_steps=100,
save_total_limit=2,

# 显存优化
dataloader_num_workers=0,
group_by_length=True,  # 把长度相近的序列分到一组

# Hugging Face Hub 集成
push_to_hub=False,  # 设为 True 则上传到 Hub
hub_model_id=f"your-username/{new_model_name}",

# 实验跟踪
report_to=["trackio"],  # 用 trackio 做实验跟踪
run_name=f"{new_model_name}-training",

)

print("Training configuration set!") print(f"Effective batch size: {training_config.per_device_train_batch_size * training_config.gradient_accumulation_steps}") ```

python output Training configuration set! Effective batch size: 4

可选:用 LoRA/PEFT 训练(省显存)

如果显存有限,或者想让迭代更快,可以用 PEFT 库的 LoRA。它只训练一小部分适配器(adapter)权重,基座模型保持冻结。之后你可以继续带着适配器用,也可以在部署前把它们合并回模型。

```python

用 PEFT 配置 LoRA

from peft import LoraConfig

peft_config = LoraConfig( r=8, lora_alpha=16, lora_dropout=0.05, bias="none", task_type="CAUSAL_LM", )

创建启用 LoRA 的 SFTTrainer

from trl import SFTTrainer

lora_trainer = SFTTrainer( model=model, train_dataset=formatted_dataset, # 带 "text" 字段的数据集,或在配置里用 messages + dataset_text_field args=training_config, peft_config=peft_config, # << 启用 LoRA )

print("Starting LoRA training…") lora_trainer.train() ```

第 4 步:初始化 SFTTrainer 并训练

我们实例化训练器,先记录一条训练前的基线生成结果,然后启动 train(),把训练得到的检查点(checkpoint)保存到配置好的输出目录。

```python

trainer = SFTTrainer( model=model, train_dataset=formatted_dataset, args=config, ) ```

然后就可以开始训练模型。

python trainer.train()

测试微调后的模型

最后,用同一个提示词(prompt)再生成一次,定性对比训练前后的输出;还可以把模型推送到 Hub 分享。

```python

测试微调后的模型

print("=== AFTER TRAINING ===") with torch.no_grad(): outputs = model.generate( **inputs, max_new_tokens=100, temperature=0.7, do_sample=True, pad_token_id=tokenizer.eos_token_id ) response = tokenizer.decode(outputs[0], skip_special_tokens=True) print(response[len(formatted_prompt):])

可选:推送到 Hugging Face Hub

if training_config.push_to_hub: trainer.push_to_hub( commit_message="Fine-tuned SmolLM3 with custom dataset", tags=["smol-course", "sft", "instruction-tuning"] ) print(f"Model pushed to Hub: {training_config.hub_model_id}") ```


练习 4:用 TRL CLI 走生产流程

前面的练习里,我们深入使用了 TRL 的 Python API 做微调,也研究了所用和所生成的数据。这一练习改用 TRL 的命令行工具(CLI)来微调模型,这也是生产环境里最常见的微调方式。

我们可以在 TRL CLI 里定义一条微调命令,之后用 trl sft 运行它。CLI 命令和 Python API 共用同一套配置项。

我们预先处理了 SmolTalk2 的 smoltalk_everyday_convs_reasoning_Qwen3_32B_think 子集,让它配合 TRL CLI 使用时更顺手。

```bash

用 TRL CLI 微调 SmolLM3

trl sft \ --model_name_or_path HuggingFaceTB/SmolLM3-3B-Base \ --dataset_name HuggingFaceTB/smoltalk2_everyday_convs_think \ --output_dir ./smollm3-sft-cli \ --per_device_train_batch_size 4 \ --gradient_accumulation_steps 2 \ --learning_rate 5e-5 \ --num_train_epochs 1 \ --max_length 2048 \ --logging_steps 10 \ --save_steps 500 \ --warmup_steps 100 \ --bf16 True \ --push_to_hub \ --hub_model_id your-username/smollm3-sft-cli ```

为了省事、也为了可复现,还可以把配置写进一个文件。比如建一个 sft_config.yaml,填入下面的内容:

```yaml

模型与数据集

model_name_or_path: HuggingFaceTB/SmolLM3-3B-Base dataset_name: HuggingFaceTB/smoltalk2_everyday_convs_think output_dir: ./smollm3-advanced-sft

训练超参数

per_device_train_batch_size: 2 gradient_accumulation_steps: 4 learning_rate: 3e-5 num_train_epochs: 2 max_length: 4096

优化

warmup_steps: 200 weight_decay: 0.01 optim: adamw_torch lr_scheduler_type: cosine

显存与性能

bf16: true dataloader_num_workers: 4 group_by_length: true remove_unused_columns: false

日志与评估

logging_steps: 25 eval_steps: 250 save_steps: 500 eval_strategy: steps load_best_model_at_end: true metric_for_best_model: eval_loss

Hub 集成

push_to_hub: true hub_model_id: your-username/smollm3-advanced hub_strategy: every_save ```

然后把这个文件提交进仓库,用 Git 管理起来。

```bash

用配置文件启动训练

trl sft --config sft_config.yaml ```

排错

遇到 GPU 显存不足(OOM)报错: - 把 per_device_train_batch_size 降到 1 - 把 max_length 降到 1024 或 512 - 用 torch.cuda.empty_cache() 清理显存

模型加载失败: - 检查网络连接 - 试试 device_map="cpu",改用 CPU 加载 - 测试时换小一点的模型,比如 HuggingFaceTB/SmolLM3-1.7B

训练失败: - 确认数据集格式正确 - 检查每条样本的长度是否合理(别太长) - 盯着训练损失(loss),它应该稳定下降

小结

恭喜!你完成了这一整套动手练习,内容覆盖:

  • SmolLM3 的聊天模板体系与双模式推理
  • 数据集的处理与准备技巧
  • 用 Python API 做监督微调
  • 用 CLI 工具走生产流程
  • 分布式训练环境搭建

这些是构建高质量指令微调(instruction-tuned)模型的基本功。接下来的模块里,我们会学习偏好对齐(preference alignment)、参数高效微调(parameter-efficient fine-tuning)和进阶评估方法。

延伸阅读

这篇在讲什么,跟咱们的课怎么对?

资料库是大厂公开教材的中文译本,偏原理和工程做法。想看面向中小企业的白话版本,去入门课场景课