首页 > 其他分享 >大模型--Megatron TP张量并行-15

大模型--Megatron TP张量并行-15

时间:2024-11-13 18:08:01浏览次数:1  
标签:15 embedding -- TP 维度 计算 forward GPU backward

目录

1. 参考

https://zhuanlan.zhihu.com/p/622212228

2. 介绍

流水线并行
数据并行(DP,DDP和ZeRO)

介绍最重要,也是目前基于Transformer做大模型预训练最基本的并行范式:来自NVIDIA的张量模型并行(TP)。
基本思想就是把模型的参数纵向切开,放到不同的GPU上进行独立计算,然后再做聚合。
之前的将的都是 模型 按照层 进行切割。

全文结构如下:
一、切分权重的两种方法
二、MLP层
三、self-attention层
四、Embedding层
五、Cross-entropy层
六、经典并行:TP + DP (Megatron + ZeRO)
七、实验效果与GPU利用率
八、参考

3. 权重的切分

设输入数据为X,参数为W。X的维度 = (b, s, h),W的维度 = (h, h')。其中:

  • b:batch_size,表示批量大小
  • s:sequence_length,表示输入序列的长度
  • h:hidden_size,表示每个token向量的维度。
  • h':参数W的hidden_size。

orward的过程如下:

图中所绘是b=1时的情况。

假设现在W太大,导致单卡装不下。我们需要把W切开放到不同的卡上,则我们面临三个主要问题:

  • 怎么切分W。
  • 切完W后,怎么做forward。
  • 做完forward后,怎么做backward,进而求出梯度,更新权重。

一般来说,我们可以沿着W的行(h维度),或者列(h'维度)切分W。下面我们分别介绍这两种切割办法,并说明它们是如何做forward和backward的。

3.1 按行切分权重

forward
我们用N来表示GPU的数量。有几块GPU,就把W按行维度切成几份。下图展示了N=2时的切割方式:

W按照行维度切开后,X的维度和它不对齐了,这可怎么做矩阵乘法呢?很简单,再把X“按列切开”就行了,如下图所示:

backward
做完forward,取得预测值Y,进而可计算出损失L,接下来就能做backward了。我们重画一下forward的过程,并在其中加入backward的部分,整体流程图如下:

f 和 g:分别表示两个算子,每个算子都包含一组forward + backward操作。
其中 forward:
f算子:X 竖直方向切割成x1 x2即可
g算子:y1 + y2 即可

图中的每一行,表示单独在一块GPU上计算的过程

f 和 g算子的backward
g 的backward:

需要把同时广播到两块GPU上,两块GPU就可以独立计算各自权重的梯度了。

f 的backward:

3.2 按列切分权重

按列切分权重后,forward计算图如下:

这个forward还是比较简单的直接切分别计算 再接到一起 即可

g的backward:
貌似都等于X
因此只要计算各自GPU上的

f 的backward:因为对于损失L,X既参与了XW1的计算,也参与了XW2的计算,因此,其中表示第i块GPU上计算到X时的梯度。

已分别介绍完了“按行”和“按列”切分权重的方法。在Megatron-LM中,权重的切分操作就是由这两个基础算子组合而成的。接下来,针对Transformer模型,我们依次来看在不同的部分里,Megatron-LM是怎么做切分的。

4. MLP层

MLP层构造最简单,所以我们先来看它。MLP层计算过程如下图:

GELU是激活函数,A和B分别为两个线性层。在Transformer里,一般设h' = 4h。
h为embedding的维度
h'为隐藏层的维度
也就是会将embedding的维度 升维到4h的一个更高的维度。

假设现在有N块GPU,我们要把MLP层的权重拆到上面做计算,要怎么拆分呢?Megatron提供的拆分办法如下:

在MLP层中,对A采用“列切割”,对B采用“行切割”。

f 的forward计算:把输入X拷贝到两块GPU上,每块GPU即可独立做forward计算。
g 的forward计算:每块GPU上的forward的计算完毕,取得Z1和Z2后,GPU间做一次AllReduce,相加结果产生Z。

g 的backward计算:只需要把拷贝到两块GPU上,两块GPU就能各自独立做梯度计算。
f 的backward计算:当当前层的梯度计算完毕,需要传递到下一层继续做梯度计算时,我们需要求得 则此时两块GPU做一次AllReduce,把各自的梯度相加即可。

为什么我们对A采用列切割,对B采用行切割呢?
这样设计的原因是,我们尽量保证各GPU上的计算相互独立,减少通讯量。

对A来说,需要做一次GELU的计算,而GELU函数是非线形的,它的性质如下:

也就意味着,如果对A采用行切割,我们必须在做GELU前,做一次AllReduce,这样就会产生额外通讯量。但是如果对A采用列切割,那每块GPU就可以继续独立计算了。一旦确认好A做列切割,那么也就相应定好B需要做行切割了。

MLP层的通讯量分析:
MLP层做forward时产生一次AllReduce,做backward时产生一次AllReduce。

AllReduce的过程分为两个阶段,Reduce-Scatter和All-Gather,每个阶段的通讯量都相等。
现在我们设每个阶段的通讯量为
则一次AllReduce产生的通讯量为,MLP层的总通讯量为
根据上面的计算图

5. Self-Attention层

看稍微复杂一点的self-attention层切割方式(Transformer中Encode和Decoder之间还有做cross-attention,但计算逻辑和self-attention一致,因此这里只拿self-attention举例)。

当head数量为1时,self-attention层的计算方法如下:

seq_len,d_model分别为本文维度说明中的s和h,也即序列长度和每个token的向量维度
attention层需要做训练的三块权重。

理清了单头,我们来看多头的情况,下图展示了当num_heads = 2时attention层的计算方法。
即对每一块权重,我们都沿着列方向(k_dim)维度切割一刀。

此时每个head上的 的维度都变成(d_model, k_dim//2)

每个head上单独做矩阵计算,最后将计算结果concat起来即可。整个流程如下:

这不就是竖直切割的方式吗?
可以发现,attention的多头计算简直是为张量模型并行量身定做的,因为每个头上都可以独立计算,最后再将结果concat起来。也就是说,可以把每个头的参数放到一块GPU上。则整个过程可以画成:

对三个参数矩阵Q,K,V,按照“列切割”,每个头放到一块GPU上,做并行计算。对线性层B,按照“行切割”。切割的方式和MLP层基本一致,其forward与backward原理也一致,这里不再赘述。

最后,在实际应用中,并不一定按照一个head占用一块GPU来切割权重,我们也可以一个多个head占用一块GPU,这依然不会改变单块GPU上独立计算的目的。所以实际设计时,我们尽量保证head总数能被GPU个数整除

Self-Attention层的通讯量分析
self-attention层在forward中做一次AllReduce,在backward中做一次AllReduce。总通讯量也是,其中
self-attention层拼接起来看整体的计算逻辑和通讯量:

6. Embedding层

输入层Embedding,
word embedding:维度(v, h),其中v表示词表大小。
positional embedding:维度(max_s, h),其中max_s表示模型允许的最大序列长度。
对positional embedding来说,max_s本身不会太长,因此每个GPU上都拷贝一份,对显存的压力也不会太大。
但是对word embedding来说,词表的大小就很客观了,因此需要把word embedding拆分到各个GPU上,具体的做法如下:

对于输入X,过word embedding的过程,就是等于用token的序号去word embedding中查找对应词向量的过程。
例如,输入数据为[0, 212, 7, 9],数据中的每一个元素代表词序号,我们要做的就是去word embedding中的0,212,7,9行去把相应的词向量找出来。

假设词表中有300个词,现在我们将word embedding拆分到两块GPU上,第一块GPU维护词表[0, 150),第二块GPU维护词表[150, 299)。
当输入X去GPU上查找时,能找到的词,就正常返回词向量,找到不到就把词向量中的全部全素都置0。按此方式查找完毕后,每块GPU上的数据做一次AllReduce,就能得到最终的输入。
例如例子中,第一块GPU的查找结果为[ok, 0, ok, ok],第二块为[0, ok, 0, 0],两个向量一相加,变为[ok, ok, ok, ok]

输出层Embedding

输出层中,同样有一个word embedding,把输出再映射回词表里,得到每一个位置的词。一般来说,输入层和输出层共用一个word embeding。其计算过程如下:

需要注意的是,必须时刻保证输入层和输出层共用一套word embedding。
而在backward的过程中,我们在输出层时会对word embedding计算一次梯度,在输入层中还会对word embedding计算一次梯度。在用梯度做word embedding权重更新时,我们必须保证用两次梯度的总和进行更新。

当模型的输入层到输入层都在一块GPU上时(即流水线并行深度=1),我们不必担心这点(实践中大部分用Megatron做并行的项目也是这么做的)。但若模型输入层和输出层在不同的GPU上时,我们就要保证在权重更新前,两块GPU上的word embedding梯度做了一次AllReduce。

7. Cross-entropy层

终于来到了计算损失函数的一层回顾一下4.2中,输出层过完embedding后的样子:

正常来说,我们需要对Y1和Y2做一次All-Gather,把它们concat起来形成Y,然后对Y的每一行做softmax,就可得到对于当前位置来说,每个词出现的概率。接着,再用此概率和真值组做cross-entropy即可。

但是All-Gather会产生额外的通讯量,当词表v很大时,这个通讯开销也不容忽视。针对这种情况,可以做如下优化:

  1. 每块GPU上,我们可以先按行求和,得到各自GPU上的GPU_sum(e)
  2. 将每块GPU上结果做AllReduce,得到每行最终的sum(e),也就softmax中的分母。此时的通讯量为
  3. 在每块GPU上,即可计算各自维护部分的e/sum(e),将其与真值做cross-entropy,得到每行的loss,按行加总起来以后得到GPU上scalar Loss。
  4. 将GPU上的scalar Loss做AllReduce,得到总Loss。此时通讯量为N。

这样,我们把原先的通讯量从 大大降至

8. 张量模型并行 + 数据并行

基本把张量模型并行的计算架构说完,对Transformer类的模型,采用最经典方法是张量模型并行 + 数据并行,并在数据并行中引入ZeRO做显存优化。具体的架构如下:

node表示一台机器,一般我们在同一台机器的GPU间做张量模型并行。在不同的机器上做数据并行。图中颜色相同的部分,为一个数据并行组。

标签:15,embedding,--,TP,维度,计算,forward,GPU,backward
From: https://www.cnblogs.com/cavalier-chen/p/18544497

相关文章

  • FreeModbus RTU 从机Hal库裸机移植避坑指南
    首先说明:FreeModbus有很多个库!!!!不同库的实现方法是略有不同的!!!本次FreeModbusRTU移植主要依据这个网友分享的工程他人移植的库你可能会在csdn看到他的文章,但是完全跟着那个文章走很混乱而且跟库的文件不一样.故而我重新整理了工程,并写了一个详细的移植教......
  • numpy浅用
        numpy是一项python语言编写的,开源的,使用github管理的数据分析工具项目。它使用与matlab相似结构的数组操作单元、矩阵操作单元,两种操作单元十分类似除了一些调用、规格和适配性问题不同,混用的话几乎不影响实际中的轻度使用。市面上很多具体的数据分析和可视化工具......
  • noip模拟12
    A花鳥風月对于每个区间,若左边端点为\(l\),右边端点为\(r\),那这个地方能放下的线段数则为\(\frac{r-l}{a+1}\)。那么每进来一个坏点,只会影响它的前驱后继的区间。那我们用set或者map维护一下前驱后继,每次加点去抵消它的区间的影响,再加回来就可以了。点击查看代码#incl......
  • 力扣刷题——3261. 统计满足 K 约束的子字符串数量 II
    看了题目的两个初始用例,感觉能用前缀和和滑动窗口来解决,前缀和设定为从下标0到当前位置所有符合条件的答案数量,于是先写了一个:vector<longlong>countKConstraintSubstrings(strings,intk,vector<vector<int>>&queries){intn=s.size();vector<longlong>pre......
  • SSH协议详解及实例分析
    一、SSH的定义SSH——secureshell;SSH为计算机网络协议,用于计算机之间的加密通信,通过加密和认证机制实现安全的访问、远程登录和文件传输等业务;SSH协议的默认端口号为22;SSH协议通过对网络数据进行加密和验证,建立SSH客户端和SSH服务器之间的安全隧道,在不安全的网络环境中为网......
  • 考研打卡(16)
    开局(16)开始时间 2024-11-13 15:51:25结束时间 2024-11-13 17:59:04现在在1016数据结构某带链的队列初始状态为front=rear=NULL。经过一系列正常的入队与退队操作后,front=rear=10.该队列中的元素个数为______(苏州大学2009年)A1B0C1或0D不确定A......
  • Day4
    Day4当天站立式会议照片团队成员姓名学号昨天已完成的工作今天计划完成的工作工作中遇到的困难林涛(组长)3122004618完成验证码校验api补足各方面null杨森3122004629完成验证码前端展示完成验证码前端展示null钟礼骏3122006504前端展示家长模块前端......
  • CSC3150 memory-mapped files
    CSC3150-Instruction-A3:IntroductionThisassignmentusesxv6,asimpleandUnix-liketeachingoperatingsystem,astheplatformtoguideyouinimplementingthemmapandmunmpsystemcalls.Thesetwoareusedtosharememoryamongprocesesandtomapfil......
  • 一图看懂云消息队列 RabbitMQ 版对比开源优势
    随着企业对消息队列的性能和稳定性要求越来越高,运维成本也随之增加。云消息队列RabbitMQ版通过架构优化:避免了消息积压导致的内存泄漏和服务器故障等稳定性问题;解决了分布式系统中的脑裂难题;并支持弹性伸缩和按量计费,有效降低资源和运维成本!那么,与开源RabbitMQ相比,云消......
  • Day5
    Day5当天站立式会议照片团队成员姓名学号昨天已完成的工作今天计划完成的工作工作中遇到的困难林涛(组长)3122004618完成验证码校验api测试api如何进行测试杨森3122004629完成验证码前端展示完成家长模块null钟礼骏3122006504前端展示家长模块完成......