什么时候会自动走分布式:`launcher.py` 里的九个环境变量默认值
本文所有事实以
hiyouga/LlamaFactory官方仓库 2026-08-09 的内容为准。我们没有安装、训练或部署过任何模型,文中数字均为仓库源码里写着的值。
同一条 llamafactory-cli train ... 命令,你在单卡机器上敲和在八卡机器上敲,走的不是同一条路。分岔发生在 src/llamafactory/launcher.py 里,判断只有几行,而真正决定行为的九个值全部只从环境变量读——它们不在 data_args 里,不在 model_args 里,也不在任何一份示例 YAML 里。
这件事最常见的表现是:有人在多卡机器上跑训练,日志里冒出一行 Initializing ... distributed tasks at: ...,而他从头到尾没写过任何跟分布式有关的配置;反过来,也有人在多机上折腾半天,日志里始终只有单节点那一行。两种情况的答案都在同一段代码里。
分岔点:什么条件下才进分布式分支
launch() 里与分布式相关的判断是一条链,按顺序读:
第一步是强制项。如果 USE_MCA 或 USE_MEGATRON_BRIDGE 任一被启用,FORCE_TORCHRUN 会被直接置为 1,源码里对应的注释原文就是 # force use torchrun。也就是说这两个开关会连带把分布式启动打开,不需要你另外设 FORCE_TORCHRUN。
第二步是主判断。进入分布式训练的条件是:command == "train",并且满足下面二者之一——
FORCE_TORCHRUN被启用;- 或者:
get_device_count() > 1,且没在用 ray,且没在用 kt。
这条链里有三个值得单独拎出来的含义。
其一,只有 train 这一个子命令会走这条路。llamafactory-cli 一共八个子命令,chat、api、export、webchat、webui、env、version 都不进这段判断。所以”我的 export 为什么没用上多卡”这类问题,答案在别处,不在这里。
其二,多卡是默认触发的。你什么都不设,只要设备数大于 1 且没在用 ray、没在用 kt,它就会自己走分布式。这跟很多人预期的”要显式开启”是反的。
其三,单卡也可以被强制拉起来。FORCE_TORCHRUN 是一个独立于设备数的开关,设了它,设备数是多少都不影响判断结果。
九个环境变量与它们的默认值
进入分支之后,启动参数全部通过 os.getenv 读取。逐个实读如下:
| 环境变量 | 默认值 |
|---|---|
NNODES | "1" |
NODE_RANK | "0" |
NPROC_PER_NODE | str(get_device_count()),即检测到的设备数 |
MASTER_ADDR | "127.0.0.1" |
MASTER_PORT | str(find_available_port()),即自动找一个空闲端口 |
MAX_RESTARTS | "0" |
RDZV_ID | 无默认(os.getenv 不带默认值) |
MIN_NNODES | 无默认 |
MAX_NNODES | 无默认 |
这张表要按”默认值是怎么来的”分三类读,读法比数值本身更有用:
第一类是写死的字符串:NNODES 是 "1"、NODE_RANK 是 "0"、MASTER_ADDR 是 "127.0.0.1"、MAX_RESTARTS 是 "0"。这四个的共同点是——不设就是单机、本机回环、不重启。多机场景下 127.0.0.1 显然不是你要的值,但具体该填什么取决于你的集群网络,官方没给通用值,我们也不替你拍。
第二类是运行期算出来的:NPROC_PER_NODE 取的是 get_device_count() 的结果,MASTER_PORT 取的是 find_available_port() 的结果。这两个的特点是——你在两台机器上敲同一条命令,拿到的默认值可能不一样,因为它们依赖执行时的现场。端口尤其是这样,不设就是每次自动挑一个空闲的。
第三类是根本没有默认值:RDZV_ID、MIN_NNODES、MAX_NNODES 这三个的 os.getenv 调用不带第二个参数。这里要顺带纠正一个容易划错的边界——代码注释里被标为 elastic launch support(弹性启动支持)的是四个变量:MAX_RESTARTS、RDZV_ID、MIN_NNODES、MAX_NNODES。也就是说这一组里 MAX_RESTARTS 有默认值 "0",另外三个没有。它们的组合语义我们另有一篇专门讲,这里只强调”无默认”这个事实本身:不设的时候,源码里没有给这三个准备任何回退值。
表外还有一个 OPTIM_TORCH,它跟上面九个不是一类:其余九个是被读出来喂给启动过程的参数值,而 OPTIM_TORCH 走的是 is_env_enabled("OPTIM_TORCH", "1") 这个形式,也就是默认启用。要关掉它需要你显式设,它具体开关了什么不在本文的核实范围内,不展开。
一个容易错位的层级问题
这九个值只存在于环境变量这一层。它们不是 data_args、model_args、finetuning_args 里的字段,也没有出现在 Quickstart 引用的那份示例 YAML 里。代码里的读取路径就是 os.getenv。
这个层级差带来两个实际后果。一是你在 llamafactory-cli train -h 的参数列表里找 nnodes 大概率找不到——它压根不是训练参数。二是把同名 key 写进 YAML 也不在这条读取路径上,得设成环境变量才进得来。这一点请以 -h 的实际输出为准,我们只陈述源码里的读取方式。
Windows 与 Linux/macOS 的设法不一样
这条差异在本站读者身上出现频率很高,分开写。
Linux / macOS:
export FORCE_TORCHRUN=1
llamafactory-cli train examples/train_lora/qwen3_lora_sft.yaml
Windows(cmd):
set FORCE_TORCHRUN=1
llamafactory-cli train examples/train_lora/qwen3_lora_sft.yaml
上面第二行的 YAML 路径抄自 README 的 Quickstart 原文。以上为按官方参数语义组合的示例,未逐项实测,以官方文档与 --help 的实际输出为准。另外 set 是 cmd 的写法,换成别的 shell 语法不同,按你手上的终端来。
顺带说一个同源的坑:README 里部署 API 那条命令写的是 API_PORT=8000 llamafactory-cli api ...,这种”变量写在命令前面”的行内前缀是 Linux/macOS shell 的语法。Windows 的 cmd 不认这种写法,你得先 set 再敲命令。看官方 README 的命令时,这类前缀要自己翻译一遍。
走没走成,怎么判定
launcher.py 里有两行日志可以直接当判定依据,原文是:
Initializing {nproc_per_node} distributed tasks at: {master_addr}:{master_port}- 仅当
int(nnodes) > 1时额外打印:Multi-node training enabled: num nodes: {nnodes}, node rank: {node_rank}
对着这两行,几种常见情况的判定动作是清楚的:
“我没配分布式,它却起了分布式”——先确认你的 shell 里是不是残留了 FORCE_TORCHRUN,再确认有没有开 USE_MCA 或 USE_MEGATRON_BRIDGE(这两个会强制置位)。都没有的话,那就是设备数大于 1 触发的默认行为。
“我有多张卡,它却没起分布式”——按判断链倒着查:command 是不是 train;是不是在用 ray 或 kt(这两个分支会让条件不成立);get_device_count() 的结果是不是真的大于 1。
“多机没生效”——直接看第二行日志在不在。那行只在 nnodes 大于 1 时打印,看不到它,说明进程读到的 NNODES 仍是 1(默认值就是 "1")——先确认这个变量有没有真的传进执行 llamafactory-cli 的那个进程,再去怀疑别的。想先看一眼环境判断,llamafactory-cli env 这个子命令的语义就是 show environment info。
什么情况说明不是这个原因——如果报错发生在上面那行日志之后,那么选路这一步已经过了,问题在训练本身(数据、模型、显存等),继续查 launcher.py 是白费功夫;如果你跑的根本不是 train,这整段代码都不会执行,同样与它无关。这一步别省,它能帮你少改一堆无关的环境变量。
一句不算结论的收尾
这篇没有给”几张卡该设几”的建议,是因为确实没有依据:NPROC_PER_NODE 该不该覆盖、MASTER_PORT 要不要固定、NNODES 怎么和你的调度器配合,取决于你的硬件和集群,官方没给通用值,我们也没有任何实测。这篇能提供的增量只有一个——README 只说分布式用法见 examples/README.md,而真正决定行为的这九个默认值全在 launcher.py 里,你现在知道去哪儿对照了。
最后补一条仓库内的写法差异,跟本篇同源:llamafactory-cli version 打印的欢迎横幅里,项目主页写的仍是带连字符的旧名 https://github.com/hiyouga/LLaMA-Factory,而仓库当前路径是 hiyouga/LlamaFactory。仓库里新旧写法并存,如实说到这儿为止,我们不推断原因。
本文依据 LlamaFactory 官方仓库(github.com/hiyouga/LlamaFactory)的 README、data/README.md、examples/ 下的配置与 src/llamafactory/hparams/ 的参数定义整理,核对日 2026-08-09。本文内容为仓库源码与文档口径,我们没有安装、训练或部署过任何模型,文中显存数字均为官方标注的估算值(README 原文标 * estimated)而非实测占用。参数与默认值随版本变动,请以 llamafactory-cli train -h 的实际输出为准。安全相关做法请结合自身环境评估,本文不构成安全方案建议。