Mobile wallpaper 1Mobile wallpaper 2Mobile wallpaper 3Mobile wallpaper 4Mobile wallpaper 5Mobile wallpaper 6
1448 words
7 minutes
qwen3 0.6b sft教程

写在前面#

最近想自己微调一个小模型玩玩,选了 Qwen3-0.6B,主要是因为穷(划掉)。试了好几个平台,最后发现 Modal 的 P100 还挺好用的,不过余额烧得也挺快。后来发现 Kaggle 有免费的 P100 可以用,就是要验证手机号,稍微麻烦点,但白嫖真香。

折腾了一晚上总算是跑通了,踩了不少坑,写个教程记录下,也给后来人省点时间。

1. 环境准备#

先检查下 GPU#

这步别忘了,不然跑起来发现是 CPU 那就哭了:

import torch
print("torch.cuda.is_available():", torch.cuda.is_available())
print("cuda device count:", torch.cuda.device_count())
!nvidia-smi

如果输出 False,那就赶紧去 Kaggle 设置里开启 GPU,或者检查下 Modal 的配置。

装依赖#

这里有个坑,transformers 版本很重要。我一开始用的最新版结果各种报错,后来降到 4.44.2 就好了:

pip install --no-cache-dir --force-reinstall --no-deps \
"protobuf==3.20.3" \
"transformers==4.44.2" \
"accelerate==0.33.0"

--force-reinstall 是为了确保版本对,别偷懒省略这个参数。

2. 数据准备#

去哪找数据?#

说实话,找合适的数据集挺费劲的。我的建议是直接去 HuggingFace 搜 “sft” 或者 “chinese sft”,能找到一大堆。

我用的是这个思维链数据集,质量还不错:

from datasets import load_dataset
ds = load_dataset("Jackrong/Chinese-Qwen3-235B-Thinking-2507-Distill-100k")

下载的时候可能会比较慢,耐心等等。Kaggle 上下载速度还行,Modal 有时候会快一些。

数据长什么样?#

这个数据集挺有意思的,有三个字段:

  • Input: 用户的问题
  • CoT_content: AI 的”内心独白”(思考过程)
  • Answer_content: 最后给用户看的回答

就是那种让模型学会”先思考再回答”的套路,挺酷的。

3. 开始微调#

加载模型#

import os
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
# 这个配置能避免显存碎片化,建议加上
if torch.cuda.is_available():
os.environ["PYTORCH_CUDA_ALLOC_CONF"] = "expandable_segments:True"
model_name = "Qwen/Qwen3-0.6B"
device = "cuda" if torch.cuda.is_available() else "cpu"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(
model_name,
torch_dtype=torch.float16 if device == "cuda" else torch.float32,
).to(device)
model.train()

第一次下载模型会比较慢,大概 1GB 多,可以去泡杯咖啡。

数据预处理(重点!)#

这部分是最容易出错的,我当时在这卡了好久:

from transformers import DataCollatorForLanguageModeling
# 先取一小部分数据试试,别一上来就全量
train_size = 1000
raw_train = ds["train"].shuffle(seed=42).select(range(train_size))
def preprocess_function(example):
"""
把数据转成 Qwen3 能懂的格式
"""
user_input = example["Input"]
cot = example["CoT_content"]
answer = example["Answer_content"]
# 关键在这里,用 <think> 标签包裹思考过程
assistant_content = f"<think>{cot}</think>{answer}"
messages = [
{"role": "user", "content": user_input},
{"role": "assistant", "content": assistant_content},
]
# 应用聊天模板,记得开启 thinking
text = tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=False,
enable_thinking=True, # 这个很重要!
)
tokenized = tokenizer(
text,
truncation=True,
max_length=1024, # 根据你的数据调整
)
tokenized["labels"] = tokenized["input_ids"].copy()
return tokenized
# 处理数据
tokenized_train = ds["train"].map(
preprocess_function,
remove_columns=ds["train"].column_names,
)
data_collator = DataCollatorForLanguageModeling(
tokenizer=tokenizer,
mlm=False,
)

配置训练参数#

这里的参数我调了好几次才找到比较合适的:

from transformers import Trainer, TrainingArguments
training_args = TrainingArguments(
output_dir="qwen3-0.6b-finetuned",
per_device_train_batch_size=1, # P100 显存有限,只能设 1
gradient_accumulation_steps=4, # 累积 4 步相当于 batch_size=4
learning_rate=2e-5, # 不要太大,容易炸
num_train_epochs=1, # 一个 epoch 就够了
fp16=True, # 混合精度,省显存
gradient_checkpointing=True, # 这个也很重要,再省点显存
logging_steps=10, # 每 10 步打印一次 loss
save_steps=50000, # 我不想频繁保存
save_total_limit=2,
report_to="none", # 不用 wandb 之类的
)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=tokenized_train,
data_collator=data_collator,
)

开始训练!#

# 深呼吸,开始
trainer.train()
# 保存模型
trainer.save_model("qwen3-0.6b-finetuned")
tokenizer.save_pretrained("qwen3-0.6b-finetuned")

1000 条数据大概要跑 20-30 分钟,可以去刷刷手机。记得看着点,别让 Kaggle 断连了。

4. 部署成 API(可选)#

训练完了想测试效果,可以起个简单的 API 服务:

装依赖#

pip install -U fastapi uvicorn[standard] nest_asyncio

写个简单的服务#

import torch
from fastapi import FastAPI
from pydantic import BaseModel
from transformers import AutoTokenizer, AutoModelForCausalLM
device = "cuda" if torch.cuda.is_available() else "cpu"
# 加载刚训练好的模型
tokenizer = AutoTokenizer.from_pretrained("qwen3-0.6b-finetuned")
model = AutoModelForCausalLM.from_pretrained(
"qwen3-0.6b-finetuned",
torch_dtype=torch.bfloat16 if device == "cuda" else torch.float32,
)
model.to(device)
model.eval()
app = FastAPI()
class GenerateRequest(BaseModel):
prompt: str
max_new_tokens: int = 128
temperature: float = 0.7
top_p: float = 0.9
@app.post("/generate")
async def generate(req: GenerateRequest):
messages = [{"role": "user", "content": req.prompt}]
text = tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True,
)
inputs = tokenizer(text, return_tensors="pt").to(device)
with torch.no_grad():
output_ids = model.generate(
**inputs,
max_new_tokens=req.max_new_tokens,
do_sample=True,
temperature=req.temperature,
top_p=req.top_p,
pad_token_id=tokenizer.eos_token_id,
)
gen_ids = output_ids[0][inputs["input_ids"].shape[-1]:]
output_text = tokenizer.decode(gen_ids, skip_special_tokens=True)
return {"output": output_text}

启动服务#

import nest_asyncio
import uvicorn
nest_asyncio.apply()
uvicorn.run(app, host="0.0.0.0", port=8000)

然后就可以用 curl 或者 Postman 测试了。

5. 如果显存不够…#

我知道很多人跟我一样都是穷学生,只能用免费的 GPU。如果上面的方法还是爆显存,试试 QLoRA:

from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training
from transformers import BitsAndBytesConfig
# 4-bit 量化,超级省显存
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_use_double_quant=True,
bnb_4bit_compute_dtype=torch.bfloat16,
)
model = AutoModelForCausalLM.from_pretrained(
model_name,
quantization_config=bnb_config,
device_map="auto",
)
model = prepare_model_for_kbit_training(model, use_gradient_checkpointing=True)
lora_config = LoraConfig(
r=16,
lora_alpha=32,
lora_dropout=0.05,
bias="none",
task_type="CAUSAL_LM",
target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj"],
)
model = get_peft_model(model, lora_config)

用这个方法,理论上 6GB 显存都能跑。

我踩过的坑#

  1. transformers 版本问题:最新版有时候会出奇怪的 bug,建议用稳定版
  2. 忘记设置 enable_thinking=True:导致模型学不到思维链,白训练了
  3. batch_size 设太大:直接 OOM,老老实实用 1 吧
  4. 学习率太高:模型直接崩了,loss 变成 NaN
  5. Kaggle 自动断连:记得时不时动动鼠标或者刷新页面

一些建议#

  • 刚开始先用小数据集(100-500 条)快速迭代,确认流程没问题
  • 定期看看 loss,如果不降了就可以提前停止
  • 保存好中间的 checkpoint,万一训练崩了还能恢复
  • 训练完记得在验证集上测试,别过拟合了

总结#

整个流程其实不复杂,主要就是:

  1. 准备好数据
  2. 正确处理成模型能吃的格式
  3. 调好参数开始训练
  4. 祈祷别 OOM

0.6B 这个模型虽然小,但用几千条高质量数据微调后,在特定领域表现还是挺不错的。关键是快,本地跑都行,不用一直盯着云平台的余额。

有问题欢迎在评论区问,我看到了会回复的。祝大家微调顺利,少踩坑!

qwen3 0.6b sft教程
https://mizuki.mysqil.com/posts/qwen3-sft教程/
Author
laoba
Published at
2026-01-23
License
CC BY-NC-SA 4.0

Some information may be outdated

封面
Sample Song
Sample Artist
封面
Sample Song
Sample Artist
0:00 / 0:00