专栏名称: PaperWeekly
PaperWeekly是一个分享知识和交流学问的学术组织,关注的领域是自然语言处理的各个方向。我们热爱知识,分享知识,希望通过我们大家的努力为自然语言处理的发展做出一点点贡献。我们每周会分享一期特定话题的论文笔记和本周值得读的相关论文。
目录
相关文章推荐
募格学术  ·  又一所学院,拟更名大学 ·  昨天  
PaperWeekly  ·  卷上天了!ACL 2025投稿ID首次破万 ·  2 天前  
募格学术  ·  痛惜!北京大学56岁副教授叶纯芳逝世 ·  2 天前  
实验万事屋  ·  要不是Redox ... ·  2 天前  
研之成理  ·  北大/剑桥合作,Nature Materials! ·  4 天前  
51好读  ›  专栏  ›  PaperWeekly

DualPipe深入浅出:没有分布式训练基础也能看懂的DualPipe全方位讲解

PaperWeekly  · 公众号  · 科研  · 2025-03-09 21:31

正文

©PaperWeekly 原创 · 作者 | 张逸骅

单位 | 密歇根州立大学博士生

研究方向 | 可信人工智能



过去的两周里,DeepSeek 在社交媒体上宣告这是他们的开源周(OpenSourceWeek),并连续五天放出了多款软件库。

前段时间分别发布了 FlashMLA(高效 Hopper GPU MLA 解码核)、DeepEP(面向 MoE 的专家并行通信库)以及 DeepGEMM(支持 FP8 的 GEMM 库)。而就在第 4 天,他们一口气开源了三大组件:DualPipe、EPLB 以及 profile-data, 其中的 DualPipe 因为引入了“双向流水线并行”这一核心理念 ,引起了广泛讨论。

本文将聚焦于 DualPipe 的核心思路: 如何在大模型的训练阶段,实现前向(forward)与后向(backward)的完全重叠,从而大幅降低流水线中的「空闲时间(bubble)」。

为了让读者们更好地理解这些概念,本文从一个通俗易懂的类比—— “机械加工中的工艺优化” ——切入,并在每个部分先讲清楚比喻场景,再与深度学习中的并行训练一一对应,让读者可以在脑海中形成清晰的“具象”画面。

同时,文末我们将深入到 DualPipe 技术的源码层面,探讨它如何进一步减少流水线气泡、实现前后向交叠、将通信带来的压力减小到极致,且如何在较复杂的混合并行场景下落地。


在大语言模型(Large Language Model)如 GPT-3、PaLM、LLama 等火热的当下,分布式训练已成为突破单卡 GPU 极限、成功训练超大模型的必备手段。

我们经常听到诸如“数据并行”“模型并行”“流水线并行”等名词,但对初学者来说,很难直观把握它们之间的区别与联系。尤其是当大家阅读到一些高级用法,如 DeepSeek-V3 里采用的 DualPipe 技术,可能会觉得晦涩难懂。

与此同时,在工业领域,优化生产工艺需要经过无数次试错;在人工智能领域,训练大语言模型同样需要反复调整参数。这两件事看似毫不相关,却有着惊人的相似性。让我们跟随老王机械加工厂的故事,看看如何用车间里的机床与工序,理解大模型训练中的四大并行技术。

1.1 单卡时代:从手工小作坊说起

在苏州工业园区,老王拥有一个不大不小的机械公司,他的公司的主要业务是为机械产品的优化加工工艺,比如铸造温度、淬火时间、切削角度等等。

每当一个新的订单到来时,老王会根据经验设计一份初始工艺手册,按照这个工艺手册进行加工,对加工后的零件进行质量检测,并根据当前加工出来的零件缺陷,从后往前,对每一道工艺进行参数调整:比如当前加工出来的产品有空隙缺陷,就告诉我们铸造温度应该升高一些。

老王的工艺流程其实和大模型训练非常契合:所谓的工艺手册就像大模型的参数一样、而加工的零件就是大模型的训练数据、不同的工艺对应大模型的各种层,机床就像 GPU 一样,最后所谓的质量检测就是损失函数的计算、而根据之间结果对工艺进行调整也正是大模型的梯度回传和参数更新的过程。


在创业初期,老王最初只接螺丝钉加工订单。这类零件加工简单,只需在一台多功能机床上完成切削、打磨两道工序。每当出现次品,老师傅就会对着成品倒推问题:如果是打磨不匀,就调整打磨参数;若是切削误差,就修改刀具角度。

整个过程都在同一台机床上闭环完成。老王的工厂就像一个手工小作坊:不成体系不成规模,但对于简单的零件还是够用的。

这就像单 GPU 训练场景。模型的所有层(工序)都在同一块 GPU(机床)上顺序执行,前向传播(加工零件)和反向传播(参数调整)都在单一设备内完成。虽然简单可靠,但面对复杂任务时,设备性能就会成为瓶颈。

1.2 模型并行(Model Parallelism):工艺手册的拆分艺术

有一天老王接到了一个以前没有遇到过的大单子:发动机曲轴的工艺优化,老王发现自己的单台机床根本无法胜任这个工作。他将铸造、热处理、精密加工等工序拆分到三台专业机床上。每台机床的操作手册都只记录对应工序的参数标准,且调整铸造参数时必须同步考虑对后续工序的影响。

此时,老王发现了一个以前没有遇到过的问题:机床的闲置问题。在零件进行铸造阶段,热处理和精密加工的机床好像没有事做;于此同时,把一个机床的加工结果搬运到另一个机床上加工的过程好像也需要时间,而在“搬运”的过程中如果不做合理的安排可能会使机床闲置的问题更加严重。

在大语言模型中,这对应“模型并行”(Model Parallel)。当模型的体量过大,单个 GPU 无法容纳所有参数时,就把模型本身(如不同层、不同模块)拆分到多个 GPU 上。


在上边的例子中,铸造就像是模型的输入层、热处理是中间层、而精密加工是输出层。模型训练时每个 GPU 负责特定层的计算,必须通过设备间通信传递中间结果。这种方法的代价是不可避免的 GPU 闲置以及需要频繁的跨设备数据传输。老王遇到的问题正是 GPU 之间的调度和通信的问题。

1.3 数据并行 (Data Parallelism):克隆车间计划

为加速工艺参数优化,资金充裕的老王在隔壁建了三个完全相同的车间。每个车间都配备全套四条产线,分别加工不同批次的涡轮盘(数据分片)。收工时,四个车间的工艺主任会开会比对数据,统一修订工艺标准。原本收到的 10,000 块原材料加工优化需要一个月,现在只需要半个月了。

老王很好奇,为什么我的车间数量翻了四倍,而速度只提升了两倍呢?和车间主任们沟通了解到,原来虽然工艺相同,不同的原材料在加工的过程中会遇到一些独特的问题,导致四个车间的收工时间不一样,你等等我、我等等你,时间就这么被浪费了。

这对应“数据并行”(Data Parallel)。每个车间(GPU)都持有完整的工艺手册(模型参数副本),但加工不同的原材料批次(数据分片)。当遇到次品(计算损失)时,各车间独立推导本批次的工艺调整方案(本地梯度),但需要将所有调整方案汇总平均(All-Reduce)后,才能更新统一的工艺标准(全局参数)。


这种方法的瓶颈在于:最慢的车间(straggler GPU)会拖累整体会议进度(通信同步开销),且车间间的沟通耗时(All-Reduce 带宽)随着车间数量增加而显著上升。

1.4 张量并行(Tensor Parallelism):协作加工超大单件

有一天老王出息了,接到了一个超级订单:飞机机体制造的工艺优化。这种订单加工的零件本身极其巨大,比如飞机机翼。尽管机翼只是某一道工序里的一个大部件,但仍然需要调用很多台同样的机床进行协同。

也就是说,这个单件虽然属于某个特定的工序模块,但其体量依然超出了单台机床的处理能力。因此,老王就安排多台相同功能的机床一同来完成同一个大零件的加工。

在大语言模型训练中,这对应“张量并行”(Tensor Parallel)。即便将模型分割成不同模块后,某些单个模块本身依然很大。


此时,需要把这部分网络层对应的张量再进行更细粒度地拆分,分别放到多个 GPU 进行并行计算。比如把一个巨大的矩阵分割成不同的块,分别放到不同 GPU 上并行做矩阵乘法,再把结果合并。这样,单层的计算负载也能够通过多卡来分摊。


这时,老王发现对机床的调度已经成了提升他工作效率的重中之重,因为此时不同机床间的协作非常密切,大部分机床都只负责某一部分或者某一小部分的零件加工,零件需要频繁地运送到某个机床又运送出去,后边工序的机床必须要前一个工序结束后才能工作,在质检后的反馈阶段,前一个工序的参数调整又必须等待后一个工序的参数调整完毕。

这样就留下了大量的闲置问题:同时加工同一个零件的机床在等着他的兄弟机床结束任务、后一个机床在等前一个机床的工件送过来,又或是前一个机床在等后一个机床的反馈报告。老王觉得必须做点什么才能让自己公司的效率更高了。

这对应”张量并行”(Tensor Parallel)的深层逻辑。当单个工序(模型层)的处理需求超过单台机床(GPU)的承载能力时,就需要将巨型零件(大张量)拆分为多个部件,分发给相同功能的机床组(GPU 组)协同加工。比如机翼的抛光工序需要四台机床分别处理不同区域的表面,再通过拼接(张量通信)确保接缝处的完美衔接。


但这类协作带来了三重挑战:零件拆分/组装需要额外运输时间(张量切分与合并的通信开销)、任何机床的延迟都会拖慢整组进度(同步等待)、质检反馈需要在机床组内部完成多轮协商(梯度同步),这些因素共同导致了新的闲置形态——”协作气泡”。

1 .5 流水线并行(Pipeline Parallelization):让不同机床同时高效运转

针对不同工序间的协作困境,老王设计了一套精巧的流水线系统:如果原始的加工路线是:铸造 - 锻造 - 热处理 - 抛光,当铸造机床完成第一批零件的初加工时,这批零件立即被送往锻造,而此时铸造机床已开始处理第二批零件;当第一批零件完成锻造进入热处理线时,第二批零件恰好在锻造线就位——就像多米诺骨牌般环环相扣。

▲ 不采用流水线并行时,数据的传输流程:数据在模型的不同部位依次传递,每次只有一个 GPU 在工作,大量的等待时间使得 GPU 的利用效率非常低。


具体得讲,在未实行流水线系统之前,四个车间的工作模式就像上图展示的这样,第一批原料在被加工成成品等待检验前(T1~T4),每个时刻仅有一台机床在工作,而当质检报告生成后,参数调整又按顺序原路返回,导致在参数调整阶段(T5-T12),仍然只有一台设备没有处于闲置状态。

在上图汇总,灰色区域表示在对应时间段,该车间处于闲置状态。

聪明的老王一眼就看出来问题:在第一批原料送给第二道工序的时候,第一道工序完全可以运送第二批原料了,同理,在第一批原料送给第三道工序的时候,第二批原来也送到了第二道工序,此时第一道工序已经开始进入第三批原料了。如此一来,这个生产线路就变成了下边这个样子:

▲ 1F1B 流水线并行方案示意图

上图展示的正是著名的 1F1B(one-forward-one-backward)流水线并行方案。其基本原则是:当某个 GPU(或机床)发现可对最近一批数据执行梯度回传时,便优先进行后向传播。


例如,在 T5 时刻,Device 4 面临两个选择——要么开始执行第二批数据的前向传播,要么对第一批数据进行后向传播;按照规则,它会优先处理第一批数据的后向传播。


与此同时,所有数据均按批次顺序依次回传,后续批次的后向传播永远在前一批次的后向传播全部启动后才开始。此外,每个设备在前向传播过程中最多只能累积一定数量的激活数据(在图中为 4),以确保每次前向计算保存的中间数据(activation)足以支撑后续的梯度回传,回到我们的例子,就好像机械加工的过程中记录的中间数据,都是在质检报告生成后用于辅助判断工艺参数调整的重要数据。


举例来说,在 T5 时刻,GPU 1 虽有机会处理第五批数据的前向传播,但为了避免激活数据过多而影响后向传播所需的存储和效率,它选择不再累积新的前向任务。


显然,即使在 1F1B 流水线方案下,部分设备仍可能出现短暂的闲置状态——这就是我们在大语言模型训练中所称的“气泡”。气泡的存在意味着设备资源没有被充分利用,降低了整体训练效率,而这正是我们迫切希望通过更先进的调度策略来解决的问题。


为了进一步优化流水线调度,老王对整个过程进行了深入观察,发现气泡较大的根本原因在于各车间组织质检报告与参数调整的反馈时间过长——对一批材料进行反馈调整的耗时大约是该批加工时间的两倍。这导致第一道工序在加工完第四批材料后,必须长时间等待才能完成第一批数据的反馈调整。

为此,老王提出了一个开创性的思路:既然反馈过程耗时如此,不妨将其拆分为两个独立部分,实现解耦。比如,每一道工艺可能同时涉及夹具设计和加工方案设计;如果每台机床能先根据质检报告对夹具设计进行参数调整,再对加工方案进行调整,而这两者又相互独立(即上一工序的夹具调整无需等待当前工序的加工方案反馈),则整体气泡率便能大幅降低。

基于这一理念,老王设计了如下图所示的改进版流水线系统:
▲ ZB1P 流水线并行方案示意图

在该设计中,每批材料的参数调整被分为两步——浅蓝色代表夹具设计调整,深蓝色代表加工方案调整。

在同一工序中,同一步骤的参数调整存在依赖关系(例如,在铸造-锻造-热处理-抛光的流程中,只有当锻造工艺的夹具设计完成后,铸造工艺才能启动对应的调整);而不同步骤之间则相互独立(例如,锻造工艺的夹具设计调整无需等待抛光工艺的加工方案反馈)。

因此,与最初的 1F1B 方案相比,该设计在保证相同激活数据数量(图中为 4)的前提下,有效减少了气泡的数量。

上图所示正是 DeepSeek-V3 技术报告中,与 DualPipe 进行比较时采用的第二个基线——ZB1P 方案。上图就是在 DeepSeek-V3 技术报告中,和 DualPipe 做比较的第二个基线:ZB1P,他在保证了和 1F1B 相同 activation 数量的情况下(图中是 4)进一步得减少了 bubble 的数量。


在大语言模型训练中,梯度回传通常分为两大步骤:


  1. 输入梯度计算: 将梯度从当前层传递至上一层;

  2. 参数梯度计算: 计算当前层参数的梯度以便更新。


以一个线性层为例, 其前向计算为 ,当损失 传回时,我们获得 ;接着需计算两个梯度:(1) —— 用于梯度回传至上一层;(2) —— 用于当前层参数更新。


令人有趣的是,这两项计算在逻辑上并不直接相关:即便某层只完成了(1)而暂未执行(2),梯度依然能够自然地向上回传。


正是基于这一特性,ZB1P 方案将每一层的(1)与(2)解耦,使得输入梯度的回传(1)能够提前完成,而参数梯度的计算(2)则可以稍后启动,从而大幅提升了流水线的调度自由度和整体效率。


现在,你已经全面了解了 DeepSeek-V3 技术报告中与 DualPipe 比较的两种流水线并行算法的原理。报告中还提供了下表,对不同流水线并行算法的效率进行了量化比较:

核心参数说明:

  • : 流水线深度,即参与并行计算的工序数量;
  • : 前向传播所需时间,对应各工序进行初步加工的时长;
  • : 后向传播所需时间,对应各工序完成反馈调整的时长;
  • : 激活数据累积窗口大小,即在梯度回传过程中用于保存中间激活数据的上限。
从上表可以看出,ZB1P 方案在保持与 1F1B 相同激活数据数量的前提下,通过将梯度回传过程拆分并解耦,显著降低了气泡数量,从而缩短了设备等待时间,提升了整体训练效率。更先进的调度策略(如 DualPipe)正是在这一优化思路基础上进一步拓展,致力于最大限度地提高大模型训练时的资源利用率和并行性能。

综上所述,老王通过不断优化流水线调度策略——从最初的 1F1B,到改进后的 ZB1P,再到最新的 DualPipe 技术——正如大语言模型训练中的不断演进与突破,每一次创新都在减少“气泡”对整体效率的影响,推动着系统向更高的性能和更优的资源利用率迈进。

1.6 当流水线依然有“死角”:ZB1P 的局限性

虽然 ZB1P 的解耦思路有效地缩短了气泡,但在老王的机床车间中,仍然存在一些“死角”式的空闲时间。

试想一下:在铸造 - 锻造 - 热处理 - 抛光这个工艺路线中,老王的铸造机床刚完成了某批材料的「夹具设计调整」就将夹具参数交给下一道锻造工序,但此时后面某道工序的“加工方案调整”却无法立刻开始,因为它依赖于前一步骤的全部调整完成后才会逐层传递下来。

由于零件的流动和多道工序的耦合关系依旧较紧密,一旦中间某道工艺的加工速度出现轻微延迟,就可能再次在流水线中累积出空闲时间,形成新的“气泡”。

在大模型训练中,ZB1P 方案虽然将输入梯度与参数梯度进行了解耦,让前向与后向的 overlap(重叠)程度比 1F1B 高出了不少,但依旧无法达到“前向与后向完美并行”这一理想状态。原因在于:

1. 流水线气泡仍然存在: 在以往的实现中,前向和后向是两个完全分开的阶段:先把所有微批数据完成前向,再做后向。这样一来,后传阶段就会浪费前面机床资源,气泡现象严重。

2. 手工调度复杂: 常规的流水线并行实现,需要手动编写大量的逻辑,比如在第几个微批的哪个时刻去发送激活值?什么时候再接收梯度?每个阶段如果不精心安排,整体就会出现等待或通信瓶颈。

2. 前后相互挤压: 前向传播虽然先行一步,但当批次数量非常大、模型层数较多时,后向计算启动多轮后,可能“挤占”前向计算所需的硬件资源(例如显存、带宽等);若资源管理不当,也会引发意外的等待和空闲。

3. 缺少前后向交叠: 在深度学习里,如果能让后向计算和前向计算(针对其他微批次)同时在不同 GPU 上并行,就能极大地提高利用率。然而,手动实现这套逻辑往往很繁琐。

拿回到老王的机床车间举例:当铸造机床与锻造机床在同一时刻几乎满载工作时,热处理机床或抛光机床一旦因为某个机械故障(类似于 GPU 运算负载不均)而被迫降低产能,那么整个流水线又会变得“前等后、后等前”。尽管 ZB1P 已经让调度灵活了不少,但这种多机床、多道工艺串行协作的空闲死角仍然无法完全避免。

于是,老王又琢磨出了更新的升级方案——通过更深层次地“打散”前向与后向的依赖,让两者在同一流水线的相邻节点中能够充分地相互交错与重叠。

换句话说,假如能让各个机床在处理后向时,依然能接收甚至处理下一批次或下一道工序的前向任务,那么流水线的并行度便能进一步加大,从而将空闲时间压缩得更小。

基于这种思路,老王开发出了一个在模型训练中同样适用的新调度策略,也就是本文的重点——DualPipe。接下来,我们将从高层视角介绍 DualPipe 的核心思想。


双管齐下的流水线调度:DualPipe

2.1 双向调度(Bidirectional Scheduling):把“前后”同时推上生产线

在传统的流水线(即单向流水线)中,如 1F1B 或 ZB1P,一台机床要么处于“前向加工”状态,要么被动等待上游机床的反馈信息以进行“后向调整”,二者通常是互斥的。

在 DualPipe 中,老王为机床配备了一个“分时工作模式”和“灵活的前后道信息传输系统”,让同一台机床可以同时进行前向和后向的操作:一方面可以执行原材料的加工任务,同时可以接受从后方传递过来的质检报告并对当前站点进行对应的参数调整。

有了这个双向运输系统,一个机床在同一时刻可以不断地接收从上游送来的原材料(对应前向输入)和从下游传来的成品反馈(对应后向梯度),真正做到“双管齐下”。

这么做有什么好处呢?DualPipe 的出现,正是为了让流水线里的前向与后向能真正做到同时进行,在大语言模型的训练当中,这么做可以最大限度地利用 GPU 资源。和传统的“单向流水线”不同,DualPipe 允许从流水线的两端同时注入微批次(Micro-batches)。

如果把流水线想象成一个长长的传送带,过去我们只能从传送带的一头放入原材料、依次通过多台机床到达终点;而 DualPipe 则在“传送带的左端和右端”同时进行传输,让机床既能对“左端”(上游)送来的原材料进行前向加工,又能在稍后对“右端”(下游)送来的半成品进行后向调整。

这个做法极大地提升了流水线整体的利用率,使得 GPU 既能处理来自“前段”的前向任务,也能接收“后段”的反馈并执行部分后向计算,避免了单向流动带来的等待。

下面这个表展示了三种流水线调度方案在“气泡”(Bubble)和激活数据(Activation)方面的差异,直观地反映了不同方法在隐藏通信延迟与调度资源方面的成效:

其中, 表示流水线的深度,即参与计算的阶段数; 分别代表前向与后向计算所需的时间,而 则是激活数据累积的窗口大小。

过对比三个方法,我们发现:

  • 1F1B 方法: 这种最基础的单向流水线调度方式, 其气泡数量为 。也就是说,每个阶段在前向和后向之间都有固定的等待时间,整个流水线几乎是严格串行的。激活数据则为 ,说明每个流水线阶段仅需存储一份激活数据。

  • ZB1P 方法: 通过将后向传播的部分计算(例如输入梯度与权重梯度的拆分)解耦, ZB1P 成功减少了气泡数量,将其降低到 。不过,激活数据的需求并未改变,仍然是

  • DualPipe 方法: DualPipe 采用双向流水线和计算与通信重叠的策略,将前向和后向同时注入流水线,从而大幅度降低了流水线中的空闲等待(气泡)。表中显示, 其气泡数量为







请到「今天看啥」查看全文