01

pretrain() 总览:训练的总调度器

training.py L753-1082 总入口

pretrain_gpt.py 中,__main__ 最终调用的就是 pretrain()。这个函数是 Megatron-LM 整个训练流程的总调度器,按顺序执行 5 个阶段。

Step 1: initialize_megatron()

解析参数 → 设置全局变量 → 初始化 torch.distributed → 创建 TP/PP/DP/CP/EP 通信组 → 设置随机种子 → 编译 C++ 依赖

Step 2: setup_model_and_optimizer()

调用 get_model() 构建模型 → 创建优化器 (Adam/Muon) → 创建 LR 调度器 → 加载 Checkpoint

Step 3: build_train_valid_test_data_iterators()

构建 train/valid/test 数据迭代器。VPP 模式下每个 vp_stage 有独立的迭代器。

Step 4: train()

执行训练主循环。每个 iteration 调用 train_step(),周期性做 evaluation 和 checkpoint。详见训练循环篇

Step 5: 收尾

保存最终 checkpoint → 在 valid/test 集上评估 → 关闭 WandB/TensorBoard → 异步存盘完成 → 退出

training.py — pretrain() 核心骨架(伪代码)L753-1082
def pretrain(
    train_valid_test_dataset_provider,  # 回调①:数据怎么来
    model_provider,                     # 回调②:模型怎么建
    model_type,                         # 回调③:模型类型标识
    forward_step_func,                  # 回调④:前向怎么算
    ...
):
    # ---- Step 1: 初始化 ----
    initialize_megatron(...)            # 分布式环境 + 通信组 + 随机种子
    args = get_args()

    # ---- Step 2: 模型 + 优化器 ----
    model, optimizer, opt_param_scheduler = setup_model_and_optimizer(
        model_provider, model_type, ...
    )

    # ---- Step 3: 数据迭代器 ----
    train_data_iterator, valid_data_iterator, test_data_iterator = \
        build_train_valid_test_data_iterators(train_valid_test_dataset_provider)

    # ---- Step 4: 训练 ----
    if not args.skip_train and args.do_train:
        iteration, num_flops = train(
            forward_step_func, model, optimizer, opt_param_scheduler,
            train_data_iterator, valid_data_iterator, config, ...
        )

    # ---- Step 5: 收尾 ----
    if args.do_valid:
        evaluate_and_print_results(...)
    if args.do_test:
        evaluate_and_print_results(...)
    maybe_finalize_async_save(blocking=True, terminate=True)
与 pretrain_gpt.py 的关系
pretrain_gpt.py 负责定义回调(get_batch、loss_func、forward_step、model_provider),然后一行 pretrain(...) 把所有回调交给训练框架。从这里开始,控制权完全转移到 training.py
02

initialize_megatron():分布式环境初始化

initialize.py L38-169 分布式 通信组

这是 pretrain() 的第一步。它负责将一组独立的 GPU 进程组织成一个协作训练集群。

initialize_megatron() 执行流程: parse_args() 解析命令行参数 │ validate_args() 校验参数合法性 │ set_global_variables(args) 设置全局单例 │ ├── args (参数) │ ├── tokenizer (分词器) │ ├── timers (计时器) │ ├── tensorboard_writer │ └── wandb_writer │ initialize_rerun_state_machine() 容错重试状态机 │ finish_mpu_init() ├── _initialize_distributed() ← 核心:创建通信组 ├── _set_random_seed() TP-aware 随机数 └── _compile_dependencies() 编译 C++ 索引构建器

2.1 _initialize_distributed():创建通信组

initialize.py L311-395

这个函数做两件事:

  1. 初始化 PyTorch 分布式:调用 torch.distributed.init_process_group(),建立进程间的 NCCL 通信后端。
  2. 创建 Megatron 并行通信组:调用 mpu.initialize_model_parallel(),根据配置的 TP/PP/DP/CP/EP 尺寸,把所有 GPU 划分为多个通信组。
initialize.py — _initialize_distributed() 核心调用L356-385
# 1. 初始化 PyTorch 分布式(NCCL 后端)
torch.distributed.init_process_group(
    backend=args.distributed_backend,   # 通常是 'nccl'
    world_size=args.world_size,
    rank=args.rank,
    timeout=timedelta(minutes=args.distributed_timeout_minutes),
)

# 2. 创建 Megatron 的多维并行通信组
mpu.initialize_model_parallel(
    tensor_model_parallel_size=args.tensor_model_parallel_size,
    pipeline_model_parallel_size=args.pipeline_model_parallel_size,
    virtual_pipeline_model_parallel_size=args.virtual_pipeline_model_parallel_size,
    context_parallel_size=args.context_parallel_size,
    expert_model_parallel_size=args.expert_model_parallel_size,
    expert_tensor_parallel_size=args.expert_tensor_parallel_size,
    order='tp-cp-ep-dp-pp',             # 默认 rank 排列顺序
    ...
)
与 rank_and_parallel_groups.html 的关系
mpu.initialize_model_parallel() 内部会调用 RankGenerator 来根据 order='tp-cp-ep-dp-pp' 的映射公式,为每种并行维度创建对应的 ProcessGroup。详细的 rank 映射算法和通信组划分逻辑,请参阅 Rank 与并行组 一文。

2.2 _set_random_seed():TP-aware 随机数

initialize.py L406-429

分布式训练中,不同并行维度对随机数的需求不同

  • DP 副本必须看到相同的模型初始化 → 需要相同的种子
  • TP 副本中的 Dropout 需要不同的随机数(否则 TP 分区间的 dropout 会完全相关,削弱正则化效果)

Megatron 维护两套 CUDA RNG,在不同场景切换使用:

initialize.py — 随机种子设置(简化)L406-429
def _set_random_seed(seed_, data_parallel_random_init, ...):
    seed = seed_
    if data_parallel_random_init:
        seed = seed_ + mpu.get_data_parallel_rank()

    # ① 默认 RNG:所有 TP rank 种子相同
    random.seed(seed)
    np.random.seed(seed)
    torch.manual_seed(seed)
    torch.cuda.manual_seed(seed)

    # ② TP 专用 RNG:每个 TP rank 种子不同(加上 tp_rank 偏移)
    _CUDA_RNG_STATE_TRACKER.add(
        'model-parallel-rng',
        seed + mpu.get_tensor_model_parallel_rank()
    )
场景各 TP rank 的数据用哪套 RNG原因
Attention 后的 residual dropout 相同(AllReduce 后) 默认 RNG(种子相同) 必须 drop 同样位置,否则 rank 间数据不一致
Attention 内部的 attention dropout 不同(不同 head) TP RNG(种子不同) 各 head 独立 drop,保持正则化效果
MLP 中间层 dropout 不同(不同 neuron 分区) TP RNG(种子不同) 各 neuron 独立 drop
为什么 TP 分区内的 Dropout 需要不同种子?具体示例

TP=2,MLP 中间层有 4 个神经元为例。g0 持有 [n0, n1],g1 持有 [n2, n3],Dropout p=0.5。

两个 rank 用同一个种子 → 产生同一个随机序列 → 同一个 mask:

相同种子 → 同一个 mask,dropout pattern 完全相关 step 1: 两个 rank 都生成 mask [keep, drop] g0: [n0, ×] g1: [n2, ×] 位置 0 keep 位置 0 keep 位置 1 drop 位置 1 drop step 2: 两个 rank 都生成 mask [drop, keep] g0: [ ×, n1] g1: [ ×, n3] → n0 和 n2 永远同生共死,n1 和 n3 永远同生共死 → 4 个独立神经元退化为 2 个"绑定对",正则化效果减半 不同种子 → 独立的 mask,每个神经元真正独立 可能出现: g0=[n0, ×], g1=[ ×, n3] → n0+n3 存活 也可能: g0=[ ×, n1], g1=[n2, ×] → n1+n2 存活 也可能: g0=[n0, ×], g1=[n2, ×] → n0+n2 存活 → 所有组合都有可能,每个神经元真正独立决定是否 drop

2.3 _compile_dependencies():编译 C++ 数据集索引

initialize.py L172-237

Megatron 的数据集使用了 memory-mapped indexed dataset,其索引构建器是用 C++ 实现的。_compile_dependencies() 在 rank 0 上编译这些 C++ 扩展,其他 rank 等待编译完成。

此外,还会检查自定义 fused kernel(如 scaled_masked_softmax)的约束条件,不满足时 fallback 到 unfused 版本。

2.4 Rerun 状态机初始化

initialize_rerun_state_machine() 在初始化阶段就创建好容错重试的状态机。它会保存/恢复 CudaRNGStatesTracker 的状态,确保重试时的随机数可以精确重放或切换到不同 GPU。

重试机制的详细工作原理(三级诊断),已在 pretrain_gpt.html — loss_func() 中介绍。

03

get_model():模型构建与并行包装

training.py L1116-1285 模型构建 DDP/FSDP

get_model() 负责把 pretrain_gpt.py 提供的 model_provider 回调变成一个可以训练的分布式模型。这个过程分为 4 层:

get_model() 的 4 层处理: Layer 1 build_model() 构建裸模型 │ Layer 2 .cuda() 移动到 GPU │ Layer 3 Float16Module() FP16/BF16 精度包装 │ Layer 4 DDP / FSDP / torch_FSDP2 数据并行包装 输入: model_provider_func (来自 pretrain_gpt.py) 输出: List[DDP(Float16Module(GPTModel))]
SPMD:所有 GPU 运行相同的代码
分布式训练使用 SPMD(Single Program, Multiple Data)模式:所有 GPU 运行完全相同的 Python 脚本,但每个 GPU 有不同的 rank,通过 if 分支走不同路径。

代码中频繁出现的 mpu 就是 megatron.core.parallel_state 模块,它在 initialize_model_parallel() 后存储了当前 rank 在并行网格中的位置。同一个函数在不同 GPU 上返回不同的值:
mpu.get_tensor_model_parallel_rank()  # g0→0, g1→1, g2→0, g3→1, ...
mpu.is_pipeline_first_stage()      # g0→True, g1→True, 其他→False
mpu.is_pipeline_last_stage()       # g6→True, g7→True, 其他→False

3.1 build_model():每张卡构建自己的模型片段

model_provider_func 就是 pretrain_gpt.py 传进来的"造模型的函数"。pre_processpost_process 标志决定造模型的哪一段——同一份代码在不同 GPU 上,因为 mpu.is_pipeline_first_stage() 返回值不同,造出来的模型也不同:

标准 PP:所有卡运行相同代码,构建不同模型片段 所有 GPU 都执行: pre_process = mpu.is_pipeline_first_stage() # 只有 pp_rank=0 返回 True post_process = mpu.is_pipeline_last_stage() # 只有 pp_rank=3 返回 True model = model_provider(pre_process, post_process) 结果 (PP=4, 24 层 GPT): g0 (pp_rank=0): model_provider(True, False) → Embedding + 层 0-5 g2 (pp_rank=1): model_provider(False, False) → 层 6-11(纯 Transformer) g4 (pp_rank=2): model_provider(False, False) → 层 12-17(纯 Transformer) g6 (pp_rank=3): model_provider(False, True) → 层 18-23 + LayerNorm + Output Head
training.py — build_model()(简化)L1134-1154
def build_model():
    if pp_size > 1 and virtual_pp_size is not None:
        # VPP 模式:构建 virtual_pp_size 个 model chunk
        model = []
        for i in range(args.virtual_pipeline_model_parallel_size):
            pre_process = mpu.is_pipeline_first_stage(
                ignore_virtual=False, vp_stage=i
            )
            post_process = mpu.is_pipeline_last_stage(
                ignore_virtual=False, vp_stage=i
            )
            this_model = model_provider_func(
                pre_process=pre_process,
                post_process=post_process,
                vp_stage=i          # 告诉 provider 这是第几个虚拟 chunk
            )
            model.append(this_model)
    else:
        # 标准模式:只构建 1 个 model
        pre_process = mpu.is_pipeline_first_stage()
        post_process = mpu.is_pipeline_last_stage()
        model = model_provider_func(
            pre_process=pre_process,
            post_process=post_process
        )
pre_process 与 post_process
这两个标志决定模型的哪些部分会被实例化:
  • pre_process=True(PP 第一个 stage)→ 实例化 Embedding 层
  • post_process=True(PP 最后一个 stage)→ 实例化 Output Head + Loss
  • 中间 stage 两者都是 False → 只有 Transformer layers
Virtual Pipeline Parallelism (VPP) 详解 vp_stage

问题:标准 PP 中,每个 stage 必须等上游 stage 算完才能开始,产生流水线气泡(GPU 空等)。气泡比例 ≈ (PP-1) / num_microbatches

VPP 的做法:把每张卡的连续层块拆成多个不连续的小块,交错排列。数据在流水线中来回穿梭多次,气泡比例降为 (PP-1) / (num_microbatches × VPP)

24 层, PP=4, VPP=2(每卡 2 个不连续的 3 层 chunk) 标准 PP(每卡 1 段连续 6 层): g0: [层 0─5] g2: [层 6─11] g4: [层 12─17] g6: [层 18─23] VPP=2(每卡 2 段不连续 3 层): g0: [层 0─2] + [层 12─14] ← model[0] + model[1] g2: [层 3─5] + [层 15─17] g4: [层 6─8] + [层 18─20] g6: [层 9─11] + [层 21─23] 前向路径穿过所有 8 个 chunk: g0(0─2) → g2(3─5) → g4(6─8) → g6(9─11) → g0(12─14) → g2(15─17) → g4(18─20) → g6(21─23) ────────── 第一轮穿过 4 卡 ────────── ────────── 第二轮再穿一遍 ──────────

代码中的 vp_stage 就是虚拟 chunk 的编号。以 g0(pp_rank=0)为例,循环 2 次造 2 个 model chunk:

g0 (pp_rank=0) 执行 build_model(): i=0: is_first_stage(vp_stage=0) → True ← 全局第一个 chunk is_last_stage(vp_stage=0) → False model[0] = Embedding + 层 0─2 i=1: is_first_stage(vp_stage=1) → False ← 不是全局第一个 is_last_stage(vp_stage=1) → False model[1] = 层 12─14(纯 Transformer 层) g6 (pp_rank=3) 执行 build_model(): i=0: is_first_stage(vp_stage=0) → False is_last_stage(vp_stage=0) → False model[0] = 层 9─11(纯 Transformer 层) i=1: is_first_stage(vp_stage=1) → False is_last_stage(vp_stage=1) → True ← 全局最后一个 chunk model[1] = 层 21─23 + LayerNorm + Output Head

所以 VPP 模式下 model 不再是一个模型,而是一个 list。每个元素是这张卡负责的一个 chunk,前向时依次执行。

3.2 GPU 放置与精度转换

模型构建后,依次执行两步转换:

training.py — GPU 放置 + FP16 包装L1191-1201
# 1. 移动到 GPU(FSDP2 除外,它在 fully_shard 时分配显存)
for model_module in model:
    model_module.cuda(torch.cuda.current_device())

# 2. FP16/BF16 精度包装
if args.fp16 or args.bf16:
    config = get_model_config(model[0])
    model = [Float16Module(config, model_module) for model_module in model]

Float16Module 是一个包装器,它将模型参数转为半精度,但保留 master weights(FP32 副本)用于优化器更新,避免精度损失。

3.3 数据并行包装:DDP vs FSDP

training.py L1218-1283

Megatron 支持三种数据并行策略,通过命令行参数选择:

策略参数特点
Megatron DDP 默认(不加额外参数) 自研 DDP,支持 overlap_grad_reduce 梯度通信重叠、自定义 bucket 大小
Megatron FSDP --use-megatron-fsdp 自研 Fully Sharded DP,将参数+梯度分片到各 DP rank,节约显存
Torch FSDP2 --use-torch-fsdp2 PyTorch 官方 FSDP2 实现,需要 torch≥2.4
training.py — 数据并行包装(简化)L1218-1278
# 选择 DP 实现
if args.use_torch_fsdp2:
    DP = torch_FSDP
elif args.use_megatron_fsdp:
    DP = megatron_FSDP
else:
    DP = DDP   # Megatron 自研 DDP

# DDP 配置(仅 Megatron DDP)
ddp_config = DistributedDataParallelConfig(
    grad_reduce_in_fp32=args.accumulate_allreduce_grads_in_fp32,
    overlap_grad_reduce=args.overlap_grad_reduce,   # 梯度通信与计算重叠
    overlap_param_gather=args.overlap_param_gather,  # 参数收集与计算重叠
    bucket_size=args.ddp_bucket_size or auto_bucket_size,
    ...
)

# 包装每个 model chunk
model = [
    DP(
        config=config,
        ddp_config=ddp_config,
        module=model_chunk,
        # VPP 模式下,model_chunk 1+ 的通信已经和计算重叠了
        # 所以关闭它们的 bucketing
        disable_bucketing=(model_chunk_idx > 0),
    )
    for model_chunk_idx, model_chunk in enumerate(model)
]
Bucket Size 自动计算
如果用户没有指定 --ddp-bucket-size,Megatron 会自动计算:
bucket_size = max(40_000_000, 1_000_000 × dp_world_size)
大 DP 集群需要更大的 bucket,确保 NCCL ring-reduce 的 chunk 足够大,维持在带宽瓶颈(而非延迟瓶颈)区间。
什么是 Bucketing?为什么需要它?计算-通信重叠

朴素做法:等所有层的梯度都算完,再发起一次大的 AllReduce。计算和通信完全串行。

Bucketing:把参数按固定大小分成若干桶。后面的层先算完梯度,攒满一个桶就立刻发起 AllReduce,同时 GPU 继续算前面的层——实现计算和通信重叠

朴素做法: 先算完,再通信(串行) 计算: ██ 层23 ██ 层22 ██ 层21 ██ ... ██ 层0 │ 通信: │ ████ AllReduce 全部梯度 ████ │ ↑ 等所有梯度算完才开始 总时间 = 计算 + 通信 Bucketing: 算一批发一批(重叠) 计算: ██ 层23 ██ 层22 ██ 层21 ██ 层20 ██ 层19 ██ 层18 ██ ... ↑ ↑ bucket 0 满了 bucket 1 满了 通信: ████ AR_0 ████ ████ AR_1 ████ ... 总时间 ≈ max(计算, 通信) ← 快得多

bucket_size 的 tradeoff:太大则桶少、重叠差(退化为朴素做法);太小则每次 AllReduce 数据量太小、NCCL 启动开销占比大。默认约 40M 参数是一个平衡点。

VPP 的 disable_bucketing 优化 VPP 反向调度

VPP 模式下每张卡有多个 model chunk。代码中 disable_bucketing=(model_chunk_idx > 0),即只有 model[0] 开启 bucketing。原因在于 VPP 的反向顺序:

VPP=2, g0 持有 model[0](层 0─2) 和 model[1](层 12─14) 反向顺序: model[1] 先算 → model[0] 后算 Phase 1: model[1] 反向(层 14→13→12) 计算: ██ 层14 ██ 层13 ██ 层12 │ │ ← model[1] 梯度算完了 Phase 2: model[0] 反向 + model[1] 梯度通信 │ 计算: ██ 层2 ██ 层1 ██ 层0 │ 通信: ████ model[1] AllReduce █│███ ↑ │ 和 model[0] 计算完美重叠 │ ← 不需要 bucketing! 一大包发出去即可 │ 拆小包反而多了 NCCL 启动开销 │ Phase 3: model[0] 梯度通信 │ 计算: (空) │ ← 没有更多计算了 通信: ████ model[0] AllReduce █│███ ↑ 没有计算可以重叠 需要 bucketing 在自身反向内部制造重叠
chunk反向顺序梯度通信能和谁重叠bucketing
model[1] 先算 和 model[0] 的计算重叠(跨 chunk) 关闭,一大包更高效
model[0] 后算 没有后续计算了 开启,在自身反向内部制造重叠
04

setup_model_and_optimizer():组装一切

training.py L1344-1501 优化器 Checkpoint

这个函数把模型构建、优化器创建和 checkpoint 加载串联在一起,返回训练所需的三件套:(model, optimizer, opt_param_scheduler)

setup_model_and_optimizer() 执行流程: get_model(model_provider) 构建 + DDP 包装 │ OptimizerConfig(**args) 从 args 构建优化器配置 │ get_megatron_optimizer() 或 创建优化器 get_megatron_muon_optimizer() (取决于 --optimizer 参数) │ get_optimizer_param_scheduler() 创建 LR 调度器 │ load_checkpoint() 加载检查点 (如果有) │ return (model, optimizer, opt_param_scheduler)

4.1 优化器选择:Adam vs Muon

training.py — 优化器创建L1368-1390
# 从 args 构建 OptimizerConfig
config = OptimizerConfig(**{
    f.name: getattr(args, f.name)
    for f in dataclasses.fields(OptimizerConfig)
    if hasattr(args, f.name)
})

# 根据 --optimizer 参数选择优化器
if 'muon' not in config.optimizer:
    # 标准路径:Adam / AdamW(分布式优化器)
    optimizer = get_megatron_optimizer(
        config, model,
        no_weight_decay_cond,    # 哪些参数不要 weight decay
        scale_lr_cond,           # 哪些参数用不同学习率
        ...
    )
else:
    # Muon 优化器(实验性)
    optimizer = get_megatron_muon_optimizer(
        config, model, ...
    )

get_megatron_optimizer() 返回的是 DistributedOptimizer,它将优化器状态(如 Adam 的 m 和 v)分片到各 DP rank 上,每个 rank 只存储和更新自己负责的那部分参数。这与在 集合通信操作 — 分布式优化器 中描述的策略一致。

4.2 学习率调度器

training.py L1288-1342

get_optimizer_param_scheduler() 支持两种训练计量方式:

  • Iteration-based--train-iters):按训练步数调度 LR
  • Sample-based--train-samples):按处理的样本数调度 LR

两者最终都会被转换为 OptimizerParamScheduler 的统一接口,支持 warmup → decay → min_lr 的标准调度曲线。支持的衰减方式包括 linear、cosine 和 WSD (Warmup-Stable-Decay)。

4.3 Checkpoint 加载

training.py L1442-1468
training.py — Checkpoint 加载L1442-1468
if args.load is not None or args.pretrained_checkpoint is not None:
    # 加载 checkpoint,恢复:
    #   - 模型权重
    #   - 优化器状态(Adam 的 m, v)
    #   - LR 调度器状态
    #   - 训练进度(iteration, consumed_samples)
    args.iteration, args.num_floating_point_operations_so_far = load_checkpoint(
        model,
        optimizer,
        opt_param_scheduler,
        checkpointing_context=checkpointing_context,
    )
else:
    # 从零开始训练
    args.iteration = 0
    args.num_floating_point_operations_so_far = 0

load_checkpoint() 会自动处理分布式 checkpoint 的分片加载——每个 TP/PP rank 只加载自己那份参数。

4.4 MoE Upcycling(可选)

training.py L1395-1441 MoE

当设置 --moe-use-upcycling 时,Megatron 会执行一次 Dense → MoE 转换

  1. 先构建一个临时的 dense 模型
  2. 从 checkpoint 加载 dense 权重
  3. 调用 upcycling_utils.load_and_upcycle_model() 将 dense MLP 的权重复制到每个 MoE expert 中
  4. 保存转换后的 MoE checkpoint,然后退出

这是一种常见的 MoE 初始化策略:从预训练好的 dense 模型出发,将每个 expert 初始化为 MLP 的副本,然后继续训练让 router 学会分配 token。

4.5 Checkpoint 格式转换(可选)

training.py L1482-1499

当设置 --ckpt-convert-format 时,setup_model_and_optimizer() 会在加载 checkpoint 后立即以新格式重新保存,然后退出。这用于在不同 checkpoint 格式之间转换(如 torchtorch_dist)。

05

数据迭代器构建

training.py L921-956 training.py L3990-4150 数据

模型和优化器就绪后,pretrain() 构建数据迭代器。这里有 VPP 和非 VPP 两条路径。

training.py — 数据迭代器构建(pretrain 内部)L921-954
if args.virtual_pipeline_model_parallel_size is not None:
    # VPP 模式:每个 vp_stage 有独立的 data iterator
    train_data_iterator = []
    valid_data_iterator = []
    test_data_iterator = []
    for vp_stage in range(len(model)):
        vp_provider = functools.partial(
            train_valid_test_dataset_provider,
            vp_stage=vp_stage
        )
        iterators = build_train_valid_test_data_iterators(vp_provider)
        train_data_iterator.append(iterators[0])
        valid_data_iterator.append(iterators[1])
        test_data_iterator.append(iterators[2])
else:
    # 标准模式:单一 data iterator
    train_data_iterator, valid_data_iterator, test_data_iterator = \
        build_train_valid_test_data_iterators(
            train_valid_test_dataset_provider
        )

5.1 build_train_valid_test_data_iterators() 调用链

数据迭代器的构建是一个三层调用链:

build_train_valid_test_data_iterators() L4076 │ ├── get_train_valid_test_num_samples() 计算 train/valid/test 各需要多少样本 │ └── build_train_valid_test_data_loaders() L4003 │ ├── build_train_valid_test_datasets() L3990 │ │ │ └── train_valid_test_dataset_provider() │ ← 来自 pretrain_gpt.py 的回调 │ ← 内部调用 BlendedMegatronDatasetBuilder │ └── build_pretraining_data_loader() │ └── DataLoader + MegatronPretrainingSampler └── 确保每个 DP rank 看到不重叠的数据切片
数据集只在需要的 rank 上构建
回忆 pretrain_gpt.html — 数据集构建 中的设计:只有 TP rank 0 + PP 第一/最后 stage 需要构建数据集。其他 rank 通过 TP broadcast 获取数据。
06

总结:初始化完成后的全局状态

pretrain() 走完前三步、即将进入 train() 时,系统已经准备好了以下全局状态:

组件内容获取方式
命令行参数 所有训练配置(模型大小、并行策略、学习率等) get_args()
分词器 SentencePiece / HuggingFace / GPT2 tokenizer get_tokenizer()
通信组 TP / PP / DP / CP / EP 各维度的 ProcessGroup mpu.get_*_group()
模型 List[DDP(Float16Module(GPTModel))],已在 GPU 上 局部变量 model
优化器 DistributedOptimizer(Adam 状态分片到各 DP rank) 局部变量 optimizer
LR 调度器 OptimizerParamScheduler(warmup → decay → min_lr) 局部变量 opt_param_scheduler
数据迭代器 train / valid / test 各一个(VPP 下为列表) 局部变量
训练进度 args.iteration + args.consumed_train_samples get_args()
日志 Writer TensorBoard / WandB / OneLogger get_tensorboard_writer()
容错 Rerun 状态机 + FT integration get_rerun_state_machine()
下一步
一切就绪后,pretrain() 调用 train() 进入训练主循环。train() 会在 while iteration < train_iters 循环中反复调用 train_step(),每步执行一次前向-反向-优化器更新。详见 训练循环篇
flowchart LR subgraph Init["初始化篇 (本文)"] A["initialize_megatron()"] --> B["get_model()"] B --> C["setup_model_and_optimizer()"] C --> D["build_data_iterators()"] end subgraph Loop["训练循环篇"] E["train()"] F["train_step()"] E --> F end D --> E