本文转自huggingface blog

作者:Stas Bekman

贡献者:Britney Muller, Douwe Kiela, Jared Casper, Jeff Rasley, Julien Launay, Leandro von Werra, Omar Sanseviero, Stefan Schweter 和 Thomas Wang。

图表绘制:Chunte Lee

-------------------------------------------------------------

近年来,训练越来越大的语言模型已经成为一种常态。虽然大家经常议论到这些模型没有被放出来以供进一步研究的问题,但鲜有人关注如何训练这些大模型的隐藏知识技巧。本文旨在改变这种状况,以176B参数的语言模型BLOOM为例,从硬件和软件两个方面阐明训练这种模型背后的技术和工程。

但首先我们要感谢那些使训练1760亿参数模型这一惊人壮举成为可能的公司和关键人物及团体。

然后将讨论硬件设置和主要技术组成。

BLOOM

Bloom项目的简介如下

贡献者

这个项目是由Thomas Wolf(Hugging Face的联合创始人和CSO)构思的,他敢于与大公司竞争,不仅要训练一个最大的多语言模型,而且要让所有人都能获得最终结果,从而使一件对大多数人来说只是一个梦想的事情成为现实。

这篇文章特别关注模型训练的工程方面的问题。BLOOM背后的技术最重要的部分是那些分享他们的专业知识并帮助我们进行编码和训练的人和公司。

主要有6组人要感谢。

  1. HuggingFace的BigScience团队,他们奉献了一半以上的全职员工,从开始到终点的训练,提供并支付了Jean Zay的计算之外的所有基础设施。
  2. 微软DeepSpeed团队,他们开发了DeepSpeed,后来又与Megatron-LM集成,他们的开发人员花了很多周的时间来研究项目的需求,并在训练前和训练期间提供了很多很棒的实际经验建议。
  3. 英伟达Megatron-LM团队,他们开发了Megatron-LM,他们对我们的许多问题的回答和提供一流的经验建议提供了极大的帮助。
  4. 管理Jean Zay超级计算机的IDRIS/GENCI团队,他们为该项目捐赠了大量的计算设备和巨大的系统管理支持。
  5. PyTorch团队创造了一个超级强大的框架,其他的软件都是基于这个框架的,他们在训练准备期间对我们给予了很大的支持,修复了多个错误,提高了训练期间我们所依赖的PyTorch组件的可用性。
  6. BigScience工程工作组的志愿者们.

要说出所有为项目工程方面做出贡献的人的名字是非常困难的,所以我只列举几个Hugging Face以外的关键人物,他们是过去14个月里这个项目的工程基础:

Olatunji Ruwase, Deepak Narayanan, Jeff Rasley, Jared Casper, Samyam Rajbhandari和Rémi Lacroix。

同时,我们也感谢所有为这个项目做出贡献的公司和其员工。

概述


BLOOM的体系结构与GPT3非常相似,并增加了一些改进,将在本文后面讨论。

该模型是在Jean Zay上训练的,Jean Zay是法国政府资助的超级计算机,由GENCI管理,安装在法国国家科学研究中心(CNRS)的国家计算中心IDRIS。这台计算机由GENCI慷慨地捐赠给项目(2021-A01012475号拨款)。

训练期间使用了以下硬件。

  • GPU。384个NVIDIA A100 80GB GPU(48个节点)+32个备用GPU
  • 每个节点8个GPU 使用NVLink 4个GPU间连接,4个OmniPath链接
  • CPU。AMD EPYC 7543 32核处理器
  • CPU内存。每节点512GB
  • GPU内存:每个节点640GB
  • 节点间连接:全能路径架构(OPA)
  • NCCL-通信网络:一个完全专用的子网
  • 磁盘IO网络。与其他节点和用户共享GPFS

检查点:

  • 主检查点
  • 每个检查点的fp32优化状态和bf16+fp32权重为2.3TB,仅bf16权重为329GB。

数据集:

  • 46种语言的1.5TB的去重编码文本,被转换为350B的独特tokens。
  • 该模型的词汇量为250,680个tokens。
  • 完整的细节请见The BigScience Corpus A 1.6TB复合多语言数据集(https://openreview.net/forum?id=UoEw6KigkUn)

176B BLOOM模型的训练在2022年3月至7月,花了大约3.5个月的时间来完成(大约1百万个小时)。

Megatron-DeepSpeed

176B BLOOM模型是使用Megatron-DeepSpeed训练的,它是2种主要技术的结合。

DeepSpeed是一个深度学习优化库,使分布式训练变得简单、高效和有效。
Megatron-LM是由英伟达公司的应用深度学习研究团队开发的一个大型、强大的转化器模型框架。
DeepSpeed团队通过将DeepSpeed库中的ZeRO分片和管道并行与Megatron-LM中的张量并行相结合,开发了基于3D并行的实现。关于每个组件的更多细节可以在下面的表格中看到。

请注意,BigScience的Megatron-DeepSpeed是原始Megatron-DeepSpeed库的一个fork,我们在其中添加了多个补充内容。

下面是哪个框架提供了哪些组件来训练BLOOM的表格:

请注意,Megatron-LM和DeepSpeed都有pipline Parallelism和BF16优化器的实现,但我们使用DeepSpeed,因为它们可以对ZeRO集成。

Megatron-DeepSpeed实现了3D Parallelism,允许巨大的模型以非常有效的方式进行训练。让我们简单地讨论一下三维组件。

  1. DataParallel(DP):相同的设置被多次复制,并且每次都被输入一个数据片。处理是平行进行的,所有设置在每个训练步骤结束时都是同步的。
  2. TensorParallel(TP):每个张量被分割成多个块,因此不是让整个张量驻留在一个GPU上,而是张量的每个碎片驻留在其指定的GPU上。在处理过程中,每个碎片在不同的GPU上被单独和并行地处理,结果在步骤结束时被同步化。这就是所谓的水平并行,因为分割发生在水平层面上。
  3. PipelineParallel(PP):模型在多个GPU上被垂直分割(层级),因此只有模型的一个或几个层被放在一个GPU上。每个GPU并行处理管道的不同阶段,并在批量中的一小块上工作。
  4. 零冗余优化器(ZeRO):也是对张量进行分片,有点类似于TP,只是整个张量在前向或后向计算时被及时重构,因此模型不需要被修改。它还支持各种卸载技术以补偿有限的GPU内存。

Data Parallelism(数据并行)

大多数拥有较少GPU的用户可能会熟悉分布式数据并行(DDP)PyTorch文档。在这种方法中,模型被完全复制到每个GPU上,然后在每次迭代之后,所有的模型都会相互同步它们的状态。这种方法可以提高训练速度,但同时也为问题投入了更多的资源,但它只有在模型可以装入单个GPU的情况下才有效。

ZeRO Data Parallelism(ZeRO数据并行)

ZeRO-powered data parallelism (ZeRO-DP)在这篇微软的博文中有所描述

(https://www.microsoft.com/en-us/research/blog/zero-deepspeed-new-system-optimizations-enable-training-models-with-over-100-billion-parameters/)

DeepSpeed-Image-1

这可能很难让人理解,但实际上,这个概念非常简单。这只是通常的DDP,除了不复制完整的模型参数、梯度和优化器状态外,每个GPU只存储其中的一个片段。然后在运行时,当需要完整的图层参数时,所有的GPU都会同步给对方提供他们错过的部分。

这个组件是由DeepSpeed实现的。

Tensor Parallelism(张量并行)

在张量并行(TP)中,每个GPU只处理张量的一个片断,只有在需要整个张量的操作中才会聚合整个张量。

在本节中,我们使用Megatron-LM论文中思路,论文链接为“Efficient Large-Scale Language Model Training on GPU Clusters”(https://arxiv.org/abs/2104.04473).

任何transformer的主要构件是一个完全连接的nn.Linear,然后是一个非线性激活的GeLU。

按照Megatron论文的符号,我们可以把它的点乘部分写成Y = GeLU(XA),其中X和Y是输入和输出向量,A是权重矩阵。

如果我们以矩阵的形式来看计算,很容易看到矩阵乘法如何在多个GPU之间分割:

Parallel GEMM

如果我们在N个GPU上逐列分割权重矩阵A,并并行执行矩阵乘法XA_1到XA_n,那么我们最终将得到N个输出向量Y_1, Y_2, ..., Y_n,它们可以独立输入GeLU。

注意,随着Y矩阵沿列拆分,我们可以沿行拆分第二个GEMM,这样它就可以直接获得GeLU的输出,而不需要任何额外的通信。

利用这个原理,我们可以更新一个任意深度的MLP,同时在每个行-列序列之后同步GPU。Megatron-LM论文的作者为此提供了一个有用的说明:

parallel shard processing

这里f在前向传递中是一个identidy算子,在后向传递中是一个全减算子,而g在前向传递中是一个全减算子,在后向传递中是一个identidy。

多头注意层的并行化甚至更简单,因为它们本身就已经是并行的,因为有多个独立的头!

parallel self-attention

特别注意,由于在前向和后向通道中每层都有两个全部减少,TP要求设备之间有非常快的互连。因此,除非你有一个非常快的网络,否则不建议在一个以上的节点上做TP。在我们的案例中,节点间的速度比PCIe慢得多。实际上,如果一个节点有4个GPU,因此最高的TP度是4。如果你需要TP度为8,你需要使用至少有8个GPU的节点。

这个组件是由Megatron-LM实现的。Megatron-LM最近扩展了张量并行性,包括序列并行性,将不能像上面那样分割的操作,如LayerNorm,沿着序列维度分割。 “Reducing Activation Recomputation in Large Transformer Models”这篇论文(https://arxiv.org/abs/2205.05198)提供了这个技术的细节。序列并行是在BLOOM训练后开发的,所以没有在BLOOM训练中使用。

Pipeline Parallelism(管道并行)

Naive Pipeline Parallelism(幼稚PP)是指在多个GPU上分散模型层组,并简单地将数据从GPU移动到GPU,就像一个大型的复合GPU。其机制相对简单,将所需的层切换.to()所需的设备上,现在每当数据进出这些层时,都将数据切换到与该层相同的设备上,其余的则不做修改。

这就执行了一个垂直的模型并行,因为如果你还记得大多数模型是如何绘制的,我们把层垂直地切开。例如,如果下图显示了一个8层的模型:

我们只是把它垂直切成两片,把0-3层放在GPU0上,4-7层放在GPU1上。

现在,当数据从第0层到第1层,第1层到第2层,第2层到第3层时,这就像一个普通模型在单个GPU上的前向传递。但是当数据需要从第3层传到第4层时,它需要从GPU0传到GPU1,这就引入了一个通信开销。如果参与的GPU在同一个计算节点上(例如同一台物理机),这种复制是相当快的,但如果GPU位于不同的计算节点上(例如多台机器),通信开销可能会明显增大。

然后第4层到第5层到第6层到第7层就像一个正常的模型一样,当第7层完成后,我们往往需要将数据送回标签所在的第0层(或者将标签送到最后一层)。现在,可以计算出来损失,并使用优化器。

问题:

  • 主要的缺陷以及为什么这个被称为 "幼稚 "的PP的原因,是除了一个GPU之外,其他的GPU在任何时候都是闲置的。因此,如果使用4个GPU,这几乎等同于将单个GPU的内存量增加四倍,而忽略了其他硬件。另外还有在设备之间复制数据的开销。因此,4个6GB的卡将能够容纳与1个24GB的卡相同的规模,使用幼稚PP,只是后者将更快地完成训练,因为它没有数据复制的开销。但是,比方说,如果你有40GB的卡,需要装一个45GB的模型,你可以用4x 40GB的卡(但由于梯度和优化器的状态,几乎不可能)。
  • 共享嵌入可能需要在GPU之间来回复制。

管道并行(PP)几乎与上述的幼稚PP相同,但它解决了GPU空闲的问题,通过将传入的批处理分成更细的微批(MBS)并人为地创建一个管道,这使得不同的GPU可以同时参与计算过程。

以下是GPipe论文中的插图,上面是幼稚PP,下面是PP:

mp-pp

从图中不难看出,PP的死区较少,即GPU闲置的地方。闲置的部分被称为 "气泡"。

图中的两部分都显示了degree 4的并行,即有4个GPU参与了管道。因此,有4个管道阶段F0、F1、F2和F3的前向路径,然后是B3、B2、B1和B0的返回反向顺序后向路径。

PP引入了一个新的超参数来进行调整,这个参数叫做chunks。它定义了有多少个数据块依次通过同一管道阶段被发送。例如,在下图中,你可以看到chunks=4。GPU0对第0、1、2和3块数据执行相同的前向路径(F0,0, F0,1, F0,2, F0,3),然后它等待其他GPU完成它们的工作,只有当它们的工作开始完成时,GPU0才开始再次工作,对第3、2、1和0块数据执行后向路径(B0,3, B0,2, B0,1, B0,0)。

请注意,从概念上讲,这与梯度累积步骤(GAS)是同一个概念。PyTorch使用的是chunks,而DeepSpeed指的是与GAS相同的超参数。

因为有了chunks,PP引入了微批(MBS)的概念。DP将全局的数据批处理量分成小批处理,所以如果你的DP度数是4,那么全局的批处理量1024会被分成4个小批(mini-batches),每个小批256(1024/4)。而如果数据块(或GAS)的数量是32,我们最终得到的微批大小是8(256/32),每个管道阶段一次只工作于一个微批。

为了计算DP+PP设置的全局批次大小,我们要做的是:MBS*chunks*DP_degree(8*32*4=1024)。

在chunks=1的情况下,你最终会得到幼稚PP,这是很低效的。如果chunks的值非常大,你就会出现微小的微批尺寸,这可能也不是很有效。因此,我们必须通过实验来找到能使GPU得到最高效率利用的值。

虽然图中显示有一个无法并行化的 "死 "时间的气泡,因为最后一个前向阶段必须等待后向阶段完成管道,但为chunks找到最佳值的目的是在所有参与的GPU上实现高并发的GPU利用率,这可以转化为最小化气泡的大小。

这种调度机制被称为全前向全后向。其他一些选择是一前一后和交错的一前一后。

虽然Megatron-LM和DeepSpeed都有自己的PP协议的实现,但Megatron-DeepSpeed使用DeepSpeed的实现,因为它与DeepSpeed的其他方面相集成。

这里还有一个重要的问题是单词嵌入矩阵的大小。虽然通常情况下,单词嵌入矩阵消耗的内存比转换块要少,但在我们的案例中,有一个巨大的250k词汇,嵌入层需要7.2GB的bf16权重,而转换块只有4.9GB。因此,我们不得不指示Megatron-Deepspeed将嵌入层视为一个转换块。因此,我们有一个72层的管道,其中2个是专门用于嵌入的(第一和最后一个)。这允许平衡GPU的内存消耗。如果我们不这样做,我们会让第一层和最后一层消耗大部分的GPU内存,而95%的GPU会使用更少的内存,因此训练的效率会大打折扣。

DP+PP

下图来自DeepSpeed管道教程,演示了如何将DP与PP相结合。

dp-pp-2d

在这里,重要的是要看到DP等级0没有看到GPU2,DP等级1没有看到GPU3。对DP来说,只有GPU 0和1,它在那里输入数据,就像只有2个GPU一样。GPU0 "秘密地 "使用PP将其部分负载卸载给GPU2。而GPU1也通过征召GPU3来做同样的事情。

由于每个维度至少需要2个GPU,这里你至少需要4个GPU。

DP+PP+TP

为了获得更有效的训练,PP与TP和DP相结合,这被称为3D parallelism(3D并行),这可以在下图中看到:

dp-pp-tp-3d

这张图来自一篇3D并行博文:Scaling to trillion-parameter models(https://www.microsoft.com/en-us/research/blog/deepspeed-extreme-scale-model-training-for-everyone/),这也是一篇不错的阅读。

由于每个维度都需要至少2个GPU,这里你需要至少8个GPU来实现全3D并行。

ZeRO DP+PP+TP

DeepSpeed的主要特点之一是ZeRO,它是DP的一个的扩展,这已经在ZeRO Data Parallelism中讨论过了。通常,它是一个独立的功能,不需要PP或TP。但它可以与PP和TP结合。

当ZeRO-DP与PP(和可选的TP)结合时,通常只启用ZeRO第一阶段,它只粉碎优化器状态。ZeRO第二阶段额外地粉碎梯度,第三阶段也粉碎模型权重。

虽然理论上可以使用ZeRO第二阶段与管道并行,但它会对性能产生不良影响。每个微批都需要一个额外的reduce-scatter集体,在分片之前聚集梯度,这可能会增加大量的通信开销。根据管道并行的性质,使用小的微批,而重点是试图平衡算术强度(微批大小)和最小化管道气泡(微批的数量)。因此,这些通信成本会受到影响。

此外,由于PP的存在,层数已经比正常情况下要少,所以节省的内存不会很大。PP已经将梯度大小减少了1/PP,因此在此基础上的梯度分片的节省没有纯DP那么显著。

ZeRO第三阶段也可以用来训练这种规模的模型,然而,它需要比DeepSpeed 3D并行实现更多的通信。经过一年前在我们的环境中进行的仔细评估,我们发现Megatron-DeepSpeed 3D并行的表现最好。从那时起,ZeRO第三阶段的性能有了显著的提高,如果我们今天来评估它,也许我们会选择第三阶段。

BF16Optimizer

在FP16中训练巨大的LLM模型是一个禁区。

我们花了几个月的时间来训练一个104B的模型,你可以从张量板上看到它是完全失败的,这证明了我们自己。在与不断发散的lm-loss斗争的过程中,我们学到了很多东西。

104B-fail

在他们训练完的530B模型后,我们也从Megatron-LM和DeepSpeed团队得到了同样的建议。最近发布的OPT-175B也报告说,他们在FP16的训练中遇到了很大的困难。

因此,早在一月份,因为我们知道我们将在支持BF16格式的A100上训练,Olatunji Ruwase开发了一个BF16Optimizer,我们用它来训练BLOOM。

如果你对这种数据格式不熟悉,请看一下比特布局。BF16格式的关键是,它具有与FP32相同的指数,因此不会受到溢出的影响,而FP16受到的影响很大! 例如,你可以做250*250=62500,但如果你要尝试255*255=65025,你就会出现溢出,这就是在训练过程中造成的主要问题。这意味着你的重量必须保持微小。一种叫做 loss scaling的技术可以帮助解决这个问题,但是当模型变得非常大时,FP16的有限范围仍然是一个问题。

BF16没有这个问题,你可以很容易地做10_000*10_000=100_000_000,而且没有问题。

当然,由于BF16和FP16的大小相同,都是2个字节,所以没有免费的午餐,使用BF16时要付出非常糟糕的精度。然而,如果你记得使用随机梯度下降及其变化的训练是一种跌跌撞撞的行走,所以如果你没有立即得到完美的方向也没有问题,你会在接下来的步骤中纠正自己。

不管是使用BF16还是FP16,还有一个权重的副本,它总是在FP32中 - 这就是被优化器更新的东西。因此,16位格式只用于计算,优化器以全精度更新FP32权重,然后在下一次迭代时将其铸成16位格式。

所有的PyTorch组件都已更新,以确保它们在FP32中执行任何累积,所以没有损失发生。

一个关键的问题是梯度累积,它是管道并行的主要特征之一,因为每个微批处理的梯度都会被累积。在FP32中实现梯度积累以保持训练的精确性是至关重要的,这就是BF16Optimizer所做的。

除了其他改进,我们认为使用BF16混合精度训练将一个潜在的噩梦变成了一个相对平稳的过程,这可以从下面的lm损失图中观察到:

176B-fail

融合的CUDA内核

GPU执行两件事:它可以将数据复制到/从内存中,并对这些数据进行计算。当GPU忙于复制的时候,GPU的计算单元就会闲置。如果我们想有效地利用GPU,我们要尽量减少空闲时间。

内核是一组实现特定PyTorch操作的指令。例如,当你调用torch.add时,它会经过一个PyTorch调度器,该调度器会查看输入的张量和其他各种东西,并决定应该运行哪些代码,然后运行它。CUDA内核是一种使用CUDA API库的特定实现,只能在NVIDIA GPU上运行。

现在,当指示GPU计算c = torch.add(a, b); e = torch.max([c,d])时,一个幼稚的方法是启动两个独立的内核,一个是执行a和b的相加,另一个是寻找c和d之间的最大值,在这种情况下,GPU从其内存中获取a和b,执行相加,然后将结果复制回内存。然后,它取来c和d,执行最大运算,并再次将结果复制到内存中。

如果我们融合这两个操作,即把它们放到一个单一的 "融合内核 "中,并直接启动这个内核,我们就不会把中间的结果c复制到内存中,而是把它留在GPU寄存器中,只需要获取d来完成最后的计算。这样可以节省大量的开销,防止GPU空转,使整个操作更加高效。

融合内核就是这样。主要是它们将多个离散的计算和数据在内存中的移动替换为融合的计算,这些计算的内存移动非常少。此外,一些融合内核重写了数学,使某些计算组可以更快地执行。

为了快速有效地训练BLOOM,有必要使用Megatron-LM提供的几个自定义融合的CUDA内核。特别是有一个优化的内核来执行LayerNorm,以及融合缩放、遮蔽和softmax操作的各种组合的内核。使用PyTorch的JIT功能,添加偏置项也与GeLU操作相融合。这些操作都是有内存限制的,因此,一旦从内存中检索到一个值,就必须将它们融合起来,使计算量最大化。因此,举例来说,在已经进行有内存约束的GeLU操作的同时增加偏置项,不会增加额外的时间。这些内核都可以在Megatron-LM资源库(https://github.com/NVIDIA/Megatron-LM)中找到。

数据集

Megatron-LM的另一个重要特征是高效的数据加载器(data loader)。在启动初始训练时,每个数据集被分割成所要求的序列长度的样本(BLOOM为2048),并创建索引为每个样本编号。根据训练参数,计算出数据集的历时数,并为该历时数创建一个排序,然后进行洗牌。例如,如果一个数据集有10个样本,并且应该经过两次,系统首先按照[0, ..., 9, 0, ..., 9]的顺序排列样本索引,然后洗牌,为数据集创建最后的全局顺序。请注意,这意味着训练不会简单地通过整个数据集,然后重复进行,有可能在看到另一个样本之前,就已经看到了同一个样本两次,但在训练结束时,模型将看到每个样本两次。这有助于确保在整个训练过程中形成平滑的训练曲线。这些指数,包括进入每个样本的基础数据集的偏移量,被保存到一个文件中,以避免每次训练过程开始时重新计算它们。然后,这些数据集中的几个可以用不同的权重混合成训练过程中看到的最终数据。

嵌入LayerNorm

当我们在努力阻止104B发散的时候,我们发现在第一个单词嵌入之后增加一个额外的LayerNorm使训练更加稳定。

这个洞察力来自于对bitsandbytes(https://github.com/facebookresearch/bitsandbytes)的实验,它包含一个StableEmbedding,这是一个带有layernorm的普通嵌入,它使用统一的xavier初始化。

位置编码

我们还用AliBi取代了通常的位置编码嵌入,这来自论文Train Short, Test Long: Attention with Linear Biases Enables Input Length Extrapolation(https://arxiv.org/abs/2108.12409),它允许推断比模型训练时更长的输入序列。因此,即使我们在长度为2048的序列上进行训练,模型也可以在推理过程中处理更长的序列。

训练的难处

随着架构、硬件和软件的到位,我们能够在2022年3月初开始训练。然而,这并不是一帆风顺的。在本节中,我们将讨论我们遇到的一些主要障碍。

在训练开始之前,有很多问题需要解决。特别是我们发现了几个问题,这些问题只有在我们开始在48个节点上进行训练时才表现出来,而在小规模上不会出现。例如,需要CUDA_LAUNCH_BLOCKING=1来防止框架挂起,我们需要把优化器组分成更小的组,否则框架会再次挂起。你可以在训练前传的编年史中详细了解这些内容。

训练中遇到的主要问题类型是硬件故障。由于这是一个拥有大约400个GPU的新集群,我们平均每周都会遇到1-2个GPU故障。我们每3小时保存一个检查点(100次迭代),所以平均来说,我们会因为硬件崩溃而损失1.5小时的训练。Jean Zay的系统管理员会替换有问题的GPU,使节点恢复正常。同时,我们还有备用节点可以使用。

我们还遇到了其他各种问题,导致了几次5-10小时的停机时间,有些与PyTorch的死锁错误有关,有些则是由于磁盘空间耗尽。如果你对具体细节感到好奇,请看训练纪实(https://github.com/bigscience-workshop/bigscience/blob/master/train/tr11-176B-ml/chronicles.md)。

在决定训练这个模型的可行性时,我们对所有这些停机时间进行了规划--我们选择了模型的大小来匹配这种可行性和我们希望模型消耗的数据量。在所有的停机时间中,我们设法在我们的估计时间内完成了训练。正如前面提到的,它花了大约100万个计算小时来完成。

还有一个问题是,SLURM的设计并不是为了供一个团队使用的。一个SLURM作业是由一个用户拥有的,如果他们不在身边,小组的其他成员就不能对运行中的作业做任何事情。我们开发了一个kill-switch的变通方法,允许组内的其他用户杀死当前进程,而不需要启动该进程的用户在场。这在90%的问题中都很有效。如果SLURM的设计者看到这篇文章,请加入Unix组的概念,这样SLURM作业就可以由一个组拥有(哈哈)。

由于训练是全天候进行的,我们需要有人随叫随到,但由于我们在欧洲和加拿大西海岸都有人,所以总的来说不需要有人带传呼机,我们只是很好地重叠在一起。当然,在周末也必须有人看管训练。我们将大多数事情自动化,包括从硬件崩溃中恢复,但有时也需要人工干预。

结论

训练中最困难和紧张的部分是训练开始前的两个月。我们面临很大的压力,必须尽快开始训练,因为资源分配的时间有限,而且直到最后一刻我们才有机会接触到A100。所以这是一个非常困难的时期,考虑到BF16Optimizer是在最后时刻编写的,我们需要对它进行调试并修复各种错误。而且正如上一节所解释的,我们发现了一些新的问题,这些问题只有在我们开始在48个节点上进行训练时才表现出来,而在小规模上不会出现。

但是一旦我们解决了这些问题,训练本身就出奇地顺利,没有大问题。大多数时候,我们只有一个人在监控训练,只有少数时候有几个人参与到故障排除中来。我们得到了Jean Zay管理部门的大力支持,他们迅速解决了训练期间出现的大部分需求。

总的来说,这是一个超级紧张但非常有意义的经历。

训练大型语言模型仍然是一项具有挑战性的任务,但我们希望通过建立和分享这项技术的开放,其他人可以在我们的经验基础上更进一步。

资源

Important links

Papers and Articles

我们不可能在这篇文章中详细解释所有的东西,所以如果这里介绍的技术激起了你的好奇心,你想了解更多,这里有一些论文可以阅读:

Megatron-LM:

DeepSpeed:

Joint Megatron-LM and Deepspeeed:

ALiBi:

BitsNBytes:

  • 8-bit Optimizers via Block-wise Quantization (在嵌入LayerNorm的背景下,但论文的其他部分和技术是惊人的,没有使用8bits优化器的唯一原因是我们已经用DeepSpeed-ZeRO节省了优化器的内存)

内容中包含的图片若涉及版权问题,请及时与我们联系删除