源码导读:Trainer 继承链与文件地图
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 从命令行到训练循环的调用栈
(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 都做同样三步:
- 调
data/loader.py · get_dataset()加载并 tokenize; - 调
model/loader.py · load_model_and_tokenizer()加载模型 + 挂 LoRA; - 构造对应 stage 的
Trainer类(继承自 HF Trainer),调trainer.train()。
13.3 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 在子类里加这几件事:
- 覆盖
compute_loss:把 LoRA / RM / DPO 的特殊 loss 计算挂进去; - 覆盖
create_optimizer:支持 LoRA+、GaLore、Apollo、BAdam 等特殊优化器; - 覆盖
_save/_load:处理 adapter / value head 单独存读; - 插入回调(
LogCallback、PissaConvertCallback、ReporterCallback)。
13.4 模型加载链:model/loader.py
load_model_and_tokenizer() 是所有 stage 都会调的入口,主要步骤:
| 步 | 调用 | 做什么 |
|---|---|---|
| 1 | load_tokenizer() | 装 tokenizer,按需 resize embedding |
| 2 | load_config() | 读 HF config,注入 rope_scaling / flash_attn 等 |
| 3 | patcher.patch_config() | monkey-patch 关键 forward(如长上下文、moe) |
| 4 | AutoModelForCausalLM.from_pretrained | 真正把权重加载到 GPU |
| 5 | patcher.patch_model() | 注入 sequence_parallel、quant 钩子 |
| 6 | adapter.init_adapter() | 按 finetuning_type 挂 LoRA / freeze / full |
| 7 | 返回 (tokenizer, model) |
model/adapter.py 是 LoRA / freeze / full 三种范式的真正实现,里面调用 PEFT 把 LoRA 挂上去。
13.5 数据加载链:data/loader.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 在框架内的真实生命周期
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 阅读路线总结
把"读完这本书"作为目标,建议这样推进:
- 跑通最小例子(本书 ch03):建立感觉;
- 把 6 类 args 文件全看一遍(
hparams/*.py):每个字段加注释; - 看一份完整 stage workflow,推荐
train/sft/workflow.py:约 100 行,覆盖"加载 → tokenize → Trainer → save"全链; - 对比看
train/dpo/workflow.py:感受 RLHF 的双模型 / value-head 差异; - 读一遍
model/adapter.py:理解 LoRA / freeze / full 是怎么挂上去的; - 读一遍
data/template.py:理解模板系统怎么处理新模型; - 动手提一个 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:22 | to_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,含 FSDP2 | qwen3_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_config | ds_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.yaml → merge_lora/qwen3_lora_sft.yaml → train_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 的关键事实:
- FastAPI + OpenAI 兼容:endpoints 是
/v1/models / /v1/chat/completions / /v1/score/evaluation; - API key 鉴权:env
API_KEY=xxx即开 Bearer Token 校验; - Lifespan:每 300s 自动 sweep GPU memory;
- infer_backend:HF / vLLM / SGLang 三选一,运行时切换不需要重启。
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 不同 |
commit 01398eb18dd4 上是精确的;若你升级了仓库,记得对照 CHANGELOG。