Chapter 04

核心抽象:ParallelContext 与 Process Group

📌 commit 2411b02nanotron 分布式的灵魂数据结构

nanotron 把 dp / pp / tp 三维 process group 装进一个 ParallelContext 对象。本章拆它的源码(不到 100 行)。

4.1ParallelContext 是什么

src/nanotron/parallel/context.py

class ParallelContext:
    def __init__(self, data_parallel_size, pipeline_parallel_size, tensor_parallel_size):
        # 1) 全局初始化
        if not dist.is_initialized():
            dist.init_process_group(backend="nccl")

        self.world_size = dist.get_world_size()
        assert dp * pp * tp == self.world_size

        # 2) 构造三维 mesh
        self.dp_pg = self._build_pg("dp", ...)
        self.pp_pg = self._build_pg("pp", ...)
        self.tp_pg = self._build_pg("tp", ...)

        # 3) 当前 rank 在每维的位置
        self.dp_rank = ...
        self.pp_rank = ...
        self.tp_rank = ...

4.2三维 process group 怎么排

nanotron 默认按 (pp, dp, tp) 顺序排:

rank = pp_rank * (dp_size * tp_size) + dp_rank * tp_size + tp_rank

这意味着同一个 tp group 里的卡 rank 相邻,让 TP 的 all-reduce 在 NVLink 域内最快。

4.316 卡示例

假设 16 GPU,dp=2, pp=2, tp=4

flowchart TB subgraph PP0["pp_rank=0 (rank 0-7)"] subgraph DP0a["dp_rank=0"] G0(0) G1(1) G2(2) G3(3) end subgraph DP1a["dp_rank=1"] G4(4) G5(5) G6(6) G7(7) end end subgraph PP1["pp_rank=1 (rank 8-15)"] subgraph DP0b["dp_rank=0"] G8(8) G9(9) G10(10) G11(11) end subgraph DP1b["dp_rank=1"] G12(12) G13(13) G14(14) G15(15) end end

group 划分:

4.4从 ParallelContext 拿 group

ctx = ParallelContext(dp=2, pp=2, tp=4)

# TP all-reduce 用 tp_pg
dist.all_reduce(tensor, group=ctx.tp_pg)

# DP all-reduce 用 dp_pg
dist.all_reduce(grad, group=ctx.dp_pg)

# PP send/recv 用 pp_pg
dist.send(tensor, dst=next_pp_rank, group=ctx.pp_pg)

4.5NanotronParameter

普通 nn.Parameter 没有"我在哪个 group 上切了"信息。nanotron 自己包了 NanotronParameter(看 parallel/parameters.py):

class NanotronParameter(nn.Parameter):
    def __new__(cls, tensor, ...):
        ...

    # 关键 metadata
    self.is_tied = False                  # tied weight(如 embed/lm_head)
    self.is_sharded = True/False
    self.shard_metadata = ShardMetadata(group, dim, ...)
    self.is_pipeline_metadata = ...

有了这层包装,optimizer / checkpoint 都能知道每个参数切到哪个 group 的哪个 rank,从而正确处理 reduce / save。

4.6跟 PyTorch DeviceMesh 比

nanotron ParallelContextPyTorch DeviceMesh
实现自家 ~100 行PyTorch 内核
跟 DTensor 配合原生
清晰度★★★★★(小巧易读)★★★★(更通用)
跟 PT 主版本绑定

4.7ParallelContext 源码定位

符号位置用途
ParallelContext.__init__ src/nanotron/parallel/context.py:12-58 校验 tp×cp×dp×pp == world_size,建所有 process group
_init_parallel_groups() parallel/context.py:59 真正调 torch.distributed.new_group
NanotronParameter parallel/parameters.py 带 sharding metadata 的 Parameter
TensorPointer parallel/pipeline_parallel/ PP 中跨 stage 引用的占位符
分布式辅助 distributed.py:1-50 new_group / reduce_scatter_tensor 等 torch.distributed 薄封装

5 个并行维度(tp/pp/dp/cp/ep)都在 ParallelContext 一个对象上。后面所有 layer / optimizer / dataloader 拿到这一个对象就够了。

4.8这章你需要带走的