序列并行-负载均衡

序列并行

  • [🚀 序列并行 (Sequence Parallelism) 详解与负载均衡优化](#🚀 序列并行 (Sequence Parallelism) 详解与负载均衡优化)
    • [1. 为什么需要序列并行?(Background)](#1. 为什么需要序列并行?(Background))
    • [2. 序列并行是怎么切的?(Mechanism)](#2. 序列并行是怎么切的?(Mechanism))
      • 流派一:Megatron-SP (侧重省显存)
      • [流派二:Context Parallelism (DeepSpeed Ulysses / Ring Attention) (侧重长文本计算)](#流派二:Context Parallelism (DeepSpeed Ulysses / Ring Attention) (侧重长文本计算))
    • [3. 核心痛点:负载不均衡 (The Load Imbalance)](#3. 核心痛点:负载不均衡 (The Load Imbalance))
    • [4. 负载均衡优化方案 (Optimization Solutions)](#4. 负载均衡优化方案 (Optimization Solutions))
      • [方案 A:锯齿状切分 (Striped / Cyclic Partitioning) ------ **最推荐**](#方案 A:锯齿状切分 (Striped / Cyclic Partitioning) —— 最推荐)
      • [方案 B:动态调度与工作窃取 (Work Stealing)](#方案 B:动态调度与工作窃取 (Work Stealing))
      • [方案 C:2D 负载均衡 (Block-wise Ring Attention)](#方案 C:2D 负载均衡 (Block-wise Ring Attention))
    • [5. 总结](#5. 总结)
      • [💡 总结图谱](#💡 总结图谱)

序列并行 (Sequence Parallelism, SP) && 负载均衡 (Load Balancing)

序列并行 主要是为了解决 Tensor Parallel (TP) 无法处理 超长上下文 (Long Context) 的问题(显存爆炸)。


🚀 序列并行 (Sequence Parallelism) 详解与负载均衡优化

1. 为什么需要序列并行?(Background)

在传统的 Megatron-LM Tensor Parallel (TP) 中:

  • 切分维度: 主要切分 Hidden Dimension ( H H H)。
  • 显存瓶颈: 虽然权重切分了,但 LayerNormDropout 操作通常是复制 (Replicated) 的。这意味着每张卡都必须存储完整的 [ B a t c h , S e q L e n , H i d d e n ] [Batch, SeqLen, Hidden] [Batch,SeqLen,Hidden] 的激活值。
  • 痛点: 当 Sequence Length ( L L L) 达到 128k 或 1M 时,光是存储这个激活值,单卡显存就爆了。

序列并行 (SP) 的核心思想:

不仅切分 Hidden 维度,在 LayerNorm 和 Attention 的维度上,沿着 Sequence Length ( L L L) 进行物理切分 。让单卡只需要存储 1 / N 1/N 1/N 的序列数据。


2. 序列并行是怎么切的?(Mechanism)

目前业界主要有两种 SP 的流派

流派一:Megatron-SP (侧重省显存)

这是 Megatron-LM v3 提出的。

  • 原理: 在 Transformer 的 LayerNorm 和 Dropout 阶段,把数据按 L L L 切分。
  • 通信变换: 将 TP 中的一次 All-Reduce 拆解为 Reduce-ScatterAll-Gather
    • Forward: MLP 输出 (TP行切) → Reduce-Scatter \xrightarrow{\text{Reduce-Scatter}} Reduce-Scatter 每个卡拿到 L / N L/N L/N 的数据 → LayerNorm \xrightarrow{\text{LayerNorm}} LayerNorm → All-Gather \xrightarrow{\text{All-Gather}} All-Gather 恢复全量 L L L 给 Attention。
  • 收益: 激活值显存占用降低到 1 / N 1/N 1/N。

流派二:Context Parallelism (DeepSpeed Ulysses / Ring Attention) (侧重长文本计算)

这是目前处理 100k+ 长文本的主流()。它直接把 Attention 计算也按 L L L 切分了。

  • KV Cache 切分:
    • TP: 切 Head。
    • SP: 切 Sequence。GPU 0 存第 0~1000 个 Token 的 KV,GPU 1 存第 1001~2000 个 Token 的 KV。
  • Q 切分:
    • GPU 0 负责计算 Query 0~1000 的 Attention 结果。
    • GPU 1 负责计算 Query 1001~2000 的 Attention 结果。

3. 核心痛点:负载不均衡 (The Load Imbalance)

在做 Context Parallelism 时,如果简单地把 Sequence 均分给不同的 GPU,会遇到严重的负载不均。

原因:Causal Mask (因果掩码 / 三角形计算)

Transformer Decoder 是自回归的,第 i i i 个 Token 只能看前 i i i 个 Token。Attention 矩阵是一个下三角矩阵

  • 场景: 序列长度 L = 8000 L=8000 L=8000,2 张卡 (GPU 0, GPU 1)。
  • 朴素切分 (Naive Split):
    • GPU 0 (负责 Seq 0~3999):
      • 第 0 个 Token:看 1 个 KV。
      • 第 3999 个 Token:看 4000 个 KV。
      • 平均计算量: ∝ 1 2 × 4000 2 \propto \frac{1}{2} \times 4000^2 ∝21×40002 (梯形面积小)。
    • GPU 1 (负责 Seq 4000~7999):
      • 第 4000 个 Token:看 4001 个 KV (前卡的 4000 + 自己的 1)。
      • 第 7999 个 Token:看 8000 个 KV。
      • 平均计算量: ∝ 1 2 × 8000 2 − GPU 0 Area \propto \frac{1}{2} \times 8000^2 - \text{GPU 0 Area} ∝21×80002−GPU 0 Area (梯形面积极大)。

后果: GPU 1 累死(计算量是 GPU 0 的 3 倍),GPU 0 算完后在那空转(Bubble)。木桶效应导致整体性能极差。


4. 负载均衡优化方案 (Optimization Solutions)

针对片内分布式或多卡集群,如何解决"三角形计算"带来的不均?

方案 A:锯齿状切分 (Striped / Cyclic Partitioning) ------ 最推荐

这是 DeepSpeed UlyssesRing Attention 常用的优化策略。

  • 思路: 不要"切大块",而是"切碎了轮流分"。
  • 做法: 假设有 2 张卡。
    • GPU 0 负责: Token { 0 , 2 , 4 , 6 , ... , 2 k } \{0, 2, 4, 6, \dots, 2k\} {0,2,4,6,...,2k}
    • GPU 1 负责: Token { 1 , 3 , 5 , 7 , ... , 2 k + 1 } \{1, 3, 5, 7, \dots, 2k+1\} {1,3,5,7,...,2k+1}
  • 效果:
    • GPU 0 算的 Token 位置虽然靠前,但和 GPU 1 几乎是交错的。
    • Token 2000 (GPU 0) 和 Token 2001 (GPU 1) 的计算负载(需要看的 KV 长度)几乎一样。
    • 宏观上,两张卡的计算负载完全平衡。

方案 B:动态调度与工作窃取 (Work Stealing)

  • 思路: 把 Attention 计算拆解成更小的 Tile (任务块)
    • 任务池: T a s k ( Q i , K V a l l ) Task(Q_i, KV_{all}) Task(Qi,KVall)。
    • 每个 Tile 的计算量是不同的(越靠后的 Q Q Q,计算量越大)。
  • 做法:
    • 使用一个全局调度器(或原子计数器)。
    • 空闲的核心去领任务。
    • 优化技巧: Longest Job First (LJF)。优先把靠后的、计算量大的 Token 分发出去,防止最后时刻出现长尾延迟。

方案 C:2D 负载均衡 (Block-wise Ring Attention)

  • 思路: 将 Attention 矩阵的计算视为 ( Q , K ) (Q, K) (Q,K) 网格。
  • 做法:
    • 让 GPU 0 计算右上角的块(本来是被 Mask 掉的,可以不存数据,但可以分配逻辑任务)。
    • 注:这种方法比较理论,实际工程中主要用方案 A。

5. 总结

序列并行有什么问题?怎么解决负载不均?

"序列并行(Context Parallelism)最大的挑战在于 Causal Mask 带来的计算不均衡

  1. 现象: Attention 矩阵是下三角的。如果按顺序物理切分 Sequence,负责后端序列的计算单元(Core/GPU)计算量会远大于负责前端序列的单元(因为后面的 Token 要看所有的历史 KV),导致严重的 Pipeline Bubble

  2. 通用解法 (Striped Partitioning):

    目前业界(如 DeepSpeed Ulysses)通用的解法是采用锯齿状(Cyclic)切分

    不把序列连续切分,而是按 Token_ID % Device_Num 进行分配。

    这样,每个 Device 都均匀地持有'头部'(计算量小)和'尾部'(计算量大)的 Token,从统计学上将计算负载完美拉平

  3. 针对'片内分布式'的思考:

    在片内多核架构下,这种 Striped 逻辑依然适用。

    但考虑到片内 NoC (片上网络) 的带宽优势,我们可以做得更激进:

    实现一个硬件感知的动态调度器 。将 Prefill 阶段的 Attention 计算拆解为细粒度的 Tile ,根据各个 Memory Block 的负载情况动态分发计算任务,这比静态的 Striped 切分更能适应动态变化的推理请求(尤其是 Chunked Prefill 场景下)。"


💡 总结图谱

方案 切分逻辑 负载均衡能力 通信复杂度 适用场景
朴素切分 [0-N] 给卡1, [N-2N] 给卡2 ❌ 极差 (三角形不均) BERT (双向注意力)
Striped切分 0, 2, 4 给卡1, 1, 3, 5 给卡2 完美均衡 中 (需 All-to-All) GPT/Llama (自回归)
Ring Attention 传递 KV Block 绕圈算 ✅ 均衡 (时间换空间) 高 (重叠计算与通信) 超长文本 (1M+)
相关推荐
optimistic_chen2 小时前
【Redis系列】分布式锁
linux·数据库·redis·分布式·缓存
byzh_rc2 小时前
[AI数学从入门到入土] 线性代数基础
人工智能·线性代数·机器学习
Aurora@Hui2 小时前
MIT NANDA:Networked Agents and Decentralized AI
人工智能
小二·2 小时前
Python Web 开发进阶实战:AI 原生应用商店 —— 在 Flask + Vue 中构建模型即服务(MaaS)与智能体分发平台
前端·人工智能·python
Aaron_9452 小时前
AnythingLLM:全栈私有化AI聊天应用平台的深度解析
人工智能
KG_LLM图谱增强大模型2 小时前
多智能体大语言模型框架赋能医学等多领域低资源命名实体识别:知识检索、消歧与反思分析的创新实践
人工智能·语言模型·自然语言处理
SmartBrain2 小时前
RAG、RAGFlow 与 Agentic RAG技术对比分析
人工智能·语言模型
guygg882 小时前
基于BP神经网络的迭代优化实现(MATLAB)
人工智能·神经网络·matlab