Chapter 03

快速上手:跑通你的第一次 LoRA SFT

📌 本章命令基于 hiyouga/LlamaFactory · commit 01398eb18dd4 。本地源码已克隆在 repos/llama-factory/ 。

3.1 两种入口:YAML 还是 Web UI?

LLaMA-Factory 提供两种使用方式,互为镜像

入口命令适合什么场景
YAML + CLIllamafactory-cli train xxx.yaml可复现、可写脚本、可上 git、生产环境
Web UI llamafactory-cli webui 第一次跑、不会写 YAML、要演示给同事看

它们在底层调的是完全同一份训练代码——Web UI 只是把 YAML 的每个字段做成了网页表单。本章带你两种都跑一次。

3.2 路线 A:用 Web UI 跑通

# 进 LlamaFactory 目录(无论怎么装的,CLI 入口都一样)
cd /Users/zjw/Documents/LLM/train/repos/llama-factory

# 启动 Web UI(默认 7860 端口,可加 --server_port 7861 改)
llamafactory-cli webui

浏览器开 http://localhost:7860/,进入 LLaMA Board 界面,关键操作步骤:

  1. 顶部 Langzh,整个界面变中文;
  2. Model nameQwen3-4B-Instruct-2507(或任何你想训的);模型源国内用户可在右上角 Model path source 里切到 ModelScope;
  3. StageSupervised Fine-Tuning
  4. Dataset 勾选 identity,alpaca_en_demo(这两个是仓库自带的 demo 数据,无需下载);
  5. LoRA configurations → 把 lora_rank 拉到 8、lora_target 设为 all
  6. 训练参数:默认值就行;
  7. Preview command,会输出对应的 CLI 命令(这一步非常宝贵——你能马上学到对应的 YAML 长什么样);
  8. Start 开始训练,下方就会实时显示 loss 曲线。

预期:在一张 24 GB 显卡上,3 epoch × 1000 条样本,大约 5–10 分钟跑完,loss 从 ~2 降到 ~0.6。

3.3 路线 B:用 YAML + CLI 跑通

打开仓库自带的范例:

cat examples/train_lora/qwen3_lora_sft.yaml

这份文件就是本章最重要的"教学样本",它的结构非常清晰,分成 5 个区段:

### model           ← 选基座模型
model_name_or_path: Qwen/Qwen3-4B-Instruct-2507
trust_remote_code: true

### method          ← 选训练算法
stage: sft
do_train: true
finetuning_type: lora
lora_rank: 8
lora_target: all

### dataset         ← 喂什么数据
dataset: identity,alpaca_en_demo
template: qwen3_nothink
cutoff_len: 2048
max_samples: 1000
preprocessing_num_workers: 16
dataloader_num_workers: 4

### output          ← 保存到哪、日志去哪
output_dir: saves/qwen3-4b/lora/sft
logging_steps: 10
save_steps: 500
plot_loss: true
overwrite_output_dir: true
save_only_model: false
report_to: none

### train           ← 标准训练超参
per_device_train_batch_size: 1
gradient_accumulation_steps: 8
learning_rate: 1.0e-4
num_train_epochs: 3.0
lr_scheduler_type: cosine
warmup_ratio: 0.1
bf16: true
ddp_timeout: 180000000
resume_from_checkpoint: null

启动:

llamafactory-cli train examples/train_lora/qwen3_lora_sft.yaml

就一行,所有事情都封装在 YAML 里。

小贴士 任何 YAML 字段都能在命令行 override:
llamafactory-cli train examples/train_lora/qwen3_lora_sft.yaml \
  learning_rate=2e-4 num_train_epochs=1
适合做超参 sweep。

3.4 训完之后

output_dir(这里是 saves/qwen3-4b/lora/sft/)会出现这些文件:

adapter_config.json            ← LoRA 配置
adapter_model.safetensors      ← LoRA 权重(增量,几十 MB)
tokenizer*                     ← tokenizer 副本(推理需要)
training_args.bin
trainer_state.json
training_loss.png              ← plot_loss=true 自动生成的曲线

注意只有 LoRA 增量,没有完整模型。如果要拿出去部署完整模型,要 merge 回基座:

llamafactory-cli export \
  model_name_or_path=Qwen/Qwen3-4B-Instruct-2507 \
  adapter_name_or_path=saves/qwen3-4b/lora/sft \
  template=qwen3_nothink \
  export_dir=merged_model

merged_model 目录下就是普通 HuggingFace 格式模型,可以 transformers.AutoModelForCausalLM.from_pretrained() 直接加载。

3.5 立刻试用训完的模型

在没 merge 的情况下也能 chat:

llamafactory-cli chat \
  model_name_or_path=Qwen/Qwen3-4B-Instruct-2507 \
  adapter_name_or_path=saves/qwen3-4b/lora/sft \
  template=qwen3_nothink \
  finetuning_type=lora

或者开 OpenAI 兼容 API:

llamafactory-cli api \
  model_name_or_path=Qwen/Qwen3-4B-Instruct-2507 \
  adapter_name_or_path=saves/qwen3-4b/lora/sft \
  template=qwen3_nothink \
  finetuning_type=lora

默认 8000 端口,curl 测试:

curl http://localhost:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "default",
    "messages": [{"role":"user","content":"你是谁?"}]
  }'

identity 数据集会让模型回答自己叫 LLaMA Board ——你能直接看到 LoRA 起效了。

3.6 把整套子命令记一下

LLaMA-Factory 用 llamafactory-cli <command> 的子命令风格,本章已经用到 4 个,全套见 src/llamafactory/launcher.py 顶部的 USAGE:

子命令用途
llamafactory-cli api 启动 OpenAI 兼容 API
llamafactory-cli chat CLI 聊天
llamafactory-cli export merge LoRA、导出模型
llamafactory-cli train 训练(本章重点)
llamafactory-cli webchat Web 聊天
llamafactory-cli webui LLaMA Board 训练 UI
llamafactory-cli env 打印环境
llamafactory-cli version 打印版本

可以用 lmf 作为 llamafactory-cli 的别名缩写。

3.7 入口背后:从 llamafactory-cli train 到 HF Trainer

"一行 llamafactory-cli train xxx.yaml"背后到底发生了什么?查 src/llamafactory/launcher.py(38–186 行)就能完整还原:

位置做什么
1cli.py:main() 根据 USE_V1 选择 v0(默认)或 v1 入口
2launcher.py:38 launch() 解析 sys.argv[1] 子命令名
3launcher.py:60–102 检测 get_device_count() > 1FORCE_TORCHRUN=1 时,自动拼出 torchrun 命令并 subprocess.run 重新拉起子进程
4子进程内:src/train.py:15 llamafactory.train.tuner 导入 run_exp,调用
5train/tuner.py:139 run_exp() read_args()(OmegaConf 解析 YAML + CLI override)
6ray_args.use_ray True → _ray_training_function;False → _training_function
7train/tuner.py:68 _training_function() get_train_args()(parser.py:304–534)拿到 5 个 dataclass
8finetuning_args.stage 分发 pt → run_pt() / sft → run_sft() / rm → run_rm() / ppo → run_ppo() / dpo → run_dpo() / kto → run_kto()
9对应 stage 的 workflow.py 加载数据 + 加载模型 + 构造 Trainer + trainer.train()

三个值得知道的关键设计:

3.8 整体流程速写

flowchart LR Y[YAML 配置] --> CLI["llamafactory-cli train"] WUI[Web UI 表单] --> Preview["Preview Command
生成等效 YAML"] Preview --> CLI CLI --> Loader[transformers 加载 base 模型] Loader --> PEFT[PEFT 注入 LoRA] PEFT --> Trainer[HF Trainer 主循环] Trainer --> Save[保存 adapter] Save --> Export["llamafactory-cli export
merge → 完整模型"] Save --> Chat["llamafactory-cli chat / api
带 adapter 推理"]