数据并行与ZeRO

数据并行回顾

数据并行(Data Parallelism,DP)是最基础的分布式训练范式:

  1. 模型复制:每张GPU持有完整模型副本
  2. 数据分片:不同GPU处理不同数据batch
  3. 梯度同步:每轮迭代后对各GPU的梯度做AllReduce同步
  4. 参数更新:所有GPU使用相同的更新后参数继续下一轮
GPU 0: [模型副本] + [数据分片0] → [本地梯度] → AllReduce → [更新后模型]
GPU 1: [模型副本] + [数据分片1] → [本地梯度] → AllReduce → [更新后模型]
...

朴素数据并行的局限

  • 显存浪费:每张GPU保存完整模型、激活值、优化器状态,显存占用极大
  • 通信瓶颈:梯度AllReduce通信量 = 模型参数量,对大模型不现实
  • 扩展性差:模型参数量超过单卡显存时无法运行

ZeRO(Zero Redundancy Optimizer)

ZeRO是微软DeepSpeed团队提出的显存优化技术,通过分片(sharding)消除数据并行中的显存冗余。

Stage 1:优化器状态分片(Optimizer State Sharding)

原理:将Adam优化器的状态(动量、方差)在数据并行进程间分片,每个GPU只保存 1/N 的优化器状态。

优化器状态总量: 2 * 参数总量(动量 + 方差)
Stage 1后: 每GPU只保存 2 * 参数总量 / N

通信开销

  • 通信量:与标准数据并行相同(梯度AllReduce)
  • 额外通信:参数分片 scatter/gather(可选)

收益:约4倍显存降低(假设N=8,则显存降至1/4)

Stage 2:梯度分片(Gradient Sharding)

原理:在Stage 1基础上,进一步将梯度分片存储。

标准DP: 每GPU保存完整梯度 → AllReduce → 每GPU有完整梯度 → 参数更新
Stage 2: 每GPU保存 1/N 梯度 → 需要时 AllReduce(分片通信)

实现机制

  1. 反向传播时本地计算梯度
  2. 执行Reduce-Scatter,每个GPU获得其他GPU数据的部分和
  3. 本地更新对应参数分片
  4. 下次前向传播前执行All-Gather重建完整梯度(可选)

通信模式

  • 通信量:与Stage 1相同,但通信模式不同(从AllReduce变为Reduce-Scatter + AllGather)
  • 可与通信计算重叠进一步优化

收益:约8倍显存降低(结合Stage 1)

Stage 3:参数分片(Parameter Sharding)

原理:将模型参数也分片存储,每个GPU只保存 1/N 的参数。

完整分片流程:
前向/反向: 动态 All-Gather 获取所需参数分片 → 计算 → 丢弃非必要分片

实现机制

  1. 前向传播时:参数分片本地计算,需要邻 GPU 参数时通过All-Gather获取
  2. 反向传播时:梯度分片本地更新,触发Reduce-Scatter同步
  3. 每轮迭代结束后参数分片自动同步

通信开销

  • 每层前向/反向都需要 All-Gather(获取参数)和 Reduce-Scatter(同步梯度)
  • 通信量显著增加,但换取极大显存节省

收益:理论上显存降低与GPU数成线性关系

ZeRO 通信量分析

Stage通信量(相比DP)显存收益
Stage 11x (相同)4x
Stage 21x (相同)8x
Stage 3~2x (AllGather+ReduceScatter)O(N)

ZeRO-DP 与标准DP对比

标准DP:
每GPU内存占用 = 参数 + 梯度 + 优化器状态 + 激活值
            ≈ 模型大小 × (1 + 2 + 4) ≈ 7× 模型大小(16位存储)

ZeRO-3:
每GPU内存占用 ≈ (参数 + 梯度 + 优化器状态) / N + 激活值
            ≈ 模型大小 / N + 激活值

DeepSpeed实现

配置文件示例

{
    "zero_optimization": {
        "stage": 3,
        "offload_optimizer": {
            "device": "cpu",
            "pin_memory": true
        },
        "offload_param": {
            "device": "cpu",
            "pin_memory": true
        },
        "overlap_comm": true,
        "contiguous_gradients": true,
        "reduce_bucket_size": 1e8,
        "stage3_prefetch_bucket_size": 1e9,
        "stage3_param_persistence_threshold": 1e5
    },
    "bf16": {
        "enabled": true
    }
}

核心API

from deepspeed import DeepSpeedConfig, initialize
model, optimizer, _, _ = initialize(
    args=args,
    model=model,
    model_parameters=model.parameters(),
    config=deepspeed_config
)

ZeRO-3 关键技术

  1. 分片通信与计算重叠:利用CUDA stream在计算时通信
  2. Gradient Accumulation:梯度累积避免流水线空闲
  3. Weight Gradients Partitioning:参数梯度自动分片
  4. Partition Communication Group:自定义通信域

ZeRO-Stage 3与PipeDream的结合

DeepSpeed支持将ZeRO与流水线并行结合:

{
    "zero_optimization": {"stage": 3},
    "pipeline": {"stages": 4}
}

每个pipeline stage内部使用ZeRO-3分片,进一步降低单卡显存。

Offload技术

DeepSpeed支持将部分数据卸载到CPU或NVMe:

  • ZeRO-Offload:优化器状态卸载到CPU,配合Stage 2
  • ZeRO-Infinity:参数和优化器状态卸载到NVMe,支持超大规模模型

性能调优

  1. 通信瓶颈:TP/PP机器与DP机器分离,避免跨域通信
  2. 通信域配置:优化 NCCL 组配置
  3. Mixed Precision:BF16训练减少通信量
  4. Async IO:参数卸载异步化避免阻塞

与其他并行策略的关系

策略维度分片对象
张量并行层内参数/激活切分
流水线并行层间模型层分Stage
数据并行batch梯度/参数同步
ZeRO数据并行维度参数/梯度/优化器状态分片

三者可组合:TP=8, PP=4, ZeRO-3 + DP = N/(8*4)

框架对比

特性DeepSpeed ZeROMegatron-FSDPPyTorch FSDP
分片方式优化器状态+梯度+参数参数+梯度+优化器状态参数+梯度
OffloadCPU/NVMeCPUCPU
通信优化Overlap + PartitionAsyncOverlap
易用性高(配置驱动)