图解大模型训练系列:序列并行2,DeepSpeed Ulysses

最近已有不少大厂都在秋招宣讲,也有一些已在 Offer 发放阶段了。

节前,我们邀请了一些互联网大厂朋友、今年参加社招和校招面试的同学。

针对新手如何入门算法岗、该如何准备面试攻略、面试常考点、大模型技术趋势、算法项目落地经验分享等热门话题进行了深入的讨论。

总结链接如下:

《大模型面试宝典》(2024版) 发布!

喜欢本文记得收藏、关注、点赞。


大家好,在序列并行系列中,我们已经介绍过了Megatron SP,今天这篇文章我们来看DeepSpeed Ulysses。

在正文开始前,请允许我吐槽一下,DeepSpeed Ulysses继承了DS家一如既往的写作和coding风格:云里雾里,梦里心里,就是走不进你的脑子里。所以虽然paper短小,coding改动也小,一切都慷慨地开源了,但一切又好像没有开源,使整个理解过程变得过于眼鼻酸涩。举些例子来说:

  • Ulysses的卖点之一【通讯量】竟然用一两句话就写过去了😢。

  • Ulysses SP的核心操作All2All过程,竟然用一个标着All2All的红箭头就概括过去了😢。

  • Ulysses + zero3这种官方安利的训练方法,竟然没有一个图例😢。

  • 诸如此类。

所以本来想偷懒不看源码,最终又要从源码开始看起。那既然说起了代码,如果你也看过ds家的代码风格的话,那你应该懂我接下来没有记录下的这些眼泪(但ulysses相关的代码其实还好)。

尽管有以上种种,当真正了解Ulysses的设计思想后,还是要佩服它的简便和轻巧,如果有做序列并行的需求,我大概率会从Ulysses开始尝试改起。

话不多说,这篇文章会尽最大可能补充ulysses的细节,全文目录如下:

一、Ulysses整体运作流程

二、Megatron VS Ulysses
2.1 Megatron通讯量
2.2 Ulysses通讯量
(1)All2All操作
(2)Ulysses fwd
(3)Ulysses bwd
2.3 通讯量对比

三、Ulysses + Zero3

四、参考

一、Ulysses整体运作流程

Ulysses的整体运作流程如下图,我们来详细解释下。

图片

设:

  • N = seq_len

  • d = hidden_size

  • P = gpu_num,在后文的解读中,我们可以发现ulysses在实际操作中,其实是1张卡算1个/若干个head的结果,所以这里还应该满足head_num是P的整数倍,不过接下来我们为了表达简便,统一把这个P直接理解成head_num。

我们来跟着这张图,走一遍ulysses的fwd过程。

(1)按seq维度切分输入数据。

对于输入X =(N, d),我们将其切分成若干个seq_chunk,作为各自gpu的输入,每个seq_chunk的尺寸为(N/P, d)。

(2)每张卡计算自己维护的seq_chunk的qkv值。

  • 由于ulysses本身不对模型做任何切割,所以每块gpu上保存有完整的模型,也就是完整的矩阵,尺寸都为(d, d)

  • 这里额外提一点,我们经常会听到ulysses可以配合zero3进行使用。在这种情况下,在进入正式计算前,每块gpu确实只保存部分模型(模型并行的形式),但实际计算时会做all-gather让每张卡拿回完整的模型再计算(数据并行的实质),所以我们依然可以理解成gpu上保存完整的模型。

  • 每块gpu上的seq_chunk正常和相乘,得到q/k/v_chunk = (N/p, d)

(3)针对q/k/v_chunk,所有卡间做一次All2All通讯,使得每张卡拿到所有seq的某1个head的q/k/v_chunk

  • 做这个All2All通讯前,每张卡上维护的q/k/v_chunk = (N/p, d),可以理解成某个seq_chunk所有head的qkv值

  • 做这个All2All通讯后,每张卡上维护的q/k/v_chunk = (N, d/P),可以理解成所有seq的某个head的qkv值。

我们以q_chunk为例,来具体看All2All是怎么实现这一点的(下图根据ulysses源码进行绘制,做了一点简化)

图片

  • 如上图所示,这里我们假设有4块卡(4个head),则最终我们希望gpu0算head0的结果,gpu1算head1的结果…以此类推。我们用不同颜色的矩形表示计算不同head需要用到的q数据。

  • 我们从上图的最左侧位于gpu0上的q0看起,它表示seq_chunk0的q结果,尺寸为(N/P, d)。不难理解,如果我们将q0沿着d维度切成P块,那么每一块就表示为了计算出对应的head所需要的q结果。其余gpu上的q_chunk也是类推。

  • 现在我们执行All2All算法,你可以将它理解成是一种“转置式”地通信方法:结合上图我们可以发现,各块卡第1列蓝色块现在都跑去gpu0,第2列绿色块现在都跑去gpu1…这就是我们说的“转置”的含义。

  • All2All结束后,我们还以gpu0为例,**它上面拥有P块(N/P, d/P)数据,表示所有seq在head0上的q结果,我们将其稍作reshape后,每块卡上最终维护的q_chunk就变成(N, d/P)。**每块卡上的k/v_chunk也是同理进行All2All通讯。

(4)每张卡拿到所有seq的某1个head的q/k/v_chunk后,我们正常执行Attention计算,最终每张卡上产出结果 chunk,尺寸为(N, d/P)

(5)针对 **chunk,所有卡间再做1次All2All通讯,最终单卡上维护的P chunk尺寸又变回(N/P, d)****。**这个All2All过程可以理解成是先前描述的All2All的反操作,作用过程相似,这里不再赘述。

(6)单张卡上拥有完整的矩阵,我们将P chunk和它相乘,得到最后的输出O chunk,尺寸为(N/P, d)

(7)进入MLP层,由于在MLP层中,不涉及token和token之间的相关性计算,所以各seq_chunk块可以独自计算。

(8)重复上述过程,直到算到Loss 为止。

  • 这里我初步判定,每张卡上算出的Loss应该就是这块卡所维护的那个seq_chunk的Loss。因为我粗看了一遍ulysses的代码,发现目前它的核心是单独设计了一个能实现sp并行的DistributionAttention的模块,然后用这个模块替换掉之前的Attention Module,通过这样一个简单的替换实现了ulysses的基本功能。再考虑到seq_chunk在MLP计算时的独立性和数据并行的特性,最终单卡Loss应该就是seq_chunk Loss,这也意味着sp组的梯度需要做AllReduce通讯,这个我们放在后面对ulysses的通讯量分析中再说。

二、Megatron VS Ulysses

不难发现,Ulysses和Megatron在分布式计算attention上有某些相似之处:

  • Megatron通过tp,显式地把Wq, Wk, Wv切分开,然后每张卡上计算所有seq的某个head的结果。

  • Ulysses通过sp+all2all,在每张卡完整保存Wq, Wk, Wv的前提下,让每张卡上计算所有seq的某个head的结果。

那么在实现相似功能的情况下,Ulysses提出的一个重要卖点是:我的通讯量低。所以接下来,就让我们来详细分析这一点。

(⚠️⚠️⚠️:如果看到下文时,发现对通讯量、激活值等等计算有疑问的朋友,可以先看这篇写**Megatron SP的文章。)**

2.1 Megatron通讯量

图片

上图展示了megatron tp + sp下的整体运作流程。

对于Attention部分:

  • 在fwd的过程中,做了1次all-gather,1次reduce-scatter

  • 在bwd的过程中,做了1次reduce-scatter,1次all-gather(其实在bwd反向传播到g前,还需要做1次all-gather,只是这个通讯量可以被计算掩盖掉,也就是还在传播到g前还在做上层的链式推导计算时,就可以开始all-gather了,所以我们这边先忽略这个额外的all-gather,但是如果你想算进去也没事)

对于MLP部分:

  • 同样是2次all-gather + 2次reduce-scatter,同理还有1次额外的all-gather可以被bwd过程中的计算时间覆盖掉,所以我们还是不计算它。

综合Attention和MLP:

  • 最终在Megatron中,Attention + MLP的通讯量为4 all-gather + 4 reduce-scatter(额外还有2次可以被bwd计算覆盖掉的all-gather不算在这里),1个all-gather/1个reduce-scatter的通讯量约为Nd(忽略batch_size),所以Megatron Attn部分的通讯量约为8Nd

2.2 Ulysses通讯量

(1)All2All操作的通讯量

图片

  • All2All操作前,每张卡上保存的数据大小为(N*d)/P,每个小数据块的大小为(N*d)/(P*P)

  • 虽然对于单卡来说,它的通讯量涉及send和accept,但整个系统的通讯量可以理解成是每张卡的send总和(因为你的accept总来自别人的send,反之亦然),所以对于单卡通讯量我们也只看send就行。

  • 对于单卡来说,它的send量 = ,约为(N*d)/P也就是单卡1次All2All的通讯量约是(N*d)/P【回顾一下,单卡做1次all-gather或reduce-scatter的通讯量是N*d】。

(2)Ulysses fwd通讯量

回顾第一部分Ulysses的fwd过程:

  • q/k/v_chunk各自做1次All2All通讯,则这里合起来做了3次All2All通讯

  • 各卡上原始的Attention结果做了1次All2All通讯

  • 综上,Ulysses fwd过程一共做了4次All2All通讯

(注意,如果配套使用了zero操作,fwd过程还会涉及模型权重的all-gather,不过这里我们不考虑这一点,我们就假设是最朴素的ulysses,单卡上有完整的模型)

(3)Ulysses bwd通讯量

这块也是我觉得比较重要,但是论文里没有展开的地方(抹泪),所以我翻了翻源码(又抹泪),根据自己的理解大致描述下bwd的过程。

图片

对于ulysses bwd的过程,对于以下两类通讯,由于理论上它们可以被bwd的计算时间覆盖,所以不计入总通讯量中:

  • 激活值的重计算:我们知道链式推导的过程中我们会用到一些激活值(比如上图中的P),而为了节省显存,大部分框架都不会把这些激活值保存下来,只有在链式传导块传递到这个激活值上时,重新做fwd算出这个激活值。比如链式传导快到上图中的P上时,我们就需要重做fwd的All2All把P算出来。我们可以在用到P前做这件事,因此重算P的All2All通讯是可以被覆盖的。图中的等等也是同理。

  • 梯度的AllReduce:

  • 假设我们现在要对计算梯度,这里假设我们有两张卡,每张卡上维护某个seq_chunk的P_chunk结果,P_chunk的尺寸为(N/2, d),则我们有:

  • 每张卡上所维护的seq_chunk最终的loss为:,完整序列的Loss为。这里为了表达简便,把计算出O以后所有的操作都用函数f来表示。

  • 所以易知:

    ,也就是的总梯度需要各块卡算出来的梯度做AllReduce。

  • 回到图中,当各卡算完各自对****的梯度后,它们可以一边继续做链式传导,一边把梯度发出去做AllReduce(因为梯度是否AllReduce完并不影响接下去的链式传导的过程),所以梯度的AllReduce也算被bwd的计算时间覆盖了,因此不纳入ulysses bwd的通讯量计算中。

明确了这两点,我们现在来分析ulysses bwd中真正有影响的通讯操作(配合上图进行阅读):

  • 首先,当我们的梯度传导到P上后,我们需要对dP做1次All2All操作,这样才算恢复fwd的路径。

  • 同理,当我们的梯度传导到V, Q, K上后,我们也需要对他们进行All2All操作,这里一共进行了3次All2All操作。

  • 你可以理解成bwd过程的All2All和fwd过程的All2All是在一样的位置做相反的操作,所以整个bwd过程也做了4次All2All操作。

这里再额外提一点,其实这4次All2All操作间也是可以覆盖的,举个例子,链式传导到V后,我们就可以对dV做All2All了,而此时我们可以继续在单卡上计算dQ和dK,所以dV的All2All操作可以被覆盖。同理dQ和dK谁先算完,谁就可以被覆盖。不过在ulysses的源码中,似乎只有dQ和dK做了这个覆盖操作的处理。Anyway,我们这边暂时不考虑bwd这4次All2All的相互覆盖。

所以:

  • ulysses的fwd做了4次All2All,bwd做了4次All2All,一共是8次All2All

  • 每次All2All的通讯量约为(N*d)/P,所以ulysses总通讯量为(8Nd)/P

2.3 通讯量的比较

回顾一下,如上文所言,在不考虑一些可以被覆盖的通讯的情况下,单卡上每个layer(mlp+attn)的通讯量为:

  • Megatron tp+sp:4 all-gather + 4 reduce-scatter,总通讯量为8Nd

  • DeepSpeed Ulysses:8 All2All,总通讯量为(8Nd)/P

仔细端详这2个通讯量,我们可以发现:

  • 对于Megatron,不管你用了多少张卡,它的单卡总通讯量都是8Nd。这意味着如果我的序列长度变长(N变大),这时你无法通过扩张卡的数量来减少单卡通讯量,那么单卡花在通讯上的时间就可能更多,进而降低了训练速度。

  • 对于DeepSpeed Ulysses,它的单卡通讯量为(8Nd)/P,这也意味着当N变大时,只要你能同倍数地调整gpu的数量(P),那么你就可能让单卡通讯量维持在一个不变的常数,使得其不随N增加而变大。不过我们要注意,P的数量其实是被head_num限制住的(ulysses源码里也做了限制),所以其实你并不能无限扩张P,因此朴素的Ulysses在实现【单卡通讯量随P scaling维持在一个不变的常数】的这个卖点上并不完美。所以我们可以对ulysses做一些改造,这里就不展开了,在后面的系列里慢慢引入吧。

三、Ulysses + Zero3

图片

针对论文和官方tutorial里提的ulysses + zero3的方法(同样也是一个卖点,但ds又没展开,抹泪),我这边大概画了一下框架:

  • 我们假设sp_size = 2, dp_size = 2。则需要的gpu数量为world_size = sp_size * dp_size = 4

  • 按照zero3的原则,我们把模型权重分成M0~M3这样的4块,分布在不同的gpu上。

  • 在开始fwd计算前,按照zero3的原则,所有卡上的权重做一次通讯,使得每块卡都拿到完整的M0,然后正常做ulysses的过程,以此类推。

关于ulysses的基本介绍就到这里了,下次我们一起来看看序列并行的第三篇,ring attention吧!

四、参考

1、https://arxiv.org/pdf/2309.14509

2、https://github.com/microsoft/DeepSpeed/blob/master/deepspeed/sequence/layer.py

3、https://github.com/microsoft/Megatron-DeepSpeed/blob/main/megatron/model/transformer.py

4、https://www.deepspeed.ai/tutorials/ds-sequence/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/907396.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MP4650模块改为固定电压记录

目标 这种电源模块,可调电位器质量不太好,可调输出电压改为固定电压。 方法 步骤 按照下图,将计算得到的R1 补到 待添加电阻处。 结论 作者使用输出5V,R1电阻使用5.1K,得到输出电压4.8V; 测试输出电流1A…

51单片机教程(二)- 创建项目

1 创建项目 创建项目存储文件夹:C51Project 打开Keil5软件,选择 Project -> New uVision Project: 选择项目路径,即刚才创建的文件夹 选择芯片,选择 Microchip(微型集成电路)&#xff0…

STM32 HAL库 SPI驱动1.3寸 OLED屏幕

目录 参考硬件引脚与接线 点亮屏幕CubeMX 配置OLED 驱动程序代码 参考 基于STM32F103C8T6最小系统板HAL库CubeMX SPI驱动7针 OLED显示屏(0.96寸 1.3寸通用)0.96 oled HAL库驱动 SPI STM32SPI驱动0.96/1.3寸 OLED屏幕,易修改为DMA控制STM32驱…

通过分解质因数求若干个数的最小公倍数

求最小公倍数的常规方法回顾 暴力枚举法 long long work(long long a,long long b) {for(long long imax(a,b);;i)if(i%a0&&i%b0)return i; }大数翻倍法 long long work(long long a,long long b) {if(a<b) swap(a,b);for(long long ia;;ia) // i 是 a 的倍数&#…

突出显示与条件匹配的列值

Goto Appearance and Conditional Formatting 外观和条件格式 突出显示与条件匹配的列值 本教程说明如何将条件格式应用于 GridControl 中的 Market Share 列&#xff0c;以突出显示与特定条件匹配的单元格。此示例突出显示小于 20% 的 Market Share 列值。 要在设计时创建新…

node.js下载、安装、设置国内镜像源(永久)(Windows11)

目录 node-v20.18.0-x64工具下载安装设置国内镜像源&#xff08;永久&#xff09; node-v20.18.0-x64 工具 系统&#xff1a;Windows 11 下载 官网https://nodejs.org/zh-cn/download/package-manager 版本我是跟着老师选的node-v20.18.0-x64如图选择 Windows、x64、v20.18…

嵌入式开发教程之Linux下IO流

一、文件的概念和类型 文件基础&#xff1a; 概念&#xff1a;一组相关数据的有序集合&#xff0c;文件名、路径。通过文件名指定访问什么文件。 文件类型&#xff1a; 常规文件 r&#xff0c;分为&#xff1a;普通文件&#xff0c;文本文件&#xff08;可见字符&#xff09…

【Python】Python自习课:第一个python程序

【Python】Python自习课&#xff1a;第一个python程序

MySQL【二】

查询列 SELECT [ALL | DISTINCT ] * | 列名1[,……列名n] FROM 表名; 查询所有选课学生的学号&#xff0c;结果去除重复值 select distinct sno from sc; 选择行 查询满足条件的数据集 SELECT 字段列表 FROM 表名 WHERE 查询条件 查询不属于数学系或外国语系的学生全部信息 …

#渗透测试#SRC漏洞挖掘# 信息收集-Shodan进阶之Mongodb未授权访问

免责声明 本教程仅为合法的教学目的而准备&#xff0c;严禁用于任何形式的违法犯罪活动及其他商业行为&#xff0c;在使用本教程前&#xff0c;您应确保该行为符合当地的法律法规&#xff0c;继续阅读即表示您需自行承担所有操作的后果&#xff0c;如有异议&#xff0c;请立即停…

Redis 位图实现签到之长时间未签到预警

#目前通行系统项目中有一个新需求【通过对通行记录数据定时分析&#xff0c;查询出长时间没 有刷卡/刷脸通行的学生】 #一看到通行签到相关&#xff0c;就想到了redis的位图&#xff0c;理由也有很多帖子说明了&#xff0c;最大优点占用空间小。 一.redis命令行 SETBIT&#…

python mac vscode 脚本文件的运行

切换到脚本文件的目录下 路径的修改 当前文件组织形式&#xff1a; 脚本文件在文件夹下&#xff1a; 赋予权限&#xff1a;chmod x ./scripts/fscd_test.sh 运行&#xff1a;./scripts/fscd_test.sh

人脑与机器连接:神经科技的伦理边界探讨

内容概要 在当今科技飞速发展的时代&#xff0c;人脑与机器连接已成为一个引人注目的前沿领域。在这一背景下&#xff0c;神经科技的探索为我们打开了一个全新的世界&#xff0c;从脑机接口到人工智能的飞跃应用&#xff0c;不仅加速了技术的进步&#xff0c;更触动了我们内心…

[论文阅读] | 智能体长期记忆

更新记录&#xff1a; 2024.11.2 人大高瓴长期记忆综述 文章目录 人大高瓴长期记忆综述智能体与环境交互记忆的来源/形式/操作来源&#xff1a;(1)当前任务历史信息 (2)其他任务的信息 (3)外部知识形式&#xff1a;如何表达记忆的内容&#xff0c;通过(1)文本 (2)参数(训练到模…

R6:LSTM实现糖尿病探索与预测

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 一、实验目的&#xff1a; 学习使用LSTM对糖尿病进行探索预测 二、实验环境&#xff1a; 语言环境&#xff1a;python 3.8编译器&#xff1a;Jupyter notebook…

基于SSM+小程序的计算机实验室排课与查询管理系统(实验室2)

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1、项目介绍 1、管理员功能有个人中心&#xff0c;学生管理&#xff0c;教师管理&#xff0c;实验室信息管理&#xff0c;实验室预约管理&#xff0c;取消预约管理&#xff0c;实验课程管理&#xff0…

软件项目实施方案,实施计划,总体实施管理方案(word原件)

一、 概述 二、 项目介绍 2.1 概览 三、 项目实施 3.1 项目实施概况 3.2 项目实施管理原则 3.3 项目组织结构 3.4 项目团队 四、 项目实施计划 4.1 项目实施工作流程 4.2 项目软件部分进度安排 4.3 网络拓扑图 4.4 服务器需求清单 五、 人员培训 5.1 培训内容 5…

【日记】第一次觉得 “届く” 是一个很难的东西(1528 字)

正文 昨天晚上吃饭路上&#xff0c;听到喵喵叫。四处张望了一下&#xff0c;看见一只野猫。天黑&#xff0c;看不清具体什么样子。我冲它喵喵叫&#xff0c;试图走近它。跑掉了。 看来我还是不讨小动物喜欢呢&#xff08;笑。 一大早去了医院。这次膝盖看了三个医生。 放射科报…

【Python单元测试】pytest框架单元测试 配置 命令行操作 测试报告 覆盖率

单元测试&#xff08;unit test&#xff09;&#xff0c;简称UT。本文将介绍在Python项目中&#xff0c;pytest测试框架的安装&#xff0c;配置&#xff0c;执行&#xff0c;测试报告与覆盖率 pytest简介 pytest是一款流行的&#xff0c;简单易上手的单元测试框架&#xff0c;…

三次样条插值算法及推导过程

目录 1、定义 2、已知条件求解 3、具体推导 4、matlab案例 5、案例结果 6、matlab仿真 1、定义 给定 n 1 n1 n1个数据点&#xff0c;共有 n n n个区间&#xff0c;三次样条方程 S ( n ) S(n) S(n)满足以下条件&#xff1a;在每个分段区间内 ( x i , x i 1 ) (x_i,x_{i1}) (…