大模型的参数量动辄上百亿,单卡显存放不下也训得慢,于是有了各种「并行」策略。数据并行是最直观的一种:把一批数据切成几份,每张卡分一份,各自算各自的,算完再对答案。本文按机制层讲法,把它的四步流程和能力边界讲清楚。
第一步:复制一模一样的副本
流程从复制模型副本开始。进来的是一个完整模型和 N 张可用显卡,每张卡先各拿一份完全相同的参数副本,初始状态下 N 个副本一模一样。这一步的代价是显存:参数量乘以 N,大模型的参数本身就占地方,副本一多,显存先被参数吃光,这也是后续 ZeRO 类优化要解决的问题。副本同步靠的是「同一份初始化」,任何一张卡的参数被意外改动,后面的同步更新就会把误差摊到全体,所以长跑的训练任务还要防单卡静默出错。
第二步:只切数据不切模型
接下来切分数据批次。进来的是一个 global batch,按卡数均分成 N 个 micro-batch,每张卡只处理自己那一份。进来的数据不同,出去的是每张卡各自的 loss 和梯度。注意切分只切数据,不切模型——这是数据并行和后面几种并行方式最根本的区别。
第三步:梯度汇总同步
每张卡在自己那份数据上完成前向和反向,算出本地梯度,然后所有卡做一次 all-reduce 通信,把 N 份梯度加起来取平均。进来的是 N 份各不相同的本地梯度,出去的是一份全局一致的梯度。这一步是数据并行的通信瓶颈,卡数越多、模型越大,同步等待越明显。
第四步:同步更新保持对齐
最后每张卡用同一份全局梯度更新自己的副本,更新公式完全相同,所以更新后 N 个副本依然一模一样,循环可以继续。整套流程下来,效果等价于用一张卡训完整个 global batch,只是速度接近除以 N。注意是「接近」而不是「等于」:通信本身要花时间,N 越大这部分占比越高,这也是为什么加卡到一定数量后回报会递减。
四步走完,每一环的进来、出去和代价可以并排看:
| 步骤 | 进来 | 出去 | 卡间动作 | 代价 |
|---|---|---|---|---|
| 复制副本 | 一个完整模型、N 张可用显卡 | N 份完全相同的参数副本 | 无,靠同一份初始化对齐 | 显存按参数量乘 N 计 |
| 切分数据 | 一个 global batch | 每卡一份 micro-batch,各自的 loss 与梯度 | 无,只切数据不切模型 | 卡多则每卡样本少,梯度变噪 |
| 梯度汇总 | N 份各不相同的本地梯度 | 一份全局一致的梯度 | all-reduce 相加取平均 | 通信瓶颈,同步等待随卡数涨 |
| 同步更新 | 同一份全局梯度 | N 份仍然一模一样的副本 | 各卡按相同公式独立更新 | 速度接近除以 N 而非等于 |
什么时候该换别的并行方式?当模型单卡放不下时,数据并行就无能为力了——副本都复制不出来,后面全免谈。这时候要看张量并行是怎么切开一层的,把单层内部拆开放;或者看流水线并行是怎么排队的,把层与层之间分段。显存紧张但不想改切分方式,ZeRO 是怎么省显存的提供第三条路。
顺带说一句,数据并行只管训练提速,不管数据质量。这就像同时开文心一言和通义千问处理两批问题,分头做得再快,答案对不对还是要逐条看;数据投毒是怎么混进去的讲的坏样本路径,在八卡机和单卡机上是一样的;而合成数据的生成过滤循环决定每张卡分到的那份数据干不干净。
- 第一步:每卡复制一份完全相同的模型副本
- 第二步:global batch 切成 N 份,只切数据不切模型
- 第三步:各卡本地梯度做 all-reduce,合成一份全局梯度
- 第四步:同一公式同步更新,副本保持一模一样
- 边界:模型单卡放不下时它无能为力,需要张量或流水线并行
关于数据并行,问得最多的三个
- 卡越多一定越快吗?:接近线性到某个点为止,之后通信开销和同步等待占比升高,八卡以上常出现加卡不加速的情况。
- 为什么 N 个副本更新后还能保持一致?:因为用的梯度是同一份全局梯度,更新公式也相同,数学上保证每步结束都回到同一状态。
- batch size 和卡数怎么配合?:global batch 固定时,卡越多每卡 micro-batch 越小,每卡样本太少梯度会变噪,具体代价见批大小那条的展开。


