前言
关于TP = 1的bug
首先在早期我开 TP=1的时候在 moe 的 1F1B ep overlap 的时候,会出现某个 gemm 算子输入为 null 的情况,而 moe training 大部分为 tp1,所以在要想打开 --overlap-moe-expert-parallel-comm 则需要设置 "mlp": False,如下:
../Megatron-LM/megatron/core/models/gpt/fine_grained_callables.py
@internal_api
def should_free_input(name, is_moe, config):
// ...
free_input_nodes = {
"mlp": False,
"moe_combine": True,
"moe_dispatch": not (enable_deepep or enable_hybridep)
and (CudaGraphScope.moe_preprocess not in config.cuda_graph_scope),
}
// ...以上为我在2025.10.14在 Megatron-LM 提的 issue : https://github.com/issues/created?issue=NVIDIA%7CMegatron-LM%7C1862
MoE 1F1B overlap
这里参考了 megatron 的论文内的图,核心就会原来不 overlap 的话 forward+backward 会和 a2a 纯串行,然后 baseline 内升级了两个 stream+两个 microbatch 的 overlap,这样就可以让通讯和计算 overlap。重点是 W/D 的进一步拆分后的 overlap:
- MB2 在 backward 的 mlp 阶段,权重和激活的计算拆开,激活的 Dgrad 先计算完,那么 MB2 的 Dispatch 就可以很快执行了,让其他 rank 也可以早早开始自己 layersN-1 的链式求导。
- MB2 的 attn 阶段同样把激活的计算拆开,一结束就可以让 pp backward的 send/recv提前并与 MB2 的权重的 attn 计算 overlap。 此时整个过程只剩下 2 个 babble;


fwd与 bwd 的 8 个操作怎么拆出来的
在一个 layer 的 scheduler 初始化的时候(TransformerLayerSchedulePlan),会去 build_transformer_layer_callables,这个函数就是来拆出 5 个相位,分别是 attn, dispatch, mlp, combine,mtp。并且在 attn 和 dispatch 这俩相位做了两层 detach。如下:
第一层就是 attn→ dispatch → mlp → combine→ 这个主路径,每个箭头一个 detach。
第二层就是 attn 和 dispatch 内部产出了跳过相位的桥接张量时也需要 detach。如 attn 内的 residual 和 shared_expert_output张量跳过 dispatch 和 mlp,直接参与 combine;
拆分后,每个相位单独包成一个 ScheduleNode 类,提供每个对象的 forward 和 backward。构造的时候接收 stream,event,forward_func和 backward_func。其中 backward 是直接走的 Variable._execution_engine.run_backward() 接口。在ScheduleNode.forward()的入口处就是上面所说的第一层 detach。
# 直接拿出了 pytorch autograd 引擎最薄的 wrapper
torch.autograd.backward(loss) # 高层公开 API
└─ torch.autograd.grad(...) # 算梯度
└─ Variable._execution_engine.run_backward(...) # ← 就是这行
└─ C++ autograd engine (torch/csrc/autograd/engine.cpp)
Variable._execution_engine.run_backward(
tensors=outputs, # 反向传播的起点:前向输出(即 loss / 中间输出)
grad_tensors=output_grad, # 从下游传进来的梯度(即 ∂L/∂output),作为初始 seed
keep_graph=False, # 反向后释放计算图(一次性 backward)
create_graph=False, # 不建二阶图(非 double backward 场景)
inputs=tuple(), # 空元组=对所有 requires_grad 的叶子求梯度
allow_unreachable=True, # 允许某些输出不可达(图断了不报错)
accumulate_grad=True, # 梯度累加到 .grad(而不是覆盖)
)run_backward返回 grad 在上层调度阶段通过自己手动往前传,如下:
# /Users/joker/Desktop/project/infrawaves/vccl-megatron/megatron/core/models/common/model_chunk_schedule_plan.py
# TransformerLayerSchedulePlan 的 run 函数
if b_layer is not None:
b_grad = b_layer.mtp_post_process.backward(b_grad) # ① 起点:b_grad = g_loss
b_grad = b_layer.moe_combine.backward(b_grad) # ② combine.backward(g_loss) → 返回 combine输入.grad → 赋给 b_grad
if b_layer is not None:
b_grad = b_layer.mlp.backward(b_grad) # ③ mlp.backward(b_grad) → b_grad 现在是 mlp输入.grad
if b_layer is not None:
b_grad = b_layer.moe_dispatch.backward(b_grad) # ④ dispatch.backward(b_grad) → b_grad = dispatch输入.grad
if b_layer is not None:
b_grad = b_layer.attn.backward(b_grad) # ⑤ attn.backward(b_grad) → b_grad = attn输入.grad