把 25 万 token 的序列切到 8 张卡上,为什么注意力不会白拿 8 倍速:环形注意力的通信账、因果三角与负载不均
主题:长上下文训练里的序列并行(Ring Attention / Striped Attention / DeepSpeed-Ulysses / USP)。口径声明:本文的通信与强度推导针对 bf16、非因果注意力前向、完整 KV 环传的 Ring 算例;算例固定 S=262,144 token(=256×1024,标题「约 25 万」是近似称呼,不等于字数),并行度 N=8、查询头 32、KV 头 8(GQA 4:1)、批 1、单层,带宽按 A100 单向 NVLink 300 GB/s 计。核心机制:固定并行度下,每台设备的计算量按 S² 增长、接收量按 S 线性增长,两者之比(算术强度)约等于「查询头与 KV 头之比 × S ÷(N−1)」;逐块重叠要用的则是单步强度,约为它的 N/(N−1) 分之一。关键陷阱:因果掩码在「连续等长分片、对角块按整块计」的示意模型下给出 1:2:3:4 的工作量分布,最慢一台决定整步耗时,示意利用率 (N+1)/2N(N=8 时 56.3%;若对角块只算下三角则 53.3%)——这是按块对计数的示意值,不是实测 MFU。Striped Attention 论文在因果训练中相对原始 Ring Attention 报告 256k token 下最高 1.45 倍端到端吞吐,不是本文八卡算例的实测结果。证据边界:只读公开论文摘要,所有显存、通信、时间数字均为本文按公开公式代入公开规格的推导值,未在真实集群实测。
先说人话:假设有一份 25 万个片段的卷宗,一张桌子放不下。办法是把卷宗按顺序分给 8 张桌子,每张只留自己那一段的「提问」(查询),但每段提问都要和全部片段比对。于是每张桌子把手上那段的「摘要」(键值)装进一个盒子递给下一张:收到一盒就立刻用它跟本桌提问比对,同时把自己这盒再递出去——不必等收齐 8 盒,也不必在桌上摊开整份卷宗。省下的是桌面面积,付出的是一圈一圈的传递(「25 万个片段」是 token 数的近似说法,不等于汉字字数)。
下面先按非因果注意力解释(每段提问要看全部片段);因果版本只允许看前面的片段,第 6 节再改。
这就是序列并行(sequence parallelism,下文简称 SP)的张力。它解决的问题很具体:单张卡装不下长度为 的序列所产生的中间激活与注意力矩阵。它付出的代价也很具体:固定并行度下,每台设备每层的接收量随序列长度线性增长,而它本地的计算量随序列长度平方增长;两者的比值才是决定成败的量,第 4 节只算这一个比值。
2023 年这一年里,这条线上出现了四个被反复引用的工作(按首发时间):Blockwise Parallel Transformer(BPT,arXiv 2305.19370,v1 2023-05-30)、DeepSpeed-Ulysses(arXiv 2309.14509,v1 2023-09-25)、Ring Attention(arXiv 2310.01889,v1 2023-10-03)、Striped Attention(arXiv 2311.09431,2023-11-15);2024 年 5 月又有把 Ring Attention 与 DeepSpeed-Ulysses 统一起来的 USP(arXiv 2405.07719,v1 2024-05-13)。它们的摘要都很短,短到容易被读成「又一个让长上下文变快的技巧」。但这几篇放一起看,其实在回答三个不同的问题:
- 显存怎么省:把注意力拆成块,永远不显式构造完整的 矩阵。
- 通信怎么藏:把 KV 块的传输塞进计算的空隙里,让网络时间和计算时间重叠。
- 负载怎么平:因果掩码让后半段的计算量天然比前半段大,切分方式必须把这份不均摊掉。
这篇文章想把这三件事拆开算清楚。全文的立场是:序列并行的收益上限不是「几张卡」,而是「每台设备的算术强度有没有越过机器的算力带宽比」。越过,通信有条件被计算掩盖;越不过,通信开销可能抵消部分甚至全部并行收益——具体抵多少,要看重叠实现与拓扑,不能只凭一个比值断言「加卡必然更慢」。
0. 先把问题说清楚:切序列不等于自动变快
标准的数据并行(DP)里,每张卡拿不同的样本,模型权重复制一份,梯度最后 all-reduce。这条路的线性加速比之所以能成立,是因为通信量只与参数量有关,与序列长度无关——每步通信的是梯度,大小固定。
张量并行(TP)切的是隐藏维:把一个线性层的权重矩阵按列或按行切开,每层要做两次 all-reduce,通信量与激活大小成正比,也就是与「批大小 × 序列长度 × 隐藏维」成正比。
流水并行(PP)切的是层:不同设备拿不同的层,靠 micro-batch 填满流水线的气泡。
这三种并行都有一个共同点:它们都没有真正解决「单条样本太长」这件事。序列长度 依然完整地躺在每一张卡的激活里。当 从 8K 涨到 256K,激活显存涨 32 倍,TP 的通信量也涨 32 倍。你可以在 8 张卡上训一个 8K 的模型,然后发现换到 256K 时同一个配置直接 OOM。
序列并行把切分维度换到了 上:每台设备持有一段连续的(或交错的)token,本地只算这一段自己的查询(query)。但注意力的定义要求每个查询都要看到全部键值,所以每台设备终究要拿到别人的键值块(KV 块)——但不是收齐再算:收到一块就用它算一块,同时把手上这块转发给下一台。这就是「省显存」与「多通信」的交换点,也是后文所有数字的来源。
一句值得记住的话:序列并行不是把工作切小了,而是把「内存墙」换成了「通信墙」,然后看网络账单能不能被计算掩盖掉。
1. 一台机器为什么装不下:三笔显存账
先把「装不下」量化。训练时单层的显存大致分三块:参数与优化器状态、激活、以及注意力计算过程中的临时张量。序列并行主要救的是后两块,但最刺眼的是注意力那一块。
注意力得分矩阵的形状是「批 × 头 × 序列 × 序列」。先约定符号(后文一直沿用): 是批大小、 是查询头数、 是序列长度(token 数)、 是每元素字节数。下面三笔账都以 、、bf16()、(即 256×1024)为例:
代入 :
这是单层的数字,而且属于「完整得分矩阵」这一粒度(查询 × 全部键,不做块化)。先把后面三个数字的所指说清:4.40 TB、17.2 GB、67 MB 都是「注意力临时张量」在不同切分粒度下的值,不是模型总显存,也不是 KV 通信缓冲区;混着比会得出错误的量级结论。一张 80 GB 的卡放不下千分之一。
这就是为什么长上下文训练从来不是「把 batch 调小」能解决的问题——矩阵是二次增长的,批大小是一次增长的,调小 batch 只是在延缓死亡。
块化(blockwise)计算是第一层解药:不同时保留整个 矩阵,而是一次只算一个 的切片,算完就把 softmax 的中间结果折叠掉。取 :
仍然太大——因为 还在里面。BPT 的做法是把自注意力和前馈网络一起块化,让「一次只处理一个查询块」成为整层的执行方式;摘要给出的结论是「最高可达」朴素 Transformer 的 32 倍、比此前的省显存方法再长 4 倍(原文用 up to,指可训练序列长度)。
环形注意力更进一步:既然一次只算一个 KV 块,那就不必同时持有「查询块 × 全部键」,而是让 KV 块绕着设备转。每台设备只保留自己那一段的 Q、K、V,外加一个「正在飞过来的 KV 块」缓冲区。单步得分窗口的开销是
三个粒度并排写清楚:4.40 TB = 完整得分矩阵(查询 × 全部键);17.2 GB = 查询块(1024 行)× 全部键;67 MB = 查询块 × 单个键块(单步得分窗口)。前两个分别按序列长度的平方与一次方增长,是序列并行要解决的;第三个基本与序列长度无关,是稳态开销。
除了这三个假设性的得分临时量,每台设备还要另留两块:一块「正在飞过来的 KV 块」缓冲(按本文的 32,768 token 分片算约 134 MB;若按 1024 token 的 tile 算约 4.19 MB),以及在线 softmax 的 状态(每行常数个标量加一个 维向量)。它们不属于上面任何一笔,读后面的通信账时别混进来。论文正文里量的是整层最大激活(Ring Attention 正文的激活对比表把 BPT 记作 量级;这一项由本轮事实审核员核对正文表格,本文未直接读取该表),与这里三个「得分临时量」不是同一口径,不能互相换算。
2. 符号约定与不变量
后文所有推导只用下面这些符号。数值示例统一取:、、、(即分组查询注意力 GQA,4 个查询头共享 1 组 KV)、、bf16。
| 符号 | 含义 | 本文示例取值 |
|---|---|---|
| 序列长度(token 数) | 262,144 | |
| 批大小 | 1 | |
| 序列并行度(context parallel 度,CP 度,即设备数) | 8 | |
| 查询头数 | 32 | |
| KV 头数(GQA 时小于 ) | 8 | |
| 单头维度 | 128 | |
| 每元素字节数 | 2(bf16) | |
| 计算 tile 的查询行数(≠ 设备分片长度) | 1024 | |
| 每台设备的序列分片长度, | 32,768 | |
| 单设备每层的计算量 | 见 §4 | |
| 机器算力带宽比(FLOP/byte) | A100 单向约 1040 |
两个不变量先立在这里,后面反复用:
不变量一(总量守恒):不管怎么切,注意力的总浮点运算量不变,非因果情形下为
系数 4 来自两次矩阵乘: 与 ,每次每元素 2 次浮点运算。因果掩码只算下三角,近似折半,记作 (这里是「有用 FLOP」的连续口径,与第 6 节按块对计数的口径不同,后者把对角块当整块算)。
不变量二(通信由 KV 决定):每台设备最终必须见过全部 KV。它自己那份不用传给自己,所以每台设备每层接收的字节数是
注意这里用的是 而不是 :GQA 下 K 和 V 只有 8 个头,查询有 32 个。这个不对称是后文算术强度公式里唯一一个「免费」的杠杆。
3. 环形传块:把注意力写成「一圈接力」
环形注意力的执行方式可以写成三条规则:
- 设备 持有一段连续 token,本地算出 。
- 在第 步,设备 用本地 与「当前持有的 KV 块」做一次块化注意力,累加到 softmax 的 running max 与 running sum 上(在线 softmax)。
- 同一步里,把当前 KV 块发给下一台设备,从上一台设备收下一块。走满一圈后,每台设备都见过全部 KV。
关键点在于第 2 步和第 3 步是同一步:发送与计算同时进行。这就是论文标题里「fully overlapping the communication of key-value blocks with the computation of blockwise attention」的意思。摘要同时强调它是精确算法:不做近似,也没有引入额外的通信或计算开销(摘要原文的表述是相对其比较基线而言,并未把基准定义成「本来就要传一遍 KV」)。
用递推写出来更清楚。令 表示第 步手上那一对键值块, 表示设备 上每一行的在线 softmax 状态,则
初始化 。Update 就是下一节那三个式子——不是「各块独立算完再合并」,而是「用新的 running max 把旧状态重新缩放后搬过去」。转完自己那块再转 次(共 个块), 就是精确结果。注意这条递推只是调度示意,不是可直接实现的递推:真实实现每一步都要同时更新 三个量,只传 会算错。因果版本不改算法:只要在算 时按 token 的原始位置施加掩码,被屏蔽的位置不进 softmax。
3.1 为什么分块还能是精确的:在线 softmax 的三元组
「分块计算」听起来像近似,其实不是——只要把 softmax 的三个状态一起滚动,分块结果与一次性计算在数学上完全相等。这也是环形注意力能自称「精确算法」的技术底座。
对每个查询行,需要三个量:当前见过的最大分数 、指数和 、以及分子(未归一化的加权和)。收到一个新块后,先算块内分数 ,再更新:
关键在于那个 的缩放因子:每当最大值被刷新,之前累积的 与 都要按比例缩小,等价于「把旧的贡献重新归一化到新的分母上」。这样无论分多少块、以什么顺序到达,最终结果都等于把所有分数放进一个 softmax 里算;输出取 即可。
这个性质对工程有三个直接后果:
- 状态大小与序列长度无关。每个查询行只需要常数个标量与一个 维向量,所以环形接力的得分窗口才能只有数十 MB(§1 里那个 67 MB,指查询块 × 单键块的窗口,不含 KV 缓冲)。
- 顺序可以任意。环形接力把 KV 块按位置排成一圈传,但对结果没有影响;条带化改变了 token 的物理顺序,只要每台设备仍然收齐所有块,结果不变。
- 数值稳定性必须靠 running max 保证。如果实现省掉 这一步(例如为了省一次乘法),长序列上会出现指数溢出,且只在特定样本上爆、很难复现。这是本文指出的实现风险,不是对某个具体实现的描述——本文没有读过这些实现的代码。
一句值得记住的话:分块不是近似,它只是把 softmax 的归一化分母拆成了可以增量更新的形式。
论文摘要里给的上界表述是「序列长度可达此前方法的设备数倍」,并演示了百万级 token 的上下文。这个表述容易被读成「8 张卡就是 8 倍长」;严格说它是显存上界,不是速度承诺。速度承诺要看下一节的比值。
4. 通信量与算术强度:什么时候重叠是免费的
重叠能不能「白拿」,取决于一秒里计算用了多久、通信用了多久。把两者都算成每设备每层的时间,比值就是判据。
单设备每层的计算量(非因果):
单设备每层的接收字节数由不变量二给出。两者的比值——也就是这台设备在这层里的算术强度——可以消掉 、 和 的一个幂次:
这个结果值得停下来看三秒:整层算术强度只由三个量决定——查询头与 KV 头之比、序列长度、并行度。它与头维度 无关,与批大小 无关(批大了计算和通信同比例涨),与块大小无关。直觉上也对:切得越细( 大),每台设备的计算量按 掉,但它要收的 KV 几乎不变(),所以强度按 掉。
但注意:这个 是「整层总量比」,用来判断逐块重叠时要用单步强度。单步里每台设备算一个块对、收一个块:
两者只差 (8 卡时约 12%),但判据要用 ,否则在阈值附近会把「勉强能藏」误判成「轻松藏住」。
代入示例:、、:
接着把它和机器比。A100 80GB 的公开规格是 bf16 稠密算力约 312 TFLOPS;NVLink 的 600 GB/s 是双向合计,而本文的 只算接收方向,所以必须用单向 300 GB/s:
重叠成立的条件是
131,072 对 1040,差两个数量级。这就是为什么在「单机 8 卡、256k token、非因果前向、按峰值估算、KV 传输被完全重叠」这个具体模型下,环形注意力的通信有条件忽略:按接收口径(7 个块,第 8 块是自己那块),每层每设备要收 0.94 GB,按 300 GB/s 算是 3.13 毫秒;而每设备的计算量是 140.7 TFLOP,按 312 TFLOPS 峰值算是 451 毫秒。前者只占后者的 0.69%。
同一层同样的形状,换成跨机 400 Gb/s 的 IB(折到每 GPU 约 50 GB/s,同样按接收方向)时,通信时间变成 18.8 毫秒,占计算的 4.2%。所以「环形注意力的通信很贵」这句话,在长序列上是错的;它在短序列 + 高并行度上才是对的。
把条件 反解,得到并行度的上限:
按 (H100 与 400 Gb/s IB 的量级,本文自算)与 GQA 4 计算:128K 序列时上限约 26.5;32K 时约 6.6;8K 时约 1.7。换句话说,序列并行只有在序列足够长的时候才划算,而且它的可用并行度是被网络带宽钉死的,不是被显存钉死的。
因果情形要把强度再砍一半:每个查询只看前面的键,计算量近似折半,而通信量不变(你还是得把全部 KV 块转一圈,只是有些块用不上、可以跳过发送,但那一版的实现复杂度会上去)。所以因果训练下有效并行度上限约为非因果的一半。
4.1 一个算例:把 8 张卡的 8 个 step 摊在时间轴上
抽象公式容易失去手感,代入一次就清楚了。同一配置(、、、、、bf16、批 1),每台设备的序列分片长度是 ,而计算 tile 仍是 (一个分片含 32 个 tile)。为了和上一节对齐,下面把「一步」定义为「用整个分片的查询算一个 KV 块」:
- 每一步的计算量是 TFLOP;
- 每一步接收的 KV 块是 MB;
- 按 312 TFLOPS 峰值算,单步计算约 56.4 毫秒;按单向 300 GB/s NVLink 算,单块传输约 0.447 毫秒;按 50 GB/s IB 算,约 2.68 毫秒。
八步里只有 7 次接收(自己那块不需要收),所以接收总量是 7 × 134 MB = 0.94 GB,累计 3.13 毫秒(NVLink)或 18.8 毫秒(IB);如果连「把自己那块发出去」也算进来,传输次数是 8 次、共 1.07 GB、约 3.58 毫秒(NVLink)或 21.5 毫秒(IB)。接收与发送是两笔账,后文的通信占比一律按接收口径算。
| 步 | 手上 KV 块 | 单步计算(峰值) | 单步接收(NVLink 300 GB/s) | 单步接收(IB 50 GB/s) |
|---|---|---|---|---|
| 1 | 自己的块(本地) | 56.4 毫秒 | 0(无需接收) | 0 |
| 2 | 邻居的块 | 56.4 毫秒 | 0.447 毫秒 | 2.68 毫秒 |
| … | … | … | … | … |
| 8 | 上一台的块 | 56.4 毫秒 | 0.447 毫秒 | 2.68 毫秒 |
| 合计 | 全部 8 块 | 451 毫秒 | 3.13 毫秒(7 次) | 18.8 毫秒(7 次) |
这张表最重要的读法不是「通信占比 0.69%」,而是两件容易被忽略的事:
第一,单步通信时间必须是单步计算时间的一小部分,重叠才有意义。如果块变小(例如把分片从 32K token 降到 2K,并行度不变但序列变短),计算按比例缩,通信的固定启动开销(kernel launch、握手、同步)却不缩,占比会迅速上升。
第二,峰值算力算出来的 56.4 毫秒是下界。真实训练 MFU 若只有 40%,单步计算变成约 141 毫秒,而通信的绝对时间不变,通信占单步时间的比例从 0.79% 降到约 0.32%——也就是说,算得慢的实现,通信更容易被藏住:低 MFU 让计算时间变长、通信占比下降。但这不等于跑得更快:MFU 低意味着每层花的墙钟时间更长。两个问题必须分开:①「通信还会不会拖后腿」看占比;②「整体吞吐好不好」看绝对时间。第 8 节与第 10 节会再回到这个区分。
(上表两个占比:0.447/56.4 = 0.79%;0.447/141 = 0.32%。)
4.2 同一配置下 Ulysses 要搬多少字节
Ulysses 不走 KV 环传,它在注意力前后各做一次 all-to-all:先把「本设备这一段序列的全部头」重排成「全部序列的一部分头」,算完再把输出重排回来。关键区别是每个设备在重排前只持有 这一段的数据,所以它的发送量是「自己那一段的四类张量」,接收量是其余 段对应的份额。按 GQA(K、V 只有 个头)计:
其中 是查询与输出、 是键与值。对照环形的 0.94 GB,在这个 GQA 配置下 Ulysses 反而少搬约四成(0.587 / 0.94 ≈ 0.63)。若是 MHA(),两项相等,都是 0.94 GB。
| 阶段 | 交换前形状(每设备) | 交换后形状(每设备) | 参与张量 |
|---|---|---|---|
| 注意力前 | () | Q、K、V | |
| 注意力后 | 输出 O |
这张表也解释了「通信量恒定」的真实含义: 在 与 同比例增长时趋于常数——所以每设备每层字节数不变。它是「每设备每层」的常数,不是「与序列长度无关」。
那为什么长上下文训练里仍然常见环形?答案不在字节数,而在三件事:① Ulysses 要求头数能被并行度整除(),GQA 模型头数少时很容易卡住;② 两次 all-to-all 是全设备参与的集合通信,延迟随规模上升,而环形是链式点对点,慢一台只影响一圈;③ 环形的实现不要求注意力头在设备间重新分布,与 GQA、变长、MoE 的组合更灵活。反过来,在胖树拓扑、头数充裕的场景,Ulysses 的 all-to-all 更容易吃满带宽,这也是 USP 强调「对网络拓扑更鲁棒」的由来。
5. 变长序列与打包:同一份显存账的另一半
上面所有推导都假设「一条样本恰好等于一个序列长度」。真实训练里这个假设几乎从不成立:语料是一堆长短不一的文档,常见做法是打包(packing)——把多篇文档首尾相接塞满一个固定长度的窗口,再用块对角掩码阻止跨文档互相注意。
打包之后, 指「打包窗口长度」,不是「单篇文档长度」。下面所有结论必须分两个分支读,否则会自相矛盾:
分支一:稠密实现,掩码只屏蔽结果、不省计算。 这时 的乘加照做,块对角掩码只是把越界位置的分数置为 。在这个分支里:计算量按窗口长度 的平方走(与不打包同量级),算术强度也按 算,序列并行的收益不变;但因果三角的负载不均会被削弱,因为早期块的大部分注意力都被掩掉了——条带化的收益因此比论文里的纯长文档场景更小。
分支二:变长 / 稀疏 kernel,真正跳过被掩掉的块。 这时工作量取决于「每个块对里有多少有效 token 对」,而有效量随文档边界分布剧烈波动。在这个分支里:计算量下降,但通信量不变(KV 块还得整块传),于是算术强度下降,通信更容易暴露;更麻烦的是,某些步的计算量骤降(那一块几乎全被掩掉),通信时间不变,那些步就退化成纯等待。
分支选择决定结论:分支一里「打包让负载更均衡」,分支二里「打包让通信更难藏」。本文的算例属于分支一;如果你的框架用的是按文档边界切块的变长 kernel,请按分支二重算。至于这两种分支在真实训练里各占多少,本文没有数据,不给比例。
除此之外,打包还有一个与分支无关的后果:长尾会把并行度锁死。序列并行的并行度必须按「最长的那条样本」配置,因为激活显存由它决定。于是当批里混着一条 262,144 token 的样本和几十条 4,096 token 的文档时,短样本也要占用同样的并行度,等于用 8 张卡去算一件一张卡就够的事。
把这件事量化一下(这是不同任务形状的对比,不是同一算例的参数变化):注意力计算量正比于长度的平方。一条 262,144 token 的样本是 个单位(归一化后),一条 4,096 token 的样本是 。一条长样本相当于约 4,100 条短样本。所以在一个混合批次里,长样本几乎独占全部算力——真正的问题是调度:如果每个 batch 都为了那条长样本拉起 8 路序列并行,剩下的容量就都空转。
工程上常见的应对是按长度分桶:长文档单独成批走序列并行,短文档走数据并行。代价是要维护两套并行配置(两组进程组、两份启动脚本),收益是短样本不再为长样本的并行度买单。这是本文给出的工程建议,不是对某家团队做法的统计——本文没有做过这项调研。
第 6 节起回到「单条长文档、不打包」的模型。
6. 因果三角:为什么前面的设备在等最后一台
上一节的所有推导都默认「每个查询看全部键」。语言模型训练不是这样:因果掩码让第 个 token 只能看到 。这条约束本身不改变算法,但会改变工作量在设备之间的分布。
下面用一个示意模型算,模型假设要写清:连续等长分片、块数等于设备数、按「有效块对」计数、对角块按一个整块计(不做下三角细算)、忽略 kernel 与通信的实现差异。结论只在这个模型内成立。
假设 台设备各拿一段连续 token,按位置从小到大编号为 。第 台设备要算的「键块 × 查询块」对,是它自己那段查询对前面所有键块(含自己)的注意力。以块为单位,工作量是
于是总工作量是 ,平均每台 ,而最慢的那台是 。整步耗时由最慢那台决定,所以利用率的上限是
代入几个常见的并行度: 时 75%, 时 62.5%, 时 56.3%, 时 53.1%, 时 51.6%。如果进一步把对角块只算下三角(更接近真实 FLOP),设备 的工作量变成 个整块当量,总量 ,利用率变成 —— 时 53.3%。两个口径差 3 个百分点,量级结论一样:在这个示意模型下,不管加多少卡,因果训练都会把约一半的算力晾在那儿。
这个结论很反直觉,但算术只有一行:设备的序号越靠后,它能看到的「前面的键」越多。最后一段的查询要看完整条序列,最前面那段的查询只看自己,工作量相差 倍——所以是前面的设备在等最后一台,而不是反过来。
Striped Attention 的做法很直接:不要给每台设备一段连续 token,而是把 token 按固定步长交替分配,让每台设备在整条序列上均匀取点。举个 8 token、4 设备的例子:连续切分是 ;条带切分(步长 4)是 ——每台设备都同时拥有靠前和靠后的 token,所以它承担的「有效块对」接近总和的四分之一。工作量变成
四台设备时每台约 2.5 单位,最大最小之比从 4:1 降到接近 1:1。论文摘要给的实测是:在 256k token(原文写法;约 26.2 万)的因果训练上,相对原始环形注意力取得最高 1.45 倍的端到端吞吐提升(A100 与 TPUv4 都测了),在 16 块 TPUv4、786k token(原文写法)时达到 1.65 倍。
注意口径:1.45 倍是端到端吞吐,不是「利用率从 56.3% 提到 100%」的比值。按本文 N=8 的粗粒度模型,那个比值是 1/0.563 ≈ 1.78;但这个 1.78 只是示意模型的算术结果,不是论文声称的「理论上限」,也不该拿来当作解释 1.45 与 1.78 差额的唯一依据——差额还牵涉逐轮同步、对角块能否跳过、tile 粒度是否足以吃到因果稀疏(论文的实验部分专门讨论了 tile 过大时无法充分利用因果掩码),以及条带化本身带来的位置编码与访存开销。把差额全部归给「条带化开销」是不严谨的。
还有一个细节值得单独说:即使负载摊平了,因果训练仍有优化空间。因为第 步里,某些设备手上的 KV 块对它自己的查询块完全用不上(全在因果掩码的「未来」侧),理想实现会跳过那一步的发送与计算。这类跳过会破坏「每台设备步调一致」的对称性,实现复杂度显著上升,论文里通常只做到部分跳过。
7. 另一条路线:Ulysses 的 all-to-all
DeepSpeed-Ulysses 换了一个切法。它不切 KV 块,而是在注意力前后各做一次 all-to-all:把「本设备持有一段序列的全部头」重排成「本设备持有全部序列的一部分头」。
这样每台设备在算注意力时,手里是完整序列、但只有 个头。于是每设备计算量是
和非因果的环形注意力完全相等——这一点应该如此,因为总计算量守恒、设备数相同。真正的差别在通信形态:如 §4.2 所算,GQA 下每设备每层约 0.587 GB(环形的 0.63 倍),MHA 下两者都是 0.94 GB。
那它凭什么值得存在?三个理由。
第一,通信量对 与 的依赖是「」这种形式:当序列长度与设备数同比例增长时,每台设备的每层字节数大致不变。论文摘要正是这么表述的:其他方法在序列变长时通信开销随之增长,而 Ulysses 在「序列长度与设备数成比例增长」时保持通信量恒定。注意这是「每设备每层」的恒定,不表示它与序列长度无关。
第二,all-to-all 在胖树(fat-tree)拓扑上比环形的点对点接力更容易跑满带宽,而环形是链式依赖:任何一台设备慢一步,整圈都要等。这也是 USP 那篇论文强调的「对网络硬件拓扑更鲁棒」。
第三,纯 Ulysses 在注意力计算上是按头均衡的:每台设备持有完整序列与相同数量的头,各头面对的是同样形状的因果矩阵,不存在连续序列切分那种 1:2:…:N 的不均。它的问题换到了别处——见下面的约束。
代价也很硬:Ulysses 要求注意力头数能被并行度整除()。GQA 模型里 KV 头常常只有 8 个,如果并行度取 16,KV 头就没法均分,实现要么复制 KV、要么退化。这就是为什么实践中经常看到「头维并行 + 序列并行」的二维分解——USP 的核心主张就是把两者统一起来,按头与序列两个维度同时切,绕开单维的整除约束。
USP 论文摘要给的实测是:在 2 个 8 卡 A800 节点上、以序列长度 208K(原文写法)训练 Llama3-8B,达到 47% 的 MFU;同时它系统比较了 SP 与 DP/TP/ZeRO/PP 的通信与显存成本,并给出混合 4D 并行的设计建议。47% MFU 要放回它的语境:这是一个「8B 模型 + 208K序列 + 16 卡」的具体配置,不是「长上下文训练的通用效率」。
8. 工程选型:CP 度怎么定
把上面的公式收成一张可操作的判断表。核心只有一条:先算单步强度,再决定并行度。
表里的 / 指二维分解中序列维与头维各自的度数,。
| 维度 | 环形(Ring / Striped) | Ulysses(all-to-all) | USP(二维) |
|---|---|---|---|
| 切分对象 | 序列(连续块或条带) | 序列,注意力前后各一次重排 | 头 + 序列同时切 |
| 每设备持有的激活 | 个 token、全部头 | 全部 、 个头 | 个 token、 个头 |
| 通信原语 | 点对点接力(send/recv) | all-to-all | 两者混用 |
| 每设备每层接收量 | 介于两者之间,按分解比例 | ||
| 硬约束 | 无明显整除约束 | 两个维度都要整除 | |
| 因果负载 | 天然不均,需条带化 | 按头均衡(但受整除约束) | 序列维仍需均衡 |
| 拓扑敏感性 | 高(链式依赖) | 中(依赖 all-to-all 带宽) | 低 |
| 主要风险 | 高并行度下退化为通信瓶颈 | 小 batch 时 all-to-all 启动开销占比高 | 实现复杂、调参面变宽 |
具体挑参数时,我会按这个顺序走:
- 先算单步强度:,训练若是因果的再乘 0.5(有效计算减半)。
- 再比机器: 要和 比。做容量规划时用峰值算力(保守,给出更小的并行度上限);判断「通信是否已被藏住」时用实测有效算力。两者方向相反:峰值 → 通信占比被高估 → 上限偏小;实测有效算力 → 占比被低估 → 上限偏大,但整步更慢——换句话说,有效算力越低,通信越容易被藏住。别把两者的结论混用。
- 再看拓扑:同一台机器内的 NVLink(单向数值见上)和跨节点的 IB(几十 GB/s)差一个数量级,跨节点时并行度上限会掉到个位数。
- 最后看对齐:序列长度和并行度最好让每设备 token 数是 2 的幂且不小于块大小,否则块边界会浪费一部分计算。
一个具体的反面例子:8K 序列、GQA 4、跨节点 IB。,而 。此时逐块重叠的条件不成立,通信开销可能抵消部分甚至全部并行收益——但是否真为负收益,要用实测端到端时间比较,不能只凭这个比值判决;这个配置下更值得先试 TP 或 PP,而不是把 CP 度往上加。
9. 论文之间不能横向相加(数字口径)
这一节是给「引用这些数字」的人看的。上面五篇论文各自报了一个漂亮数字,但它们测的东西不是同一件事,放在一句话里并列会立刻失真。
| 论文 | 报出的数字(原文口径) | 测的是什么 | 不能怎么读 |
|---|---|---|---|
| BPT(2023-05-30 提交) | 可训练序列最高可达朴素 Transformer 的 32 倍、比此前省显存方法最高 4 倍(原文 up to) | 可训练的最大序列长度(显存口径) | 不是速度倍数,也不是吞吐提升 |
| Ring Attention(2023-10-03 提交) | 序列长度可达此前方法的设备数倍、支持百万级 token 上下文 | 显存上界与可用上下文长度 | 不是「8 卡 8 倍速」 |
| Striped Attention(2023-11-15 提交) | 256k token 端到端吞吐最高 1.45 倍;16 块 TPUv4、786k token 时 1.65 倍 | 相对原始环形注意力、因果训练的端到端吞吐 | 不是利用率从 56.3% 到 100% 的 1.78 倍(1.78 是本文示意模型值) |
| DeepSpeed-Ulysses(2023-09-25 提交) | 摘要并列报告:序列长 4 倍、训练快 2.5 倍;并称序列与设备同比例增长时通信量恒定 | 端到端训练吞吐 + 理论通信分析 | 摘要没有说明这两个数字是否来自同一次对照实验,不应替它补写实验条件 |
| USP(2024-05-13 提交) | 2 个 8 卡 A800、Llama3-8B、208K 序列下 47% MFU | 特定配置下的模型算力利用率 | 不是通用效率上限,也不是与前面几篇同条件对比 |
三条口径纪律,值得写进任何一份长上下文方案里:
第一,「长度倍数」与「速度倍数」是两个量纲。BPT 的 32 倍、环形的「设备数倍」都是显存意义上的,它们回答「能不能装下」;Striped 的 1.45 倍、Ulysses 的 2.5 倍回答「快不快」。把前者的数字贴到后者的位置,是这类文章最常见的错误。
第二,MFU 这类比率必须带配置。47% MFU 是在 16 卡、8B 模型、208K 序列下的读数;换成 64 卡或换成 70B 模型,同一个实现的 MFU 会大幅变化。凡是看到「我们达到了 X% MFU」而不给序列长度、模型规模、卡型与网络,基本等于没给。
第三,长度的写法不统一,读数前先换算。本文算例固定 262,144 token;标题里的「约 25 万」是近似称呼;论文实验保留摘要原写法(256k、786k、208K),不强行统一进制;「4K 文档」是与长窗口不同的任务形状,不是同一算例的参数变化。
本文自己算的那批数字(4.40 TB、17.2 GB、67 MB、149,797 FLOP/byte、131,072 FLOP/byte、451 毫秒、3.13 毫秒、18.8 毫秒、0.587 GB、并行度上限 26.5 / 6.6 / 1.7)全部属于「按公开公式代入公开规格」的推导值,不是任何论文的实测,也不是在这台机器上跑出来的。它们的作用是给出量级与判断方向,不能当作性能承诺。
10. 边界与未解
必须把这篇文章的能力边界说清楚,否则上面那些漂亮的比值会被误用。
第一,本文没有实测。 所有性能数字要么是论文摘要里的原文口径,要么是按公开公式代入公开规格的推导值。真实的环形注意力实现还要处理通信与计算的重叠粒度、CUDA stream 调度、在线 softmax 的数值精度、以及不同框架的 kernel 融合差异——这些都可能让「理论 0.7% 的通信开销」在实际训练里显著变差,但变差多少取决于实现,本文没有实测数据,因此不给具体百分比。
第二,峰值算力是理想值,用它算 会高估通信占比。 我用 312 TFLOPS(A100 bf16 稠密)做分母,真实训练 MFU 常在 30–50%,实测有效算力只有峰值的三到五成。用峰值算出的 偏大、通信占比偏大,属于保守估计;用实测值算则偏乐观。做容量规划用前者,判断「通信是否已藏住」用后者,两者结论不能互换:有效算力越低,通信越容易被藏住,但整体也越慢。
第三,负载均衡的收益依赖实现质量。 条带切分把示意模型的 56.3% 往上推,但它同时改变了 token 的物理排布,位置编码、KV 的收集、后续层的连续访存都会受影响;因果对角块能否真正跳过也取决于 tile 粒度。论文报的 1.45 倍是「整体」结果,包含了这些因素;换成另一种实现,这个倍数可能显著不同。
第四,长上下文推理与训练是两套账,但不能反过来断言「推理一定藏不住」。 训练时要存激活、要反向传播,序列并行省的是激活显存;推理时要存 KV cache,decode 阶段每步查询很短、算术强度低,重叠条件比训练苛刻得多。不过 Ring Attention 论文的附录专门分析了 decode/prefill 类推理,并给出 32 块 TPUv5e、LLaMA-7B 的例子,在相应带宽与有效算力下仍可实现重叠。所以正确的说法是「推理能否重叠必须按有效算力、带宽与 KV 块大小另算」,而不是「一定藏不住」。这也是 2025–2026 年 KV cache 分层与跨架构搬运那条线(本站分别于 2026-10-28 讨论统一逻辑地址、2026-10-29 讨论 GPU/NPU 分工)与序列并行常被混谈的原因——它们解决的是不同阶段的瓶颈。
第五,MoE 与变长批次会让静态切分更难。 专家路由本身就会造成设备间负载不均,叠加上因果三角的不均,静态块划分很难同时照顾两头。截至 2026-11-03,这条线上公开的成熟做法看起来还不多——但这只是本文作者的印象:本轮只读了五篇论文摘要,没有做系统调研,不应当作行业结论。
第六,本文没有覆盖数值等价性的细节。 论文都强调「精确算法」,指的是数学上与一次性计算等价;但浮点下不同累加顺序会带来微小差异,长时间训练里这种差异会不会被放大,取决于优化器与精度策略,本文没有展开。
11. 把公式变成一次实测:三步判定法
上面的推导全部可以用一小时内的一次实测钉住。三步,只需要小规模作业,不必等大训练跑完。
第一步:测有效带宽,不要看规格表。 用 nccl-tests 的 all_reduce_perf 在目标拓扑(同机 NVLink 或跨机 IB)上跑一次中等消息大小(如 128 MB),读它打印的 busbw(有效带宽,单位 GB/s)。环形接力走的是点对点,严格说应该用 sendrecv_perf 测;两者差一个量级时(例如 all-reduce 走 NVLS 加速而 p2p 没有),要按点对点的数字算。规格表上的数值是上限,实测常见只有它的六七成——而且要分清厂商标的是单向还是双向。
第二步:测单步计算时间,算出有效算力。 拿一个与目标形状相同的小作业(同分片长度、同头数、同头维),用 profiler 取单层注意力的中位耗时,反推有效 FLOPS。这个数字通常只有峰值的 30–50%,而它才是「通信会不会被藏住」这个问题该用的分母。
第三步:代入判据。 用第一步的带宽算 ,用第二步的有效算力算单步计算时间与单步通信时间,得到通信占比。
这里说的「通信占单步时间的比例」只有一个口径:单步接收时间 ÷ 单步计算时间(都取实测中位数,不扣除重叠),不是「通信时间 ÷ 总训练时间」,也不是「扣掉重叠后暴露出来的等待」。5% 与 15% 两个分界是本文给出的经验启发式,不是任何论文的结论,也不是理论判据:
| 通信接收时间 / 单步计算时间 | 本文的读法 | 建议动作 |
|---|---|---|
| 小于 5% | 重叠余地大 | 按当前并行度试跑,重点看别的瓶颈 |
| 5% – 15% | 重叠能否完全藏住取决于实现 | 加大分片、减少并行度、或换更快的互联,并实测端到端时间 |
| 大于 15% | 通信开销已不可忽视 | 降并行度、考虑 all-to-all 形态、或改用 TP/PP;是否负收益必须实测 |
(注意:即使比值到 20%,也不等于「通信主导」——它只说明通信是计算的 20%;在完全重叠的实现里,它可能仍不增加墙钟时间。表里第三行写的是「不可忽视」,不是「主导」。)
这个表的价值在于它的两个参数——eta 与有效算力——都取自你自己集群的实测,而不是别人论文里的配置。同一条公式在 NVLink 机器上给出「8 路很轻松」,在同一批机器的跨节点集群上可能给出「最多 4 路」。
若手上还没有集群,只能用峰值算力做纸上量级估算:它能排除明显不划算的配置(例如短序列 + 高并行度),但不能据此宣布「通信已被藏住」——后者必须实测。
12. 附:五个常见误解
整理这篇文章时反复出现的五个误读,逐条给一句反证。
误解一:「8 路序列并行 = 8 倍长、8 倍快」。 8 倍长是显存意义的上界(设备数倍),速度与它无关。速度由单步算术强度与机器算力带宽比决定,可能接近线性,也可能被通信抵消。
误解二:「通信可以完全藏在计算后面」。 只有单步计算时间显著大于单步通信时间才成立。序列越短、并行度越高、网络越差,这个前提越不成立。
误解三:「并行度越高越好,反正显存省得更多」。 强度按约 衰减,而每设备接收量几乎按常数走。N 翻倍,每设备计算减半、接收量不减,摊到每份工作上的通信成本翻倍。
误解四:「条带化只是换个 token 顺序,没有成本」。 它改变了位置编码、KV 收集与访存连续性,还影响对角块能否被跳过。论文的 1.45 倍是端到端结果,已经把成本算进去了。
误解五:「GQA 只影响显存和推理成本」。 在序列并行里, 直接出现在单步强度公式里,也直接决定环形接力的字节数。它是长上下文训练里最便宜的一个杠杆。
13. 与 TP / PP / DP 的组合:长上下文为什么先加 CP
序列并行不是替代品,它是 4D 并行里的第四个维度。总设备数等于四个维度的乘积:
四个维度各自解决不同的瓶颈,这是判断「该加哪一个」的唯一依据:
| 维度 | 解决什么瓶颈 | 每设备每层的通信量级 | 通信原语 | 适合的拓扑 |
|---|---|---|---|---|
| DP | 吞吐(样本不够多) | 梯度:与参数量成正比 | all-reduce | 跨节点可接受 |
| TP | 权重与单层激活装不下 | (两次激活 all-reduce) | all-reduce | 必须高带宽(同机) |
| PP | 层数太多、权重装不下 | 只传边界激活 | 点对点 | 跨节点 |
| CP | 单条序列的激活装不下 | 点对点 / all-to-all | 跨节点可接受(环形) |
注意第三列:在同一个配置(、hidden 、bf16)下,TP 每设备每层要搬
而 CP 只要 0.94 GB,相差约 9 倍。这个差距的来源有三层:
- TP 每层要做两次激活 all-reduce(注意力后、MLP 后),CP 每层只走一遍 KV。
- all-reduce 在环形算法下每设备要搬接近两倍的输入量,而 CP 的接力是单向点对点。
- CP 搬的是 KV(8 个头),TP 搬的是完整隐藏状态(32 个头宽度);GQA 的折扣只对 CP 生效。
这里两个数都是前向激活/注意力通信的近似,不是完整训练的正反向总通信;「9 倍」省略了 all-reduce 与 KV 接收各自的 因子(都保留时约为 8 倍),所以只应读作量级。
所以「长上下文训练应该优先加 CP 而不是 TP」这句话,在通信量上是有依据的。但它有三个前提,缺一条就不成立:
- TP 通常留在机内。NVLink 单向 300 GB/s 对 IB 50 GB/s 是 6 倍,把 9 倍的字节差抵掉之后,跨机 CP 未必比机内 TP 便宜。真正该比的不是字节数,是「字节数 ÷ 该链路的单向带宽」。
- CP 只在长序列上占优。序列长度掉到 8K,CP 的强度掉两个数量级,上面所有结论反转。
- CP 与 TP 的收益不能相乘。两者都在减每设备的显存,但 TP 减的是权重与隐藏状态,CP 减的是激活;同时开两个,边际收益递减很快,而通信成本是相加的。
一个 64 卡的组合示例(仅示意维度乘积):、、、,乘积 64。要算它的通信账,必须先把四件事写清:① 每个数字统计的是哪一段(TP 组内 all-reduce / CP 组内点对点);② 该配置下的序列长度与批大小;③ 是发送量、接收量还是收发合计;④ 链路是机内 NVLink 还是跨机 IB。缺任一条,把前面 8.59 GB / 0.94 GB 直接搬过来都是错的——因为 、 与进程组都变了。
14. 小结
把全文压成五句话:
- 序列并行把「显存墙」换成「通信墙」:省下的是激活,付出的是每层把 KV 块转一圈。
- 能不能有条件地白拿,只看一个比值: 是否大于机器的「算力 ÷ 单向带宽」。
- 这个比值与批大小、头维度无关,只受 GQA 头比、序列长度、并行度影响——所以长序列是序列并行的前提,不是结果。
- 因果训练会额外砍掉一半有效计算,并且把工作量按约 分布到连续分片对应的设备上,示意利用率约 ;条带化是把这份不均摊平的最简手段。
- 所有「倍数」都必须带口径:长度倍数不是速度倍数,MFU 不是通用效率,跨论文的数字不能相加。
如果你正在决定「要不要为一条 128K 的训练任务上 8 路序列并行」,先做两件事:① 算一遍单步强度(一张纸就够);② 用实测有效算力与实测单向带宽算 ——这一步必须在目标集群上测,纸上推不出来。第 11 节给出三步实测法。
📋 来源与核验记录
本轮(2026-11-03)逐条打开并核读的一手来源如下。所有摘要引文均取自 arXiv 摘要页原文,未使用二手转述;文中引用的数字只取摘要中明确写出的口径。
- Liu & Abbeel,Blockwise Parallel Transformer for Large Context Models,arXiv:2305.19370(v1 2023-05-30,v3 2023-08-28)。本轮读取摘要页:https://arxiv.org/abs/2305.19370 。用于「块化后仍与总序列长度成正比」与「比朴素 Transformer 最高 32 倍、比此前省显存方法最高 4 倍(up to)」两处。
- Liu, Zaharia, Abbeel,Ring Attention with Blockwise Transformers for Near-Infinite Context,arXiv:2310.01889(v1 2023-10-03,v4 2023-11-27)。本轮读取摘要页:https://arxiv.org/abs/2310.01889 。用于环形接力算法、KV 传输与块化注意力完全重叠、以及「序列长度可达此前方法的设备数倍」与百万级 token 上下文的表述。
- Brandon 等,Striped Attention: Faster Ring Attention for Causal Transformers,arXiv:2311.09431(2023-11-15)。本轮读取摘要页:https://arxiv.org/abs/2311.09431 。用于因果三角导致的负载不均、条带切分定义、以及 256k token 下最高 1.45 倍与 16 块 TPUv4 / 786k token 下 1.65 倍的实测口径。
- Jacobs 等,DeepSpeed Ulysses: System Optimizations for Enabling Training of Extreme Long Sequence Transformer Models,arXiv:2309.14509(v1 2023-09-25,v2 2023-10-04)。本轮读取摘要页:https://arxiv.org/abs/2309.14509 。用于 all-to-all 重排、通信量在序列与设备同比例增长时恒定的表述、以及摘要并列报告的「4 倍长、2.5 倍快于当时 SOTA 基线」。
- Fang & Zhao,USP: A Unified Sequence Parallelism Approach for Long Context Generative AI,arXiv:2405.07719(v1 2024-05-13,v5 2024-07-02)。本轮读取摘要页:https://arxiv.org/abs/2405.07719 。用于二维分解、对拓扑更鲁棒的表述、以及 2×8 A800 / Llama3-8B / 208K 序列下 47% MFU 的口径。
本文自行推导(非任何论文的实测数字,仅用于给量级):
- 未块化时单层得分矩阵显存 TB(、、、bf16);查询块 × 全部键的临时量 GB();查询块 × 单键块的得分窗口 MB。
- 接收口径 GB;NVLink 单向 300 GB/s 下整层 3.13 毫秒、单块 0.447 毫秒;IB 50 GB/s 下 18.8 毫秒;计算 451 毫秒(312 TFLOPS 峰值);通信/计算 = 0.69%(NVLink)与 4.2%(IB)。
- 单步强度 FLOP/byte;整层强度 FLOP/byte。
- 机器算力带宽比 :A100 单向 NVLink 约 、H100 与 400 Gb/s IB 约 、A100 与 400 Gb/s IB 约 FLOP/byte。
- 并行度上限(按 、):128K 约 26.5、32K 约 6.6、8K 约 1.7。
- Ulysses 每设备每层接收量 GB(GQA)与 GB(MHA),对照环形 0.94 GB。
- 因果示意模型:对角块按整块计利用率 ( 时 56.3%);对角块只算下三角时 (53.3%);1.78 是示意模型下的最大最小比,不是论文上限。
- TP 与 CP 的前向通信量近似 8.59 GB 与 0.94 GB(约 9 倍,保留 因子约 8 倍)。
- 文中百分比全部来自本文推导或公开经验区间,不取自任何论文摘要:通信接收/单步计算 0.69%(整层)、0.79%(单步)、0.32%(MFU 40% 时)、4.2%(IB)、0.7%(约整层、四舍五入);单步强度与整层强度相差约 12%((N−1)/N);MFU 30%–50% 与「峰值的三到五成」为公开经验区间;判据表 5% / 15% 为本文经验分档;§12 误解二所用 20% 仅为举例说明「比值高≠通信主导」,不是观测值;因果有效计算折半对应 50% / 100% 两个参照。
- 因果示意模型的利用率:N=2/4/8/16/32 时分别为 75% / 62.5% / 56.3% / 53.1% / 51.6%(按 (N+1)/2N);对角块只算下三角时 N=8 为 53.3%(按 N/(2N−1))。
- 一条 262,144 token 与一条 4,096 token 的注意力工作量比约 4,100;混合批里长样本占 98.5%——这只是该特定混合例子的推导值,不是语料统计。
未核验项与限制:
- 未在真实集群上复现任何实验;未编译或运行 Ring Attention / Striped Attention / Ulysses / USP 的开源代码。
- 峰值算力与带宽取自厂商公开规格的量级,未做本机实测;A100 312 TFLOPS 为 bf16 稠密值(不含稀疏),H100 与 IB 的 为量级估算。
- 5% / 15% 两个判据阈值是本文的经验启发式,没有论文或实测支撑;§5 的「按长度分桶」与 §10 的「成熟做法不多」均为作者工程印象,没有统计支撑。
- 论文摘要未给出的实现细节(默认块大小、是否跳过无效 KV 发送、在线 softmax 的数值策略)本文不做推测;正文中凡涉及实现差异处均标注为「取决于实现」或「实现风险」。
- 本文不评价各实现在真实业务负载下的优劣,只做机制与量级分析。