想象你走进音乐厅,一支大型合唱团正在排练《欢乐颂》。作曲家把总谱写成厚厚一叠——这张总谱记录了所有声部的旋律,就像机器学习中的权重矩阵 W,每一行都是一条旋律线。为了让女高音、女中音、男高音、男低音四个声部同时开唱,指挥拿起剪刀,把总谱按声部拆成四份,每份只含几行旋律。歌词也顺势分成四句,每个声部各唱一句。当所有人同时开口,四个声部的声音在音乐厅里自然叠加,观众的耳朵里便收到了完整的和声。 这就是“行并行”的智慧:把一个巨大的矩阵乘法拆成多个小矩阵乘法,让多块 GPU 分头计算,最后用一次 All-Reduce 把结果汇聚起来。行并行是张量并行的两大基石之一,与列并行像一对默契搭档,共同撑起了 Megatron-LM 等框架中 Transformer 模型的并行训练。本文用合唱团的比喻,从切分原理、前向传播、反向传播、组合设计到工程实现,把行并行讲得透透的。

岗位关联

掌握行并行的切分逻辑与通信模式,是理解大模型张量并行组合设计的钥匙。无论你做训练加速、推理优化还是性能分析,这套知识都能帮你准确判断多卡通信瓶颈,是分布式训练工程师的必备素养。

目录
  1. 可视化演示
  2. 1. 行切分原理
  3. 2. 前向传播流程
  4. 3. 反向传播特性
  5. 4. 与列并行组合
  6. 5. 通信开销分析
  7. 6. 工程实现要点
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

动态演示行并行Row Paralle的核心机制,通过总览/传输/转换/输出四种模式展示关键概念与交互流程。

本节配有交互动效(进入视口后自动加载,约 3KB)。

行并行Row Paralle:行并行切 行并行切分方式与输入分片要求 前向All-Reduce求和与 核心机制可视化 行并行Row Paralle整体架构与关键组件

1. 行切分原理

想象你走进音乐厅,看到一支大型合唱团正在排练《欢乐颂》。作曲家把总谱写成厚厚一叠——这就是权重矩阵 W,每一行都是一条旋律线。为了让女高音、女中音、男高音、男低音四个声部同时开唱,指挥拿起剪刀,把总谱按声部拆成四份,每份只含几行旋律。这个动作,就是行并行的核心直觉:把权重矩阵按行切开。

不过,光切歌谱还不够。每位歌手要唱,手里还得有对应的歌词;歌词来自输入 X。既然歌谱按行切了,歌词也得跟着按列切成四句,每个声部拿一句。于是输入矩阵 X 被切成 X₁、X₂、……、Xₚ,连同权重分片一起分给各台 GPU。

用数学语言说:设权重 W 的形状是 (k, n),输入 X 的形状是 (b, k)。行并行把 W 沿行方向切成 p 块,每块 Wᵢ 的形状是 (k/p, n);同时把 X 沿列方向切成 p 块,每块 Xᵢ 的形状是 (b, k/p)。设备 i 拿着 (Xᵢ, Wᵢ) 这对数据,在本地做矩阵乘法。虽然每台设备手里的“谱子”变小了,但 p 块拼在一起,参数总量和切分前分毫不差。

每个声部歌手手里只有几行谱子和一句歌词,但他们知道自己唱的是整首歌的一部分。这些“部分”如何变成完整的和声?答案就在下一节的前向传播。

W=[W1W2⋮Wp],X=[X1X2⋯Xp]W = \begin{bmatrix} W_1 \\ W_2 \\ \vdots \\ W_p \end{bmatrix}, \qquad X = \begin{bmatrix} X_1 & X_2 & \cdots & X_p \end{bmatrix}
这两个式子说明:权重按行切、输入按列切,两边一一配对,切完后总数据量不变。
  1. 权重按行切块把 (k, n) 的权重矩阵沿行方向均分成 p 块,每个 Wᵢ 是一个 (k/p, n) 的子矩阵。
    Wi∈R(k/p)×nW_i \in \mathbb{R}^{(k/p) \times n}
  2. 输入按列切块把 (b, k) 的输入矩阵沿列方向均分成 p 块,每个 Xᵢ 是一个 (b, k/p) 的子矩阵。
    Xi∈Rb×(k/p)X_i \in \mathbb{R}^{b \times (k/p)}
  3. 配对分发设备 i 拿到自己的 (Xᵢ, Wᵢ) 后,在本地算出部分结果 Yᵢ。
    Yi=Xi Wi∈Rb×nY_i = X_i \, W_i \in \mathbb{R}^{b \times n}

2. 前向传播流程

演出时刻到了。指挥的手一抬,四个声部同时开口——女高音唱出明亮的高音区旋律,男低音托起沉稳的低音线。单独听任何一声部,都只是碎片;但当所有声音在大厅中叠加,观众听到的是一首完整的《欢乐颂》。这个“声音叠加”的过程,对应行并行的 All-Reduce 汇聚。

技术上的 All-Reduce 不是在空气中传播声音,而是把各设备算出的局部结果 Yᵢ 做逐元素相加。为什么是加法而不是拼接?因为矩阵分块乘法告诉我们:输入按列切、权重按行切后,整体乘积等于各局部乘积之和。每一个局部乘积只是“部分和”,所有部分和加起来才是正确答案。

完整的前向流程分三步:第一步,每台设备用本地数据算 Yᵢ = XᵢWᵢ;第二步,执行一次 All-Reduce(归约操作为加法),把 p 个 Yᵢ 加起来;第三步,每台设备都拿到完整的输出 Y,交给下一层。注意,这里每台设备都持有完整 Y,而知道 Y 的梯度 dY 也是完整共享的——这为反向传播“零通信”埋下了伏笔。

合唱的魅力正在于此:每个声部只发出 1/p 的声音,观众听到的却是完整旋律;每台设备只算了 1/p 的活,下一层拿到的 Y 与串行计算结果完全一致。声音叠加是瞬时的,但 All-Reduce 要花通信时间——这个代价留到第五节细算。

Y=∑i=1pXi Wi=X WY = \sum_{i=1}^{p} X_i \, W_i = X \, W
分块乘法的分配律保证:局部结果之和,等于不切分时的完整乘积。
  1. 局部乘积设备 i 计算 Xᵢ 与 Wᵢ 的乘积,结果的形状是 (b, n)。
    Yi=Xi WiY_i = X_i \, W_i
  2. All-Reduce 求和所有局部结果经过一次求和归约,累加为完整输出。
    Y=∑i=1pYiY = \sum_{i=1}^{p} Y_i
  3. 与整体等价由分块矩阵乘法性质,部分和之和等于整体乘积。
    ∑i=1pXi Wi=X W\sum_{i=1}^{p} X_i \, W_i = X \, W

3. 反向传播特性

演出结束,指挥没有让大家集合复盘,而是说:“今晚表现不错,各声部自己回去练自己的部分就好了。”为什么可以各练各的?因为每个声部的问题只和自己的谱子与歌词有关。行并行的反向传播正是这样:不需要任何跨卡通信。

数学上,损失 L 对输出 Y 的梯度 dY 由上层反向传来,对每台设备来说它都是已知的。由于 Y = ΣYᵢ,而求和运算的梯度就是“广播”——∂L/∂Yᵢ = ∂L/∂Y = dY,所以每台设备手里的 dY 可以直接用于本地计算,不需要等任何人。

于是两个梯度都在本地完成:权重梯度 dWᵢ = Xᵢᵀ · dY,只需要自己的输入分片和全局输出的梯度;输入梯度 dXᵢ = dY · Wᵢᵀ,只需要全局输出梯度和自己的权重分片。其中 dXᵢ 恰好就是完整输入梯度 dX 的第 i 列块,天然按位置存放,不需要 All-Gather 拼接。这与列并行恰好对称:列并行是“前向 All-Gather、反向 All-Reduce”,行并行是“前向 All-Reduce、反向零通信”。

每个声部回家自己练声,互不打扰。这份“静音”的优雅,在与列并行组合时体现得淋漓尽致——列并行负责反向的 All-Reduce 通信,行并行负责前向的 All-Reduce 通信,两队声部交错发声,谁都不抢谁的麦。

dWi=XiT dY,dXi=dY WiTdW_i = X_i^T \, dY, \qquad dX_i = dY \, W_i^T
两个等式的共同点是:右边只出现本设备的 Xᵢ 或 Wᵢ,以及全局共享的 dY,因此不需要任何通信。
  1. 输出梯度可复用因为输出是局部结果之和,所以每个局部输出对损失的偏导都等于 dY。
    ∂L∂Yi=∂L∂Y=dY\frac{\partial L}{\partial Y_i} = \frac{\partial L}{\partial Y} = dY
  2. 权重梯度本地算输入分片的转置乘输出梯度,得到第 i 块权重梯度。
    dWi=XiT dYdW_i = X_i^T \, dY
  3. 输入梯度本地算输出梯度乘权重分片的转置,得到完整输入梯度的第 i 列块。
    dXi=dY WiTdX_i = dY \, W_i^T

4. 与列并行组合

合唱团里通常分“高声部组”和“低声部组”,两组既要独立训练,又要默契配合。列并行与行并行正是这样一对黄金搭档:一个按“列”切矩阵,一个按“行”切矩阵,在 Transformer 的 MLP 层中配合得天衣无缝。

Megatron-LM 的 MLP 包含两个线性层,中间夹一个激活函数。设计者的安排是:第一层用列并行(权重 W₁ 按列切),第二层用行并行(权重 W₂ 按行切)。为什么这么配?关键在输出与输入的“咬合”——列并行算出的激活输出在特征维度上天然是切分的,而行并行恰好要求输入按列切分。两者一拼,中间根本不需要把激活值拼接完整再分发。

具体流程是:设备 i 持有 W₁ 的第 i 个列块 W₁,ᵢ 和 W₂ 的第 i 个行块 W₂,ᵢ。前向时,设备 i 先算出 Uᵢ = XW₁,ᵢ(列并行局部输出,不需要通信),接着就地过激活函数得到 Yᵢ = σ(Uᵢ),然后直接做行并行的局部乘法 Zᵢ = YᵢW₂,ᵢ,最后 All-Reduce 得到完整 Z。全程 Y 从未被拼成完整矩阵,省掉了一次 All-Gather 加一次切分的通信开销。

高声部组把旋律劈开分给组员(列并行),低声部组在同一时间接力竖切和声(行并行),两组之间不需要停下来把声音合一遍再重新分工。这种“中间状态零拼接”的配合,正是大模型训练中省通信的精妙设计。

Z=∑i=1pσ(X W1,i)W2,iZ = \sum_{i=1}^{p} \sigma\left(X \, W_{1,i}\right) W_{2,i}
这个式子把两层并行串成一条链:列并行局部算完激活,行并行直接接力求和,中间没有拼接步骤。
  1. 列并行的局部输出每台设备用完整 X 乘 W₁ 的第 i 个列块,得到未经激活的部分特征。
    Ui=X W1,iU_i = X \, W_{1,i}
  2. 激活就地作用GELU / ReLU 是逐元素操作,可以放心作用于每个分片。
    Yi=σ(Ui)Y_i = \sigma(U_i)
  3. 行并行接力求和Yᵢ 正好是行并行所需的输入分片,乘 W₂ 的行块后求和。
    Z=∑i=1pYi W2,iZ = \sum_{i=1}^{p} Y_i \, W_{2,i}

5. 通信开销分析

和声虽美,但把几十个声部的声音汇聚起来是有代价的——团员们得移动位置、对齐节奏。在多卡训练中,通信比计算更昂贵。所以我们需要精确地知道:一次 All-Reduce 到底搬了多少数据?

行并行前向只有一次 All-Reduce,它的通信量由输出矩阵 Y 的大小决定。设批大小为 B,输出特征维度为 N,每台设备的局部结果 Yᵢ 就是一个 B×N 的矩阵。All-Reduce 要在 p 台设备之间把这个矩阵的所有局部版本归约成一份。

一次 All-Reduce 的通信量怎么算?理想化的环形归约中,每台设备总共发送和接收各约 (p-1)/p 份数据。因此单次通信的流量(以元素个数计)约为 2BN(p-1)/p。这个数字与模型参数量无关,只和输出形状及设备数挂钩——当 N 很大时,通信占比会明显上升,这也是为什么张量并行一般只在单机多卡(NVLink 高速互联)内使用。

合唱团人越多,每个团员需要和其他人对齐的比例反而越高((p-1)/p 趋向 1)。但妙的是,列并行把类似的开销放在了反向,行并行把它放在前向——两个声部组交错发声,通信高峰被削平,整体训练更顺畅。

Ccomm=2×B×N×p−1pC_{\mathrm{comm}} = 2 \times B \times N \times \frac{p-1}{p}
通信量 = 每台设备局部输出元素数 × 交换比例 × 收发双倍计数。
  1. 局部输出大小每台设备的 Yᵢ 有 B 行 N 列,共 B×N 个元素。
    ∣Yi∣=B×N|Y_i| = B \times N
  2. 归约交换比例p 台设备做全归约时,每台实际需要交换 (p-1)/p 份数据。
    p−1p\frac{p-1}{p}
  3. 收发双向计数发送和接收各算一次流量,所以乘 2。
    C=2×B×N×p−1pC = 2 \times B \times N \times \frac{p-1}{p}

6. 工程实现要点

成熟的合唱团靠纪律保证演出质量:谱子怎么分、谁领唱、座位怎么排,都有讲究。工程上落地行并行同样有几条“排练纪律”,稍不留神就会跑调。

首先是权重初始化。由于每台设备只持有一块 Wᵢ,初始化随机种子必须按分片对齐,使得所有分片拼接后整体分布与不切分的权重一致。否则可能出现某些设备初始化过大,模型训练直接发散。出于同样的道理,优化器状态(如 Adam 的一阶/二阶动量)也应随分片存放在各设备上,显存自然均摊。

其次是偏置处理。行并行的输出是求和得到的,偏置 b 的形状与输出维度一致,不能按设备切分。如果每台设备都把 b 加在各自的局部结果上,再 All-Reduce,最终偏置会被放大 p 倍。正确做法是:All-Reduce 之后再统一加一次 b;或让某台设备加 b,借 All-Reduce 自然广播。还有一点是显存负载均衡:输入按列切分后,各设备存储的激活量与特征分片成正比,与列并行配对的层必须保证特征维度对齐,避免某块 GPU 变成“显存热点”。

分谱清晰(初始化对齐)、领唱明确(偏置只加一次)、座位合理(负载均衡)——把这些纪律执行到位,行并行才能真正发挥“人多力量大”的优势。Megatron-LM、TensorRT-LLM 等框架正是靠这些细节,让千万亿参数的模型训练成为可能。

Y=(∑i=1pXi Wi)+bY = \left( \sum_{i=1}^{p} X_i \, W_i \right) + b
偏置只能加一次,位置在 All-Reduce 之后;若加在局部会重复 p 次。
  1. 错误的局部加偏置若每台设备都加 b 再归约,偏置会被累加 p 次。
    ∑i=1p(XiWi+b)=XW+pb≠XW+b\sum_{i=1}^{p} (X_i W_i + b) = X W + p b \neq X W + b
  2. 正确的全局加偏置先归约局部结果,再加一次偏置。
    Y=AllReduce(∑i=1pXiWi)+bY = \mathrm{AllReduce}\left(\sum_{i=1}^{p} X_i W_i\right) + b
  3. 分片权重等价性切分后再拼接,应当与原始权重的分布一致。
    W=[W1;W2;⋯ ;Wp]W = \left[ W_1; W_2; \cdots; W_p \right]

AI 应用场景

场景1:Megatron-LM 大规模语言模型训练

阶段:分布式训练优化

解决的问题:GPT-3 这类千亿参数模型,单张 GPU 显存完全装不下 MLP 层权重。传统做法要么把整个权重放一个设备计算,要么用数据并行反复复制模型——前者放不下,后者通信爆炸。行并行配合列并行,把每个 Transformer 块中的 MLP 权重拆分到多卡上,使模型规模突破单卡显存上限,同时把通信开销控制到最小。

具体案例:训练 175B 参数的 GPT-3 时,Megatron-LM 对每个 Transformer 的 MLP 层应用“列并行 → 激活 → 行并行”的组合:第一层 W₁ 按列切分到 8 张 GPU,激活函数在分片上就地计算,第二层 W₂ 按行切分接力,最后 All-Reduce 汇聚。8 卡协同工作,仿佛 8 个声部同唱一首歌,训练吞吐量大幅提升。

场景2:大模型推理引擎的多卡张量并行

阶段:模型推理部署

解决的问题:推理时模型权重需加载到 GPU 显存,单卡放不下百亿级模型;同时推理延迟要求高,不能频繁跨卡搬运权重。行并行把权重行分片分布到多卡,配合列并行共同服务一次前向推理,在保持低延迟的同时扩展显存容量。

具体案例:vLLM、TensorRT-LLM 等推理引擎在加载 LLaMA-70B 时,将每个线性层的权重同时按“列切”和“行切”分配到 4 张 A100 上。每张卡只算自己那几分之一的矩阵乘法,最后 All-Reduce 合并输出。用户无感知地获得接近单卡的速度,模型可用的显存却翻了 4 倍。

Python 演示

python54 行
import numpy as np  def row_parallel_forward(X, W, p=2):    """Simulate row-parallel forward with p devices."""    batch, in_f, out_f = X.shape[0], W.shape[0], W.shape[1]    chunk = in_f // p     # 1. split weight by rows, split input by columns    W_chunks = [W[i * chunk:(i + 1) * chunk, :] for i in range(p)]    X_chunks = [X[:, i * chunk:(i + 1) * chunk] for i in range(p)]     # 2. each device computes local product    local_out = [X_chunks[i] @ W_chunks[i] for i in range(p)]     # 3. All-Reduce: sum all local outputs    Y_parallel = local_out[0]    for i in range(1, p):        Y_parallel = Y_parallel + local_out[i]    return Y_parallel  def row_parallel_backward(dY, X, W, p=2):    """Simulate row-parallel backward: zero cross-device communication."""    batch, in_f, out_f = X.shape[0], W.shape[0], W.shape[1]    chunk = in_f // p    W_chunks = [W[i * chunk:(i + 1) * chunk, :] for i in range(p)]    X_chunks = [X[:, i * chunk:(i + 1) * chunk] for i in range(p)]     # local gradients, no communication needed    dW_chunks = [X_chunks[i].T @ dY for i in range(p)]    dX_chunks = [dY @ W_chunks[i].T for i in range(p)]    return dW_chunks, dX_chunks  if __name__ == "__main__":    rng = np.random.default_rng(42)    batch, in_f, out_f = 8, 6, 4    X = rng.normal(size=(batch, in_f))    W = rng.normal(size=(in_f, out_f))    dY = rng.normal(size=(batch, out_f))     # forward: compare with reference    Y_ref = X @ W    Y_row = row_parallel_forward(X, W, p=2)    print("Forward match:", np.allclose(Y_ref, Y_row))     # backward: compare gradients    dW_ref, dX_ref = X.T @ dY, dY @ W.T    dW_parts, dX_parts = row_parallel_backward(dY, X, W, p=2)    dW_cat = np.concatenate(dW_parts, axis=0)   # stack row chunks    dX_cat = np.concatenate(dX_parts, axis=1)   # stack column chunks    print("dW match:", np.allclose(dW_ref, dW_cat))    print("dX match:", np.allclose(dX_ref, dX_cat))
目的:用 numpy 模拟 2 台设备的行并行前向与反向,验证“前向 All-Reduce 求和、反向零通信”的数学等价性。
  1. W_chunks = [W[i * chunk:(i + 1) * chunk, :] for i in range(p)]把权重矩阵按行切成 p 块,每台设备拿一块。
  2. X_chunks = [X[:, i * chunk:(i + 1) * chunk] for i in range(p)]把输入按列切成 p 块,与行块配对。
  3. local_out = [X_chunks[i] @ W_chunks[i] for i in range(p)]每台设备只做自己的局部矩阵乘法。
  4. Y_parallel = Y_parallel + local_out[i]模拟 All-Reduce 的求和归约过程。
  5. dW_chunks = [X_chunks[i].T @ dY for i in range(p)]权重梯度只用本地输入分片计算,不跨卡。
  6. dX_chunks = [dY @ W_chunks[i].T for i in range(p)]输入梯度也在本地算,天然按列分片存放。
  7. np.allclose(Y_ref, Y_row)验证并行结果与串行参考结果完全一致。

常见误区

误区我以为行并行就是把输出矩阵按行切开,每个 GPU 负责输出的一部分行,这样输出维度就被分到不同卡上了。

正解行并行切的是权重矩阵的行,也就是输入特征维度 K。权重被切成 p 个行块后,输出维度 N 保持完整,每台设备算出的 Yᵢ 形状是完整的 (batch, N),最后通过 All-Reduce 相加。真正把输出维度切开的是列并行(按列切权重)。

为何常见:矩阵乘法的行和列都有“切分”操作,初学者很容易把权重行切分和输出行切分混为一谈;加上行并行名字里的“行”字具有误导性。

误区我认为既然前向要做一次 All-Reduce 汇聚结果,反向传播时自然也要再做一次 All-Reduce 把梯度汇总回来。

正解行并行的 All-Reduce 只出现在前向。反向传播时,由于输出梯度 dY 是全局共享的,每个设备用本地的 Xᵢ 和 Wᵢ 就能算出 dWᵢ 和 dXᵢ,不需要任何跨卡通信。真正的“反向 All-Reduce”发生在列并行中。

为何常见:对称联想导致——列并行是前向 All-Gather、反向 All-Reduce,人们想当然地认为行并行也应该两边都有通信。

误区我觉得每台 GPU 都应该看到完整的输入 X,这样才能独立算出自己的部分结果,行并行应该只切权重不切输入。

正解行切分权重后,输入 X 必须按列切成 p 块,与行块一一配对。因为 XW 的乘法中,X 的列维度必须与 W 的行维度匹配。若给每台设备完整 X,X 与 Wᵢ 的形状根本对不上(列数 k ≠ k/p)。

为何常见:列并行是“输入完整、输出切分”,容易让人误会行并行也类似;忽略了行并行要求输入切分才能相乘。

误区我以为 All-Reduce 就是把各 GPU 算出的部分结果拼在一起,像拼图一样组成完整输出,名字里既然有 All 就是大家把数据合起来。

正解All-Reduce 是“归约后广播”:先把各设备的数据做逐元素相加(或其他归约操作如 max),再把结果发给所有设备。行并行用的是求和归约。拼接操作叫 All-Gather。虽然列并行前向用到 All-Gather,但行并行用的是 All-Reduce——两者都是“合”,方式完全不同。

为何常见:英文术语 All-Reduce 和 All-Gather 都带 All 前缀,中文翻译都接近“聚合”,初学者极易混淆。

误区既然权重都切成块了,偏置 b 也应该跟着切成几块,每台设备存一份,反正都是“模型参数的一部分”。

正解偏置 b 的形状与输出维度 N 一致,而行并行中输出 N 没有被切分。如果每台设备都把 b 加到局部结果再归约,最终偏置会被放大 p 倍。正确做法是在 All-Reduce 之后统一加一次 b,或者由某一台设备加上后靠归约广播到所有设备。

为何常见:参数切分的直觉被过度推广——忽略了偏置与输出维度的绑定关系,以及归约求和会累加的特性。

面试题

Q1. 行并行中权重矩阵 W 按什么方向切分?

单选题 · easy

  • A.按行切分← 正确答案
  • B.按列切分
  • C.按块切分
  • D.不切分

答案:A。行并行的名字已经揭示了切法:把权重矩阵沿行的方向切成 p 个水平条带,每台设备分到一个条带。这就像合唱团把总谱按声部行撕开,每个声部只拿自己那几行。列并行才是按列切分,别搞混。

Q2. 行并行中 All-Reduce 的主要作用是什么?

单选题 · easy

  • A.拼接各设备的输出
  • B.对各设备局部结果求和← 正确答案
  • C.复制完整输出到各卡
  • D.切分输出到各设备

答案:B。行并行前向最后要求所有局部结果相加,All-Reduce 做的就是“求和后广播”。它不是拼接(那是 All-Gather),也不是简单的复制或分发。和声的“叠加”正是 All-Reduce 的灵魂。

Q3. 行并行中局部输出 Yᵢ 的形状正确的是?

单选题 · mid

  • A.批长乘输出维度 [b, n]← 正确答案
  • B.批长乘输入分片 [b, k/p]
  • C.输入分片乘输出 [k/p, n]
  • D.减半批长乘输出 [b/p, n]

答案:A。每台设备虽然只算了一个局部乘积,但局部结果的形状与完整输出一致,都是 (batch, N)。因为输出维度没有被切分,切掉的是输入特征维度。就像每个声部唱出来的旋律片段,时长和音域都是完整的,只是缺少其他声部的和声。

Q4. 行并行中每台设备需要哪些数据分片?

多选题 · mid

  • A.权重矩阵的部分行← 正确答案
  • B.输入矩阵的部分列← 正确答案
  • C.完整的权重矩阵
  • D.完整的输入矩阵

答案:AB。行并行中每台设备需要权重矩阵的部分行(Wᵢ)和输入矩阵的部分列(Xᵢ),两者配对才能做矩阵乘法。完整的权重和完整输入是列并行的需求,行并行不需要。

Q5. 行并行的反向传播需要通信吗?

单选题 · mid

  • A.需要,前反向都要通信
  • B.不需要,反向零通信← 正确答案
  • C.反向需要 All-Gather
  • D.与权重大小相关

答案:B。行并行的反向传播是零通信:梯度 dY 全局共享,权重梯度 dWᵢ 用本地 Xᵢ 算,输入梯度 dXᵢ 用本地 Wᵢ 算。这像合唱结束后各声部自己回家练声,不需要凑在一起开会。

Q6. 行并行中输入矩阵 X 如何切分?

单选题 · easy

  • A.按列切分为 p 块← 正确答案
  • B.按行切分为 p 块
  • C.不切分直接广播
  • D.按块切分为 p² 块

答案:A。输入 X 必须按列切成 p 块,这是因为 X 的列数必须与 W 的行数匹配。权重按行切了多少块,输入就按列切多少块,一一对应。把输入广播给所有设备是列并行的做法。

Q7. 行并行中 dXᵢ(输入梯度的分片)如何计算?

单选题 · mid

  • A.由 dY 与 Wᵢ 转置的本地积← 正确答案
  • B.从其他设备广播获取
  • C.All-Gather 拼接得到
  • D.先 Reduce 再 Scatter

答案:A。dXᵢ 的计算只需要本设备的权重分片 Wᵢ 和全局输出梯度 dY,即 dY @ Wᵢᵀ。它是完整输入梯度 dX 的第 i 列块,按位置存放即可。不需要广播,也不需要拼接。

Q8. 关于行并行的描述,正确的是?

多选题 · hard

  • A.前向需要 All-Reduce 求和← 正确答案
  • B.反向不需要跨卡通信← 正确答案
  • C.权重梯度可以本地计算← 正确答案
  • D.输入必须全量广播到各卡

答案:ABC。行并行的三个特征:前向 All-Reduce 求和、反向零通信、权重梯度本地计算。D 错得离谱——输入需要的是按列切分而非全量广播。这是行并行与列并行最核心的差异。

Q9. MLP 中第一层用列并行、第二层用行并行的核心原因是?

单选题 · hard

  • A.列并行计算速度更快
  • B.免去层间特征拼接通信← 正确答案
  • C.行并行无法配合激活函数
  • D.为了减少整体参数量

答案:B。MLP 第一层列并行输出的是特征维度的分片,第二层行并行输入的恰好是特征维度的分片,两者咬合后中间激活值无需拼接和再切分,省掉一次 All-Gather 加一次切分的通信。不是为了快,也不是为了砍参数。

Q10. 若偏置 b 在每台设备局部相加后再 All-Reduce,最终输出会怎样?

单选题 · extreme

  • A.偏置被放大 p 倍← 正确答案
  • B.偏置被缩小 p 倍
  • C.没有任何影响
  • D.All-Reduce 自动修正偏置

答案:A。偏置 b 与输出维度绑定,行并行中输出维度没被切分,所以 b 不能分片。若每台设备局部加 b 再归约,偏置会被求和 p 次,放大 p 倍。正确做法是归约后再加一次 b,就像合唱的领唱只能有一个,不能四个声部各唱一遍主旋律。