数据并行是最基础的,每个 GPU 跑完整模型,只是数据不同。
模型并行是个统称,主要包含张量并行(切分一层内部的权重矩阵)和流水线并行(切分不同的网络层)。
实际训练大模型时,通常是数据并行 + 张量并行 + 流水线并行三种一起用,就像搭积木一样组合。大家不需要一次记住所有细节,先把这个“切分什么”的框架建立起来,后面再慢慢深入就好。
把一层内部的矩阵运算切开。比如一个 [4096, 4096] 的权重矩阵,切成 4 份,每张卡算一份,最后把结果拼起来。通信非常频繁,通常只在单节点内用(靠 NVLink)。
把不同的层放到不同 GPU 上。比如 32 层模型,GPU 0 放 1-8 层,GPU 1 放 9-16 层……数据依次流过。通信量小,但会有“气泡”(bubble)——某些 GPU 在等前面的结果时是空闲的。
ZeRO属于数据并行技术,在ZeRO中,每个 GPU 都要跑完整个模型,从单次前向传播的计算效率来看,ZeRO 确实不如模型并行“优雅”。但为什么大家还是大量用 ZeRO,甚至在很多场景下它比模型并行更受欢迎?
我们知道,每个 GPU 跑完整模型效率低,这个判断在计算层面是对的。但在工程层面,ZeRO 有几个模型并行很难比的优点:
模型并行(尤其是张量并行)需要重写模型的计算逻辑,把矩阵乘法切开、插入通信原语。这通常要改模型代码,调试困难。
ZeRO 基本不需要改模型代码,只要在训练脚本里加几行配置(比如 DeepSpeed 的 zero_optimization),现有模型就能直接跑。这对绝大多数研究者和工程师来说,是巨大的便利。
模型并行里,不同层的计算量可能差很多(比如 Transformer 里 attention 和 FFN 的计算量不同),切分后容易出现某些 GPU 忙死、某些 GPU 闲死的情况,需要仔细设计切分策略。
ZeRO 下每个 GPU 跑的是完全相同的计算图,只是数据不同,负载天然均衡,不需要复杂的切分调优。
模型并行的通信发生在层与层之间,通信量和模型结构强相关,有时会出现通信瓶颈。
ZeRO 的通信主要是参数/梯度的 All-Gather 和 Reduce-Scatter,模式固定,容易和计算重叠(overlap),工程上更好优化。
模型并行通常受限于单节点内的高速互联(比如 NVLink),跨节点扩展时通信开销会急剧上升。
ZeRO 天然是数据并行的扩展方式,可以轻松扩展到成百上千个 GPU,跨节点也能工作。
数据并行是“把训练数据切开”,模型并行是“把模型切开”,ZeRO是数据并行的增强版,它要解决的是“数据并行太费显存”的问题,
它是“把冗余的数据副本切开”。 ZeRO 的“每个 GPU 跑完整模型”看似笨,但换来了低代码侵入、好负载均衡、易扩展,这在工程上往往比省那一点计算效率更重要。
评论专区
评论加载中...登录后即可发表评论