Chapter 03
快速上手:swift sft 训 Qwen
ms-swift 的核心入口是命令行 swift sft。本章用 5 行命令训出一个 Qwen2.5-7B 的 LoRA,并讲清楚每个字段。
3.15 行训完
swift sft \
--model Qwen/Qwen2.5-7B-Instruct \
--train_type lora \
--dataset AI-ModelScope/alpaca-gpt4-data-zh \
--output_dir ./output \
--num_train_epochs 1 --learning_rate 1e-4 \
--per_device_train_batch_size 1 --gradient_accumulation_steps 16 \
--max_length 2048 --torch_dtype bfloat16 \
--lora_rank 16 --lora_alpha 32 \
--target_modules all-linear
跑完 ./output/v0-xxx/ 下产物:
checkpoint-200/
├── adapter_config.json
├── adapter_model.safetensors # LoRA adapter ~10MB
├── args.json # 训练参数全量记录
├── trainer_state.json
└── tokenizer files
3.2关键字段解读
| 字段 | 含义 | 建议 |
|---|---|---|
--model | 模型 ID(魔搭 / HF) | 必填 |
--train_type | lora / full / dora / longlora / galore / ... | lora 默认 |
--dataset | 数据集 ID 或本地 jsonl | 魔搭 / HF / 本地都行 |
--output_dir | 保存路径 | 自动加 v0-时间戳子目录 |
--torch_dtype | bfloat16 / float16 | bf16 优先 |
--max_length | 截断 | 2048-4096 |
--lora_rank / lora_alpha | LoRA 配置 | 16 / 32 |
--target_modules | "all-linear" / 列名列表 | all-linear 起步 |
3.3多卡训练
# 单机 8 卡(torchrun)
CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 \
NPROC_PER_NODE=8 \
swift sft \
--model Qwen/Qwen2.5-7B-Instruct \
--train_type lora \
--dataset alpaca-zh \
--deepspeed default-zero2 # ★ 内置 DeepSpeed 配置
--deepspeed 几个 preset:
| preset | 对应 |
|---|---|
| default-zero0 | 纯 DDP,无 ZeRO |
| default-zero1 | ZeRO-1(optim 切) |
| default-zero2 | ZeRO-2(+grad 切) |
| default-zero3 | ZeRO-3(+param 切) |
| default-zero2-offload | ZeRO-2 + CPU offload |
3.4QLoRA
swift sft \
--model Qwen/Qwen2.5-7B-Instruct \
--train_type lora \
--dataset alpaca-zh \
--quant_method bnb \
--quant_bits 4 \
--bnb_4bit_compute_dtype bfloat16 \
--bnb_4bit_quant_type nf4 \
--bnb_4bit_use_double_quant true
3.5验证训完的模型
swift infer \
--adapters ./output/v0-xxx/checkpoint-200 \
--stream true
或推理脚本:
from swift.llm import PtEngine, RequestConfig, InferRequest
engine = PtEngine(model_id_or_path="./output/v0-xxx/checkpoint-200")
resp = engine.infer(
[InferRequest(messages=[{"role":"user","content":"你好"}])],
RequestConfig(max_tokens=100),
)
print(resp[0].choices[0].message.content)
3.6第一次的常见坑
| 问题 | 处理 |
|---|---|
| 模型下载慢 | 设 USE_HF=1 走 HuggingFace;或 MODELSCOPE_CACHE 持久化 |
| OOM 第一步 | 开 --gradient_checkpointing true |
| OOM 在 eval | 降 --per_device_eval_batch_size 1 |
| chat template 报错 | 显式 --template qwen |
3.7入口背后:从 swift sft 到 Trainer
"一行 swift sft"背后的真实调用栈(基线 commit b58b1bd 上的 v4 结构,跟旧 v3 的 swift/llm/ 嵌套已经不一样了):
| 步 | 位置 | 做什么 |
|---|---|---|
| 1 | swift/cli/main.py ROUTE_MAPPING | 按子命令名 dispatch(line 14–27) |
| 2 | swift/cli/sft.py | 从 swift.pipelines 导入 sft_main 并调用 |
| 3 | main.py line 38–71 | 检测 .yaml / .json 首参数,merge 进 CLI args |
| 4 | main.py line 86–102 | 训练命令(pt / sft / rlhf / infer)自动包 torchrun |
| 5 | swift/pipelines/train/sft.py SwiftSft.run() | SwiftPipeline 基类的 run 方法;下面是它内部 4 步 |
| 5a | swift/model/register.py | get_model_tokenizer() 按 ModelType 查注册表加载 |
| 5b | swift/template/register.py | get_template_meta() 解析 template(指定或自动) |
| 5c | swift/dataset/loader.py | get_dataset() 加载 + preprocessor 归一化 |
| 5d | swift/trainers/trainer_factory.py | TrainerFactory 按 task_type / rlhf_type 选 trainer(DPO/GRPO/SFT/...) |
| 6 | swift/trainers/seq2seq_trainer.py:26 | Seq2SeqTrainer(SwiftMixin, DataLoaderMixin, HfSeq2SeqTrainer).train() |
三个关键观察:
- v4 目录扁平化:v3 时所有训练相关在
swift/llm/下,v4 拆到 top-level(swift/model/、swift/template/、swift/dataset/、swift/trainers/、swift/pipelines/),互不嵌套; - pipeline = 流程编排:
swift/pipelines/把"加载 → 构造 trainer → train"封装为一组类(SwiftSft / SwiftRLHF / SwiftInfer等),实际不重写算法只编排; - Trainer 用多继承:
Seq2SeqTrainer(SwiftMixin, DataLoaderMixin, HfSeq2SeqTrainer)—— ms-swift 不抛弃 HF Trainer,而是 mixin 注入 template / 序列并行 / 插件优化器等扩展。
3.8这章你需要带走的
- 核心命令:
swift sft --model ... --dataset ... --train_type lora; - 多卡用
NPROC_PER_NODE=8+--deepspeed default-zero2; - QLoRA 加四个
--quant_*参数; - 训完用
swift infer --adapters …直接推理验证。