
如果你第一次看到 TP、DP、PP、CP、EP 这五个缩写大概率会有点头大。我第一次接触大模型分布式训练时就是这样模型本身在单卡上明明能跑通为什么到了集群上还要拆成这么多维度后来帮算法团队调试一个 70B 参数的训练任务被 Infra 同学追问“TP 打算开几PP 呢梯度累积设多少”我才真正意识到这几个字母背后其实是同一套显存与通信经济学。这篇是“算法同学学 Infra”系列的第二篇我尽量不讲论文公式全用直觉和工程经验把这件事讲清楚目标是让你看完之后别人再说 TP8、PP4、DP8你能立刻知道集群长什么样、每张卡的显存都花到哪去了、哪个环节会成为瓶颈。1. 先建立直觉五种并行到底在解决什么问题1.1 单卡训练为什么走不通先说显存墙。拿一个 7B 模型举例BF16 精度下权重就要 14GB单卡 80GB 的 A100/H100 看起来放得下对吧但训练不是只有权重。你还要存梯度又是 14GB用 Adam 优化器做混合精度训练时还要额外保存 FP32 主权重、一阶动量、二阶动量这部分每参数大约 12 字节7B 参数就是 84GB。光这几项加起来已经超过 110GB还没算前向计算过程中那些激活值。所以 7B 模型想在单卡上用 Adam 做全参数训练80GB 的卡根本不现实。再说算力墙。训练一个 token 大约需要 6N 次浮点运算N 是模型参数量。7B 模型就是每个 token 大约 42 GFLOPs100B tokens 的数据量就是 4.2e21 FLOPs。一张 H100 的 BF16 稠密算力大概 1e15 FLOPs/s 量级单卡纯算就要四五十天更不用说数据搬运、通信同步、低效利用这些现实损耗。所以数据并行、模型并行这些手段不是“加分项”而是在大模型训练里必须做的事。1.2 一张表看穿五种并行的本质区别这五个缩写经常放在一起容易让人以为是一套体系的五个组件实际上它们各自切的维度完全不同解决的问题也完全不同。我习惯用一张表把“切什么、收益是什么、代价是什么”说清楚并行策略切分对象核心收益主要代价典型场景DP 数据并行训练数据 batch吞吐量随卡数近似线性提升每步梯度同步产生通信模型单卡放得下时最简单的扩展方式TP 张量并行层内的矩阵权重单层权重显存变小、单层计算变快每层都有高频 all-reduce极吃网络延迟单层矩阵太大、GPU 放不下时PP 流水线并行Transformer 层每卡只放一部分层显存压力大减跨 stage 传激活值存在气泡层数很深、模型整体放不下时CP 上下文并行序列长度 / KV 状态支持超长上下文训练与推理注意力需要环形传输通信复杂32K、128K 以上超长序列EP 专家并行MoE 网络里的专家只激活部分专家计算量大降all-to-all 通信负载可能不均MoE 架构的大规模训练做个人味很重的类比DP 是“同一张卷子复印几份几个人各做各的再做答案对齐”TP 是“一道题本身太大切两半一人算一半再拼答案”PP 是“试卷按大题拆开第一个人做第一题第二个人做第二题串成流水线”CP 是“卷子太长每个人只负责看一段但段落之间要互相传递”EP 是“请了一批专家每道题找对口的专家做做完再传回来”。不管哪种本质都是把显存和算力分散到多张卡上再用通信把它们重新粘起来区别只在于从哪个维度切。2. 数据并行 DP最符合直觉的并行方式2.1 从“每个人看不同题目”讲起数据并行是算法同学最容易接受的一种并行方式因为它完全不打乱模型结构。假设你有 4 张卡、一个全局 batch size 是 32那就每张卡分到 8 条样本每张卡上都放一份完整的模型副本各自做前向、各自算梯度。但这里有个关键问题模型参数是所有卡共享的。如果各卡拿着自己的 8 条样本梯度直接更新参数那 4 张卡更新四次参数早就飞了。所以每步反向算完梯度之后必须先做一次梯度同步也就是 all-reduce把 4 份梯度求平均得到全局梯度后再统一更新。这就是 PyTorch DDP 在做的事。这套逻辑很像一个团队分工做题每个人独立做完自己的那部分再对答案最后每个人按统一答案订正。它对模型的精度几乎没有任何影响因为从数学上讲并行计算结果和非并行计算的全局梯度是一致的前提是用了同一个随机种子初始化、同一个 batch 划分。2.2 梯度同步的代价为什么 DP 不是免费的DP 的通信成本不算小。一次 all-reduce 的通信量只跟模型大小有关跟 batch size 没有关系。7B 模型用 BF16 存梯度每步梯度同步要汇总的数据就是 14GB8 卡时每张卡都要参与广播规约。这个通信发生在每个训练 step 里模型越大、step 越多累积的时间就越夸张。所以 DP 在实际应用中有一个经验判断模型能放进单卡显存时DP 是最佳选择但模型太大、单卡放不下时纯 DP 就不够用了因为模型副本本身已经撑爆显存。这时候就需要往模型内部切或者用 FSDP 这种分片方案。2.3 显存不够时FSDP 和 ZeRO 在干什么FSDPFully Sharded Data Parallel和 DeepSpeed 的 ZeRO 思路很像既然 DP 每张卡都放完整模型太浪费那就把参数、梯度、优化器状态都分片到所有卡上每张卡只存 1/N。但模型前向的时候每张卡又需要完整的参数来做矩阵运算怎么办答案是 all-gather 临时取回。比如在某个 Transformer 层前向之前把该层参数从所有卡收集回来算完这一层再释放。等反向的时候再按需取回计算完立即把梯度归位。这本质是“用通信换显存”训练时不需要的权重和数据不长期占用显存要用时再传。这个方案很香代价是通信量比纯 DDP 更大因为除了梯度同步还要频繁做参数收集。所以 FSDP 在小规模集群上不一定比纯 DP 快但它在单卡显存逼近极限的时候能保住训练跑起来。3. 张量并行 TP把矩阵运算本身切碎3.1 一个线性层怎么切成两半张量并行是 Megatron-LM 那套思路它不再按数据分而是按矩阵内部维度分。一个线性层 Y XWX 的形状是 [batch, in]W 的形状是 [in, out]其中 in 和 out 在 Transformer 里通常就是 hidden size 的倍数。TP 有两种切法。第一种叫列切column parallel把 W 按输出维度切成 W1 和 W2各自形状是 [in, out/2]。X 完整复制给两张卡两张卡分别算 XW1 和 XW2得到 Y1 和 Y2最后拼起来得到完整的 Y。前向拼接反向的时候要把梯度 split 回两张卡。第二种叫行切row parallel把 W 按输入维度切成两半X 也按列切开两张卡各自算一半矩阵乘法的累加结果最后需要一次 all-reduce 把两块部分和加起来才能得到最终的 Y。反向的时候同样要把梯度广播回去。如果只写公式会很抽象伪代码长这样# 列切W1 [in, out/2], W2 [in, out/2] Y1 X W1 # 卡 0 Y2 X W2 # 卡 1 Y torch.cat([Y1, Y2], dim-1) # 行切W1 [in/2, out], W2 [in/2, out] X1 X[:, :in//2] X2 X[:, in//2:] Y X1 W1 X2 W2 # 需要一次 all-reduce3.2 通信频率决定了 TP 必须绑在高速网络TP 的显存收益很明显参数、梯度、优化器状态都按 TP 维度切成 1/TP矩阵运算也被拆小单卡显存压力大幅下降。但代价是通信极其密集。Transformer 每个 attention 块和 MLP 块里通常有两处 all-reduce前向一次、反向又是一轮模型的层数又深算下来每个训练 step 里多层反复通信。这就是为什么 TP 几乎必须在一台机器内部、依赖 NVLink 这类高带宽低延迟的互联来做。跨节点做 TP 不是不行但普通万兆网或 IB 网络的延迟和带宽很难撑住每层的高频 all-reduce性能会掉得非常难看。实际排布时TP 通常优先放在同一节点内的 8 张卡上跨节点的并行维度交给 PP 和 DP。3.3 Transformer 里的 QKV 投影与输出投影怎么配合在标准 Transformer 层里TP 的切法是有讲究的。attention 部分的 QKV 三个线性层适合用列切这样不同的 head 被分到不同卡上天然的布局就是每个 GPU 负责一部分注意力头attention 后面的输出投影适合用行切把各个卡的局部注意力结果 all-reduce 合并。MLP 也类似第一个全连接层做列切中间的激活函数每个卡独立算第二个全连接层做行切最后 all-reduce。整体上可以理解成“一个算子被物理拆分后前向和反向都有一对 f 和 g 操作来保证跨卡数据流动正确”。框架里用 Megatron-LM 或相关库时这些细节已经被封装了但理解这一层你会更清楚为什么 TP 的通信会出现在这些位置。3.4 别把 TP 里的序列并行当 CP和 TP 经常一起出现的还有个词叫序列并行SPSequence Parallel。它做的事情是把 LayerNorm、Dropout 这些沿着 token 维度有独立状态的算子的激活值也按序列切到各卡从而省掉一部分激活显存。它和 CP 不是一回事SP 通常和 TP 配合使用只是进一步把非矩阵类的算子也拆开CP 则专门针对超长序列的注意力部分后面会单独讲。读框架代码时看到“sequence parallel”先确认它是不是在 TP 语境内别和长序列并行混了。4. 流水线并行 PP切模型的层而不是切矩阵4.1 按层分配每个 GPU 负责一段PP 的思路更贴近直觉模型有几十上百层按层切成几段每张卡只负责其中一段。比如一个 32 层模型4 张卡做 PP卡 0 负责第 1 到 8 层卡 1 负责 9 到 16 层依此类推。数据流是依次往下传的卡 0 算完第 8 层的输出传给卡 1 继续算第 9 到 16 层这个过程很像工厂流水线。因为每张卡只需要保存自己那部分层的权重、梯度和优化器状态显存压力比完整模型副本小很多。同时模型层数越深PP 的扩展性越好因为并行粒度是“层”不是矩阵里的每一个维度。4.2 micro-batch 与 1F1B 调度但朴素的流水线有个大问题同一时刻可能只有一张卡在计算其他卡都在等。比如卡 0 算完第一个 batch 传给卡 1 之后如果卡 0 没有新 batch 可算它就只能空转。为了解决这个问题生产上几乎都用 micro-batch把一个大的 batch 再切成很多小 batch依次灌进流水线。这样卡 0 算完第一个 micro-batch 传给卡 1 后立刻开始算第二个 micro-batch流水线里的每一段都能持续运转。最常用的调度叫 1F1Bone forward one backward每个 stage 交替执行一个 micro-batch 的前向和反向这样能把显存峰值控制得更低。读者不需要手写调度但要知道一点micro-batch 数量直接影响气泡率和显存峰值它是一个实实在在的调优参数。4.3 气泡率计算PP4 的代价PP 存在一个不可避免的“气泡”流水线刚启动和最后排空时总有 stage 在等待这个空档比例大概可以写成气泡率 (P-1) / (MP-1)P 是流水线 stage 数M 是 micro-batch 数。举个例子PP4、micro-batch 数16气泡率约 15.8%如果把 micro-batch 提到 32气泡率降到约 8.6%。所以生产环境里通常会把 M 设得比较大把气泡压下去。但 M 变大会增大激活显存所以实际配置时往往要和 activation checkpointing、梯度累积一起权衡。这里给算法同学一个直觉PP 不是免费的它的成本是气泡和调度复杂度但换来的显存收益非常可观。5. 上下文并行 CP为超长序列量身定做5.1 长序列到底难在哪当模型要支持 32K、128K 甚至更长的上下文时单卡根本放不下整个序列的激活值和 KV cache。比如处理一条 128K 长度的序列纯 attention 的复杂度虽然是线性注意力优化后能缓解但 KV 在内存里依然很大而且 MHA 的中间结果本身就占显存。如果只是硬塞进一张卡很快会 OOM。CP 的切入点是序列维度把一条长序列切成 C 段每张卡负责其中一段 token 的 query 和 key/value 计算。每张卡只需要保存 1/C 的 KV 状态显存压力瞬间降下来。这是它和 TP、PP 最本质的区别切的是“时间轴/序列轴”不是层内矩阵也不是模型的层。5.2 Ring Attention让 KV 在卡间转圈标准 attention 里每个 query 要和所有 key 做计算。如果每张卡只留了自己那一段 KVquery 就只能看到局部信息算出来的 attention 不完整。所以 CP 必须让 KV 在卡之间转起来最典型的实现叫 Ring Attention。大概流程是每张卡保存自己那段的 query 和 KV初始状态各算各的局部注意力然后把自己的 KV 块传给下一张卡同时接收上一张卡的 KV 块再和本地 query 继续算注意力。这样经过 C 轮之后每个 query 都能和所有 key 算过一遍。听起来像“卷子轮流改”每张桌子拿一部分卷子卷子轮流转一圈每个人都看过所有卷子。代价是纯计算量不变但通信增加了而且通信模式是点对点环形传输。5.3 CP 和 TP 的常见配合方式实际部署里 CP 很少单独用。它一般和 TP 组合在一起TP 负责把层内矩阵计算切到多卡CP 负责把序列长度切到多卡。比如一个节点 8 张卡设 TP4、CP2那相当于 4 张卡组合做矩阵切分再分成两组各处理一半序列。这样既能压住大矩阵的显存又能扛住超长序列。这个组合在推理时也特别重要。长上下文服务场景下KV cache 是显存大头CP 能显著降低单卡 KV 占用。目前很多推理引擎里已经支持类似配置算法同学做长上下文模型服务时建议优先考虑 TPCP 而不是只堆 TP。6. 专家并行 EPMoE 模型的必经之路6.1 MoE 让参数变多、计算变少MoEMixture of Experts是当前大模型卷参数量的一个重要手段。它的特点是模型总参数很大但因为稀疏激活每个 token 只经过路由网络选择出的少数几个专家 FFN。比如一个 MoE 层里有 64 个专家每个 token 只激活 2 个专家那么总参数量虽然很大实际计算量并不随专家总数线性增长。这就带来一个新问题专家的权重到底放在哪张卡上如果每个 GPU 都复制全部专家权重那 MoE 的大参数优势就没意义了显存会爆炸。EP 的做法是把不同专家分布到不同 GPU 上每个 GPU 只持有部分专家。token 从哪个卡发出不重要重要的是它能被送到“拥有对应专家”的卡上完成计算算完再送回原来的卡。6.2 all-to-alltoken 在不同 GPU 之间“串门”EP 的核心通信模式是 all-to-all。普通的 DP 通信是 all-reduce所有卡拿着同样大小的数据做规约TP 也是 all-reduce 居多。但 EP 里每张卡上都有一些 token 要发给专家所在的不同卡发件方和收件方是多对多的关系而且每张卡发往不同目标的数据量还不一样。这个模式很像物流分拣中心一批包裹要从各个网点送到不同的处理仓库每个仓库只处理特定类别的货所有网点之间需要互相派送。all-to-all 的高峰通信量会非常大所以 EP 对网络带宽和拓扑非常敏感。实际工程里EP 通常会优先把专家放在同一个节点内尽量减少跨节点 all-to-all 的数据量。6.3 负载均衡是 EP 最大的坑EP 最让人头疼的问题不是显存而是负载不均衡。如果某几个专家特别“热门”大量 token 都路由过去那几张卡的算力会打满其他拿着冷门专家的卡却在空转。这也是为什么 MoE 训练里要额外加负载均衡 loss目的就是让 token 分布尽量均匀。除了负载均衡 loss工程上还可以做专家分组、token drop、动态调整路由策略等手段。算法同学在评估 MoE 效果时不能只看模型精度还要看训练吞吐是否被不均衡拖累。如果你发现 GPU 利用率忽高忽低、每 step 时间波动很大优先怀疑 EP 的负载均衡。7. 组合拳一套接近生产的并行配置怎么定7.1 一个 64 卡集群的配置实例实际大规模训练很少只用一种并行最常见的是 DP TP PP 组合有时再加上 CP 或 EP。先牢记一个基本公式总 GPU 数 DP × TP × PP × CP如果 EP 存在它一般是在某个维度内部再展开。假设你在 8 节点 × 8 卡 64 卡集群上训练一个 70B 模型典型排法有两种思路方案配置特征ATP8PP8DP1每卡只放 70B/(8×8)≈1.1B 参数显存最省但 TP 大、PP 气泡压力大调度复杂BTP4PP4DP4保留 4 份模型副本显存稍重但 DP 的梯度同步能让 batch 更大总体吞吐通常更稳实际操作中节点内的 8 卡优先给 TP跨节点的维度用 PP 或 DP。配置时要把 TP 设置在 NVLink 域内PP 尽量让相邻 stage 之间有较高带宽DP 对网络要求最低可以放得比较远。EP 在 MoE 模型里通常会打断这个整齐公式比如一个 DP4 × EP8 的配置里4 份模型副本各自并行但每份模型内部又按专家维度切成 8 份所有副本共享同一套专家布局。7.2 推理场景和训练场景为什么不一样训练和推理的并行配置不能直接照搬。训练时优化器状态、梯度、激活值占掉大量显存所以需要 PP 来切层、FSDP/ZeRO 来分片优化器状态。推理时模型已经固定没有梯度、没有优化器状态显存大头是权重和 KV cache所以很多时候只需要 TP 和 CP。比如跑一个长上下文推理服务权重放不下就加 TPKV cache 放不下就加 CP很少需要把 PP 开到很大因为推理的 batch 通常比较小流水线气泡会非常难看。你如果直接把训练时的 TP8、PP8 配到推理服务上你会发现第一 token 延迟变得很高吞吐反而上不去因为流水线深、通信多但计算量远没有训练时候那么大。7.3 主流框架分别覆盖哪些并行PyTorch DDP 和 FSDP主要覆盖 DP 和分片式数据并行。DeepSpeedZeRO 分片、流水线并行PP都支持也被广泛用在 DP 为主的大规模训练里。Megatron-LMTP、PP、CP、EP 支持最全是目前很多大模型训练底座。vLLM、SGLang 等推理引擎主要支持 TP、PP、CP对长上下文服务越来越重视。不同框架对并行维度的命名和组合约束有差异但底层通信原语都差不多all-reduce 对应 DP/TP 的梯度或结果规约all-gather 对应 FSDP/ZeRO 的参数收集all-to-all 对应 EP 的 token 路由send-recv 对应 PP 的 stage 间传输。看框架文档时先定位四个原语就不容易被 API 绕晕。8. 算法同学最常踩的坑与快速决策清单8.1 卡数多不等于跑得快最容易踩的坑是盲目加大 TP 或 PP。TP 从 4 提到 8单个矩阵计算量确实变小了但每层 all-reduce 的通信次数变多如果 batch 或 sequence 不够长计算时间不足以掩盖通信时间整体反而更慢。PP 从 2 提到 4气泡率上升micro-batch 不够多时吞吐直接往下掉。判断并行配置好不好不要看单卡利用率这一个指标要看 samples/s 或 tokens/s 的实际吞吐。我见过不少算法同学盯着 nvidia-smi 看到 GPU 利用率 90% 就觉得没问题但实际上大量时间花在通信等待上利用率指标会骗人。最直接的办法是用同一个模型、同一个小数据集分别在不同配置下跑 50 个 step比较每秒处理样本数。8.2 显存 OOM 时的排查顺序训练时遇到 OOM第一个反应往往是减小 batch size这没错但它是最后手段不是最优手段。我建议按这个顺序排查权重 梯度 优化器状态是否已经接近卡的上限。比如 70B 全参数训练配 TP4每卡权重加优化器状态大概率超过 40GB需要继续加 TP、PP 或开 FSDP/ZeRO。激活值是否过大。激活值反而不容易一眼看出来试试打开 activation checkpointing通常能省掉一大块显存。框架的通信缓冲区是不是在占显存。Megatron 之类框架会预留一部分显存给通信 buffer配置 message buffer size 可以调整。最后再考虑减小 batch size 或梯度累积因为这会影响训练效率和模型收敛行为。8.3 一份决策清单解决 80% 的选型问题模型单卡能放下想扩大吞吐优先 DP 或 FSDP简单直接。模型权重已经超过单卡显存优先 TP并且让 TP 待在节点内。层数特别深、TP 已经尽量大了还不够加 PP把层切成多段。要处理 32K 以上超长序列加 CP优先配合 TP。模型是 MoE 架构加 EP配合 DP 或 TP。网络条件一般、没有高速互联少用大 TP多用 DP PP。这条清单不是绝对公式但能解决大部分初期选型困惑。真正深入之后你会发现每个并行维度之间还会互相影响比如梯度累积和 DP 组合会改变有效 batch size改变学习率预期EP 和 PP 组合时各 stage 的计算量可能不再均匀。把这些关系摸一遍才算真正把五个字母吃透了。最后说一点个人感受。算法同学学这些东西最难的不是记缩写而是建立“每个字母背后都是成本”的意识DP 是通信换吞吐TP 是用高速互联换显存PP 是用气泡换显存CP 是用环形传输换长上下文EP 是用 all-to-all 换稀疏计算。我后来每次调并行配置都会先问自己三个问题模型到底多大节点内和跨节点的网络带宽大概多少我真正要压的是显存、吞吐还是长序列支持把这三个问题的答案写在纸上再去看框架文档基本不会选错。希望这篇能把你的直觉也建立起来。