原文出处:Hands-On Exercises: Fine-Tuning SmolVLM2-2.2B-Instruct 原作者:Hugging Face · 许可证:Apache-2.0 License 中文译本由诸葛AI学院整理,仅供学习参考,版权归原作者与 Hugging Face 所有。
欢迎来到实操部分!这里会让你把学过的视觉语言模型(Vision Language Model, VLM)知识,全部在 HuggingFaceTB/SmolVLM2-2.2B-Instruct 上练一遍。练习从基础概念逐步推进到进阶技术,帮你积累真实的动手经验。
原文此处有一个页面横幅,提供了本练习对应的 Google Colab 笔记本。
学习目标
完成这些练习后,你将能够:
- 处理 VLM 数据集:探索并准备 HuggingFaceM4/ChartQA。
- 优化训练:用量化和 PEFT 实现高效微调。
- 动手微调模型:分别通过 Python API 和命令行工具训练 HuggingFaceTB/SmolVLM2-2.2B-Instruct。
- 为 TRL 适配数据集:把 VLM 数据集整理好,无缝接入 TRL 工作流。
- 走向生产:理解如何扩展和管理面向生产的 VLM 微调工作流。
练习 1:探索 SmolVLM2-2.2B-Instruct
目标: 熟悉 SmolVLM2-2.2B-Instruct 模型,并用数据集里的一个样本对它做一次评估。
环境准备
⚠️ 警告 - 训练需要至少 8GB 显存的 GPU。CPU/MPS 可以跑格式化和数据集探索,但训练较大的模型大概率会失败。 - 第一次运行要下载几个 GB 的模型权重,请确保磁盘有 15GB 以上的空闲空间,网络稳定。 - 如果你需要访问私有仓库,用
login()登录 Hugging Face Hub。
先安装所需的库:transformers、datasets、trl、huggingface_hub 和 trackio。这些包提供了处理模型、数据集和 Hugging Face Hub 的工具。
```bash
安装所需依赖包(在 Colab 或你的环境里运行)
pip install transformers datasets trl huggingface_hub trackio num2words==0.5.14 ```
导入依赖
现在导入后面要用的主要依赖:
```python
导入依赖
import torch import os from transformers import AutoProcessor, AutoModelForImageTextToText, BitsAndBytesConfig from transformers.image_utils import load_image ```
加载模型和处理器
1. 选择设备
先确定模型跑在哪个设备上。可以是 GPU(cuda)、Apple Silicon(mps),或者兜底用 CPU。
python
device = (
"cuda"
if torch.cuda.is_available()
else "mps" if torch.backends.mps.is_available() else "cpu"
)
2. 登录 Hugging Face
要处理私有模型,或者把你的微调模型推送到 Hub(本练习就会这么做),你需要用 Hugging Face 账号完成认证。
提示 访问令牌可以在个人资料的 Hugging Face tokens 页面创建并复制。
python
from huggingface_hub import login
login()
3. 加载模型和处理器
最后加载 HuggingFaceTB/SmolVLM2-2.2B-Instruct 模型。这里也一并初始化了 AutoProcessor,它负责让文本和图像在进入模型前都被正确预处理。
```python model_name = "HuggingFaceTB/SmolVLM2-2.2B-Instruct" model = AutoModelForImageTextToText.from_pretrained( model_name, dtype=torch.bfloat16, ).to(device)
processor = AutoProcessor.from_pretrained(model_name) ```
探索数据集
这一步加载 ChartQA 数据集的一个小子集:训练集和验证集各取 10%,让练习跑得快、也好管理。
接着我们用 matplotlib 展示其中一张图表图像,对模型的输入有个直观感受。同时打印对应的提问(query)和标签(label),帮你看清数据集的结构和模型要处理的任务类型。
原文此处内嵌了 HuggingFaceM4/ChartQA 数据集的在线浏览窗口,可以直接翻看训练集样本。
```python from datasets import load_dataset import matplotlib.pyplot as plt
train_dataset, eval_dataset = load_dataset("HuggingFaceM4/ChartQA", split=["train[:10%]", "val[:10%]"]) example = train_dataset[1] image = load_image(example["image"])
print(example["query"]) print(example["label"][0]) ```
输出
```text How many values are below 40 in Unfavorable graph? 6 ```python
plt.imshow(image)
plt.axis("off")
plt.title("Sample Chart Image")
plt.show()
原文此处有一张图,画的就是上一步用 matplotlib 显示出来的那张样本图表。
构造聊天式提示
我们创建一个聊天消息列表,里面放着用户提问和图像。
再用 processor.apply_chat_template,把它转换成模型期望的确切输入格式。
```python
定义聊天式提示
messages = [ {"role": "user", "content": [ {"type": "image", "image": image}, {"type": "text", "text": example["query"]}, ]} ]
应用聊天模板
chat_prompt = processor.apply_chat_template( messages, add_generation_prompt=True\ ) print(chat_prompt) ```
输出
```text <|im_start|>User:跑一次推理
把聊天提示和图像编码成张量(tensor),让模型生成回复,最后把输出的令牌(token)解码回文本。
```python
输入编码
inputs = processor(images=[image], text=chat_prompt, return_tensors="pt").to(device)
生成模型输出
with torch.no_grad(): output = model.generate(**inputs, max_new_tokens=20)
裁掉生成结果里属于输入的部分,只留新生成的 ids
trimmed_generated_ids = [out_ids[len(in_ids) :] for in_ids, out_ids in zip(inputs.input_ids, output)]
解码输出文本
output_text = processor.batch_decode( trimmed_generated_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False ) print(output_text[0]) ```
输出
```text 3. ```模型给出了一个回复,但不太对,做一下微调还能改进。既然已经见过怎么用 SmolVLM2-2.2B-Instruct 构造提示、生成回复,接下来就该学怎么用 LoRA(Low-Rank Adaptation,低秩适配)高效地适配和微调模型。这个思路让你用更少的资源训练大模型,也为模型接下游任务做好准备。
练习 2:用 LoRA 微调模型
这个练习里,我们用 LoRA 来高效微调视觉语言模型。
LoRA 的原理是把可训练的低秩矩阵注入模型已有的层,让大模型可以用少得多的可训练参数完成微调。这么做减少内存占用、加快训练,性能还不掉。
python
system_message = """You are a Vision Language Model specialized in interpreting visual data from chart images.
Your task is to analyze the provided chart image and respond to queries with concise answers, usually a single word, number, or short phrase.
The charts include a variety of types (e.g., line charts, bar charts) and contain colors, labels, and text.
Focus on delivering accurate, succinct answers based on the visual information. Avoid additional explanation unless absolutely necessary."""
我们要把数据集格式化成聊天机器人式的结构,每条样本包含:
- 一条系统消息,定义助手的角色
- 图表图像
- 用户提问
- 期望的回答
这正是 SFTTrainer 期望的格式,包括 images 和 messages 两列。关于如何为 VLM 后训练准备数据集,可以阅读官方文档。
格式化数据集
第一步是把数据结构整理成适合 VLM 训练的样子。我们定义一条系统消息,指示模型扮演图表分析专家,对图表图像给出简洁、准确的回答。
python
def format_data(sample):
return {
"images": [sample["image"]],
"messages": [
{
"role": "system",
"content": [{"type": "text", "text": system_message}],
},
{
"role": "user",
"content": [
{
"type": "image",
"image": sample["image"],
},
{
"type": "text",
"text": sample["query"],
},
],
},
{
"role": "assistant",
"content": [{"type": "text", "text": sample["label"][0]}],
},
],
}
现在按聊天机器人结构格式化数据,给模型搭好交互格式。
python
train_dataset = [format_data(sample) for sample in train_dataset]
eval_dataset = [format_data(sample) for sample in eval_dataset]
配置 LoRA
这里我们定义一个 LoraConfig:
r和lora_alpha控制适配矩阵的秩和缩放。target_modules指定要适配模型的哪些部分。task_type设为因果语言建模。
然后用 get_peft_model 把 LoRA 应用到基座模型上,并打印可训练参数,确认适配生效。
```python from peft import LoraConfig, get_peft_model
配置 LoRA
peft_config = LoraConfig( lora_alpha=16, lora_dropout=0.05, r=8, target_modules=["q_proj", "v_proj"], task_type="CAUSAL_LM", )
应用 PEFT 模型适配
peft_model = get_peft_model(model, peft_config)
打印可训练参数
peft_model.print_trainable_parameters() ```
搭好 Trainer
我们用 SFTConfig 来配置 trl 的 SFTTrainer:
num_train_epochs、batch_size和gradient_accumulation_steps控制训练循环。gradient_checkpointing和bf16优化内存与速度。learning_rate管理优化过程。train_dataset和eval_dataset与你的数据集对齐。
这样 trainer 就准备好用 PEFT/LoRA 做微调了。
```python from trl import SFTConfig, SFTTrainer
用 SFTConfig 配置训练参数
training_args = SFTConfig( output_dir="smol-course-smolvlm2-2.2b-instruct-trl-sft-ChartQA", num_train_epochs=1, per_device_train_batch_size=4, gradient_accumulation_steps=4, learning_rate=1e-4, logging_steps=25, save_strategy="steps", save_steps=25, optim="adamw_torch_fused", bf16=True, push_to_hub=True, report_to="trackio", max_length=None, )
初始化 Trainer
trainer = SFTTrainer( model=model, args=training_args, train_dataset=train_dataset, eval_dataset=eval_dataset, peft_config=peft_config, )
让 SFTTrainer 的参数与你选定的数据集保持一致。
```
训练并保存模型
现在跑训练循环:
trainer.train()启动 LoRA 微调。trainer.save_model()把训练好的模型存到本地。
这一步做完,模型只带着极少的额外参数,就能应对下游任务了。
```python
训练模型
trainer.train()
保存模型
trainer.save_model(training_args.output_dir) ```
Python 方式的微调和 LoRA 打底之后,我们可以用 TRL CLI 把这套流程搬进生产环境。不用写完整的 Python 脚本,就能自动化微调、搭出可复现的流水线。
练习 3:用 TRL CLI 走生产工作流
前面的练习聚焦在用 Python API 微调 SmolVLM2-2.2B-Instruct,涉及数据集准备和聊天式提示的生成。
这个练习演示怎么用 TRL CLI 做微调。这是生产环境里的常见工作流,CLI 让你不写 Python 脚本也能跑实验、管理训练。想复习的话,我们之前在第 1 单元介绍过这个工具,同样的概念和排错建议都适用。
TRL CLI 用的是和 Python API 相同的逻辑与配置项,只是包装成一个简单的命令行界面。从模型、数据集,到训练超参数、输出位置,全部可以在一条命令里定义。
下面的例子展示怎么在 trl-lib/llava-instruct-mix 数据集上微调 SmolVLM2-2.2B-Instruct:用 LoRA 做参数高效微调,用混合精度加快训练,并可选地推送到 Hub 分享模型。注意这次换了数据集。
之所以换数据集,是因为它本身已经按前面讨论过的 VLM 期望结构格式化好了。
--model_name_or_path指定要微调的基座模型。--dataset_name和--dataset_config定义数据集和子集。--output_dir设置保存微调模型的本地目录。--per_device_train_batch_size和--gradient_accumulation_steps控制有效批量大小和内存占用。--learning_rate、--num_train_epochs和--max_length定义核心的训练超参数。--bf16开启混合精度,在兼容的 GPU 上训练更快、更省内存。--push_to_hub和--hub_model_id允许把训练好的模型自动上传到你的 Hugging Face Hub 仓库。
用 TRL CLI 在功能上等价于写一个完整的 Python 训练脚本,但配置更快、更容易复现,特别适合生产流水线或自动化训练工作流。
bash
trl sft \
--model_name_or_path HuggingFaceTB/SmolVLM2-2.2B-Instruct \
--dataset_name trl-lib/llava-instruct-mix \
--output_dir ./smolvln-instruct-sft-cli \
--per_device_train_batch_size 1 \
--gradient_accumulation_steps 16 \
--learning_rate 2e-4 \
--num_train_epochs 3 \
--max_length -1 \
--logging_steps 5 \
--save_steps 100 \
--warmup_steps 50 \
--bf16 True \
--push_to_hub \
--hub_model_id your-username/smolvlm2-2.2b-instruct-sft-cli
练习 4:用 Hugging Face Jobs 训练
在第 1 单元,我们介绍过 Hugging Face Jobs(HF Jobs),并演示了怎么用这个托管云服务微调模型。HF Jobs 提供完全托管的基础设施来训练模型,不用自己搭 GPU、管理依赖、配置本地环境。这对 SFT 训练尤其有用:它既吃资源又费时间。
用同样的思路,我们也能让 HF Jobs 来微调视觉语言模型。需要的话,回看第 1 单元,温习 HF Jobs 和它的工作流程。
下面是一个用 TRL 官方维护的 SFT 脚本发起训练任务的例子:
```bash
直接使用 TRL 维护的 SFT 脚本
hf jobs uv run \ --flavor a10g-large \ --timeout 2h \ --secrets HF_TOKEN \ --with num2words==0.5.14 \ "https://raw.githubusercontent.com/huggingface/trl/main/trl/scripts/sft.py" \ --model_name_or_path HuggingFaceTB/SmolVLM2-2.2B-Instruct \ --dataset_name trl-lib/llava-instruct-mix\ --learning_rate 5e-5 \ --per_device_train_batch_size 4 \ --max_length -1 \ --max_steps 1000 \ --output_dir smolvlm2-2.2b-instruct-sft-jobs \ --push_to_hub \ --hub_model_id your-username/smolvlm2-2.2b-instruct-sft-jobs \ --report_to trackio ```
任务发起后,HF Jobs 会在云端处理整个训练过程。你可以直接在 Hugging Face Hub 上监控进度、查看日志、跟踪指标。
任务完成后:
- 微调后的模型会出现在你指定的
output_dir里。 - 如果用了
--push_to_hub,模型还会在你的 Hugging Face 账号下访问,随时可做推理或继续微调。 - 重新运行或修改任务配置,就能轻松地续跑、复制或放大训练。
这套工作流去掉了管理本地资源的负担,让你专注于模型实验和评估。
测试你的知识
本单元到这里就完成了,干得漂亮!现在通过测验检验一下学习成果。
进阶学习资源
以下是一些有用的资源,帮你加深理解,继续在视觉语言模型和 TRL 工作流上做实验:
- TRL 文档:使用 TRL 的完整参考,包括 Python API 和 CLI。
- HuggingFaceTB/SmolVLM2-2.2B-Instruct 模型卡:关于模型架构、训练和用法的详细信息。
- HuggingFaceM4/ChartQA 数据集:用于训练和微调 VLM 的数据集。
- Hugging Face Hub:分享你的微调模型、发现社区模型的平台。
- Hugging Face Discord 社区:加入社区,参与讨论、获取支持、交流排错。