ZeRO-3:省下副本之后,怎样算完一层?
E04/b0 · 1 · 每卡仍跑全部层
GPU 0 · 数据 A
主权重+动量
无本层完整副本
本卡数据:L₁ → … → Lₙ
GPU 1 · 数据 B
主权重+动量
无本层完整副本
本卡数据:L₁ → … → Lₙ
GPU 2 · 数据 C
主权重+动量
无本层完整副本
本卡数据:L₁ → … → Lₙ
GPU 3 · 数据 D
主权重+动量
无本层完整副本
本卡数据:L₁ → … → Lₙ
真实预取、驻留与重叠策略会改变时序和峰值;这不是把不同层永久分配给不同卡。
先锁定一个不会变的条件:四张卡各有自己的数据,每一份数据仍要经过模型的全部层。我们现在跟踪其中一层,并不把第一层永久交给第一张卡、第二层永久交给第二张卡。图上的四种颜色表示这个层的参数分片归谁保存。
教师备课:指图与模拟问答
指图与推进 · 不朗读教师指向当前高亮对象,随后推进。
E04/b1 · 2 · 临用时收集
GPU 0 · 数据 A
主权重+动量
θ₀ θ₁ θ₂ θ₃
数据始终留在本卡计算
GPU 1 · 数据 B
主权重+动量
θ₀ θ₁ θ₂ θ₃
数据始终留在本卡计算
GPU 2 · 数据 C
主权重+动量
θ₀ θ₁ θ₂ θ₃
数据始终留在本卡计算
GPU 3 · 数据 D
主权重+动量
θ₀ θ₁ θ₂ θ₃
数据始终留在本卡计算
真实预取、驻留与重叠策略会改变时序和峰值;这不是把不同层永久分配给不同卡。
轮到这一层时,四张卡交换它们负责的分片,于是每张卡都临时拥有这一层的完整参数。这叫 all-gather,中文可以直接理解为收集到完整视图。箭头送来的是本层需要的参数,不要求一次把全模型所有层都聚齐。
教师备课:指图与模拟问答
指图与推进 · 不朗读教师指向当前高亮对象,随后推进。
E04/b2 · 3 · 本地前向
GPU 0 · 数据 A
主权重+动量
θ₀ θ₁ θ₂ θ₃
本地前向:输入 → 输出
GPU 1 · 数据 B
主权重+动量
θ₀ θ₁ θ₂ θ₃
本地前向:输入 → 输出
GPU 2 · 数据 C
主权重+动量
θ₀ θ₁ θ₂ θ₃
本地前向:输入 → 输出
GPU 3 · 数据 D
主权重+动量
θ₀ θ₁ θ₂ θ₃
本地前向:输入 → 输出
真实预取、驻留与重叠策略会改变时序和峰值;这不是把不同层永久分配给不同卡。
现在材料齐了,各卡就可以用完整本层参数处理自己的输入,产生交给下一层的中间结果。我们把这些中间结果叫激活。然后按同样办法继续后面的层,最终形成各卡数据对应的损失。参数相同不意味着激活相同,因为各卡读的数据不同。
教师备课:指图与模拟问答
指图与推进 · 不朗读教师指向当前高亮对象,随后推进。
E04/b3 · 4 · 释放临时完整参数
GPU 0 · 数据 A
主权重+动量
无本层完整副本
释放临时完整视图
GPU 1 · 数据 B
主权重+动量
无本层完整副本
释放临时完整视图
GPU 2 · 数据 C
主权重+动量
无本层完整副本
释放临时完整视图
GPU 3 · 数据 D
主权重+动量
无本层完整副本
释放临时完整视图
真实预取、驻留与重叠策略会改变时序和峰值;这不是把不同层永久分配给不同卡。
本例采用最容易看清节省来源的策略:本层前向算完,就释放刚才临时收齐的完整参数,只保留自己负责的分片。因此全模型没有在每卡长期变回完整副本。代价也已经埋下:一会儿反向如果还需要这些参数,我们要再收集一次。
教师备课:指图与模拟问答
指图与推进 · 不朗读教师指向当前高亮对象,随后推进。
E04/b4 · 5 · 反向再收集并计算
GPU 0 · 数据 A
主权重+动量
θ₀ θ₁ θ₂ θ₃
本地反向:计算参数梯度
GPU 1 · 数据 B
主权重+动量
θ₀ θ₁ θ₂ θ₃
本地反向:计算参数梯度
GPU 2 · 数据 C
主权重+动量
θ₀ θ₁ θ₂ θ₃
本地反向:计算参数梯度
GPU 3 · 数据 D
主权重+动量
θ₀ θ₁ θ₂ θ₃
本地反向:计算参数梯度
真实预取、驻留与重叠策略会改变时序和峰值;这不是把不同层永久分配给不同卡。
前向走完后,从损失沿层往回传播。轮到这一层时,再次收集本层参数,用它和反向传来的信息计算梯度。这里画了第二次收集,是为了让通信代价真实可见。工程上可以预取或者延迟释放,但那又会改变峰值内存;没有一种图能同时免费省掉所有存储与通信。
教师备课:指图与模拟问答
指图与推进 · 不朗读教师指向当前高亮对象,随后推进。
E04/b5 · 6 · 梯度归约到负责人
GPU 0 · 数据 A
主权重+动量
归约后梯度 g0
数据始终留在本卡计算
GPU 1 · 数据 B
主权重+动量
归约后梯度 g1
数据始终留在本卡计算
GPU 2 · 数据 C
主权重+动量
归约后梯度 g2
数据始终留在本卡计算
GPU 3 · 数据 D
主权重+动量
归约后梯度 g3
数据始终留在本卡计算
真实预取、驻留与重叠策略会改变时序和峰值;这不是把不同层永久分配给不同卡。
四张卡各算出了本地数据的贡献。接下来先把对应梯度汇总,再把合并后的各段发到负责那一段参数的卡。这叫 reduce-scatter:归约后分片。它不是随便分走四份未经合并的梯度;每个最终分片都包含四份数据的贡献,平均方式仍遵守训练的约定。
教师备课:指图与模拟问答
指图与推进 · 不朗读教师指向当前高亮对象,随后推进。
E04/b6 · 7 · 更新本卡状态
GPU 0 · 数据 A
主权重+动量 已更新
无本层完整副本
仅更新自己负责的片
GPU 1 · 数据 B
主权重+动量 已更新
无本层完整副本
仅更新自己负责的片
GPU 2 · 数据 C
主权重+动量 已更新
无本层完整副本
仅更新自己负责的片
GPU 3 · 数据 D
主权重+动量 已更新
无本层完整副本
仅更新自己负责的片
真实预取、驻留与重叠策略会改变时序和峰值;这不是把不同层永久分配给不同卡。
最后各卡只更新自己负责的主权重和动量,并得到新的工作参数分片。下一轮收集时,拿到的就是更新后的参数。这一圈走完,节省从哪里来、通信为什么出现,就连在一起了。DeepSpeed ZeRO、PyTorch 的全分片数据并行 FSDP,是可以使用的工程路线;具体预取和驻留不同,不能当成逐细节相同的软件。接下来我们换一种切法:直接把计算分给不同设备。
教师备课:指图与模拟问答
指图与推进 · 不朗读教师指向当前高亮对象,随后推进。
补充推导、边界与来源
这里展示“算完即释放完整层参数”的教学调度。每张数据并行卡都有自己的输入,并依次执行全部层。计算某层前,通过 all-gather 汇集该层分片;本地前向完成后释放临时完整参数,保留所属分片。全网前向形成损失以后,反向沿层返回,需要时再次收集该层参数,计算本地梯度;reduce-scatter 将跨数据卡的梯度汇总并分给相应所有者;各卡更新自己负责的主权重、动量与工作参数分片。
all-gather 是“把各处分片拼成完整视图”,reduce-scatter 是“先合并贡献,再分开保留结果”。实际实现可能预取、复用或延长参数驻留以换取通信效率,所以 32 GB 不代表峰值。DeepSpeed ZeRO 与 PyTorch FSDP 都可用于这类分片训练,但具体策略需按实现和版本核对。
本页证据与条件
A19;A22;A23;P11