Data Parallel
数据并行
核心解释
Data Parallel 把不同数据交给多份模型。各 rank 用相同参数计算本地梯度,再合并梯度并执行一致的参数更新。DDP 是这一训练方式的常用实现。[1]
设有 个 rank,每个 rank 处理相同数量的有效样本,局部损失 使用均值归约。全局平均梯度为:
DDP 通常在每个 rank 保存完整模型、梯度与优化器状态。反向过程中,已经准备好的梯度可以按 bucket 发起同步,让通信与后续反向计算重叠。[2]
ZeRO 逐步分片优化器状态、梯度和参数,减少副本之间的重复存储。FSDP 的完整分片模式会在计算前收集当前模块的参数,随后释放完整参数或继续保留,并把梯度归约到对应分片。[3]
选择分片粒度和预取策略时,需要一起考虑长期保存的状态、临时参数、激活及通信。增加 rank 数可以分摊模型状态,但每个 rank 的计算量变小后,通信更容易成为瓶颈。[4]
资料
Ultra-Scale Playbook:副本、梯度与状态分片 ↗
从 Data Parallelism 读到 ZeRO,对照通信图和显存图,区分增加数据副本与分片模型状态。
PyTorch Distributed:DDP 的设计论文 ↗
看梯度 bucket、计算通信重叠与跳过同步如何协作,理解 DDP 为什么不只是一次 AllReduce。
PyTorch:DistributedDataParallel 教程 ↗
沿进程启动、模型包装和训练循环进入实现,继续看不均匀输入与梯度累积的处理。
ZeRO:逐步去除模型状态的冗余 ↗
用原论文的显存分析理解优化器状态、梯度和参数分片,再核对不同阶段的通信开销。
PyTorch:FSDP2 的参数生命周期 ↗
从 fully_shard 追踪参数 AllGather、梯度 ReduceScatter 和预取,理解保存分片与临时完整参数的区别。
TorchTitan:FSDP2 的设计、验证与实现 ↗
结合设计文档、数值验证 PR 与训练代码,理解按参数分片、通信分组和预取如何落地。
QA
各卡都对 loss 求平均,再平均梯度,一定等于全局平均吗?
每个 rank 的有效样本数或有效 token 数相同时,局部平均再跨 rank 平均等于全局平均。数量不同时,直接平均会让较小的分片占更大权重。
设第 个 rank 有 个有效 token,局部平均梯度为 。全局 token 平均梯度应按 加权。采用默认按 rank 平均的 DDP 时,可以把局部平均 loss 乘以 ,其中 是参与同步的 rank 数。
梯度累积时,分母还应覆盖整次更新中的所有有效 token。计算这个计数时,padding 与被 mask 的位置不能算进有效 token。
FSDP 和 TP 都分片权重,为什么还要区分?
常见 FSDP 会在计算前收集当前模块需要的完整参数,各数据 rank 用它处理自己的输入。TP 则在计算期间继续持有权重分片,由多张卡共同完成同一层的计算。
这使它们的通信对象和时机不同:FSDP 主要围绕参数与梯度的生命周期,TP 主要围绕层内计算与激活布局。两者可以在不同 DeviceMesh 维度组合。
DDP 与完整分片训练,通信量怎样比较?
设同步组有 个 rank,完整模型参数和梯度的有效大小都为 字节。先用 Ring 算法,只统计每个 rank 的发送量。DDP 一次梯度 AllReduce 约为 。
若完整分片训练在前向后释放完整参数,并在反向前重新收集,一轮典型过程包含两次参数 AllGather 和一次梯度 ReduceScatter,约为 。
参数与梯度精度不同、保留完整参数、重计算或混合分片都会改变这个计数。字节数也不直接决定步时:需要继续看哪些通信能与计算重叠。
梯度累积时,为什么常常先 no_sync,最后再同步?
在同一次参数更新内,梯度可以先在本地累积,再统一同步,减少重复的梯度归约。DDP 的 no_sync 需要包住对应的前向和反向,最后一次正常的前向与反向触发同步。
累积的 loss 仍需按这次更新的有效 batch 归一化。FSDP 的梯度同步与参数收集是不同控制项,关闭梯度同步并不自动消除参数 AllGather,也可能增加梯度的显存占用。
为什么 HSDP 要在一组卡内分片,再在组间复制?
在较小的组内分片,可以把频繁的参数收集限制在较快的互连内。不同组各自处理数据,再同步对应的梯度分片。
代价是模型状态会在多个组之间重复保存。它用更多显存换取不同的通信布局,是否更快取决于模型、batch 和节点内外带宽。
推理里的 DP,也要像训练一样同步梯度吗?
推理不计算用于参数更新的梯度。普通稠密模型的多个服务副本可以各自处理不同请求,主要目的是扩展吞吐和并发容量。
训练中的 DP 则需要把不同数据产生的梯度合起来。两者都把输入分给多份模型,但不能把训练的梯度同步成本直接算到推理副本上。
FSDP 预取更积极,怎样判断省下的等待是否值得额外显存?
待解
同时观察完整参数的存活区间、通信缓冲区、激活峰值和未被计算覆盖的 AllGather。最合适的分组大小会怎样随模型和 batch 改变?