跳转至

并行策略与显存

📊 数据并行是否能减少单卡显存?为什么?

💡 结论:标准数据并行(DDP)不能减少单卡显存,每张卡依然需要完整的模型、优化器和激活。显存压力没有减轻,只是通过多卡并行提高了总吞吐量。

🔍 原理:

  • 在数据并行中,每张 GPU 拥有模型参数的完整副本、完整的优化器状态以及各自的输入数据分片。前向/反向计算独立进行,仅在反向传播后对梯度做一次 All-Reduce,然后每张卡用平均梯度更新自己的完整模型。

  • 因为每张卡都存储了同样的权重、梯度和优化器,单卡显存占用与单卡训练完全相同。唯一可能增加的显存是通信缓冲区,但那微不足道。

  • 因此,数据并行解决的是“训练速度”问题,而非“单卡装不下”的问题。当模型大到单卡放不下时,必须引入模型并行(如 ZeRO、TP、PP)来分片模型。

✅ 所以,如果面临单卡显存不足,不能指望增加数据并行卡数来解决,必须采用张量并行、流水线并行或 ZeRO 分片等策略。


🧩 张量并行(TP)是如何切分模型权重以减少单卡显存的?

💡 张量并行将层内的权重矩阵沿列或行切分,每张卡只存储权重的一部分,前向/反向时通过通信来合成完整结果,从而直接将单卡权重显存降至 1/TP 度。

🔧 具体切分方式(以 Megatron-LM 风格为例):

  1. 列切分(Column Parallel)
  2. 以线性层 Y = XA 为例,权重矩阵 A 的形状为 [hidden_in, hidden_out]。TP 将 A 按列切成 [hidden_in, hidden_out/TP] 的多个子块,每张卡存放一个子块 A_i。输入 X 复制到所有卡。
  3. 每张卡独立计算 Y_i = X A_i,得到形状 [batch, seq, hidden_out/TP] 的部分结果。然后通过 All-Gather 将所有 Y_i 合并成完整输出 Y。单卡权重显存降为 1/TP。

  4. 行切分(Row Parallel)

  5. 通常与前一个列并行层配对。权重矩阵 B 按行切分:[hidden_out/TP, hidden_in]。此时每张卡处理输入的一部分(来自上一层的部分输出),计算 Z_i = Y_i B_i,形状 [batch, seq, hidden_in]。
  6. 最后通过 All-Reduce 将所有卡的 Z_i 相加得到完整结果。单卡权重显存同样降为 1/TP。

  7. 注意力层切分

  8. 将 Q、K、V 的头数按 TP 切分,每张卡只计算部分注意力头,然后 All-Reduce 输出。多头注意力的权重自然被分片。

✅ 效果:

若 TP=4,每张卡的模型权重(包括 MLP 和注意力)显存大约变为原来的 1/4,立竿见影。代价是每层都需要 All-Gather 或 All-Reduce,通信量巨大,因此 TP 通常只在高带宽的节点内(NVLink)使用。


🔢 用 TP=4 训练一个 7B 模型,每张卡权重显存大约变为多少?

💡 7B 模型 FP16 权重约 14 GB,TP=4 单卡权重显存降至约 3.5 GB。加上不可切分的轻量层和通信缓冲区,约 3.5-4 GB。

🧮 详细计算:

  • 7B 参数,FP16 精度,总权重显存 = 7 × 10^9 × 2 字节 = 14 GB。

  • 张量并行将绝大部分参数(>99%)切分到 4 张卡,单卡权重 = 14 GB / 4 = 3.5 GB。

  • 极少量的非并行层(如 LayerNorm/RMSNorm、嵌入层)可能被复制或切分策略不同,但参数量极小(<0.1B),占用约 0.2 GB。

  • 外加 NCCL 通信缓冲区(约 0.2-0.5 GB),实际单卡权重占用约 3.7-4 GB。

📌 注意: 这仅权重的节省。优化器状态和激活也会相应被切分减少。TP=4 时,优化器状态也降为约 1/4(Adam 状态原约 56 GB,降至 14 GB)。因此 TP 能线性削减单卡显存,非常高效。


🚂 流水线并行(PP)为什么能减少单卡显存?它切分的是什么?

💡 流水线并行(PP)通过将模型的不同层分配到不同设备,每张卡只存储和处理一部分连续层,从而单卡权重和激活显存都大幅减少。它切分的是模型深度(层数)。

🔍 原理:

  • 假设模型有 32 个 Transformer 层,PP 度数为 4,则将 Layer 1-8 放在 GPU0,Layer 9-16 放 GPU1,依此类推。

  • 每张卡仅拥有部分层的参数以及这些层的优化器状态和梯度,权重显存自然与层数成正比,约降为 1/PP。

  • 前向过程中,GPU0 计算 micro-batch 0 的 1-8 层,然后将中间激活(hidden states)传给 GPU1。 GPU1 继续计算,同时 GPU0 开始处理下一个 micro-batch。

  • 激活显存:因为每张卡只处理部分层,每层的激活驻留时间有限,且通过调度可限制同时存在的 micro-batch 数量。相比单卡保存所有层的激活,单卡激活显存显著降低。

🧩 切分的是什么?

切分的是模型层的集合,而不是层内张量。因此 PP 的通信只发生在切分点,传输的是层间激活,数据量远小于 TP 的 All-Reduce。这使 PP 适合跨节点部署,通信带宽要求较低。

✅ 因此,PP 通过横向切分模型深度,直接减少单卡权重和激活,并以较小的通信开销实现。


⚖️ 1F1B 调度与 GPipe 调度相比,在显存占用上有什么优势?

💡 1F1B(One Forward One Backward)调度通过交错执行前向和反向,限制了同时驻留在显存中的激活数量,从而比 GPipe 的“全前向再全反向”显著降低激活显存峰值。

📊 对比分析:

  • GPipe 调度: 先完成所有 micro-batch 的前向传播,存储全部中间激活,然后再进行反向。假设有 M 个 micro-batch,PP 深度为 P,则某设备需要同时存储 M 个 micro-batch 的激活(每个经过该设备层的激活)。激活峰值 ≈ M × 单 micro-batch 激活大小。M 越大,显存占用极高,为了减少显存常被迫减少 micro-batch 数量,但会增大流水线气泡。

  • 1F1B 调度: 前向执行一段时间后,尽早开始反向。控制前向和反向交替,保证每个设备上同时存在的激活数量上限仅为 min(M, P) 个 micro-batch 的激活。通常 M <= P 时,激活峰值恒定,不再随 M 线性增长。因此可以使用更大 M 来减少气泡,而不会撑爆显存。这就是 1F1B 的核心显存优势。

📈 结果:在相同 micro-batch 数下,1F1B 的显存峰值远小于 GPipe;在相同显存限制下,1F1B 允许更多 micro-batch,提高流水线效率。因此现代 PP 训练几乎都使用 1F1B 或其变体(如 interleaved 1F1B)。


🧬 序列并行(SP)主要减少哪部分显存?通常和哪些并行策略结合?

💡 序列并行(Sequence Parallelism, SP)主要减少激活显存中的大张量,特别是 LayerNorm 和 Dropout 前后的冗余激活副本,通常与张量并行(TP)结合使用,进一步缓解长序列训练的内存压力。

🔬 具体作用:

  • 在标准的 Transformer 中,有些区域(如 LayerNorm、Dropout)对整个序列维度进行操作,张量并行不能切分它们,其输入/输出需要在所有 TP 卡间复制,造成激活冗余。

  • 序列并行将这些不可切分区域的序列维度也切分到不同卡上。例如,LayerNorm 的输入 [batch, seq, hidden] 沿着 seq 维切分成 [batch, seq/TP, hidden],每张卡只计算自己那部分。这样就消除了该区域的重复激活,节省的显存大致与 TP 度相当。

  • 特别适用于长序列场景(如 32K-128K tokens),因为激活大小与序列长度成正比,SP 可线性减少这部分开销。

🔗 结合策略:

  • SP + TP:是标准组合,Megatron-LM 中就用 SP 代替 TP 中的部分数据复制,以支持更长上下文训练。

  • 也可与 PP 和 DP 结合,在更复杂的 3D 并行中进一步压缩激活峰值。

✅ 因此,序列并行通过切分序列维度,消除层归一化等区域的多卡激活冗余,有效降低长序列训练时的激活显存瓶颈。


🤔 为什么 TP 的通信量较大,但对显存的节省是立竿见影的?

💡 因为 TP 直接在层内切分权重张量,权重和激活都成倍减少,而通信虽频繁但每次数据量相对较小,且由高速 NVLink 承载,因此显存节省“即时可见”,且不会因通信而回弹。

🔍 立竿见影的原因:

  1. 权重显存线性压缩:每张卡只需存储 1/TP 的权重,这是最直接的节省。

  2. 激活显存同样缩减:因为计算也切分,中间激活只保留了 1/TP 的大小。

  3. 通信不影响显存:TP 通信传递的是部分计算结果(如部分输出或梯度),通信缓冲区虽会占用些许显存(通常几十 MB),但远小于节省的权重大小。不像某些策略(如 offload)需要用显存放通信缓冲。

  4. 没有额外常驻内存:TP 是纯分布式计算,没有产生新的持久化副本。计算完成后,通信用的临时张量立即释放。

📊 比较:

假设 7B 模型,单卡权重 14 GB,TP=4 后显存即刻降至约 3.5 GB。通信增加的 All-Gather 和 All-Reduce 仅占用几 MB 临时缓冲,对 14GB 权重来说忽略不计。因此 TP 被视为“最直接”的显存削减手段。通信量大是指它对卡间带宽要求高,可能成为延迟瓶颈,但不影响显存节约程度。


⚖️ 使用 PP 时,各卡之间的显存分配是否均匀?如何调整?

💡 默认按层数平均分配通常较为均匀,但由于各层参数量和激活大小可能不完全相同,以及嵌入/输出头的影响,首尾卡可能占用更多显存。需要手动调整切分边界来实现负载均衡。

📊 不均匀原因:

  • 嵌入层(Embedding)和输出层(LM head)通常参数多、激活大,如果放在第一张和最后一张卡,这两卡显存占用明显高于中间卡。

  • 即便中间 Transformer 层,某些层(如带更大的 FFN 膨胀)可能参数略多,但差异不大。

  • 激活内存主要取决于层数和 micro-batch 调度,首尾卡由于流水线 bubble,可能积压稍多激活。

🛠️ 调整方法:

  1. 不均匀层分配:不按等层数切,而是按总参数量切。给参数量少的卡多分配一些层,反之少分配。例如 Embedding 层所在的 GPU,少分配几层 Transformer 以平衡。

  2. 移动嵌入层:可将 Embedding 层和输出头放在同一张卡(或同一个 TP 组),并通过共享嵌入权重减少冗余。

  3. 利用 TP 配合:在 PP 基础上,对首尾大层使用 TP 切分,减小单卡压力。

  4. 自动调优工具:Megatron-LM 等提供 --num-layers-per-virtual-pipeline-stage 等参数灵活配置,也可通过 profile 获取每层计算和内存开销,使用线性规划算法寻找最优分割点。

✅ 因此,PP 的显存均衡需要根据层特性微调分割点,避免首尾卡成为瓶颈,结合 TP 或手动层分配能有效实现。


🌐 3D 并行中,如何平衡显存节省和通信开销?

💡 3D 并行(TP+PP+DP/ZeRO)的平衡本质是一个“多维背包问题”:在满足单卡显存约束下,寻找最小通信开销、最高吞吐的组合。通常优先最大化 DP 以扩展性,再用 TP 解决层内超大显存问题,最后用 PP 连接跨节点,以通信量最小为准则分配卡数。

⚖️ 平衡原则:

  1. 优先数据并行(DP) 因为 DP 无额外通信(仅梯度 All-Reduce),扩展性最好。显存允许时,尽可能增加 DP 度来提升吞吐。当单卡显存不够时,引入 ZeRO-3(可视为 DP 的升级),用通信换显存。

  2. 其次考虑张量并行(TP) 当 ZeRO-3 或 DP 仍无法容纳模型,或者长序列导致激活过大,使用 TP 在节点内切分层内权重和激活。TP 通信量大,应限制在高速 NVLink 域内(单机)。通信开销与 TP 度正比,因此 TP 度不宜过大,够用即可。

  3. 最后引入流水线并行(PP) 跨节点使用 PP,因为其通信量小(仅传输层间激活)。PP 可能产生气泡,通过增加 micro-batch 数和 1F1B 调度降低。平衡点:PP 度越大,单卡显存压力越小,但气泡增多,吞吐可能下降。通常 PP 度与节点数相关。

  4. 全局调优 给定总卡数 N,拆分为 DP × TP × PP。显存约束:单卡必须能装下 1/TP 的权重和 1/(TP×PP) 的激活(简化)。通信开销:TP 产生 All-Reduce 费用;PP 产生 P2P 费用;DP 产生梯度 All-Reduce。用性能模型估算每种组合的吞吐(tokens/s),选择最优。

  5. 动态调整 实际训练中,如果显存充足,可降低 TP/PP,增加 DP 来提升速度。如果显存吃紧,增大 TP/PP 或启用 ZeRO-3。许多框架提供自动并行化工具(如 DeepSpeed Autotuning),自动搜索最佳配置。

📌 经验法则:

  • 7B-13B 模型(长序列):通常 TP=1~2 + PP=1 + ZeRO-3 即可。

  • 70B+:TP=4~8(单机)+ PP=2~4(跨机)+ ZeRO-3DP

  • 显存与通信的平衡最终要通过实测吞吐确定,不能单看理论。

因此,3D 并行平衡精髓在于:用最小的 TP/PP 满足显存需求,将最多的卡留给 DP 以获得高可扩展性和高吞吐,同时利用节点内高速带宽承担 TP 的通信代价。


🧠 专家并行(Expert Parallelism)如何减少 MoE 训练时的显存?

💡 专家并行将 MoE 中的不同专家(FFN)放置到不同的 GPU 上,每张卡只存储一部分专家权重及其优化器状态,从而显著降低单卡显存占用,代价是引入 All-to-All 通信来路由 token 到对应专家。

🔍 工作原理:

  • 在 MoE(如 Mixtral 8x7B)中,每个 Transformer 层包含多个专家(如 8 个),每次 token 只激活其中 top-2。

  • 若不使用专家并行,一张卡必须容纳所有 8 个专家的完整权重(以及优化器状态),显存压力很大。

  • 专家并行将专家分布在多个设备上,例如 EP=4,则每卡仅存储 2 个专家。路由时,每个 token 经过门控网络选择专家 ID,然后通过 All-to-All 通信将 token 的隐状态发送到对应专家所在的 GPU 上进行计算,计算完再 All-to-All 传回原卡。

  • 这样,单卡的专家权重显存降为 1/(EP 度),并且优化器状态、梯度也相应分片。

✅ 节省的具体效果:

  • Mixtral 8x7B(总参数量 ~46.7B)中专家 FFN 占绝大多数参数。EP=4 时,单卡只需存储约 1/4 的专家权重,显著降低训练显存门槛。

  • 注意力层等共享部分通常仍复制或使用其他并行方式。

⚠️ 注意: 专家并行需要高效的 All-to-All 通信,对网络带宽要求较高。它常与数据并行、张量并行混合使用,以平衡计算和通信。


📊 在分布式训练中,除了模型本身,还有什么因素会影响单卡显存均衡?

💡 除了模型权重、梯度、优化器状态外,激活值、通信缓冲区、显存碎片、数据加载缓存、框架预留空间以及负载不均衡都会显著影响单卡显存,导致各卡占用不一致,甚至 OOM。

🔎 具体因素:

  1. 激活显存与重计算策略 不同卡上的层可能由于计算量不同(如首尾层的 Embedding/Head),激活峰值差异大。梯度检查点设置和序列并行也会影响激活分布。

  2. 通信缓冲区 NCCL 集合通信需要预留缓冲区,其大小与并行策略和消息量有关。TP 或 EP 的 All-to-All 缓冲区会占用额外显存。

  3. 显存碎片 PyTorch 缓存分配器可能在不同卡上产生不同程度的碎片,导致某些卡实际可用连续内存少于其他卡。

  4. 数据加载与预处理 DataLoader 使用 pin_memory 和预取会占用 CPU 内存,但可能间接影响 GPU 显存(如异步拷贝时的缓冲)。如果某卡处理的数据样本长度不同,也会导致激活峰值差异。

  5. 框架预留与 CUDA context 每个 CUDA context 占用约 0.5-1 GB,不同卡上 context 开销相同,但若某卡还承担额外任务(如通信协调),可能多出一些分配。

  6. 负载不均衡 在 PP 中,如果各卡分配的层数或参数量不均,显存会倾斜。在 EP 中,如果专家分配不均衡,也可能某卡专家过多。

🛠️ 改善方法:使用 torch.cuda.memory_stats() 检查每卡内存分配,利用 profiling 工具分析各卡显存占用,并通过调整并行分割参数或均衡数据分布来达到平衡。


🔥 为什么有时即使使用了 TP 和 PP,单卡显存依然紧张?

💡 TP 和 PP 虽然能大幅削减权重和激活,但长序列、大 batch 和 KV Cache(推理时)或激活重计算的限制,以及未切分层的累积和通信缓冲区仍可能导致显存吃紧。

🔍 主要原因:

  1. 激活显存依然是瓶颈 TP 切分了层内权重和部分激活,但一些区域(如 LayerNorm)在纯 TP 下仍会保留完整的激活副本。若序列长度极大(如 128K),即使层数被 PP 切分,单卡的激活可能仍很高。

  2. 未切分的固定开销 Embedding 层、输出头、位置编码等通常不被 TP/PP 完美切分,可能被复制到每张卡,当词汇量巨大时(>100k),这些层本身就能占数 GB。

  3. 通信缓冲区占据显存 TP 需要 All-Reduce/All-Gather 缓冲区,PP 需要发送/接收中间激活的缓冲区。在大规模并行时,这些缓冲可能占用数 GB。

  4. 优化器状态 使用 ZeRO-1/2 时优化器状态可能仍完整存储(除非用 ZeRO-3),造成显存压力。

  5. Micro-batch 过大 为了减少 PP 气泡,通常增大 micro-batch 数,而这会增加激活峰值(受限于 1F1B 的上限,但若 M > P 仍有累积),从而抵消了部分 PP 节省的显存。

  6. 推理时 KV Cache 推理阶段,KV Cache 随序列长度线性增长,而 TP/PP 只能切分权重,KV Cache 若不使用张量并行切分或量化,依然是单卡完整存储(或分头存储),长上下文下会爆显存。

✅ 因此,显存紧张时需进一步采用序列并行(SP)、KV Cache 量化、激活重计算、专家并行等组合手段,并减小 batch 或序列长度。


📏 微批次(micro-batch)大小对显存有何影响?

💡 micro-batch 大小直接决定了前向传播过程中产生的激活显存,几乎与 micro-batch 成正比。增大 micro-batch 能提高 GPU 利用率,但会线性增加单卡激活占用,可能导致 OOM。

🔬 详细分析:

  • 在流水线并行或梯度累积中,一个 step 会被拆分成多个 micro-batch。每个 micro-batch 的输入形状为 [micro_bs, seq_len, hidden]。

  • 每层产生的中间激活(如注意力矩阵、FFN 输入输出等)大小与 micro_bs × seq_len 成正比。因此,单卡的激活峰值近似正比于同时驻留的 micro-batch 数量和每个 micro-batch 的大小。

  • 在 1F1B 调度下,最大驻留 micro-batch 数通常为 min(PP 深度, 总 micro-batch 数)。若 micro-batch 尺寸扩大,即使数量不变,激活显存也会线性增长。

  • 对训练吞吐而言,较大的 micro-batch 能提升矩阵乘法效率,更充分利用 GPU。所以需要在显存允许的范围内取最大可能值。

🎯 实践建议:当显存不足时,首先应减小 micro-batch 大小,并通过梯度累积保持全局 batch 不变。若已用极小值仍 OOM,则必须启用梯度检查点、序列并行或调整并行度。


🤝 在使用 ZeRO-3 时,是否还需要 TP?两者如何协同?

💡 ZeRO-3 已能将模型权重、梯度和优化器状态分片到所有数据并行卡上,理论上可以替代 TP 的显存节省效果,但在超大模型或长序列场景下,ZeRO-3 与 TP 结合能进一步降低单卡激活显存和通信压力,提升训练效率。

🔗 协同机理:

  • ZeRO-3 将全部模型状态(参数、梯度、优化器)分片到 DP 组的所有卡上,前向时通过 All-Gather 收集所需权重,计算后再释放。其显存节省程度随 DP 度增加而提高,通信量主要是 All-Gather 和 Reduce-Scatter。

  • TP 则切分层内张量,直接减少单卡上的权重和激活,并伴随 All-Reduce 通信。TP 的通信开销通常大于 ZeRO-3,但可以大幅降低单卡的激活峰值(因为层内的计算也被切分)。

  • 两者结合:在 DP 组内部(ZeRO-3)再嵌套 TP 组。例如总卡数 = DP × TP。ZeRO-3 负责跨节点的模型状态分片,TP 在节点内进一步切分层内权重和激活。这样可以获得双重显存削减:ZeRO-3 降低模型状态的单卡占用,TP 降低激活和权重的内存峰值。尤其对于长序列,TP 切分激活的能力是 ZeRO-3 不具备的。

  • 典型配置:训练数百 B 模型时,常采用 ZeRO-3(跨机)+ TP(节点内)混合。例如 64 卡,设 TP=4,DP=16,ZeRO-3 在 DP 组内分片。

✅ 因此,ZeRO-3 与 TP 是互补关系。ZeRO-3 解决模型存储,TP 解决激活和超大层的切分,协同后能训练更大、更长的模型。


⏳ 流水线并行的气泡对显存有影响吗?

💡 气泡(pipeline bubble)本身不直接增加显存占用,但为了减少气泡而增加 micro-batch 数量,会间接增加激活驻留,从而增大显存压力。因此,气泡与显存之间存在间接权衡。

🔍 机制:

  • 气泡是指流水线中设备空闲等待的时间,由前后依赖导致。气泡大小与 micro-batch 数量 M 和 PP 深度有关,气泡率 ≈ (P-1)/M。

  • 为了降低气泡,通常会增大 M。但在 1F1B 调度下,更多 micro-batch 意味着更多并发激活需要存储(直到 min(M,P) 上限)。当 M 超过 P 时,每张卡上同时存在的激活数量会稳定在 P(PP 深度),不再增长;但若 M 过大,激活峰值已达平台,显存不再随 M 增加。但若原 M 很小,增加 M 会增加激活峰值。

  • 因此,气泡大 → 我们想增大 M → 激活显存可能上升。但通过合理的 1F1B 调度,可以控制峰值在 P 个 micro-batch 的水平。所以气泡对显存的直接影响有限,主要是间接地通过调节 M 来影响。

⚙️ 实践中:若显存紧张,可容忍更大气泡(减少 M),以降低激活峰值;反之若显存充裕,可增大 M 减少气泡,提升吞吐。


⚖️ 为什么数据并行+ZeRO 的组合在显存和通信之间找到了一个平衡点?

💡 纯数据并行显存压力大,纯模型并行通信压力大。ZeRO 通过对模型状态(优化器、梯度、参数)分片,在数据并行的基础上用少量额外通信换取了大量显存削减,使得大模型训练可以在标准集群上高效进行。

🔍 平衡点解析:

  • 标准 DP:显存占用=完整模型,通信仅梯度 All-Reduce,量小。但模型大了装不下。

  • 模型并行 (TP/PP):可训练更大模型,但 TP 通信极大(每层 All-Reduce),PP 有气泡且扩展性有限。

  • ZeRO 三步走:

  • ZeRO-1:将优化器状态分片到 DP 各卡,通信增加 Reduce-Scatter(优化器状态更新),但节省优化器显存(约 4×)。
  • ZeRO-2:加梯度分片,通信增加梯度 Reduce-Scatter,进一步节省梯度显存。
  • ZeRO-3:加参数分片,前向/反向需 All-Gather 参数,通信增加,但将模型参数显存分片,单卡只需 1/DP 的权重。 通信增量从 DP 的 All-Reduce 梯度,变成 All-Gather 参数 + Reduce-Scatter 梯度,通信量大约是原来的 1.5 倍。而显存却可以降为原来的 1/DP。

  • 对于 DP 度较高的集群(如 64 卡),ZeRO-3 几乎可线性降低单卡显存,通信开销仍可接受,因为现代网络(100Gbps+)可以隐藏这部分通信延迟。这比纯 TP 的巨大 All-Reduce 开销小得多。

✅ 因此,ZeRO 利用 DP 组内的高带宽,将模型状态分散存储,达到了“显存降、通信增”的帕累托最优,成为大模型训练的事实标准之一。


🔧 你如何为给定的模型和硬件配置选择最优并行度?

💡 采用“先满足显存约束,再最大化吞吐”的决策流程:通过估算或工具确定能装下模型的最小并行度,然后调整 DP/TP/PP 组合以最大化训练速度或推理吞吐。

📐 步骤:

  1. 估算单卡最小显存需求 计算模型总权重、优化器、梯度、激活(针对目标 batch 和序列长度),用公式或内存估算工具(如 DeepSpeed 的 mem_estimator)得到单卡所需显存。

  2. 确定必需的模型并行度 单卡显存不足时,引入模型并行。根据卡间带宽,优先选择 ZeRO-3(需要高速网络)或 TP(需要 NVLink)。一般原则:节点内用 TP,跨节点用 ZeRO-3 或 PP。计算最小 TP × PPZeRO 度 使得每卡权重+优化器 < 显存容量。

  3. 考虑激活瓶颈,加入序列并行/梯度检查点 若序列很长,激活可能成为主要瓶颈。启用梯度检查点和序列并行,重新评估所需并行度。

  4. 分配总卡数 总卡数 N = DP × TP × PP。在满足显存约束后,剩余卡全部用作 DP 以提升吞吐。DP 度越高,吞吐扩展性越好。但要确保通信不成为瓶颈(DP 的 All-Reduce 对带宽需求高)。

  5. 性能建模或自动调优 使用 DeepSpeed Autotuning、Megatron-LM 的性能模型,或者手动小规模实验,测量不同组合的 tokens/sec。选择吞吐最高的配置。

  6. 验证均衡性 检查各卡显存占用是否均衡,避免单卡瓶颈。

📌 实例: 对于 70B 模型,单卡 80GB A100。目标序列长度 4096,batch=128。

  • 纯数据并行单卡无法容纳,需模型并行。

  • 尝试 ZeRO-3 + TP=2,DP 度 = 总卡数/(TP) 等。最终通常选用 TP=2~4, PP=1~2, ZeRO-3。

✅ 核心思想:显存约束下的最大 DP,才是最高效的并行配置。


🧬 解释一下 Megatron-LM 中的序列并行如何与 TP 结合减少激活显存。

💡 Megatron-LM 的序列并行(SP)是对张量并行的补充:在 TP 切分注意力/MLP 的权重和激活的同时,SP 将 LayerNorm 和 Dropout 区域的冗余激活沿序列维度切分,避免多卡复制,从而进一步降低长序列训练的激活峰值。

🔬 结合机制:

  • 在标准的 Transformer 块中,张量并行切分了 QKV 和 MLP 的列/行,但在 LayerNorm 和残差连接处,每张卡仍持有完整的序列维度张量 [batch, seq, hidden],这些激活并没有被 TP 切分,造成显存冗余。

  • 序列并行将 seq 维度切分为 TP 份,每张卡只拥有 seq/TP 的片段。在进入 LayerNorm 之前,各卡独立对子序列做归一化;随后再进入注意力的 TP 切分区域。

  • 具体实现中,在前向的某些非 TP 区域,通过 gather / scatter 在序列维度上重排张量,使得每张卡只需存储序列的一部分,而非完整序列。

  • 这样,原本在所有 TP 卡上重复存储的 [batch, seq, hidden] 激活,现在只占用 1/TP 的显存,效果与增加 TP 度相当。对于 128K 等超长序列,节省的激活显存可达几十 GB。

🤝 与 TP 的关系: SP 是 TP 的自然延伸,常用于 TP>1 且序列较长时。两者一起使用可将激活显存降至原来的约 1/TP^2(针对部分区域)。Megatron-LM 中通过 --sequence-parallel 标志开启。

✅ 因此,序列并行利用序列维度切分,消除 TP 无法覆盖的激活冗余,是长序列大规模训练的必备技术。


🌌 在超大模型训练中,为什么通常采用 DP + TP + PP + ZeRO 的组合?

💡 单一并行策略无法同时满足超大模型的显存、通信和扩展性要求。混合并行通过各取所长:TP 解决层内超大张量,PP 跨节点分配层,ZeRO 分片模型状态,DP 提供线性扩展,共同突破规模瓶颈。

🔍 各角色分工:

  • TP(张量并行):切分层内矩阵,大幅降低单卡权重和激活,但通信密集,受限于节点内高速互联。

  • PP(流水线并行):将模型分层到不同节点,通信量小(仅传递激活),适合跨机扩展,但引入气泡,需要配合 micro-batch 优化。

  • ZeRO(数据并行的升级):在 DP 组内分片优化器、梯度和参数,用通信换单卡显存,扩展性极佳,适合跨机大规模并行。

  • DP(数据并行):在以上策略基础上进一步扩展吞吐,处理更多数据。

⚙️ 协同模式:

例如训练 GPT-4 规模模型(>1T),集群数千卡。典型配置:

  • 每个节点内 8 卡使用 TP=8 切分单个 Transformer 层。

  • 多个节点组成 PP 组,将 100+ 层切到多个节点,用 PP 连接。

  • 所有节点同时属于一个大的 ZeRO-3 数据并行组,模型状态全局分片。 这种 DP × TP × PP 的 3D 并行,结合 ZeRO 状态分片,既能放下巨大模型,又具有良好的扩展性。

📈 没有 ZeRO 的话,DP 每卡要存完整模型状态,不可行;没有 TP 的话,单卡激活容不下;没有 PP 的话,跨机通信带宽扛不住。 因此混合并行成为唯一解。

✅ 所以,DP+TP+PP+ZeRO 是当前千亿/万亿参数模型训练的工业标准,各策略互补,实现规模与效率的统一。


🆚 并行策略对推理时显存的优化与训练时有何不同?

💡 训练时的并行策略重点在于降低权重、梯度、优化器和激活的全套显存,而推理时只需考虑权重和KV Cache,因此优化目标和策略组合有明显差异。

🔍 关键区别:

维度 训练 推理
优化器状态与梯度 大量显存占用(~8×权重),需 ZeRO 或分片 无需优化器和梯度,无此开销
激活显存 反向传播需保存中间激活,激活占比高,需梯度检查点、序列并行 仅前向,无反向激活,但长序列的 KV Cache 成为主要瓶颈
通信需求 频繁的 All-Reduce/All-Gather,可接受较高延迟 对延迟敏感,通信开销直接影响响应时间,通常避免跨机并行
批处理 通常 batch 较大以充分利用 GPU,激活压力大 单个请求 batch=1 常见,但服务时合并动态 batch,计算强度低,带宽瓶颈凸显
显存节省手段 TP、PP、ZeRO、梯度检查点、序列并行 量化(INT4/INT8)、GQA/MQA、PagedAttention、KV Cache 量化、并行有限使用
并行策略应用 常常需要 TP+PP 才能容纳模型 推理倾向少用或不用 TP/PP,因为延迟增大。大模型用 TP 单节点部署,或用 PP 跨机但牺牲延迟
KV Cache 训练时不需要(或仅需微调的短序列) 推理时是主要内存消耗,需专门管理(PagedAttention、共享前缀)

📌 总结:训练并行策略是为了“跑起来”,推理并行策略是为了“跑得快且省”。推理优化更侧重减少单个请求的显存占用和带宽消耗,采用量化与 KV Cache 优化,而非复杂的分布式并行。