我最早以为,"模型太大放不下"就是权重太多。后来我在一条很长序列上做训练,模型不算大,却照样 OOM。盯着报错里 tensor 的 shape,我才反应过来:真正把显存吃光的,不是那几亿个参数,而是这条序列本身穿过每一层时留下的中间状态。

一句话说清问题:单条样本的序列长度,超过了单 GPU 的显存容量。Transformer 训练时,每个 token 的 hidden state 会按层保存下来用于反向传播;序列越长,这份激活越大。序列并行要做的事,就是把这根又长又直的序列,按序列维切成 N 段分给 N 张卡。
为什么数据并行和张量并行救不了你
数据并行切的是 batch。batch size=1 时,这条样本无论如何都在同一张卡上。张量并行切的是权重,但每个 token 的 hidden state 依然是完整 S×H;S 本身越长,单卡上需要保留的激活就越多。
所以只能切最后一个维度:序列维 S。把 S/N 段放每张卡上。
切完序列之后,什么可以直接算
Transformer 里的大部分操作是按 token 独立处理的:LayerNorm 是每个 token 对 H 维归一化,FFN 也是每个 token 自己算。序列切分之后,这些部分直接并行,不需要通信。
真正麻烦的是 attention。每个 query token 要跟全序列的 key/value 做计算,也就是说,attention 的依赖关系横跨所有分片。序列并行方案的分歧,都集中在 attention 这一步怎么跨卡。
三种主流序列并行
Megatron 的序列并行:TP 的黄金搭档
NVIDIA 最初用Megatron-LM的张量并行解决权重放不下,但激活还是爆。后来在Reducing Activation Recomputation in Large Transformer Models中提出把序列维也切了:GEMM 继续按 tensor 切,LayerNorm、Dropout 按 sequence 切,层与层之间用 all-gather/reduce-scatter 重新收拢数据。
这样做的直接收益是:每张卡不再保存完整序列的激活;而它带来的通信,基本只在 transformer 层边界出现。Megatron 的序列并行很少单独存在,实际训练通常是 TP+SP 一起用。
DeepSpeed Ulysses:用 all-to-all 换乘序列和 head
all-to-all 用大白话说:每张卡把自己手里的数据按目标卡切成 N 份,发给所有卡,同时从其他卡各收一份。Ulysses 把 attention 里的 head 也切成 N 份。attention 之前,原本序列切块的 GPU 通过 all-to-all,把数据重排成 head 切块:每张卡拿到完整的 S 个 token,但只拿 1/N 的 head。
计算完自己的 head 之后,再用一次 all-to-all 换回来。通信量是 O(SH/N),GPU 越多,单卡通信量越低。DeepSpeed Ulysses 论文的摘要原话是:
"We introduce DeepSpeed Ulysses, a simple, portable, and effective methodology for enabling highly efficient and scalable LLM training on very long sequences."
它的天花板也很明确:attention head 数有限,N 不能无限开。
Ring Attention:不换数据,数据来找你
Ring Attention的哲学完全不同。它不把整条序列凑齐再算,而是每张卡持有自己的 Q 块和一个 KV 块,KV 块沿环状拓扑转圈。每收到一个 KV 块,就用分块 softmax 更新本地输出,再传给下一张卡。
因为 Q 和 KV 都同时被切成 N 块,单卡 attention 内存降到 O(SH/N),而且不依赖 head 数量。代价是 KV 要绕完一整圈,通信延迟随 N 线性增长。
一张表说清三套方案的代价
| 方案 | 核心通信 | 每 GPU 通信量(数量级) | 主要限制 |
|---|---|---|---|
| Megatron TP+SP | all-gather / reduce-scatter | O(SH) | 和张量并行绑定 |
| DeepSpeed Ulysses | all-to-all | O(SH/N) | attention 头数有限 |
| Ring Attention | 点对点环形 | O(SH) | 通信延迟随 N 线性上升 |
如果只看显存,三套方案都能把单卡激活降到 O(SH/N);真正要选的是通信代价。日常 8k、16k 序列,可能 Megatron TP+SP 就够;上百万 token 的超长上下文,Ulysses 和 Ring Attention 更有机会。
几个容易被绕进去的点
有 FlashAttention,序列并行还重要吗?
重要。FlashAttention 砍掉的是 O(S²) 的 attention 分数矩阵,序列并行解决的是 S×H×L 的激活体积。一个管算法层,一个管系统层,两者常常叠着用。
ZeRO 不是也在省显存?
ZeRO 把 optimizer state、gradient、权重切开,省的是模型状态。它不切激活。序列一长,爆的恰恰是激活。所以 ZeRO 和序列并行不冲突,是两条正交的省显存路线。
序列并行和上下文并行是什么关系?
大体是同一个东西的不同叫法。Meta 训练Llama 3的 4D 并行里,Context Parallel 就是切序列维;PyTorch torchtitan 里也这样叫。别被名字带偏。
什么时候它才是必需品
序列并行没有让算力变多,它是用通信换显存。常规 4k/8k 长度,开 SP 可能比不开更慢;但到了 128k/1M,单卡连一条序列都放不下,SP 就从优化变成必要。
选型上,如果集群有 NVLink/NVSwitch 这种高带宽互联,Ulysses 的 all-to-all 很划算;如果是普通 RDMA/以太网,Ring Attention 的点到点通信更容易用 overlap 遮住延迟。大规模训练的实际方案,常常是 DP×TP×PP×SP/CP 四维并行,再叠加 ZeRO 和 FlashAttention。序列并行只是其中一环,但没有这一环,长上下文训练的显存天花板就顶在那里。
读到这里,你或许还想看论文原文
原创文章,作者:guanweilu,如若转载,请注明出处:https://guanweilu.cn/article/1430.html