Tensor Parallel

张量并行

核心解释

Tensor Parallel 把同一层的权重与计算分到多张 GPU。每张卡计算自己负责的部分。通信操作将这些结果合并。

线性层计算 Y=XW⊤+bY = XW^{\top} + b,其中 XX 是输入,WW 是权重,bb 是偏置。

以不含偏置的两层 GeLU MLP 为例。第一层权重 W1W_1 沿输出特征维切分,也就是切分权重的行。每张卡独立计算一部分中间特征。第二层权重 W2W_2 沿对应的输入特征维切分,也就是切分权重的列,直接使用本地特征。各卡的输出相加后,得到完整结果。[1]

Ur=GeLU⁡(XW1,r⊤)Y=∑rUrW2,r⊤\begin{aligned} U_r &= \operatorname{GeLU}(XW_{1,r}^{\top}) \\ Y &= \sum_r U_r W_{2,r}^{\top} \end{aligned}

这里的 rr 表示 GPU 编号。W1,rW_{1,r} 和 W2,rW_{2,r} 是这张卡持有的权重分片。

分片保存张量的不同区段,通过拼接还原。局部贡献保存同一个结果的部分求和项,通过归约相加还原。完整副本则让每张卡保存相同的完整结果。

Sequence Parallel(SP)让部分层边界的激活沿序列维保存为分片。输入与输出的布局决定这些边界上的通信。[2]

资料

QA

局部输出的形状已经完整,为什么还要 AllReduce?

行并行 GEMM 中,每张卡只计算自己持有的中间维分片。各卡输出的形状相同,每份输出都只包含一部分求和项。

AllReduce 将这些输出逐元素相加。每张卡因此得到完整结果 YY。

Y=U0W2,0⊤+U1W2,1⊤=Y~0+Y~1Y = U_0W_{2,0}^{\top} + U_1W_{2,1}^{\top} = \widetilde{Y}_0 + \widetilde{Y}_1

为什么常见的 MLP 先做列并行,再做行并行?

列并行沿输出特征维切分,行并行沿输入特征维切分。在 PyTorch 的权重布局中,它们分别对应权重的行分片和列分片。第一层在本地执行 GeLU。第二层直接使用本地特征,省去了两层之间的特征汇集。

如果第一层沿求和维切分,各卡得到的是局部乘积。GeLU 是非线性函数。因此,各卡需要先合并局部乘积,再执行 GeLU。下面的不等式一般成立。

GeLU⁡(a+b)≠GeLU⁡(a)+GeLU⁡(b)\operatorname{GeLU}(a+b) \ne \operatorname{GeLU}(a)+\operatorname{GeLU}(b)

MoE 中,TP 和 EP 应该怎么选?

TP 把一个专家的矩阵分到多张卡。EP 把不同专家放到不同卡,再把 token 路由到对应专家。两者可以组合:先分布专家,再对每个专家使用 TP。

选择取决于专家大小、每个专家收到的 token 数量和 GPU 互连。专家矩阵继续切小后,GEMM 效率可能下降。EP 则需要处理 token 分发、结果合并和专家负载不均。

Attention 与专家层可以使用不同的并行度。MoE Parallel Folding 展示了这种组合,也比较了专家内部 TP 与 EP 的性能。阅读实验时,同时看模型、batch 和节点拓扑。

一次 AllReduce 到底传了多少数据?

先固定计量范围:这里计算 Ring AllReduce 中,每张卡发送的有效数据量。共有 pp 张卡,每张卡输入 T×HT\times H 个元素,每个元素占 bb 字节。输入大小为 S=THbS=THb。

ReduceScatter 和 AllGather 各发送 (p−1)S/p(p-1)S/p 字节。每张卡的接收量与发送量相同。

例如,8 张卡对 4096×81924096\times8192 的 BF16 张量做一次 Ring AllReduce。每张卡输入 64 MiB,发送 112 MiB,接收 112 MiB。收发合计是 224 MiB。

计算一个训练步时,需要继续统计前向、反向和重计算中的通信调用。实际耗时还取决于算法、拓扑、消息大小与计算重叠。跨节点链路上的实际字节数要结合通信拓扑统计。

Vsend=2p−1pTHbV_{\mathrm{send}} = 2\frac{p-1}{p}THb

训练与推理,选择 TP 并行度时关注什么?

训练要同时容纳权重、梯度、优化器状态和激活。比较配置时,应固定全局 batch 与序列长度,并计入前向、反向、重计算和优化器更新的时间。

推理还要给 KV Cache 留出空间。Prefill 一次处理较多 token,通常更容易受计算吞吐限制。Decode 每条序列每步产生一个 token,小 batch 时更容易受权重读取和通信延迟限制。增加并发后,瓶颈也会变化。

服务侧需要同时看吞吐、首 token 延迟和相邻输出 token 的时间间隔。固定输入输出长度与到达负载,再比较 TP 配置。比较时也要固定 batch 与调度方式,才能分辨 TP 本身带来的变化。

把通信放到另一个 stream,就能隐藏 TP 通信吗?

还要看数据依赖。如果 GEMM 需要完整的 AllGather 结果,单纯换一个 stream 并没有让两者可以同时执行。Async TP 会把通信和 GEMM 拆成较小的部分,让已到达的数据先参与计算。

拆分也有成本:小矩阵的执行效率、同步次数和通信内核占用的资源都可能影响收益。应比较端到端时间,并在时间线上检查真正被覆盖的通信与额外计算开销。

SP 减少了长期保存的激活,显存峰值也一定会降低吗?

待解

一次前向与反向中,输入分片、AllGather 缓冲区和 GEMM 工作区分别在什么时候分配和释放?

增加 TP 并行度后,怎样判断省下的计算是否抵得过通信?

待解

固定模型、精度、输入输出长度与负载,分别观察 prefill 和 decode。怎样从 GPU 时间线区分 GEMM 变小、通信等待与重叠不足?