执行摘要
- 一句话:修复 spmd_types 与选择性激活检查点兼容性崩溃
- 推荐动作:该 PR 值得阅读,特别是对 TorchTitan 引擎或分布式训练中线程本地 mesh 传播机制感兴趣的开发者。设计决策(禁用 autograd 多线程)参考了 TorchTitan 上游实践,思路清晰。注意兼容性风险,建议环境确认 PyTorch 版本 >=2.5.0。
功能与动机
当 spmd_backend=spmd_types 与 activation_checkpoint=selective 组合,且 use_torch_compile=False 时,训练崩溃,错误为 spmd_types.types.SpmdTypeError: assert_type(...) requires an active mesh, but no current mesh is set.。根本原因是 spmd.assert_type 需要从 train_context 获取线程本地 SPMD mesh,但由于选择性激活检查点在 loss.backward() 期间重新运行前向传播,且 verl 在 Ray 非主线程上执行 step,导致 autograd 工作线程丢失了 mesh。编译开启时避免了此问题(因为编译会内联重计算),因此该 bug 仅在编译关闭时出现。
实现拆解
本 PR 仅修改 verl/workers/engine/torchtitan/transformer_impl.py 一个文件,主要包含三处变更:
-
_init_device_mesh 中禁用 autograd 多线程(第 290-293 行):在构建设备网格后,调用 torch.autograd.set_multithreading_enabled(False)。这确保了反向传播和激活检查点重计算在调用线程上执行,从而可以访问线程本地的 SPMD mesh。该变更参考了 TorchTitan 的 init_distributed 实现。
-
forward_backward_batch 中包裹 train_context(第 359-365 行):将 micro-batch 循环置于 self.trainer.train_context() 上下文管理器中,使得 SPMD mesh 在前后向传播中持续生效。选择性激活检查点重新运行前向时,仍能获取正确的 mesh。
-
model_forward_step 中移除多余的 train_context(第 392-396 行):由于 forward_backward_batch 已经提供了 train_context,此处的嵌套包装变得冗余,因此移除,以保持清晰。
关键文件:
verl/workers/engine/torchtitan/transformer_impl.py(模块 训练引擎;类别 source;类型 core-logic): 核心变更文件,包含了所有修复逻辑:禁用 autograd 多线程、包裹 train_context、移除冗余上下文。
关键符号:未识别
关键源码片段
verl/workers/engine/torchtitan/transformer_impl.py
核心变更文件,包含了所有修复逻辑:禁用 autograd 多线程、包裹 train_context、移除冗余上下文。
# verl/workers/engine/torchtitan/transformer_impl.py
def _init_device_mesh(self):
"""Initialize the device mesh for TorchTitan style parallelism."""
world_size = torch.distributed.get_world_size()
self.parallel_dims = ParallelDims(
dp_shard=self.engine_config.data_parallel_shard_size,
dp_replicate=self.engine_config.data_parallel_replicate_size,
cp=self.engine_config.context_parallel_size,
tp=self.engine_config.tensor_parallel_size,
pp=self.engine_config.pipeline_parallel_size,
ep=self.engine_config.expert_parallel_size,
world_size=world_size,
)
self.device_mesh = self.parallel_dims.build_mesh()
# Mirror torchtitan 's init_distributed (which verl bypasses): disable autograd
# multithreading so backward - thread activation - checkpoint recompute can access the
# thread - local SPMD mesh / process groups (e .g . current_spmd_mesh ().get_group (...)).
torch.autograd.set_multithreading_enabled(False)
def forward_backward_batch(self, data: TensorDict, loss_function: Callable, forward_only=False):
"""Perform forward and optionally backward pass on a batch."""
# ... setup code omitted ...
ctx = torch.no_grad() if forward_only else nullcontext()
# train_context activates the (thread - local) SPMD mesh required by spmd_types; it must
# span backward too, since activation - checkpoint recompute re - runs the forward there.
for micro_batch in micro_batches:
with self.trainer.train_context(), ctx:
loss, output = self.forward_step(micro_batch, loss_function=loss_function, forward_only=forward_only)
if not forward_only:
loss.backward()
output_lst.append(output)
return postprocess_batch_func(output_lst=output_lst, indices=indices, data=data)
def model_forward_step(self, *, inputs, extra_inputs=None, extra_kwargs=None):
# ... non - PP path:
assert len(model_parts) == 1
# train_context (SPMD mesh) is set by the caller (forward_backward_batch),
# so we remove the redundant wrapper here.
pred = model_parts[0](inputs, **extra_inputs, **extra_kwargs)
if isinstance(pred, DTensor):
pred = pred.full_tensor()
评论区精华
Review 中 gemini-code-assist[bot] 指出,torch.autograd.set_multithreading_enabled 在 PyTorch 2.5.0 中引入,而 veRL 仍支持 PyTorch 2.4.0(如 Docker 镜像 vemlp-th2.4.0-cu124-...),直接调用可能导致 AttributeError。建议通过 getattr(torch.autograd, "set_multithreading_enabled", None) 进行版本兼容性处理,并在 API 不可用时回退到 nullcontext()。然而,该 PR 最终并未采纳此建议,而是直接调用该 API。这可能是因为 veRL 实际上已升级最低 PyTorch 版本要求,或该问题在目标环境中不存在。wuxibin89 已批准该 PR。
- PyTorch 版本兼容性:set_multithreading_enabled 在 2.5.0 中引入 (correctness): 未采纳,PR 中直接使用了该 API。可能由于 veRL 已实际要求 PyTorch >=2.5.0。
风险与影响
- 风险:主要风险在于兼容性:
torch.autograd.set_multithreading_enabled 仅在 PyTorch 2.5.0+ 中可用。如果用户仍使用 PyTorch 2.4.0,将导致 AttributeError。虽然 veRL 的部分 Docker 镜像标记为 2.4.0,但可能实际运行时已升级至 2.5.0,需确认最低 PyTorch 版本要求。此外,禁用 autograd 多线程可能对多线程数据加载或其他依赖 autograd 多线程的特性产生性能影响,但影响范围有限(仅影响 TorchTitan 引擎,且仅在初始化时设置一次)。
- 影响:直接影响:修复了 TorchTitan 引擎中使用
spmd_types + 选择性激活检查点 + 关闭编译时的崩溃问题,使得该配置组合能够正常工作。影响范围:仅影响 verl/workers/engine/torchtitan/transformer_impl.py 中的 TorchTitan 引擎路径,不影响其他引擎(如 FSDP、Megatron)或默认配置。对用户:使用 TorchTitan 引擎且采用上述配置的用户将受益。
- 风险标记:缺少测试覆盖, 兼容性风险(PyTorch 版本依赖)
关联脉络
- PR #6916 [trainer] fix: Update latest TorchtitanEngine: 同一文件(transformer_impl.py)的近期修改,涉及 TorchTitan 引擎更新,与本 PR 的修复在同一代码路径上。
参与讨论