Megatron Core 代码地图与 RL 训推
v7 的概念齐了,还剩两个缺口。面试官会追问“这在 Megatron 里是怎么写的”,团队现在又在做 RL post-training。这一课把每一版对到 megatron/core/ 的文件上,带读一层 Transformer,再讲 RL 里同一份 weight 怎么在训练和生成两种切法之间来回搬。
一个仓库,两样东西
- Megatron Core(
megatron/core/):一个库,提供能自由组合的并行积木,有 transformer 模块,TP、PP、DP、EP、CP,FP16、BF16、FP8、FP4。可以用pip install megatron-core单独安装 - Megatron-LM:搭在 Core 上的参考训练脚本(根目录的
pretrain_gpt.py、megatron/training/) - 谁在用 Core:README 点名 Megatron Bridge(Hugging Face 和 Megatron 的 checkpoint 双向转换),官方文档还列了 NeMo RL、NeMo Framework 和 Model Optimizer
parallel_state:给每张卡发一组坐标
Process group 是一组要一起做 collective 的 rank,像微信群,all-reduce 只在群里发。每张卡同时在一个 TP 群、一个 DP 群和一个 PP 群里。
例子:16 张卡(2 台机器 × 8),TP = 2、PP = 2,DP 由代码算出来,16 ÷ (2 × 2) = 4。initialize_model_parallel 的默认 order="tp-cp-ep-dp-pp" 越靠左变化越快,CP、EP 都是 1 时就是按 tp、dp、pp 的顺序编号:
例:rank 5 = 1 + 2 × 2 + 8 × 0,坐标是 (tp 1, dp 2, pp 0),它在下表的 [4, 5]、[1, 3, 5, 7]、[5, 13] 三个群里。
| 群 | 个数 × 每群卡数 | 成员 | 在哪 |
|---|---|---|---|
| TP | 8 × 2 | [0, 1] [2, 3] … [14, 15] | 相邻 rank,同一台机器(第 8 课的规则) |
| DP | 4 × 4 | [0, 2, 4, 6] [1, 3, 5, 7] [8, 10, 12, 14] [9, 11, 13, 15] | 这个例子里也在机内 |
| PP | 8 × 2 | [0, 8] [1, 9] … [7, 15] | 跨机器 |
算成员的是 RankGenerator 类,其他代码用 get_tensor_model_parallel_group() 这类函数拿到群,再在群里调 NCCL。
文件地图
都在 megatron/core/ 下:
| 对应 | 文件 | 先看这几个名字 |
|---|---|---|
| process group | parallel_state.py | initialize_model_parallel、RankGenerator |
| 第 5 课 TP | tensor_parallel/layers.py | ColumnParallelLinear、RowParallelLinear、VocabParallelEmbedding |
| 第 5 课 f / g | tensor_parallel/mappings.py | copy_to_tensor_model_parallel_region(f)、reduce_from_tensor_model_parallel_region(g) |
| vocab-parallel loss | tensor_parallel/cross_entropy.py | vocab_parallel_cross_entropy |
| 一层 Transformer | transformer/transformer_layer.py、attention.py、mlp.py | TransformerLayer、SelfAttention、MLP |
| 第 6 课 PP | pipeline_parallel/schedules.py | get_forward_backward_func,1F1B 和 interleaved 的 forward_backward_pipelining_* |
| 第 4 课 DDP | distributed/distributed_data_parallel.py | DistributedDataParallel(bucket、overlap) |
| 第 4 课 ZeRO-1 | optimizer/distrib_optimizer.py | DistributedOptimizer |
| 第 7 课 MoE | transformer/moe/router.py、token_dispatcher.py | TopKRouter、MoEAlltoAllTokenDispatcher |
| checkpoint | dist_checkpointing/ | 加载时可以换并行配置 |
| 本课 RL | resharding/ | swap_model_weights |
怎么读:一个文件 15 分钟
- 读每个
class的 docstring,说出它解决第几课的什么问题 - 看
forward调了哪个通信函数,对上前面数过的通信次数 - fusion、FP8、CUDA graph 的分支先跳过
先读最核心的四个,约一小时:parallel_state.py → layers.py → mappings.py → attention.py 和 mlp.py。注意默认的 Transformer Engine spec 把 LayerNorm 融进了 linear_qkv(TELayerNormColumnParallelLinear),pre_mlp_layernorm 变成 IdentityOp,第一次读看 models/gpt/gpt_layer_specs.py 里的 get_gpt_layer_local_spec 更清楚。
带读:一层 TransformerLayer 的 forward
用 Qwen3-8B 的维度、TP = 2。Megatron 的 activation 按 [s, b, h] 排,sequence 在前。
input_layernorm:每卡对完整的 [s, b, 4096] 算一遍(没开 SP)self_attention(SelfAttention)linear_qkv:ColumnParallelLinear,gather_output=False。输出宽度 = Q 4096 + K 1024 + V 1024 = 6144,每卡 3072(16 个 Q head、4 个 KV head)。f 在它内部,backward 时 all-reduce input 的 gradient(参数名allreduce_dgrad)core_attention:DotProductAttention,用 Transformer Engine 时是TEDotProductAttention。每卡只算自己的 head,不通信linear_proj:RowParallelLinear,input_is_parallel=True(输入已经切好)。每卡用 [2048, 4096] 的 weight 算出部分和,g 做 all-reduce(forward 第 1 次),开了 SP 换成 reduce-scatter
self_attn_bda:bias-dropout-add,最后加 residualpre_mlp_layernormmlp(MLP)linear_fc1:ColumnParallelLinear。SwiGLU 的 gate 和 up 合成一个矩阵,宽度 2 × 12288 = 24576,每卡 12288activation_func:SwiGLU,在本卡算linear_fc2:RowParallelLinear,每卡 [6144, 4096],g 做 all-reduce(forward 第 2 次)
mlp_bda:再加一次 residual
数一下:forward 2 次 all-reduce,backward 2 次(linear_qkv、linear_fc1 的 input gradient),和第 5 课一致。每层约 193M 个 parameter(attention 42M + MLP 151M),TP = 2 时每卡约 96M。
RL post-training:一个训练引擎,一个 inference engine
GRPO、PPO 的每一轮先 rollout,用当前 policy 生成一批回答,主要是 decode,memory-bound(第 0 课)。再 training,算 reward 和 advantage 后做 gradient update,就是第 1–8 课的内容。两件事各用最合适的引擎:
- verl:训练端 FSDP、FSDP2 或 Megatron-LM;rollout 用 vLLM、SGLang 或 HF
- NVIDIA NeMo RL:训练端 Automodel(PyTorch 原生的 FSDP2、TP 等)或 Megatron(通过 Megatron Bridge);生成端 vLLM、SGLang 或 Megatron 自带的 inference
为什么每轮都要重切 weight:update 之后 inference engine 手里还是旧 weight,不同步的话 rollout 用的就是旧 policy。两边切法又不同。例如 8 张卡,训练用 TP4 × PP2(每卡一半的层、每层 1/4 的矩阵),vLLM 用 TP8(每卡全部的层、每层 1/8 的矩阵),所以每个 parameter 都要先拼起来再重切。存储格式也不同,Megatron 的 linear_qkv 按 query group 交错存(q1 q2 k1 v1 | q3 q4 k2 v2 | …),HF 和 vLLM 的 Q、K、V 是分开的,还要重排、改名。NeMo RL 把这一步叫 refit,Megatron Core 有专门的 resharding/。
要搬多少:8B 的 bf16 weight 是 16 GB,8 张卡每卡 2 GB,走 NVLink 约 4.4 ms,走 IB 约 40 ms。70B 就是 140 GB,而且每轮都要搬。
| colocated(同一批卡) | separate(分开的卡) | |
|---|---|---|
| 怎么跑 | 训练和 rollout 轮流用同一批卡,训练时 inference 端释放 KV cache | 一批卡只训练,另一批只生成 |
| weight 怎么传 | 不出机器,NeMo RL 用 CUDA IPC 直接共享 GPU memory | 跨网络,NeMo RL 默认用 NCCL broadcast |
| 取舍 | 没有卡闲着,传得快,但同一时刻只有一边在干活 | 两边能同时跑、各选并行配置,但要用落后几步的 policy(off-policy),否则一边空转 |
| 例子 | verl 的 hybrid engine(hybrid_engine: true,默认);NeMo RL colocated.enabled: true | NeMo RL colocated.enabled: false |
去查一下OpenManus-RL 基于 verl。打开你的启动脚本或 config:actor_rollout_ref.actor.strategy 是 fsdp 还是 megatron?actor_rollout_ref.rollout.name 是 vllm 还是 sglang,rollout 的 tensor_model_parallel_size 是几?hybrid_engine 是不是 true?查清楚就能讲出你那套训推每轮怎么同步 weight,这正是团队在做的事。NVIDIA 2025-10-31 的 “Deep Learning Framework Interns” LinkedIn 招聘帖把 Megatron-Core、Megatron-Bridge、NeMo-RL 列在一起,主题之一是用 NeMo-RL 做 RL post-training。2026 年夏天一位 NeMo 和 Megatron 组实习生的简历写的是给 NeMo-RL 加 delta-compressed weight 和 GPUDirect RDMA 的 refit。
30 秒英文回答
Megatron Core is NVIDIA's library of composable parallel building blocks; Megatron-LM, Megatron Bridge and NeMo RL build on it. parallel_state gives every rank TP, DP and PP coordinates. TP groups are adjacent ranks on NVLink, and PP groups cross nodes. In a layer, linear_qkv and linear_fc1 are column-parallel, linear_proj and linear_fc2 are row-parallel: two all-reduces forward, two backward. In RL, a trainer like Megatron or FSDP alternates with an inference engine like vLLM. Their layouts differ, say TP4 × PP2 versus TP8, so after every update the weights are resharded and synced.
自测
parallel_state.py 做什么?
按各维的大小和 order 给每个 rank 算坐标,建好各个 process group。默认 tp 变化最快,所以 TP 群是相邻 rank,落在机内。
16 卡,TP = 2、PP = 2、DP = 4,rank 13 在哪几个群?
13 = 1 + 2 × 2 + 8 × 1,坐标 (tp 1, dp 2, pp 1)。TP 群 [12, 13],DP 群 [9, 11, 13, 15],PP 群 [5, 13]。
ColumnParallelLinear 在哪个文件?一层里哪些 linear 用它?
tensor_parallel/layers.py。linear_qkv 和 linear_fc1 用它,linear_proj 和 linear_fc2 用 RowParallelLinear。f、g 在 mappings.py。
RL 为什么要 reshard weight?
update 后 inference 端的 weight 过期,而两端的切法和格式都不同(TP4 × PP2 vs TP8,QKV 交错存 vs 分开存),要拼起来重切再发过去。
Megatron Core 给了什么,是只用 PyTorch FSDP 得不到的?
FSDP 只在 DP 方向切 model state(约等于 ZeRO-3),activation 不切。Megatron Core 另外提供 TP + SP、PP schedule、CP、EP、distributed optimizer、FP8 kernel,以及能换并行配置加载的 distributed checkpoint,70B 以上、长序列、MoE 时缺的正是这些。
想看细一点 6.1 TP Linear · 6.2 TP communication · 6.5 Pipeline Parallel · 6.6 DP、ZeRO、FSDP · 6.8 MoE 与 Expert Parallel · 6.9 怎么选 parallelism 配置 · 3.15 RLHF、DPO、GRPO