执行摘要
- 一句话:移除 Ray runtime env 中 PYTHONPATH 转发,修复作业提交冲突
- 推荐动作:值得快速浏览,不必精读。核心收获是 Ray runtime_env 合并的约束:同名键会在 Job-level 与 programmatic 之间冲突。如果团队经常使用 Ray Job 提交训练,建议在文档中明确 PYTHONPATH 必须通过 runtime-env 提供;若存在 out-of-band ray start 场景,可在未来通过更明确的配置开关替代自动转发。
功能与动机
PR body 明确指出:When a job submitted through ray job submit --runtime-env already defines PYTHONPATH, verl adds the same key again to ray.init(runtime_env=...). Ray rejects the merge and training fails before initialization. 因此需要撤销 #7101 引入的自动转发,避免重复键冲突导致训练无法启动。
实现拆解
- 定位变更入口:
verl/trainer/constants_ppo.py 中的 get_ppo_ray_runtime_env(config=None) 是构造 PPO Ray 运行时环境的核心函数,它在调用时复制 PPO_RAY_RUNTIME_ENV["env_vars"],过滤已存在的变量,并强制注入确定性相关变量。
- 删除 PYTHONPATH 转发:base 版本在函数末尾检测
os.environ.get("PYTHONPATH"),若非空则写入 runtime_env["env_vars"]["PYTHONPATH"];head 版本删除这段逻辑(含 3 行注释),函数在注入四个确定性变量后直接返回 runtime_env。
- 保留既有行为:过滤逻辑、Megatron/MindSpeed 的
CUDA_DEVICE_MAX_CONNECTIONS 设置、以及 PYTHONHASHSEED 等变量的注入均保持不变,未影响其他调用方。
- 测试与配套:本次没有新增或修改测试,也没有配置文件或部署脚本变更;PR 仅通过 pre-commit 对
constants_ppo.py 的检查。潜在回归风险在于依赖自动转发的非 Ray Job 场景。
关键文件:
verl/trainer/constants_ppo.py(模块 训练入口;类别 source;类型 core-logic;符号 get_ppo_ray_runtime_env): 唯一变更文件,get_ppo_ray_runtime_env() 是 PPO Ray runtime env 的唯一构造入口,删除 PYTHONPATH 转发直接影响所有 Ray 后端 PPO 训练的启动行为。
关键符号:get_ppo_ray_runtime_env
关键源码片段
verl/trainer/constants_ppo.py
唯一变更文件,get_ppo_ray_runtime_env() 是 PPO Ray runtime env 的唯一构造入口,删除 PYTHONPATH 转发直接影响所有 Ray 后端 PPO 训练的启动行为。
def get_ppo_ray_runtime_env(config=None):
"""
返回 PPO 训练使用的 Ray runtime environment。
该函数避免重复注入当前进程已经存在的环境变量,
并始终在调用时刻(而非 import 时刻)注入关键变量。
Args:
config: 可选训练配置。当引擎策略为 Megatron 且 GPU 是 Hopper/Ampere 时,
会额外设置 CUDA_DEVICE_MAX_CONNECTIONS=1。
"""
# 从 Ray Job 配置中读取 working_dir,避免重复设置
working_dir = (
json.loads(os.environ.get(RAY_JOB_CONFIG_JSON_ENV_VAR, "{}"))
.get("runtime_env", {})
.get("working_dir", None)
)
runtime_env = {
"env_vars": PPO_RAY_RUNTIME_ENV["env_vars"].copy(),
**({"working_dir": None} if working_dir is None else {}),
}
# 仅 Megatron 在 Hopper/Ampere 上需要该设置,MindSpeed 也需要
if _is_hopper_or_ampere and _uses_megatron(config):
runtime_env["env_vars"]["CUDA_DEVICE_MAX_CONNECTIONS"] = "1"
if _uses_mindspeed(config):
runtime_env["env_vars"]["CUDA_DEVICE_MAX_CONNECTIONS"] = "1"
# 当前进程已设置过的变量不再重复注入,避免覆盖已有值
for key in list(runtime_env["env_vars"].keys()):
if os.environ.get(key) is not None:
runtime_env["env_vars"].pop(key, None)
# 这四个变量始终在调用时注入(而不是 import 时)
for key in ("PYTHONHASHSEED", "VERL_FULL_DETERMINISM", "VLLM_BATCH_INVARIANT", "VERL_RL_INSIGHT_ENABLE"):
runtime_env["env_vars"][key] = os.environ.get(key, "0")
# 注意:PR #7313 之前这里会把 driver 的 PYTHONPATH 转发给 Ray worker,
# 但如果任务由 `ray job submit --runtime-env` 提交且已定义 PYTHONPATH,
# 重复注入同一键会让 Ray 拒绝合并 runtime_env,训练在初始化前失败。
# 因此该转发已被移除,PYTHONPATH 由 Ray Job runtime env 统一负责传播。
return runtime_env
评论区精华
本 PR 没有任何 review 评论(comments_count=0、review_comments_count=0),由作者 yyDing1 直接提交、wuxibin89 合并。虽然没有公开讨论,核心设计权衡在于:修复了 Ray Job 合并冲突,但收紧了使用约定——自定义 PYTHONPATH 必须由 Ray Job runtime-env 显式提供;当初 #7101 为了支持 out-of-band ray start 场景而引入的自动转发被完全撤销。
风险与影响
- 风险:兼容性风险:直接
ray.init() 或 ray start 集群上,driver 的 PYTHONPATH 不再自动传给 worker,依赖 PYTHONPATH 暴露的非 site-packages 包(如 CI 镜像中的 /workspace/Megatron-LM)可能 ImportError。缺少测试覆盖:无对应单元测试,后续若重新加入转发或调整 runtime_env 结构,无法自动发现冲突。正确性风险:修复依赖用户已在 Ray Job runtime-env 中正确设置 PYTHONPATH,否则行为会从原来的启动崩溃变为静默导入失败。
- 影响:用户侧:通过
ray job submit --runtime-env 提交且已定义 PYTHONPATH 的用户从启动崩溃变为正常训练;但未正确配置 runtime-env 的用户可能遇到新的导入失败。系统侧:get_ppo_ray_runtime_env 是所有 PPO Ray 训练的公用函数,影响所有 Ray 后端 PPO 配置的启动环节,但对默认(无 PYTHONPATH 需求)训练无影响。团队侧:撤销了 #7101 的兼容性设计,后续涉及 PYTHONPATH 传播的需求需在设计层面统一。
- 风险标记:Ray 启动路径变更, 缺少测试覆盖, 依赖外部 runtime_env 传递 PYTHONPATH
关联脉络
- PR #7101 PYTHONPATH forwarding (reverted by #7313): PR body 明确说明本 PR reverts #7101 引入的 PYTHONPATH 转发,二者构成直接 revert 关系。
参与讨论