Chapter 13

源码导读:Trainer 继承链与文件地图

📌 本章所有路径基于 hiyouga/LlamaFactory · commit 01398eb18dd4 。 目标:读完之后你 给 LLaMA-Factory 提 PR 时知道该改哪个文件 。

13.1 源码顶层地图

src/llamafactory/
├── cli.py                       ← 命令入口(USE_V1 决定走 v0 / v1)
├── launcher.py                  ← 9 个子命令调度 + torchrun 自动拉起
├── hparams/                     ← 6 类 dataclass + parser
│   ├── model_args.py            ModelArguments(聚合 7 个 mixin)
│   ├── data_args.py             DataArguments
│   ├── training_args.py         继承 HF Seq2SeqTrainingArguments
│   ├── finetuning_args.py       FinetuningArguments(聚合 8 个 mixin)
│   ├── generating_args.py       GeneratingArguments
│   ├── evaluation_args.py       EvaluationArguments
│   └── parser.py                ★ get_train_args / get_infer_args / get_eval_args
├── data/                        ← template / dataset / mm_plugin / collator
│   ├── template.py              ★ 全部对话模板(line 487 TEMPLATES)
│   ├── parser.py                DatasetAttr + dataset_info.json 解析
│   ├── aligner.py               原始数据 → 标准化格式
│   ├── processor/               各 stage 的 tokenize 逻辑
│   ├── mm_plugin.py             多模态插件(Qwen2vlPlugin 等)
│   ├── loader.py                get_dataset() 入口
│   └── collator.py              SFTDataCollatorWith4DAttentionMask / Pairwise...
├── model/
│   ├── loader.py                load_model / load_tokenizer / load_processor
│   ├── adapter.py               ★ init_adapter 决策树 (full/freeze/lora/oft)
│   ├── patcher.py               patch_config / patch_model 自动修复点
│   └── model_utils/             quantization / liger / longlora / rope / moe /
│                                 kv_cache / mod / attention / unsloth / visual ...
├── train/                       ← 训练管线,按 stage 分子目录
│   ├── tuner.py                 ★ run_exp() 顶层 + export_model()
│   ├── trainer_utils.py         GaLore / APOLLO / BAdam 优化器接入
│   ├── callbacks.py             LogCallback / PissaConvertCallback / ...
│   ├── sft/   pt/   rm/   ppo/   dpo/   kto/   distillation/   mca/   hyper_parallel/
│   └── 每个 stage 下都有 trainer.py + workflow.py + metric.py
├── chat/                        ← chat 子命令 + ChatModel
│   ├── chat_model.py            run_chat() 入口
│   ├── hf_engine.py / vllm_engine.py / sglang_engine.py
│   └── base_engine.py
├── api/                         ← OpenAI 兼容 HTTP server
│   ├── app.py                   FastAPI 入口
│   ├── chat.py / completion.py / score.py
│   └── protocol.py              OpenAI 兼容数据结构
├── eval/                        ← 评测(MMLU、CEval、CMMLU 等)
│   ├── evaluator.py
│   └── template.py              评测 prompt 模板
├── webui/                       ← Gradio LLaMA Board
│   ├── interface.py             ★ run_web_ui() / run_web_demo()
│   ├── engine.py                后端 orchestration
│   ├── runner.py                训练任务异步执行
│   ├── manager.py               UI 组件状态注册表
│   ├── chatter.py               多 engine chat 抽象
│   └── components/              train / data / chatbot / eval / export / top / footer
├── extras/                      ← logging / env / packages / plotting
├── third_party/                 ← unsloth / liger / muon / mca 等封装
└── v1/                          ← USE_V1=1 启用的新架构(trainers / core / accelerator / plugins)

新手第一次读源码,按 cli.py → launcher.py → train/tuner.py → train/<stage>/workflow.py 的顺序读,2–3 小时能把"训练一次"的调用栈走通

13.2 从命令行到训练循环的调用栈

flowchart TB CLI["python -m llamafactory.cli train xxx.yaml
(llamafactory-cli train xxx.yaml)"] CLI --> Mn["cli.py · main()"] Mn --> Ln["launcher.py · launch()"] Ln --> SW{"command 分发"} SW -- train --> Tr["tuner.py · _training_function()"] SW -- chat --> Ch["chat/chat_model.py"] SW -- api --> Ap["api/app.py"] SW -- export --> Ex["train/tuner.py · export_model()"] Tr --> GA["hparams/parser.py
get_train_args() → 6 个 args"] GA --> Stg{"finetuning_args.stage 是哪个?"} Stg -- pt --> RPt["train/pt/workflow.py · run_pt()"] Stg -- sft --> RSft["train/sft/workflow.py · run_sft()"] Stg -- rm --> RRm["train/rm/workflow.py · run_rm()"] Stg -- ppo --> RPpo["train/ppo/workflow.py · run_ppo()"] Stg -- dpo --> RDpo["train/dpo/workflow.py · run_dpo()"] Stg -- kto --> RKto["train/kto/workflow.py · run_kto()"]

每个 workflow.py 都做同样三步:

  1. data/loader.py · get_dataset() 加载并 tokenize;
  2. model/loader.py · load_model_and_tokenizer() 加载模型 + 挂 LoRA;
  3. 构造对应 stage 的 Trainer 类(继承自 HF Trainer),调 trainer.train()

13.3 Trainer 继承关系

flowchart TB HF["transformers.Trainer
(HuggingFace 官方)"] Seq["transformers.Seq2SeqTrainer"] HF --> Seq Seq --> CSft["sft/trainer.py
CustomSeq2SeqTrainer"] HF --> CDpo["dpo/trainer.py · CustomDPOTrainer
(继承自 trl.DPOTrainer)"] HF --> CKto["kto/trainer.py · CustomKTOTrainer
(继承自 trl.KTOTrainer)"] HF --> CRm["rm/trainer.py · PairwiseTrainer"] HF --> CPpo["ppo/trainer.py · CustomPPOTrainer
(继承自 trl.PPOTrainer)"] HF --> CPt["pt/trainer.py · CustomTrainer"]

所有 stage 的 Trainer 都继承自 HF / TRL 已有的 Trainer。LLaMA-Factory 在子类里加这几件事:

13.4 模型加载链:model/loader.py

load_model_and_tokenizer() 是所有 stage 都会调的入口,主要步骤:

调用做什么
1load_tokenizer() 装 tokenizer,按需 resize embedding
2load_config() 读 HF config,注入 rope_scaling / flash_attn 等
3patcher.patch_config() monkey-patch 关键 forward(如长上下文、moe)
4AutoModelForCausalLM.from_pretrained真正把权重加载到 GPU
5patcher.patch_model() 注入 sequence_parallel、quant 钩子
6adapter.init_adapter() finetuning_type 挂 LoRA / freeze / full
7返回 (tokenizer, model)

model/adapter.py 是 LoRA / freeze / full 三种范式的真正实现,里面调用 PEFT 把 LoRA 挂上去。

13.5 数据加载链:data/loader.py

flowchart LR Y[YAML dataset 字段] --> Par["parser.py
读 dataset_info.json"] Par --> Cnv["converter.py
统一成 sharegpt 格式"] Cnv --> Tpl["template.py
按模板拼 prompt"] Tpl --> Tok["processor/
tokenize + 多模态处理"] Tok --> Pk["packing? neat?"] Pk --> Coll["collator.py
组 batch"] Coll --> DL[DataLoader]
文件职责
data/parser.py dataset_info.json 读注册项
data/converter.py 把不同格式(alpaca / sharegpt)统一到内部 schema
data/template.py 所有模型对话模板的注册表(第 4 章重点)
data/processor/ 分 stage 的 tokenize 逻辑(sft、pairwise、unsupervised 等)
data/mm_plugin.py 多模态插件(第 9 章重点)
data/collator.py 动态 padding / packing 后的 batch 组装

13.6 LoRA 在框架内的真实生命周期

flowchart TB A["YAML: finetuning_type=lora,
lora_rank=8, lora_target=all"] A --> B["model/loader.py 加载基座
(可能 4-bit 量化)"] B --> C["model/adapter.py · init_adapter()"] C --> D["调 peft.get_peft_model()
注入 LoRA 旁支"] D --> E["train/<stage>/workflow.py
构 Trainer"] E --> F["Trainer.train()"] F --> G["每 save_steps 触发:
只 save LoRA adapter"] G --> H["训练结束:
output_dir 下有 adapter_model.safetensors"] H --> I["可选: llamafactory-cli export
= load base + adapter, merge_and_unload(), save"]

13.7 想给 LLaMA-Factory 提 PR?建议从这些地方入手

改动类型对应文件
支持一个新模型 / 新模板 data/template.py_register_template
支持新数据集格式 data/converter.py + data/parser.py
新 PEFT 算法 model/adapter.py 加分支;可能要等 peft 上游先 merge
新训练 stage(如自定义 RL) 新建 train/<new_stage>/ 目录,模仿现有 stage 结构
新 loss / 新 pref_loss train/dpo/trainer.py · _compute_loss()
新多模态架构 data/mm_plugin.py 加 Plugin 类
新加速后端(如 vAttention) third_party/ 加封装,model/loader.py 加开关
修复 Web UI 一个字段不更新 webui/

13.8 阅读路线总结

把"读完这本书"作为目标,建议这样推进:

  1. 跑通最小例子(本书 ch03):建立感觉;
  2. 把 6 类 args 文件全看一遍hparams/*.py):每个字段加注释;
  3. 看一份完整 stage workflow,推荐 train/sft/workflow.py:约 100 行,覆盖"加载 → tokenize → Trainer → save"全链;
  4. 对比看 train/dpo/workflow.py:感受 RLHF 的双模型 / value-head 差异;
  5. 读一遍 model/adapter.py:理解 LoRA / freeze / full 是怎么挂上去的;
  6. 读一遍 data/template.py:理解模板系统怎么处理新模型;
  7. 动手提一个 PR(哪怕只是文档修一条),跑一遍 contribution 流程。

13.9 延伸阅读

资源用途
GitHub hiyouga/LlamaFactory 主仓库 issues / PRs
docs.llamafactory.net 官方文档站
知乎专栏 hiyouga / LLaMA-Factory tag 作者第一手讲解
HuggingFace transformers Trainer 源码 本书所有 Trainer 的母类
huggingface/peft LoRA / DoRA 等算法本体
huggingface/trl DPO / KTO / PPO Trainer 上游
本目录 PEFT 那本书低层 LoRA 实现深读
本目录 TRL 那本书 对齐算法的母库深读

13.10 6 类 args 的真实 file:line 锚点(升级版)

ch04.9 已经给过一遍;这里给"配套调用关系"的速查:

符号位置用途
ModelArguments hparams/model_args.py:542 聚合 7 mixin
DataArguments hparams/data_args.py:23 __post_init__ 在 line 189 自动 packing
FinetuningArguments hparams/finetuning_args.py:444聚合 8 mixin;__post_init__ 在 line 560 派生 use_ref_model / lora_alpha 等
TrainingArguments hparams/training_args.py:143 继承 HF Seq2SeqTrainingArguments(或 USE_MCA=1 时的 Mca 版)
GeneratingArguments hparams/generating_args.py:22to_dict(obey_generation_config) 在 line 70
EvaluationArguments hparams/evaluation_args.py
get_train_args() hparams/parser.py:304 YAML → 5 个 dataclass,含派生字段计算(line 512–519)
read_args() hparams/parser.py:85 OmegaConf 解析 + CLI override
run_exp() train/tuner.py:139 顶层入口
_training_function() train/tuner.py:68 按 stage 派发到 run_pt / run_sft / ...
export_model() train/tuner.py:234 merge + 量化 + 导出

13.11 examples/ 目录详解

仓库的 examples/读 YAML 学用法的最高密度资源。按目录列:

目录示范了什么典型 YAML
train_lora/ LoRA SFT / DPO / KTO / reward / pretrain,~32 份qwen3_lora_sft.yaml / qwen3_lora_dpo.yaml / qwen3vl_lora_sft.yaml
train_qlora/ 4-bit 量化 + LoRA(BNB / HQQ / EETQ / GPTQ / AWQ / AQLM)qwen3_lora_sft_otfq.yaml / llama3_lora_sft_gptq.yaml
train_full/ 全参 SFT,含 FSDP2qwen3_full_sft.yaml / qwen3_full_sft_fsdp2.yaml
merge_lora/ LoRA merge / GPTQ 导出 / Ollama 包qwen3_lora_sft.yaml(注意是 merge 的,不是训练)
inference/ chat / api 推理vllm.yaml / sglang.yaml
deepspeed/ ZeRO-0/2/3 + FP16/BF16/FP8 ds_configds_z3_config.json
accelerate/ HF Accelerate 配置(DDP / 设备映射)
extras/ GaLore / BAdam / APOLLO / Muon / LoRA+ / PiSSA / OFT / NEFTune各算法独立 YAML
ktransformers/ CPU-GPU 混合训练 / 推理
megatron/ Megatron-core 后端(2025-10 新)strategy: megatron
ascend/ 华为 NPU 训练
v1/ 实验性 v1 架构示例

新人最值得先打开的三份:train_lora/qwen3_lora_sft.yamlmerge_lora/qwen3_lora_sft.yamltrain_qlora/qwen3_lora_sft_otfq.yaml。这三份覆盖了 90% 的常见场景。

13.12 v0 vs v1 架构对比

仓库正在用 src/llamafactory/v1/ 重构内部架构。v0(默认)和 v1 都共存于同一份代码,靠 USE_V1 环境变量切。本书所有章节讲的都是 v0;新手别动 v1。下表给"两者怎么不一样"的速查:

维度v0(默认)v1(实验)
启用方式 默认 USE_V1=1 或 v1/ 目录下子命令
架构 HF Trainer 子类继承链 BaseTrainer → SFT/DPO/KTO 子类,pluggable engine
配置入口 hparams/parser.py v1/config 模块
数据 pipeline monolithic data/loader.py v1/core/data_engine.py 解耦
稳定性 ★★★★★ 生产推荐 ★★ 实验,接口可能变
是否在演进 只接 bugfix + 新模型 / 新方法 新架构演进焦点

读 v1 源码时不要拿 v0 的字段名去对——v1 的 BaseTrainer 抽象重写了配置层。跟踪 v1 进度:定期看 src/llamafactory/v1/ 下的 README 和近期 PR。

13.13 API / WebUI / Chat 入口速查

本书 ch12 提了导出后部署,这里把 "代码层入口" 串起来:

子命令入口函数关键文件
train tuner.run_exp() train/tuner.py:139
chat chat_model.run_chat() chat/chat_model.py
api api.run_api() api/app.py(FastAPI + uvicorn,默认 :8000)
export tuner.export_model() train/tuner.py:234
webui interface.run_web_ui() webui/interface.py(Gradio,默认 :7860)
webchat interface.run_web_demo() 同上
eval evaluator.run_eval() eval/evaluator.py

API server 的关键事实:

13.14 WebUI 组件清单(webui/components/

组件tab主要功能
train.py Train FinetuningArguments / TrainingArguments 表单生成,"Preview command" 出 YAML / CLI
data.py Train / Eval dataset_info.json 下拉 + 数据预览
chatbot.py Chat chat 流式界面
infer.py Chat infer_backend 切换(HF / vLLM / SGLang)
eval.py Evaluate MMLU / CEval / CMMLU 跑分 UI
export.py Export merge / quantize / Ollama 导出 UI
top.py 顶部 语言切换(en / zh / ru / ko / ja)
footer.py 底部 版本 / license

WebUI 的哲学:UI 表单 → 内部生成 YAML / 命令 → subprocess 调 CLI。所以"WebUI 能做的,CLI 都能做"。差异仅在方便度

13.15 跟着测试读 API

测试示范了什么
tests/data/test_template.py template 注册 + encode_oneturn / encode_multiturn
tests/data/test_processor.py SupervisedDatasetProcessor / PairwiseDatasetProcessor
tests/data/test_collator.py 4D attention mask collator
tests/model/test_adapter.py init_adapter 四条路径
tests/model/test_patcher.py 各 model-specific patch
tests/eval/test_eval.py MMLU 评测最小例
tests_v1/ v1 架构的全部 tests,结构和 v0 不同
恭喜 到这里你已经读完了 LLaMA-Factory 中文 tutorial 的全部 13 章。 剩下的就是用它,在用的过程中持续读源码 / 提 issue / 提 PR。 本书在浅克隆的 commit 01398eb18dd4 上是精确的;若你升级了仓库,记得对照 CHANGELOG。