☰
五种并行策略全解析:大模型分布式训练核心指南
2026/11/2 12:28:55 网站建设 项目流程

如果你跟我一样是做算法出身,第一次面对分布式训练脚本时,大概率会有这种体验:模型结构门清,loss曲线看得津津有味,但看到训练框架里--tensor-parallel-size 8、--pipeline-parallel-size 4、--data-parallel-size 8这种参数时,就只剩一个念头——这些到底在切什么,为什么非得这么切。

我之前也以为“分布式”就是把卡凑多、把模型塞进去。直到真正动手把一个LLM从单卡搬到多卡,把TP、DP、PP、CP、EP这五个概念逐一对着显存、带宽、训练时间去理解,才意识到并行策略本质上是一套“怎么切模型、怎么切数据、怎么同步结果”的取舍。这篇是“算法同学学Infra”系列的第二篇,我用尽量靠近算法的语言,把这五种并行策略一口气讲清楚。看完你至少能回答三个问题:每种并行切的是什么维度,通信代价有多大,实际训练或推理时怎么组合。

1. 先想清楚一件事:并行策略到底在解决什么

在讨论具体技术之前,得先对齐一个共识:在单卡上跑大模型,究竟卡在哪?答案是两个地方,一是显存墙,二是算力墙。

显存墙最容易理解。一个7B参数的模型,BF16精度下权重就要占14GB,看起来单张A100 80GB似乎能装下,但训练不是只有权重。每个参数还要占用梯度空间,Adam优化器还要额外保存一阶矩和二阶矩,这两项状态通常以FP32保存。粗略一算,权重加梯度加优化器状态就超过100GB,还没算前向传播过程中必须保留的激活值。激活值的大小取决于batch和序列长度,一放大又是几十GB开销。单卡放不下,这是分布式计算最原始的动机。

算力墙更加隐蔽。即便模型塞进单卡,单卡算力也远远不够。训练一个像样的LLM要几千亿token过一遍,单卡几个月都跑不完,所以得用大量GPU并行计算。但算力叠加不等于效率叠加,因为多卡协同需要交换数据。GPU算力动辄几百TFLOPS,而主流网络带宽只有每秒几十到几百GB,量级上差了一大截。一旦通信比例过高,加的卡越多,浪费越严重。

这时“并行策略”的定义就清晰了:把一个大模型的存储和计算拆到多张卡上,同时尽量压低卡与卡之间的通信代价。拆的对象不同,就有了五种并行。后面我会反复强调一条主线:每个并行策略“切的是什么维度、同步的数据量有多大、对网络带宽有多敏感”。把这三件事想清楚,基本就掌握了LLM分布式计算的全部骨架。

2. DP数据并行:最贴近算法直觉,但梯度同步不是免费的

2.1 原理:每个卡各算各的batch

数据并行(Data Parallelism,DP)之所以适合作为入门第一讲,是因为它和算法同学熟悉的“小批量随机梯度下降”几乎是一一对应的。

做法很简单:每张卡各自保存一份完整的模型副本,训练时把一个大的全局batch平均切成N份,分给N张卡。每张卡独立做前向传播、反向传播,算出自己那份数据对应的梯度,接着所有卡把梯度做一次全局同步(all-reduce),得到平均梯度,再用它更新各自手中的模型副本。一轮结束后,所有卡上的模型参数完全一致,再进入下一轮。

这个思路对算法同学来说格外自然——batch维度本来就是样本独立假设,把不同样本分到不同卡上互不影响。模型结构不需要任何改动,训练框架早就把DP封装好了,所以它也是最早被大规模使用的并行策略。

2.2 梯度同步的通信账

但“每步同步一次梯度”这件事,不是免费的。模型有多大,梯度同步的通信量就有多大。

以7B参数模型为例,每个梯度如果用FP32保存就是4字节,那么一次迭代每张卡要同步28GB的梯度裸数据。实际工程里all-reduce的通信量还要再乘一个系数,因为环状实现里每个节点既要发出去也要收回来,整体大约相当于把这份数据在网络里流转两遍。也就是说,每训练一步,光是梯度同步就要在网络里搬运五六十GB的数据。

这个数字落到硬件上是什么概念?现代数据中心常见的800Gbps高速网络,理论带宽大概100GB/s左右,搬完这些数据至少半秒钟。如果你的机间网络还停留在200Gbps,那就要好几秒。假设模型单步纯计算只要0.3秒,通信却占了0.5秒,系统效率就崩了。更麻烦的是,模型越大,这个梯度同步的通信量越线性上涨。所以“模型太大了就靠堆DP卡来提速”在工程上根本走不通——最终会被梯度通信锁死。

2.3 ZeRO与FSDP:DP的显存改良版

既然传统DP每个卡都要保存完整模型副本,显存浪费太严重,工程上便出现了ZeRO和FSDP这套改良方案。它的核心思路,是把模型参数、梯度、优化器状态这三种东西按DP维度切分到不同卡上,也就是每卡只保存完整状态的N分之一,而不是全部。

计算时需要用哪一层参数,就通过all-gather把那一层的权重从其他卡收集过来;反向算完梯度后,再用reduce-scatter把属于自己负责的那份梯度收回来,其他梯度分发给对应设备。这样单卡显存从“必须装下完整模型”降为“装下N分之一”,模型规模再大也就有了训练的可能。

这里必须澄清一个很多文章会带偏的认知:FSDP并没有让通信量变小,它只是把显存压力分摊了。每次迭代,参数要all-gather一遍,梯度要reduce-scatter一遍,算上回传,网络里搬的数据量和传统DP是同一数量级的。FSDP解决的是“放得下”,而不是“跑得快”。

2.4 DP的真正适用范围

所以DP不是大模型的最终解法,它最舒服的使用场景,始终是“模型本身能放进单卡”的时候。

比如小模型全参微调,单张A100就能装下权重、梯度和优化器状态,那用DP就是最优解:逻辑简单、框架成熟、通信不是瓶颈。再比如LoRA、QLoRA这类参数高效微调,可训练参数只有几个百分点,DP的梯度同步量被压得很低,随便堆卡效果都不错。反过来,如果是70B级别的全量训练,单卡连权重都放不下,DP就只能跟TP、PP组合使用,或者靠FSDP的权重切分把模型塞进多卡。

3. TP与PP:拆算子与拆层,是两种思路完全不同的模型切法

DP解决的是数据维度的并行,可当模型单卡装不下的时候,必须动模型本身的结构。这就有两种截然不同的切法:张量并行(Tensor Parallelism,TP)和流水线并行(Pipeline Parallelism,PP)。

3.1 张量并行TP:把矩阵乘法拆开做

TP的切法,算法同学其实很熟——它就是分块矩阵乘法。以一个线性层Y = XW为例,权重矩阵W可以按列切成W1和W2,交给GPU0和GPU1分别计算XW1和XW2,最后拼在一起得到完整输出。也可以按行切开,每个设备负责一部分输入特征的计算,最后做一次All-Reduce把分块结果累加。

真实Transformer的TP实现,通常是把hidden维切开。Self-Attention里的QKV投影按列切分,输出投影按行切分;MLP第一层按行切、第二层按列切。每引入一个切分点,在层内就要多一次All-Reduce同步。一个标准Transformer层里,attention和MLP两处各需要一次,所以每层至少做两次跨卡同步。层数越多,这个频率越高。

TP的通信量其实不算大。按每批处理4096个token、hidden size为4096、BF16精度来算,一次All-Reduce也就三十几MB。问题在于它是“高频小报文”模式:每个Transformer层都要来两次同步,一次前向加一次反向至少要翻倍。这种模式对单次延迟极其敏感,所以TP对互连带宽要求最高。实践中TP几乎只能在一台机器内部做,依靠NVLink的高带宽和低延迟,跨节点做TP基本等于自废武功。

TP带来的收益也很直接:每个设备只保存N分之一的权重,单卡显存压力大幅降低,计算量也摊给了N张卡。这也是为什么大模型训练里,只要机内带宽充足,TP几乎是“单机内必选”。

3.2 流水线并行PP:按层切段,像工厂流水线

PP的思路跟TP完全不同。它不去动单个算子内部的计算,而是把模型按层切成若干段,每段交给一组设备。数据流像工厂流水线:前向传播从第一段进入,算完传给第二段,再传给第三段,直到输出;反向传播再沿相反顺序传回梯度。

最朴素的实现是“串行等待”:一个时刻只有一段在计算,其他段全部空闲,总耗时和单卡跑完整模型差不多,完全赚不到并行收益。为了让大家同时干活,引入micro-batch机制:把大batch再切成更小的微批,第一段算完一个微批后立刻传给第二段,自己接着算下一个微批,让各段同时处理不同微批。工程上再配1F1B调度(一个前向、一个后向交替执行),设备利用率可以拉到比较高的水平。

但PP再怎么优化,也会留下一种叫“气泡时间”的浪费。流水线从启动到灌满、再从排空到收尾,总有设备在等待。气泡占比粗略估算大约是 (PP-1) 除以 (PP-1 + 微批数量)。PP=4时,只切8个微批,气泡可能接近30%;把微批加到32个,可以压到10%以下。不过微批越多,激活值占用越高,这又是和显存打架的取舍。

跟TP比,PP的通信量小得惊人,只在相邻两段之间的边界传一次激活值,大小是微批与序列长度和hidden size的乘积,也就几十MB,而且频率低。所以PP可以放心大胆地跨节点跑,普通数据中心网络就够用。这也是TP和PP在工程上天然互补的原因。

3.3 TP优先还是PP优先

工程上的直觉是“TP优先于PP”。只要机内带宽足够、卡数够用,先用TP把模型的张量维度切了,因为TP通信频率太高,必须用高速互联,而高速互联资源通常只覆盖很小一块物理范围。等到TP切到头还是放不下,再上PP做跨节点扩展。

现实中很多70B级别模型的训练配置就是这种思路的典型代表:一台8卡机器内部TP=8,把每层张量切成8份;机器之间PP=4,把80层模型切成4段,分别放在4台机器上。这样每个并行策略都贴合物理拓扑,通信代价最小。

4. CP上下文并行:长序列场景下绕不开的第四维

4.1 KV cache带来的显存压力

再看一种单卡扛不住的情况。假设模型只有几B参数,权重随便放,但用户上下文窗口从8K一路涨到128K甚至1M。这时候的瓶颈不在权重,而在KV cache和attention的中间激活。

KV cache的大小等于每token固定字节数乘上下文长度。粗略算一个7B规模、32层、标准MHA结构的模型:每个token、每层都要给K和V各存一份向量,算下来每个token在整模型里要占几百KB,上下文一到32K,光KV cache就要吃掉十几甚至几十GB。模型再大一点、序列再长一点,单卡就是铁定装不下。

DP按batch切分,但一个长句子只有一个样本,batch没法切;TP按hidden维切,对KV cache的token维压力反而缓解有限;PP按层切,每一层该有的KV总量还是落在对应卡上。于是有了专门切序列维的并行:上下文并行(Context Parallelism,CP)。

4.2 Ring Attention到底在做什么

CP把一条长序列切成N块,分给N张卡,每张卡只负责算自己那块的Q、K、V。但标准attention里,输出需要所有token的K和V,如果只做全量KV的All-Gather,虽然显存分摊了,但通信量和完整KV一样大,而且每张卡依然要把全量KV放到显存里才能算attention,等于白切。

工程上更常用的做法是Ring Attention。把参与CP的卡排成一个环,每张卡先算好当前块的K、V,然后按环传下去。每张卡在每个时刻只持有一个K/V块,用它和自己手上的Q、局部K计算部分attention score,再按“局部softmax”的方式逐步累加。一个环全部转完,所有token的KV都被消费过一次,输出也就齐了。这个方案的关键好处是,每张卡峰值显存只跟block大小相关,而不是整条序列的长度,attention的平方级计算量也被分摊到多卡并行。

CP的通信量跟序列长度成正比,而且每个attention块都要传KV,频率并不低,所以它对带宽要求蛮高,通常限定在高速互联范围内使用。训练时期Prefill阶段是CP收益最大的场景,因为Prefill本来就在处理长序列,attention计算密度高,CP能直接把计算量和存储同时摊开。

4.3 CP与TP、PP的区别和配合

CP和TP都发生在Transformer层内部,一个切序列维,一个切hidden维,它们可以叠加:TP负责模型宽度,CP负责上下文长度,DP负责样本数量。长上下文场景里常见的组合就是“TP × CP × DP”。

推理时CP有个容易被忽略的尴尬点。decode阶段是自回归逐步生成,每步只新出一个token。序列维被切开后,不同设备各自持有之前算好的KV块,每生成一个新token都可能要跨设备交换中间结果,同步开销不小。所以有些推理框架只在Prefill阶段启用CP,decode阶段要么把序列尽量放回单卡,要么做专门的CP解码优化。这个细节属于看技术文档时很难意识到的坑。

5. EP专家并行:MoE模型的专属解法

5.1 稀疏激活带来的“专家切分”需求

有了CP这个“切新维度”的先例,EP就更好理解了。专家并行(Expert Parallelism,EP)服务于MoE(混合专家)模型。MoE层里有一组专家,可能是8个、64个甚至更多,每个token经router打分后只被派给其中top-2个专家计算。模型总参数量很大,但单个token实际参与的权重只有一小部分,这就是稀疏激活。

如果按Dense模型的方式直接做TP或PP,会非常浪费。要么每个专家权重在每张卡上都复制一份,显存直接爆炸;要么被TP切得七零八落,但稀疏激活又让大多数设备在大多数时间闲着。EP的思路是把不同专家放到不同设备上,每台设备只保存其中几个专家,router决定某个token去哪个专家,这个token的hidden state就先发到目标专家所在设备,算完再传回来。

5.2 All-to-All通信与负载均衡困境

EP的核心通信模式是all-to-all。这和DP、TP的All-Reduce完全不一样:源设备上的token根据路由结果分别发往很多目标设备,同时每台设备也会收到来自很多源设备的token。它更像“按内容分拣包裹”,小包多、路径动态,对网络拓扑尤其敏感。

另一个绕不开的坑是负载均衡。真实数据里router对专家的选择绝不会均匀,很可能少数专家收到一半token,其他专家闲着。设备负载不均,并行效率直接崩。工程上的常规解法有三类:一是加一个辅助的负载均衡loss,让router学得尽量均匀;二是给专家设置容量因子,限制单个专家最多接收的token数,超出部分做重算或丢弃;三是在推理场景用在线路由调整,根据实时请求分布动态改变token分配。这些方案各有取舍,但核心目的都一样:让所有专家设备尽量忙起来。

5.3 EP与DP的取舍标准

这里有个非常实际的判断标准:什么时候用EP,什么时候用DP?

如果模型总参数量不大,所有专家复制到每张卡也放得下,那DP的MoE往往更好。因为每个token不需要跨卡传递,路由完全在卡内完成,通信为零。只有当专家总参数量大到单卡放不下,才被迫用EP。

即便决定用EP,也要权衡batch大小。EP的通信开销来自“把token发给远程专家”,batch越大,一次批量发越划算,通信占比越低。如果batch很小,比如在线推理时单请求只有几十个token,把token发到远程专家的网络代价可能比计算本身还高,EP并不会让系统更快。因此EP不是MoE的唯一选项,而是“显存不够时为了跑起来并压缩通信”的选择。实际工程里EP通常还要跟DP叠加:一组设备放一部分专家,另一组设备放另一部分专家,两组之间用DP做数据并行。

6. 组合与选型:从7B到70B再到超长上下文

6.1 三种典型场景的并行配置

理解了每种并行的原理后,真正的问题来了:一个模型到底该上哪些并行,各配多大?我拿三个场景举例。

第一个,7B Dense模型,8张A100 80GB,序列长度4K。BF16权重只有14GB,但全参数训练还叠加梯度和优化器状态,单卡其实很紧张。入门级配置可以是TP=2加DP=4:TP把hidden维切成2份,DP把数据切成4份。这个组合实现简单、通信压力不大,是很多人第一次跑多卡训练的默认选项。

第二个,70B Dense模型,32张A100 80GB。BF16权重约140GB,训练压力更大。典型配置是TP=8加PP=4,DP先设1:8卡一台机器内做TP,80层模型切成4段放到4台机器上做PP。等跑通之后再加DP=2甚至更高,复制出多个完整流水线副本提升吞吐。这刚好对应物理拓扑——节点内NVLink跑TP,节点间普通网络跑PP,通信模式各得其所。

第三个,MoE模型外加长上下文。这时并行维度通常会同时用到TP、CP、EP和DP。TP切共享层,CP切序列,EP把专家分布到卡上,DP负责复制整份计算。看着复杂,其实就是把前面那些“切法”当成相互独立的自由度,需要哪个维度就开哪个维度。

6.2 五种并行的参数对比

并行策略切分维度核心通信模式带宽敏感度典型使用位置
DP数据并行batch维All-Reduce(或All-Gather+Reduce-Scatter)中到高,随模型规模线性增长所有层之外
TP张量并行hidden维/算子维每层多次All-Reduce极高,必须NVLink单节点内部
PP流水线并行层维相邻stage点对点传递低,普通网络即可跨节点
CP上下文并行序列维KV块环形传递高长序列节点内
EP专家并行专家维All-to-All高,受路由动态影响MoE专家设备组

这张表建议直接收藏。判断一个新框架某个参数有没有配错,对照这五行基本能定位。

6.3 训练和推理的差异化处理

还有一个容易忽略的地方:同一套并行策略,放在训练和推理两个阶段,瓶颈完全不同。

训练时,显存主要被参数、梯度、优化器状态和激活值占据,目标是把吞吐最大化。PP的气泡、DP的梯度同步,都是为了整体吞吐量可以接受的代价;只要整张卡能被喂饱计算,慢一点没关系。

推理时,显存主要被权重和KV cache占据,目标从“吞吐”转成“延迟”。Prefill阶段计算密度高,TP、CP都能明显加快;decode阶段几乎被内存访问和KV cache读取主导,这时候要尽量减少单条序列跨太多设备的情况,避免每一步都做昂贵的跨卡通信。对算法同学来说,我最常给的提醒是:别把训练时的并行配置直接照搬到推理服务,尤其是CP和PP,它们在推理侧的行为和训练差别非常大,必须用真实请求压测后再调。

7. 调试与踩坑:先把通信占比看明白,再谈调优

7.1 拿到Profiler再判断

我见过太多人对着并行参数瞎猜。对算法同学来说,第一个建议是:不要猜,去测通信占比。

训练框架日志未必直接给你通信数据,但NVIDIA的Nsight Systems、PyTorch自带的Torch Profiler都能看到NCCL调用在时间线上的分布。打开一次step的timeline,看通信占用整个step的比例。如果超过30%,你的并行组合大概率配得不合理:可能是TP切太碎导致同步频率过高,可能是DP模型太大导致梯度同步太重,也可能是PP微批太少导致气泡太大。有理有据地调,比拍脑袋换参数快得多。

7.2 我踩过的几个具体坑

TP跨节点是第一个大坑。TP每层要同步好几次,跨节点延迟比NVLink高出一个量级还多,结果就是整个训练流程被通信拖到几乎不缩放。TP的粒度永远先卡在“一台机器内的卡数”。

PP的微批数量和气泡之间是典型权衡。微批越多,气泡越小,但激活值占用越高,非常容易OOM。常规做法是先设一个保守的微批数,观察气泡占比,再逐步往上加。很多框架默认值其实偏保守,手动调一调往往有惊喜。

EP的All-to-All会被小batch拖死。推理时如果一次请求只有几十个token,发给远端专家的数据包太小,网络时间全耗在包处理上。给EP做并发合并、把多条请求攒成一个大batch,比调多复杂的负载均衡算法都有效。

长上下文的KV cache也容易让人误判。总以为模型权重才是显存大头,实际序列一长,KV cache可以比权重还夸张。先用GQA/MQA减少KV head数量,或者把KV cache量化打开,往往比硬加CP更划算。CP是解决“确实放不下”的手段,而不是为了炫技。

7.3 给算法同学的“最小上手路线”

真想彻底搞懂这些并行,我的建议是不要一上来就啃超大规模集群。先在单机8卡上跑一个7B模型,分别试TP=8和TP=2+DP=4,用profiler看通信差异;再开PP=2,观察气泡时间如何变化;然后换一个长序列数据集,加上CP看看Prefill吞吐;最后把模型换成开源的MoE模型,调EP去理解All-to-All的通信模式。整个过程不需要新集群,一台8卡机器就能完成。

等你把这五轮实验跑完,对并行策略的直觉就建立起来了。以后再遇到某个新训练框架的新参数,你基本能在半小时内反应出它切的是哪个维度、代价是什么、极限在哪里。这套思考方式,比记住任何一份静态配置都有用。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询