Megatron-LM vs DeepSpeed vs FSDP:三大训练框架的选型指南和实战对比

训练一个 70B 模型,你有 8 张 80GB 的 A100。NVIDIA 工程师跟你说:用 Megatron-LM。微软的人说:用 DeepSpeed。PyTorch 的人说:用 FSDP。三个人都拍胸脯保证自己能省 80% 显存、提速两倍、稳定不掉点。

AI technology illustration

我当年就在这个岔路口浪费了整整一周,起因是我天真地以为这三个框架是同一个问题的三种解法,挑个快的就行。后来才发现,它们解决的问题根本不在一个维度。选错框架,比选错显存策略更致命。

张量并行:把同一个矩阵拆开让多张卡一起算

先说 Megatron-LM。它来自 NVIDIA 2019 年的论文,核心是张量并行。一个 Transformer 里的 Linear 层,本质是矩阵乘法。普通数据并行是每张卡存一份完整权重、各自算各自的 batch;Megatron 反过来,把权重矩阵本身拆成几块,分别放在不同 GPU 上,计算时每张卡只做自己那块局部计算,再通过 all-reduce 把结果拼起来。

具体到实现,Megatron 会把 QKV 和 output 这些 Linear 的权重按行或列切开。每层 forward 至少做两轮 all-reduce 通信。一张卡跑一轮完整前向,等于把整个模型的通信链路都走了一遍。因此张量并行非常依赖高带宽——单机内的 NVLink 是它的主场,跨节点用它就是自杀式体验。

我在一个 30B 模型上试过 Megatron,改了一整天模型代码,把 attention、linear 全部替换成张量并行版本,终于跑通,但通信占比高得吓人。后来换成 FSDP,十分钟烧通,速度还差不多。这个经历让我记住了:张量并行解决的是单个权重矩阵过大、一张卡放不下的问题,而不是显存优化的一般解。

ZeRO 和 FSDP:不拆计算,拆冗余

DeepSpeed 的 ZeRO 来自微软 2020 年的论文,它的思路完全不同。数据并行训练时,每张卡都保存一份完整的参数、梯度和优化器状态。拿 10B 参数模型举例,混合精度下模型状态总占用约 160GB:fp16 参数 20GB,fp16 梯度 20GB,fp32 参数副本 40GB,Adam 的一阶二阶动量 80GB。8 张卡就是 8 份完全重复的存储。ZeRO 的洞察是:这些冗余没必要存在。

于是它把优化器状态(ZeRO-1)、梯度(ZeRO-2)、参数(ZeRO-3)按卡数均分。计算的前向/反向过程中,先 all-gather 取出完整参数,算完一块就释放,等需要时再取。每一张卡并不持有完整模型副本,但整组卡的算力仍然协同完成了一次完整训练。

FSDP 可以理解为 ZeRO-3 在 PyTorch 生态中的原生实现。它把模型按层递归包装,每一层是一个分片单元。默认情况下,每个 FSDP 实例持有该层参数的一个 shard,前向传播时先 all-gather 凑齐这一层的完整权重,计算完立刻释放,反向传播时再对梯度做 reduce-scatter 分片累积。用代码表达就是这么几行:

from torch.distributed.fsdp import FullyShardedDataParallel as FSDP
model = FSDP(model)  # 等价于 ZeRO-3 的分片策略

顺带一提,FSDP 的每一步通信都发生在不同层之间,因此可以和计算天然重叠——前向算第 1 层时,正好去通信第 2 层的参数。这也是它在单机 8 卡上速度不输 Megatron 的原因之一。

一张表看清三者的适用边界

下表是我根据源码、论文和实测整理的差异,横向看就能明白为什么有人喊着 "无脑上 FSDP",也有人坚持 Megatron 不可替代。

维度 Megatron-LM (TP) DeepSpeed ZeRO-3 FSDP
切分对象 权重矩阵内部的维度 参数、梯度、优化器状态按卡均分 参数、梯度、优化器状态按层均分
通信模式 每层多次 all-reduce forward all-gather,backward reduce-scatter 与前同,但按层粒度频繁发出
通信量级 约等于张量大小 × 层数 × 2 约等于模型大小(比 DP 多个零头) 与 ZeRO-3 同级
跨节点扩展 差,受限于带宽 优秀,可到数千卡 优秀
易用性 需要改模型定义 命令行集成,HF ecosystem 友好 PyTorch 原生 API,几行代码搞定
额外能力 流水线并行、序列并行 CPU/NVMe offload、通信压缩 torch.compile 集成、meta device

注意,FSDP 和 ZeRO-3 在通信量上并没有本质差别,差别在实现粒度。FSDP 以模块为单位递归分片,能够跟 PyTorch 的计算流调度器重叠得更细;DeepSpeed 则在通信压缩、offload 和批处理优化上做得更老辣。

如果把三种方案放在一起,你会发现它们的通信开销跟模型结构的关系完全不同。张量并行的通信量正比于 hidden_size × num_layers,几乎不随 batch size 变化;ZeRO/FSDP 的通信量正比于参数总量,和 batch size 无关。所以当 batch 很小时,张量并行更亏;当 batch 很大时,两者都还可以。这个规律是我被拷打了好几次才总结出来的。

实战选型:我踩过的坑和你的行动路线

如果你现在要训一个模型,可以按下面顺序拍板:

  1. 模型能完整塞进单卡(比如 7B 的 fp16 约 14GB,80G 卡无压力)——直接用普通 DDP,或者加一个 ZeRO-1/2 就好,没必要引入分片通信。
  2. 单卡装不下,但单机 8 卡能装下——优先用 FSDP 或 ZeRO-3。它们的通信模式对 NVLink 友好,同时以后想扩到多机也不用改代码。
  3. 如果模型大到单机上怎么分都放不下(单个权重矩阵超过单卡显存),必须上 Megatron 的张量并行——只有它能切开单个矩阵。
  4. 多节点场景下,用 FSDP/ZeRO-3 做横向扩展,必要时与 Megatron 的 TP+PP 混合。NVIDIA 和微软已经把这个组合做成了 Megatron-DeepSpeed。

另一个实用的坑:如果你只有一两张卡但想训大模型,DeepSpeed 的 ZeRO-Offload 可以把优化器状态放到 CPU 内存里,这是 FSDP 短期没有的对标功能。

四个常见误区

FSDP 就是 ZeRO-3

方向相同,但实现视角不同。FSDP 递归包装每个子模块,能在更细粒度上调度通信与计算;ZeRO 作为训练引擎,用统一的抽象管理参数分区,并额外提供 offload、checkpoint 等能力。

越省显存越快

分片降低了显存占用,但换来的是额外的 all-gather/reduce-scatter。在通信带宽足够时性能几乎无损,否则反而变慢。这就是为什么单机小模型不如 DDP。

张量并行总能省显存

它能把单个矩阵的存储切开,但同时要存储激活值和临时通信缓冲,实际显存收益不一定比 ZeRO 大。而且你必须为它付出沉重的代码修改成本。

这三个框架只能选一个

现实训练中经常同时用两三种。TP 处理单个权重矩阵,PP 处理层间,ZeRO/FSDP 处理跨节点的冗余状态,它们互补。

我的最终判断

如果你要快速跑通一个实验,而且愿意接受 PyTorch 原生 API,FSDP 是最低摩擦的选择。如果你在微软生态、需要 CPU offload 或者复杂 checkpoint 机制,DeepSpeed 更成熟。如果你要冲千亿模型,并且对每一层手写优化有足够耐心,Megatron-LM 给你的控制力最强。

但别把这三者当成对立的。今天你要做一个生产级训练系统,大概率是 FSDP 或 DeepSpeed 打底,再根据模型特征叠加 Megatron 的算子级并行。理解了它们各自的切分哲学,你就能在任何一个新框架出现时一眼看清它到底在做哪一层优化。

原创文章,作者:guanweilu,如若转载,请注明出处:https://guanweilu.cn/article/1370.html

赞 (0)
上一篇 2026年9月28日 上午1:47
下一篇 2026年9月28日

相关推荐