并行策略基础:数据并行、模型并行、流水线并行的概念与对比

聊到分布式训练,绕不开的就是三种基本并行策略。说实话,很多初学者一上来就被这些概念搞晕了。我当年刚接触时也差不多,总觉得它们之间界限模糊。今天咱们就把这三兄弟掰开揉碎了讲清楚。

为什么需要并行?

先问个问题:你训练一个百亿参数的大模型,单张显卡装得下吗?

答案显然是否定的。就算装得下,训练时间也让人崩溃。我有个项目,单卡训练一个中型BERT模型,跑了整整两周。后来改成8卡并行,时间压缩到两天。这就是并行的价值——要么解决显存放不下的问题,要么解决训练太慢的问题。

三种并行策略,说白了就是解决这两个核心矛盾的。

数据并行:最直观的思路

数据并行,顾名思义,就是把数据切分开。

每张卡上都放一份完整的模型副本。然后把训练数据切成N份,每张卡处理自己那份。每张卡独立计算梯度,最后把梯度汇总更新模型。

我习惯把数据并行比作「多个学生做同一套卷子」。每个学生(GPU)都拿着同样的教材(模型参数),但各自做不同的题目(数据分片)。做完后大家对照答案(梯度同步),修正自己的理解(参数更新)。

核心要点: 数据并行解决的是「数据太多,单卡处理太慢」的问题。模型本身必须能放进单卡显存。

实际项目中,数据并行是最容易上手的方案。PyTorch的DistributedDataParallel(DDP)几乎开箱即用。我曾经在一个推荐系统项目里,用DDP把训练速度提升了将近4倍。但要注意,当模型大到单卡放不下时,数据并行就失效了。

避坑指南: 我曾经遇到过梯度同步时通信开销过大,导致加速比不理想的情况。后来发现是batch size太小,每步计算时间短,通信时间占比就高了。解决办法是适当增大batch size,或者使用梯度累积。

模型并行:把模型拆开

模型并行解决的是「模型太大,单卡放不下」的问题。

做法是把模型的不同层或不同参数分配到不同GPU上。每张卡只负责模型的一部分。数据在卡间流动,依次经过各卡上的层。

举个例子,一个12层的Transformer,可以切成3份,每份4层,分别放在3张卡上。数据先经过卡1上的1-4层,结果传给卡2处理5-8层,最后卡3处理9-12层。

这里有个关键点:模型并行中,同一时刻只有一张卡在工作,其他卡在等待。这会导致GPU利用率不高。我见过不少团队踩过这个坑——模型是放进去了,但训练速度反而比单卡还慢。

注意: 模型并行会引入严重的「计算空闲」问题。因为层与层之间有依赖关系,必须等前一层算完才能算后一层。说白了,这是一种串行化的并行。

我个人习惯把模型并行用在「实在没办法」的场景。比如模型大到单卡显存的2倍以上,数据并行又用不了,那就只能上模型并行。但我会尽量配合其他策略一起使用。

流水线并行:模型并行的升级版

流水线并行,本质上是对模型并行的优化。它解决了模型并行中GPU空闲的问题。

怎么优化的?把数据也切成微批次(micro-batch)。

你想想看,模型并行中卡2在等卡1算完。但如果把数据切成4个微批次,卡1算完第一个微批次后,立刻传给卡2,同时卡1开始算第二个微批次。这样卡1和卡2就能同时工作了。

这就好比工厂流水线。每个工位(GPU)只负责一道工序(模型层)。第一个工件进入工位1,完成后进入工位2,同时工位1开始处理第二个工件。流水线一旦填满,所有工位都在工作。

核心要点: 流水线并行通过引入微批次,让不同GPU可以同时处理不同数据的不同层,大幅提升利用率。

我记得在一个GPT类模型的训练中,我们用了流水线并行。刚开始没调好微批次大小,性能提升有限。后来把微批次数量从2调到8,吞吐量直接翻倍。嗯,这里要注意,微批次太多也会引入额外的调度开销,需要找到一个平衡点。

三种策略的对比

说了这么多,咱们用一张表格来对比一下:

维度 数据并行 模型并行 流水线并行
解决什么问题 数据太多,训练慢 模型太大,放不下 模型太大,且GPU空闲
模型副本数 每卡一份完整模型 每卡一份模型切片 每卡一份模型切片
数据分配 数据切分到各卡 数据完整流过各卡 数据切分为微批次
通信模式 梯度同步(AllReduce) 激活值传递(P2P) 激活值传递(P2P)
GPU利用率 高(同步等待少) 低(串行等待多) 中高(流水线填满后)
实现难度 低(框架原生支持) 中(需手动切分) 高(需调度微批次)
适用场景 模型可放入单卡 模型超大,无法放入单卡 模型超大,且追求吞吐

从表格能看出来,三种策略各有侧重。实际项目中,很少只用一种策略。我参与过的大规模训练任务,基本都是混合使用。比如数据并行+流水线并行,或者数据并行+模型并行+流水线并行。

知识体系结构图

下面这张图展示了三种并行策略的核心逻辑和关系:

并行策略核心逻辑 分布式训练并行策略 数据并行 模型并行 流水线并行 每卡一份完整模型 数据切分到各卡 梯度同步(AllReduce) 每卡一份模型切片 数据完整流过各卡 串行计算,GPU空闲多 每卡一份模型切片 数据切分为微批次 流水线填满后高利用率 实际项目常混合使用:数据并行 + 流水线并行

如何选择?

说了这么多理论,到底怎么选?我个人的经验是:

  • 模型能放进单卡:优先用数据并行。简单、稳定、框架支持好。
  • 模型超出单卡显存2倍以内:考虑流水线并行。配合数据并行一起用效果更好。
  • 模型超大(超出单卡显存数倍):模型并行+流水线并行+数据并行,三管齐下。但实现复杂度会飙升。

我曾经接手过一个项目,团队一开始用了纯模型并行,结果8张卡利用率不到30%。后来改成流水线并行,利用率提升到70%以上。说白了,选对策略比盲目堆卡更重要。

一个小建议: 刚开始做分布式训练时,先从数据并行入手。等熟悉了通信模式和性能调优,再尝试更复杂的策略。别一上来就搞混合并行,容易把自己绕进去。

三种并行策略,各有各的适用场景。理解它们的核心思想和差异,是分布式训练能力进阶的第一步。后面我们会深入每种策略的实现细节和调优技巧。

想要更多资料,联系可可