LLaMA Factory:环境、双架构与调用链
本系列第 8/17 章。分析基线是 LLaMA Factory 0.9.6.dev0。从本章起连续四章阅读同一仓库,顺序不要跳:先分清环境与架构,再进入配置与训练,然后是推理与界面,最后收束到对齐与分布式。本章只回答三个问题:安装时哪些版本不能错、v0 与 v1 究竟是什么关系、一条训练命令如何走到 Trainer。三个问题都清楚了,再打开下一章的 YAML 才不会把字段读错位置。
把这三件事放在最前面,是因为后续几乎所有误读都从这里开始。依赖装错,后面的 YAML 再正确也会在 import 或 parser 处失败;把 v1 当成 v0 的加速开关,会整栈换掉 launcher;找错入口,多卡训练甚至不会启动 torchrun。先建立地图,再填细节。后面三章默认读者已经接受这张地图。
1. 环境:硬约束与验收
仓库用 Hatchling 构建,包名 llamafactory,源码采用 src/ 布局。pyproject.toml 的 requires-python 是 >=3.11。基础安装会同时带上训练、Web UI 与 API 依赖,仓库没有把它们拆成可选 extras。因此“只想装一个最小训练包”在当前版本里并不存在;可选能力另外放在 requirements/ 下,例如 bitsandbytes、DeepSpeed、vLLM、SGLang,由运行时检查决定缺了哪一项。
训练核心的版本边界必须同时看下限、上限和排除项:
| 包 | 约束 |
|---|---|
torch |
>=2.4 |
transformers |
>=4.55、<=5.6,且排除 4.57.0 |
peft |
0.18.x |
transformers!=4.57.0 是显式排除,不是文档笔误。无约束执行 pip install -U transformers peft,很容易把排除版本或越界的 PEFT 装回来。机器上的 CUDA、驱动、显存属于硬件策略,不是仓库硬约束;官方 Docker 镜像用过 Ubuntu 22.04、CUDA 12.4、Python 3.11、PyTorch 2.6.0,那只是镜像构建环境,不等于唯一支持组合。Python 用系统包、虚拟环境还是 Conda,同样属于机器策略,仓库只要求正式版解释器满足下限。同一前缀里不要混用多种解析器反复安装。
两个控制台入口完全等价,都注册到 llamafactory.cli:main:
1 | llamafactory-cli ─┐ |
安装后先做验收,不要立刻下载大模型:
1 | llamafactory-cli version |
version 应打印 0.9.6.dev0。env 打印 Python、PyTorch、Transformers、Datasets、Accelerate、PEFT,以及可选的 TRL、DeepSpeed、bitsandbytes、vLLM。默认 dataset_dir 是相对路径 data:在仓库根目录运行,或把路径改成绝对路径。CPU 可以验证导入与参数解析,但不能把“大模型训练可用”当成安装通过的标准。可选依赖按需安装即可:用到 4/8 bit QLoRA 再装 bitsandbytes,用到 ZeRO 再装 DeepSpeed,用到对应推理后端再装 vLLM 或 SGLang。解析器会在功能被启用时检查这些包,空装一堆用不到的 extras 并不能让验收更稳。
2. 双架构:整栈切换,不是局部优化
cli.py 在导入业务模块之前判断 USE_V1。因此 v1 不是 v0 Trainer 上的一个布尔开关,而是命令分发、配置系统、数据引擎、模型加载与训练循环的整体替换。两套体系可以维护各自的依赖层次,代价是配置文件和命令不能互换。
1 | llamafactory-cli ... |
默认 v0 使用扁平 YAML/JSON,经 OmegaConf 合并后再交给 Hugging Face 的 HfArgumentParser。v1 使用独立的 v1/config/,大量字段改成嵌套插件块,例如分布式、优化器、PEFT 各有 name。v1 当前没有 api、webui、export 路由;env 与 version 在 v1 launcher 中仍抛 NotImplementedError。不能把一份 v0 YAML 加上 USE_V1=1 原地迁移,默认遇到遗留字段会直接报错。实验命令应从 examples/v1/ 选取,例如 USE_V1=1 llamafactory-cli sft examples/v1/train_lora/train_lora_sft.yaml。
阅读源码时先走完一条 v0 训练链,再对照 v1。同名概念——stage、LoRA、FSDP、DPO——在两套实现里不保证字段、默认值或 YAML 结构一致。把 v1 理解成“另一份产品”,比理解成“v0 的新版本开关”更不容易走错目录。
为什么必须在 cli.py 里、而不是在 Trainer 里切换?因为两套 launcher 随后会导入完全不同的配置类与训练器。若先导入 v0 的 hparams 再试图启用 v1,进程里已经留下一套 dataclass 与依赖假设。先判断环境变量、再导入对应 launcher,才能让两套体系各自保持干净的依赖树。这不是风格偏好,而是当前源码的分叉位置。
3. 默认 v0 的训练调用链
多卡必须使用 llamafactory-cli train。launcher 在命令为 train,并且满足“FORCE_TORCHRUN=1,或设备数大于 1 且未启用 Ray/KTransformers”时,会用 subprocess 拉起 torchrun ... src/llamafactory/launcher.py。子进程执行文件底部的 __main__,绝对导入并调用 run_exp(),不再进入 launch(),因此不会无限重启。src/train.py 只是薄入口,不含自动 torchrun。调试器若看到父子两次进程,这是多卡启动的预期现象。
单进程路径可以写成:
1 | cli.main |
五个训练 dataclass 的顺序固定:ModelArguments、DataArguments、TrainingArguments、FinetuningArguments、GeneratingArguments。stage 的合法值只有 pt|sft|rm|ppo|dpo|kto。ORPO、SimPO、IPO 不是额外 stage,它们是 stage: dpo 下 pref_loss 的取值。把营销名写成独立 stage,会在参数校验处失败。
v0 的分层大致是:入口层(cli、webui、api)调用用例层(train、chat、eval),用例层再组合 data、model、hparams,底层工具在 extras。Web UI 最终仍生成参数并启动 CLI 子进程,不是另一套训练实现。API 复用 chat 门面。扩展通常沿着一条纵向链路改动:新模板改 template.py,新数据格式改 converter,新 stage 要同时改 workflow、tuner 路由和数据 processor。
也可以用目录来记责任。src/llamafactory/launcher.py 负责命令与多卡重启;hparams/parser.py 负责输入契约;train/tuner.py 负责 stage 与特殊后端路由;data/loader.py 与 model/loader.py 分别是数据和权重的总入口;chat/、api/、webui/ 只是同一套核心能力的三种呈现。eval/ 仍留在仓库里,但 CLI 的 eval 命令已经直接不可用,不要从目录名反推命令表。实验代码全部在 src/llamafactory/v1/,测试则分成 tests/ 与 tests_v1/。
环境出问题时应按“解释器 → 依赖 → 硬件 → 参数”的顺序缩小范围。先看 python --version 是否满足 3.11,再 llamafactory-cli env 核对 Transformers 与 PEFT 是否落在边界内,然后检查 torch.cuda.is_available(),最后才用 train -h 或小样本训练验证解析。报告问题时带上 env 输出、实际命令、YAML 和第一条完整异常,比只说“装好了但跑不起来”有效得多。
把调用链当成一张交通图,而不是一串文件名。用户只接触 llamafactory-cli;cli.py 决定走哪座城市(v0 或 v1);v0 的 launcher.py 决定是单车还是车队(单进程或 torchrun);run_exp 才是真正开始干活的车站。车站里先检票(五个 dataclass),再按车票上的 stage 把旅客送到对应车间。车间里的两道工序几乎总是成对出现:先把数据变成张量,再把模型放到可训练状态,最后交给 Trainer 循环。后面三章分别展开检票规则、车间工序,以及车间之外的售票窗口(Board 与 API)。先有这张图,读源码时才知道自己站在哪一层。
4. 本章应先记住的边界
环境、架构与入口一旦记错,后面三章的配置都会“看起来正确、运行不起来”。请先核对这四条:
- 依赖要同时满足下限、上限和排除项;
peft锁在0.18.x,transformers不能是4.57.0。 llamafactory-cli与lmf是同一入口,真正的分叉发生在USE_V1。USE_V1=1换掉整个 launcher,v1 没有 API、Board 与 export,也不能原地使用 v0 YAML。- 多卡训练入口是
llamafactory-cli train,不是src/train.py;调用链的枢纽是run_exp与五个 dataclass。记住入口,比记住某一个 YAML 字段更能避免整章后面的误操作。
下一章把这份调用链展开为可写的 YAML、可对齐的数据 schema,以及六个 stage 共用的训练骨架。请继续阅读:LLaMA Factory:配置、数据模块与训练流水线。
正在加载留言…