Chapter 05

FSDP2:和 FSDP1 的区别在哪

📌 commit af33f762024 重写的 FSDP,PyTorch 主推

FSDP 是 PyTorch 自家的 ZeRO-3 实现。2024 重写后叫 FSDP2,TorchTitan 全用 FSDP2。本章讲两者差异。

5.1FSDP 是什么

Fully Sharded Data Parallel:把 model 参数、梯度、optimizer state 切到所有 DP rank 上,每张卡只持 1/N 份。forward / backward 时按需 all-gather 重组完整 weight。等价于 DeepSpeed ZeRO-3。

5.2FSDP1 的痛点

5.3FSDP2 的设计

FSDP1FSDP2
参数表示FlatParameterDTensor
state_dictcallback 风格原生 named_parameters() 直接用
跟 TP 配合原生兼容(都基于 DTensor)
partial freeze直接 p.requires_grad = False
torch.compile限制多原生支持
API 入口FullyShardedDataParallelfully_shard(函数)

5.4FSDP2 API 风格

from torch.distributed.fsdp import fully_shard

# FSDP2 是函数式 API,不是包装类
for layer in model.layers:
    fully_shard(layer, mesh=mesh["dp_shard"])
fully_shard(model, mesh=mesh["dp_shard"])

# 之后正常 forward/backward
out = model(x)
out.loss.backward()
optimizer.step()

不再有 FullyShardedDataParallel(model) 这种包装;而是用 fully_shard() 函数原地给指定 module 标记 sharding。

5.5HSDP:Hybrid Shard Data Parallel

FSDP2 支持二维 mesh,外维 Replicate + 内维 Shard,节省跨机带宽:

mesh = init_device_mesh("cuda", (2, 8), mesh_dim_names=("dp_replicate", "dp_shard"))
# 假设 16 GPU 分布在 2 节点 × 8 GPU
# - 节点内 8 卡做 FSDP shard
# - 节点间 2 个副本之间做 DDP all-reduce

fully_shard(model, mesh=mesh, reshard_after_forward=True)

对应 TorchTitan 配置:

[training]
data_parallel_replicate_degree = 2     # 节点间副本
data_parallel_shard_degree = 8         # 节点内 shard

5.6TorchTitan 里的 FSDP2 用法

torchtitan/distributed/parallelize_llama.py::apply_fsdp

def apply_fsdp(model, dp_mesh, ...):
    fsdp_config = {"mesh": dp_mesh, "mp_policy": MixedPrecisionPolicy(
        param_dtype=torch.bfloat16,
        reduce_dtype=torch.float32,
    )}
    # 给每个 TransformerBlock 单独 fsdp
    for layer in model.layers.values():
        fully_shard(layer, **fsdp_config)
    fully_shard(model, **fsdp_config)

5.7性能对比

Llama-3 8B、8×A100、bf16、seqlen=8K:

方案MFUtok/s/GPU备注
DDP (太大跑不下)OOM
FSDP1~42%~3,400baseline
FSDP2~48%~4,000compile 友好
FSDP2 + torch.compile~54%~4,500+ compile
FSDP2 + TP=2~52%~4,300大模型显存压力大时

5.8常见踩坑

现象处理
OOM 第 0 stepfsdp_use_orig_params 在 FSDP2 默认 true;问题在 chunk 太大
save ckpt 后加载错必须用 dcp(详见 ch10)
load HF state_dict 失败name 不一致;FSDP2 的 named_parameters() 不带 fsdp 前缀
慢 1.3×检查 reshard_after_forward;显存够时关掉

5.9这章你需要带走的