新闻  |   论坛  |   博客  |   在线研讨会
GPT-3模型为何难以复现?这也许是分布式AI框架的最优设计(1)
AI科技大本营 | 2021-05-15 11:59:48    阅读:969   发布文章

2020 年,最轰动的 AI 新闻莫过于 OpenAI 发布的 GPT-3 了。它的1750亿参数量及其在众多NLP任务上超过人类的出众表现让大家坚信:大模型才是未来。但与之带来的问题是,训练超大模型所需的算力、存储已不再是单机就能搞定的了(之前的 BERT 还是可以用 DGX-1/2 这样的超级服务器训练)。

NVIDIA 估算过,如果要训练GPT-3 ,即使单个机器的显存/内存能装得下,用 8 张 V100 的显卡(一台 DGX-1 的配置),训练时长预计要 36 年;即使用 512 张 V100 ,训练也需要将近 7 个月;如果你拥有 1024 张 80GB A100, 那么完整训练 GPT-3 的时长可以缩减到 1 个月。

这意味着训练大模型一定是一个分布式问题。对算力的需求还是一个相对容易解决的问题,因为拥有大集群的组织并不只 OpenAI 一家,而如何解决上千块 GPU 的分布式训练问题才是关键。

即使你是一位非常优秀的数据科学家,知晓并能解决 Transformer 相关的所有算法问题,但如果你不是分布式专家,不知道如何解决分布式训练时上百台服务器之间的通信、拓扑、模型并行、流水并行等问题,你甚至都无法启动这次训练。这也解释了为什么时隔一年,只有 NVIDIA 、微软等大企业可以复现 GPT-3 。

目前开源的 GPT 模型库主要是 NVIDIA 的 Megatron-LM 和微软的 DeepSpeed。其中,微软的 DeepSpeed 的模型并行等内核取自 Megatron,且 DeepSpeed 主打的是,在数据并行下如何以更少的机器去跑更大的模型 ( ZeRO 、 ZeRO-Offload 等都是用梯度切片、计算、内存/硬盘换入换出来省显存),所以我们本文主要介绍和对比 Megatron 。

简单比较一下 NVIDIA 的 Megatron 和 微软的 DeepSpeed:

DeepSpeed 本质上是一种“节省显存”的数据并行,即:数据并行的优化版。DeepSpeed 假设了单层参数量可以在单张显卡上放得下,如果不满足这个假设,那么仍然需要使用模型并行,而且 DeepSpeed 的模型并行是通过调用 Megatron 来实现的。

根据 NVIDIA 最新的那篇论文(链接:https://arxiv.org/abs/2104.04473,也是下面本文重点要介绍的),Megatron 在大规模训练的效率是超过 DeepSpeed 不少的。

而 DeepSpeed 的论文一直强调:可以用更少机器训练更大的模型,但没有突出过在效率上的优势。

DeepSpeed 后来又出了一篇论文:ZeRO-Infinity(链接:https://arxiv.org/abs/2104.07857),当单层参数量在单张显卡上放不下的时候,它通过对这一层算子切片,一片一片来执行,使得单卡也能跑起来一个巨大的层,可以理解成一种 “时间”轴上展开的模型并行。

Megatron 和 DeepSpeed 都是基于 PyTorch ,分别由 NVIDIA 和微软经过深度定制开发,专门为支持 PyTorch 分布式训练 GPT 而设计的。我们会简单介绍一下 NVIDIA 如何使用 PyTorch 搞分布式训练 GPT ,然后重点介绍 OneFlow 如何用一套通用设计非常简单清晰地解决了这个难题,同时我们还在已有的测试规模上性能超过 NVIDIA。

相信读完此文,你就会发现 PyTorch 、 Megatron ( NVIDIA ) 、DeepSpeed ( Microsoft ) 都走了一个非常长的弯路,这条弯路从大方向上就走错了,不仅是弯路,你还会发现 Megatron 的代码只能被 NVIDIA 的分布式训练专家所复用,它对于 PyTorch 的算法工程师而言门槛极高,是非常难用的,以至于任何想要用 PyTorch 复现一个分布式大模型的算法工程师,都得先等 NVIDIA 开发完才能再使用 Megatron 提供的模型。同时,我们也通过这样一个例子来证明:为什么一个分布式深度学习框架要像 OneFlow 这样设计。

本文内容较多,先列出主要目录:

1.分布式训练 GPT 的必要并行技术

流水并行

梯度累加

后向重计算

1F1B 策略

2.Megatron:PyTorch 分布式训练的极限,痛点在哪儿?

流水并行 PyTorch 需要手写专家级复杂调度器

模型并行 PyTorch 需要手工排线,在 kernel 里手写特定的、经过复杂推导的通信原语

3.OneFlow 用一致性视角(Consistent View)轻松填平分布式训练难的鸿沟

流水并行 ,只需要配置 Placement 就够了

数据 + 模型的混合并行,只需要配置 Variable 的 SBP 就够了

OneFlow:让每一位算法工程师都有能力训练 GPT

4.为什么分布式深度学习框架要像 OneFlow 这样设计?

OneFlow 系统层面如何实现流水并行

OneFlow 系统层面如何实现混合(数据 & 模型)并行

5.GPT 训练性能对比: OneFlow vs Megatron

纯数据并行性能对比

纯模型并行性能对比

混合并行性能对比

流水并行 + 混合并行 性能对比

6.小结

分布式训练 GPT 的必要并行技术

最近,NVIDIA 放出了一篇重量级的论文:Efficient Large-Scale Language Model Training on GPU Clusters ,用了 3072 张 80GB A100 训练 GPT( NVIDIA 也确实够壕,这个集群的成本就不止 5 亿了),最大规模的模型参数量达到了 1T(是 GPT-3 原版的 5 倍)。

1.png

NVIDIA 训练 GPT-3 最大到 1T 参数规模

论文里 NVIDIA 介绍了分布式训练超大规模模型的三种必须的并行技术:

  • 数据并行(Data Parallelism)

  • 模型并行(Tensor Model Parallelism)

  • 流水并行(Pipeline Model Parallelism)

其中数据并行是大家都熟知的最常见的并行方式,而模型并行(NVIDIA 论文里叫做 "Tensor 级别的模型并行" )是对某一层(如 Linear/Dense Layer 里的 Variable )的模型 Tensor 切分,从而将大的模型 Tensor 分成多个相对较小的 Tensor 进行并行计算;流水并行(NVIDIA 论文里叫做流水线级别的模型并行),是将整个网络分段(stage),不同段在不同的设备上,前后阶段流水分批工作,通过一种“接力”的方式并行。

对于最大的 1T 规模的模型,NVIDIA 一共使用了 384 台 DGX-A100 机器(每台装有 8 张 80GB A100 GPU),机器内部各 GPU 间使用超高速 NVLink 和 NVSwitch 互联,每台机器装有 8个 200Gbps 的 InfiniBand (IB) 网卡,可以说是硬件集群顶配中的顶配了。

那么,这些机器是如何协同工作的?GPT 网络是由很多层 Transformer Layer 组成的,每一层内部是一个由多层 MLP 和 attention 机制组成的子图,对于参数规模 1T 的 GPT 而言就有 128 层的 Transformer Layer,这个超大超深的网络被分割成了 64 个 stage ,每个 stage 跑在 6 台 DGX-A100 上,其中 6 台机器之间进行数据并行,每台机器内部的 8 张卡之间做模型并行,整个集群的 3072 张 A100 按照机器拓扑被划分成了 [6 x 8 x 64] 的矩阵,同时使用数据并行 & 模型并行 & 流水并行 进行训练。

2.png

3072 张 A100 集群拓扑

1.流水并行

从上述的机器拓扑中可以发现,流水并行是 3072 块 A100 能训练 GPT 的关键。因为无论是数据并行还是模型并行,都会在相应的机器之间进行全连接的通信,当机器数量增大时,通信开销和时延会大到难以忍受。而流水并行既解决了超大模型无法在单设备上装下的难题,又很好解决了机器之间的通信开销的问题,每个阶段(stage) 和下一个阶段之间仅有相邻的某一个 Tensor 数据需要传输,每台机器的数据传输量跟总的网络大小、机器总数、并行规模无关。但流水并行为了多个阶段之间可以流水起来,还依赖两个重要的特性: 梯度累加(Gradient Accumulation) 和 亚线性内存优化( Sublinear Memory Cost 2016, 陈天奇)。

近期,百度和华为相继发了自己的千亿级中文预训练模型的宣传文。其中,百度提出了 "4D混合并行",本质上是 Megatron 里的数据并行 + 模型并行 + 流水并行 + DeepSpeed 里的 ZeRO 优化 ;华为文章中的 “5D混合并行”,是将重计算(Checkpointing, 亚线性内存优化的一种)作为了第5维 (其实百度也做了重计算,只是没有将其列为多维并行中的一维)。

在介绍这两个特性之前,我们先简单解释一下深度学习训练和模型更新的两种约束:BSP (Bulk Synchronous Parallel) 和 SSP (Stale Synchronous Parallel ) ,其中 BSP 是最常见的模型更新规则:每个 batch 的前向计算都需要使用最新的模型,那么就要求上一个 batch 的后向计算结束且在模型更新后,下一个 batch 的前向才能开始。如果使用 BSP 去做流水并行,我们就会发现每个阶段的前向和后向是完全串行的,其中一个设备在工作时,其他所有设备都在等待,那么分布式的优势就完全没有被发挥出来:

3.png

BSP 各个阶段串行执行

BSP 且没有 Gradient Accumulation 下的流水并行。假设整个网络被等分切成 4 个 stage,每个 stage 使用一个 device ,则在BSP下,各个设备串行执行,中间有大段的气泡。一般后向计算时间是前向计算的两倍,如果算上 Checkpointing 的重计算部分,是前向计算的三倍。我们可以从上图中看到,这种情况下有 70% 的时间设备是空闲的。

而 SSP 就是异步模型更新,允许前向计算时可以不使用最新的模型,而使用落后几个版本之内的模型。SSP 在 GPT-3 的训练中并没有被 NVIDIA 采用,其主要原因有以下几点:

SSP 的模型收敛性并没有被严格论证, 且有论文 GeePS 指出 SSP 的收敛效果不如 BSP ;

SSP 会在 GPU 上同时出现几个不同版本的模型,而 GPT-3 又是一个非常大的模型网络,多份模型所带来的显存开销不可接受;

BSP 通过 Gradient Accumulation + Checkpointing 就可以很好的解决 GPT-3 中的流水并行问题。

另外, NVIDIA 的论文的分析前提就是 BSP 情况下, 根据严格的参数优化器更新方式, 流水并行气泡的占比是 Bubble time fraction = (p - 1) / m,其中 p 是 stage 数, m 是梯度累加的 micro-batch 数。如果采用 SSP,则 NVIDIA 整篇文章的理论基础就没有了。

"Pipeline parallelism comes in a few flavors: the mode discussed in this paper uses flushes to ensure exact strict optimizer semantics."

2.梯度累加

Gradient Accumulation 就是把一个大 Batch 拆分成多个 micro-batch , 每个 micro-batch 前后向计算后的梯度累加,在最后一个micro-batch累加结束后,统一更新模型。

micro-batch 跟数据并行有高度的相似性:数据并行是空间上的, 数据被拆分成多个 tensor,同时喂给多个设备并行计算,然后将梯度累加在一起更新;而 micro-batch 是时间上的数据并行, 数据被拆分成多个 tensor, 按照时序依次进入同一个设备串行计算,然后将梯度累加在一起更新。当总的 batch size 一致,且数据并行的并行度和 micro-batch 的累加次数相等时,数据并行和 Gradient Accumulation 在数学上完全等价。Gradient Accumulation 通过多个 micro-batch的梯度累加使得下一个 micro-batch 的前向计算不需要依赖上一个 micro-batch 的反向计算,因此可以畅通无阻的进行下去(当然在一个大 batch 的最后一次 micro-batch 还是会触发这个依赖)。

Gradient Accumulation 解决了很多问题:

在单卡下,Gradient Accumulation 可以将一个大的 batch size 拆分成等价的多个小 micro-batch ,从而达到节省显存的目的。

在数据并行下,Gradient Accumulation 解决了反向梯度同步开销占比过大的问题(随着机器数和设备数的增加,梯度的 AllReduce 同步开销也加大),因为梯度同步变成了一个稀疏操作,因此可以提升数据并行的加速比。

在流水并行下, Gradient Accumulation 使得不同 stage 之间可以并行执行不同的 micro-batch, 从而让各个阶段的计算不阻塞,达到流水的目的。

单纯通过 micro-batch,我们就实现了 GPipe (2018)论文中的流水并行,在 stage 数量为 4, micro-batch 数量为 8 (每个 batch 在计算 8 个 micro-batch 且 累加 8 次梯度后更新一次模型)下的时间线如下图所示:

4.png

使用梯度累加后的 Pipeline 时间线

在 GPipe 的流水并行示例中,每个“时间点” 可以在多个阶段(stage)上同时做不同的micro-batch,图中每个方块中的标号表示了第几个 micro-batch;同一个 micro-batch 还是串行的经过所有的 stage,在这种情况下,每个设备的空闲时间只有 25% 左右。

但这种流水并行存在一个问题:显存占用太大。如果每个 micro-batch 前向计算的中间结果(activation)被后向计算所消费,则需要在显存中缓存 8 份(梯度累加的次数)完整的前向 activation。这时就不得不用另一项重要的技术:重计算(Checkpointing)。

*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
推荐文章
最近访客