实验室
环境 · 训练 · 压测
老师的节奏是实验驱动的。先把这三站走通,六课公式才有落点。你现在的卡:A100-40G,用 Qwen3-1.7B / 4B。
第一次训练只做这一件事
把 Qwen3-1.7B / 4B 基座变成会按指令回答的助手。框架是 TRL 的 SFTTrainer。A100-40G 大约 45 分钟;T4 请改 0.6B 或开 Unsloth,大约 90 分钟。
Archify · workflow
第一次训练:Qwen3-1.7B QLoRA
从确认 GPU 到保存 adapter,中间不要换模型。
- GPU 绿灯
- 4-bit 加载
- 挂 LoRA
- 洗成 messages
- SFTTrainer
- 保存 adapter
加载
拟合
留档
上机准备
GPU 绿灯
记下显存 GB
4-bit 加载
NF4 + 双重量化
Qwen3-1.7B-Base
挂 LoRA
r=32 α=64
约 2% 参数
TRL 训练
洗成 messages
alpaca_gpt4_zh
SFTTrainer
lr 2e-4 · 1 epoch
有效 batch 16
产出
训前三问
先记下胡话
保存 adapter
./qwen3-1.7b-sft/final
- 挂 LoRA → 先生成
- 洗成 messages → 只留 messages
这次实验的固定配方
- 模型 Qwen3-1.7B-Base,数据 llamafactory/alpaca_gpt4_zh
- QLoRA r=32 α=64,学习率 2e-4,1 个 epoch,A100-40G 约 45 分钟
100 步检查点
- 损失明显下降:继续训完
- 损失不动:先查 ChatML / messages 列,不要先改算法
Archify · dataflow
第一次 SFT 的数据怎么进模型
原始 alpaca 必须变成 role/content 列表,SFTTrainer 才认。
原始
清洗
格式
训练
产出
alpaca_gpt4_zh
指令对
第 1 课
质量过滤
短回复丢掉
>30 字
划分
95 / 5
seed=42
messages
role + content
唯一保留列
ChatML
Qwen 模板
掩码损失
只学 assistant
SFT 核心
SFTTrainer
QLoRA 一步
TRL
LoRA adapter
约 2% 参数
可接着 DPO
10 条人工看
对照基座
- alpaca_gpt4_zh → instruction/output
- alpaca_gpt4_zh → 同库划分
- 质量过滤 → 转 role
- 划分 → train/eval
- messages → 套模板
- ChatML → mask=1 仅助手
- messages → 只留这一列
- 掩码损失 → 损失
- SFTTrainer → 保存
- LoRA adapter → 加载再生成
SFTTrainer 认什么
- 只保留 messages 列,其他列删掉
- 每条是 user / assistant 的 role-content 列表
掩码一旦错
- 如果 user 的字也算损失,模型会学复述问题
- 格式错了训练不会报错,输出却会变怪
步骤 1
确认 GPU 再加载
打印 CUDA 是否可用、显存 GB。4-bit NF4 + 双重量化加载 Qwen3-1.7B-Base。
步骤 2
挂 LoRA,冻结原权重
r=32,alpha=64,目标层 q/k/v/o/gate/up/down。可训练参数约 2%。
步骤 3
训前先问三句
「用三句话介绍量子计算」 「写一个 Python 函数计算斐波那契数列」 「请以 JSON 格式列出中国四大发明」
步骤 4
数据洗成 messages
llamafactory/alpaca_gpt4_zh → role/content。丢掉过短回复。95/5 划分。
步骤 5
SFTTrainer 一次跑完
100 步后损失必须下降。不降:查格式,不要改算法。保存 ./qwen3-1.7b-sft/final。
SFTConfig 固定配方
# 固定配方,第一次不要改
# 模型 Qwen/Qwen3-1.7B-Base
# 数据 llamafactory/alpaca_gpt4_zh
# QLoRA NF4, r=32, alpha=64, 全线性层
from trl import SFTTrainer, SFTConfig
sft_config = SFTConfig(
output_dir="./qwen3-1.7b-sft",
num_train_epochs=1,
per_device_train_batch_size=4,
gradient_accumulation_steps=4,
learning_rate=2e-4,
lr_scheduler_type="cosine",
warmup_ratio=0.1,
bf16=True,
gradient_checkpointing=True,
max_length=512,
packing=False,
logging_steps=10,
eval_strategy="steps",
eval_steps=100,
report_to="none",
seed=42,
)