#十九、分布式与系统方向的标准答案速查区

#29. DP / TP / PP 分别是什么?

#标准答案

DP(Data Parallel)是每张卡放完整模型、处理不同数据,再同步梯度。它实现简单,但模型必须单卡放得下,而且梯度同步开销会随着规模增大。

TP(Tensor Parallel)是在单层内部把大矩阵拆到多张卡上共同计算,适合单层太大、单卡放不下的情况,但层内通信非常频繁,对高速互联依赖很强。

PP(Pipeline Parallel)是按层把模型切成多个 stage,让不同卡负责不同层,再通过 micro-batch 流水线执行。它适合超深模型,但会有 pipeline bubble 和负载均衡问题。

一句话总结:DP 切数据,TP 切层内矩阵,PP 切网络层。


#深度解析

1. 三种并行的切分维度对比

维度 DP (Data Parallel) TP (Tensor Parallel) PP (Pipeline Parallel)
切分对象 训练数据 (batch) 单层内的权重矩阵 模型的层 (layer)
切分方向 数据维度 (N) 特征/隐藏维度 (d) 层维度 (L)
通信操作 all-reduce (梯度同步) all-reduce / all-gather (层内激活) point-to-point (stage 间)
通信频率 每步一次 每层前向/反向各一次 每 stage 边界一次
单卡模型 完整模型 部分权重 (如 1/2, 1/4) 部分层 (如 1/4 层数)
适用场景 模型能放下,需加速训练 单层太大放不下 层数太多、模型太深
扩展上限 受 batch size 限制 受 hidden dim 限制 (通常 ≤8) 受层数限制

2. 形象化类比

把训练大模型比作工厂生产:

  • DP:多组工人,每组有完整设备,各加工不同批次的原料(数据)
  • TP:一组工人合作操作一台超大设备,每人负责设备的一部分(矩阵的不同列/行)
  • PP:流水线,工人 A 做第一道工序,工人 B 做第二道,产品依次传递

3. 为什么单一并行不够?

以训练 GPT-3 175B 为例:

  • 模型权重 FP16:350 GB → 单卡放不下 → 需要 TP 或 PP
  • 单层 FFN 参数量:4 × d_model × d_ff = 4 × 12288 × 49152 ≈ 2.4B = 4.8 GB → 单卡单层也紧张 → 需要 TP
  • 层数 96 层 → 适合 PP
  • 最终配置:TP=8(单机内)× PP=12(跨机)× DP=?(视 batch size 而定)

4. 三种并行的通信量定量分析

假设模型参数量 P,数据并行度 D,张量并行度 T,流水线并行度 Pp

并行方式 每步通信量 通信频率 对带宽要求
DP 2P (梯度 all-reduce) 每步一次
TP 2 × batch × seq × d / T (激活值) 每层两次 极高
PP 2 × batch × seq × d (激活值) 每 stage 两次

TP 的通信最频繁且对延迟敏感,因此 TP 通常只在单机内(NVLink)使用。

5. 面试官常见深挖追问

  • "DP 的梯度同步用 all-reduce,能不能用 reduce-scatter + all-gather 替代?"
    • 答:可以,而且某些场景下更优。Ring all-reduce 本质是 reduce-scatter + all-gather 的组合。在带宽受限环境下,reduce-scatter + all-gather 的带宽利用率可能更好。此外,FSDP/ZeRO-3 就利用了 reduce-scatter + all-gather 来实现参数分片的梯度同步。
  • "TP 为什么通常不超过 8?"
    • 答:1)通信开销:TP 每层的激活需要 all-reduce,切得越碎通信次数越多;2)计算效率:矩阵切太碎后,每张卡的计算量太小,kernel launch 开销占比上升;3)硬件限制:一台机器通常 8 张 GPU(NVLink 全互联),超过 8 需要跨机通信,带宽骤降。因此 TP 通常限制在单机内。
  • "PP 的 bubble 怎么计算?"
    • 答:Pipeline bubble = (Pp - 1) / (Pp + m - 1),其中 Pp 是 pipeline stage 数,m 是 micro-batch 数。例如 4 个 stage、8 个 micro-batch 时,bubble = 3/11 ≈ 27%。增加 micro-batch 可以减小 bubble,但不能无限增大(受显存限制)。

#30. 为什么大模型训练通常需要混合并行?

#标准答案

因为单一并行方式通常只能解决一个问题。

  • DP 解决吞吐扩展,但模型还是要单卡放得下;
  • TP 解决单层太大,但通信很重;
  • PP 解决网络太深,但有流水线气泡。

真实大模型通常参数太多、层数太深、训练吞吐要求又高,所以必须组合使用,比如 TP + PP + DP,再叠加 ZeRO/FSDP 去进一步切状态。


#深度解析

1. 单一并行策略的局限性

并行方式 解决的问题 无法解决的问题 限制原因
纯 DP 加速数据吞吐 模型太大单卡放不下 每张卡需存完整模型
纯 TP 单层太大放不下 层数太多总参数量过大 通常最多切 8 份
纯 PP 层数太多放不下 batch size 太小效率低 bubble overhead
纯 ZeRO-3 显存不足 单 layer 超出单卡容量 只分片状态,不切计算

2. 混合并行的层次选择原则

决策流程(从里到外):

Step 1: 单层能否放下?
  └─ 否 → TP(张量并行,通常单机 8 卡)

Step 2: 模型总参数量是否超出单机?
  └─ 是 → PP(流水线并行,跨机切层)

Step 3: batch size 是否足够大?
  └─ 是 → DP(数据并行,复制到多组)

Step 4: 优化器状态是否还占太多显存?
  └─ 是 → ZeRO/FSDP(进一步分片状态)

3. 典型模型的混合并行配置

模型 参数 TP PP DP ZeRO GPU 总数
GPT-3 175B 175B 8 12 ~16 ZeRO-1 ~1536
LLaMA-2 70B 70B 8 8 4 FSDP 256
GPT-4 (估计) ~1.8T 8 16 大量 ZeRO-3 数万

4. 通信层次与硬件亲和性

并行层 通信类型 推荐硬件 带宽要求
TP all-reduce (频繁) 单机 NVLink 极高 (>400 GB/s)
PP p2p send/recv 同机柜 IB/RoCE 高 (>50 GB/s)
DP all-reduce (梯度) 跨机 IB/RoCE/以太网 中 (10-50 GB/s)
ZeRO all-gather / reduce-scatter 同机房网络

设计原则:高带宽需求的并行放在物理距离近的设备上

5. 面试官常见深挖追问

  • "为什么 TP 通常和 PP 不共用同一组卡?"
    • 答:TP 需要极高的通信带宽(NVLink),通常限制在单机 8 卡内。PP 的通信量相对较小,可以跨机。如果把 TP 扩展到跨机,通信会成为严重瓶颈。因此典型配置是:单机内 TP(8 卡),机柜间 PP,数据中心间 DP。
  • "如果模型很大但数据很少,怎么配并行策略?"
    • 答:数据少意味着 DP 的扩展空间有限(batch size 小)。此时应优先 TP+PP 把模型铺开,DP 维度可以很小甚至为 1。同时考虑 gradient accumulation 来模拟大 batch。如果显存还是不够,叠加 ZeRO-3/FSDP 进一步节省。
  • "混合并行时,怎么确定每个维度的具体数值?"
    • 答:经验法则:1)TP 先确定(看单层是否放得下,通常 1/2/4/8);2)PP 再确定(看总层数,通常 2-16);3)DP 最后用总 GPU 数除以 (TP×PP) 得到。需要保证每个 stage 的参数量均衡,且 micro-batch 数足够大以减小 bubble。

#31. ZeRO-1/2/3 的核心区别是什么?

#标准答案

核心就是“切得越来越多”。

  1. ZeRO-1:切 optimizer states(优化器状态);
  2. ZeRO-2:再切 gradients(梯度);
  3. ZeRO-3:进一步连 parameters(参数)也切分。

stage 越高,显存越省,但通信和工程复杂度通常也越高。


#深度解析

1. 模型状态显存构成

训练时单卡显存占用(以 Adam 优化器为例):

总显存 = 参数(2 bytes in FP16) + 梯度(2 bytes) + 优化器状态(12 bytes)
       + 激活值 + 临时缓存

优化器状态 = 动量(momentum) + 二阶矩(variance) + 主权重(FP32)
           = 4 + 4 + 4 = 12 bytes / 参数

对于 1B 参数模型:

  • 参数:2 GB (FP16)
  • 梯度:2 GB
  • 优化器状态:12 GB
  • 模型状态合计:16 GB

2. ZeRO 各 Stage 显存节省对比

假设:7B 模型,8 卡,Adam 优化器

组件 无 ZeRO ZeRO-1 ZeRO-2 ZeRO-3
参数 14 GB 14 GB 14 GB 14/8 = 1.75 GB
梯度 14 GB 14 GB 14/8 = 1.75 GB 14/8 = 1.75 GB
优化器状态 84 GB 84/8 = 10.5 GB 84/8 = 10.5 GB 84/8 = 10.5 GB
模型状态小计 112 GB 38.5 GB 26.25 GB 14 GB
节省比例 0% 66% 77% 87.5%

注:以上是理论值,实际还需加上激活值和碎片开销。

3. ZeRO 各 Stage 的通信模式

Stage 通信操作 通信量 额外开销
ZeRO-1 梯度 all-reduce(标准 DDP) 2P
ZeRO-2 梯度 reduce-scatter + 更新后广播 2P 略高
ZeRO-3 参数 all-gather(前向/反向)+ 梯度 reduce-scatter 3-4P/step 明显更高

ZeRO-3 的通信量最大,因为每层前向/反向都需要 all-gather 参数。

4. ZeRO-Offload:进一步省显存

ZeRO-Offload 将优化器状态和计算卸载到 CPU:

  • ZeRO-Offload (Stage 2):优化器状态在 CPU,计算在 GPU
  • ZeRO-Infinity:参数、梯度、优化器状态都可以分页到 NVMe SSD

代价:CPU-GPU/SSD 数据传输成为瓶颈,训练速度下降 10-40%。

5. 面试官常见深挖追问

  • "ZeRO-3 和 FSDP 有什么区别?"
    • 答:核心思想相同(参数分片),但实现细节不同:1)FSDP 是 PyTorch 原生,ZeRO 是 DeepSpeed 的;2)FSDP 的 shard 逻辑更灵活(支持 auto_wrap_policy),ZeRO-3 更自动化但控制粒度较粗;3)FSDP 与 PyTorch 生态集成更好(如 compile、checkpointing),ZeRO 功能更全面(支持 Offload、MoE 等)。面试中可以说"它们解决同一问题,FSDP 更适合 PyTorch 用户,ZeRO 功能更丰富"。
  • "ZeRO-3 训练速度会变慢多少?"
    • 答:取决于模型大小和互联带宽。在 NVLink 环境下(带宽 400+ GB/s),ZeRO-3 的 overhead 通常 5-15%;在 PCIe 环境下(带宽 32 GB/s),overhead 可能 20-40%。因为 ZeRO-3 每层都需要 all-gather 参数,通信量与层数成正比。
  • "什么情况下 ZeRO-2 就够了,不需要上 ZeRO-3?"
    • 答:当模型能放下参数+梯度,只是优化器状态占太多时。例如 7B 模型单卡:参数 14GB + 梯度 14GB = 28GB,加上激活值后可能接近 40GB。如果卡有 40-48GB,ZeRO-2(分片优化器状态到 10.5GB)就够了。但如果卡只有 24GB,就需要 ZeRO-3 进一步分片参数。

#32. FSDPDDP 最本质的差别是什么?

#标准答案

DDP 的前提是每张卡都能放下完整模型,核心是同步梯度;FSDP 则是把参数、梯度和优化器状态按 shard 分散到多卡上持有,在需要时再 all-gather 或聚合。

所以最本质的区别是:

  • DDP 更像”完整复制 + 梯度同步”;
  • FSDP 更像”参数分片 + 按需聚合”。

#深度解析

1. DDP vs FSDP 显存对比(7B 模型,8 卡,Adam)

显存项 DDP FSDP (ZeRO-3等价)
参数 14 GB × 8 = 112 GB 14/8 = 1.75 GB/卡
梯度 14 GB × 8 = 112 GB 14/8 = 1.75 GB/卡
优化器状态 84 GB × 8 = 672 GB 84/8 = 10.5 GB/卡
模型状态总计 896 GB 14 GB/卡
激活值 ~10-20 GB/卡 ~10-20 GB/卡
单卡总显存 ~120+ GB ~30-40 GB

FSDP 将模型状态显存从”每卡完整复制”变为”每卡只存 1/N”。

2. FSDP 的生命周期

前向传播 (Forward):
  1. all-gather 参数: 从其他卡收集当前层需要的完整参数
  2. 计算该层前向
  3. 释放非本 shard 的参数(可选,参数分片)

反向传播 (Backward):
  1. all-gather 参数: 重新收集该层完整参数
  2. 计算梯度
  3. reduce-scatter 梯度: 将梯度规约到对应卡上

参数更新 (Optimizer Step):
  每张卡只更新自己 shard 的参数和优化器状态

3. FSDP 的 wrap 策略

FSDP 需要决定”按什么粒度分片”:

wrap 策略 粒度 优点 缺点
wrap 整个模型 实现简单 每次 all-gather 都要通信全部参数
wrap 每层 (Layer) 通信与计算可重叠 需要手动或自动识别层边界
wrap 每个 Transformer Block 平衡 最常用
wrap 每个 Linear 通信量最小 管理复杂度高

PyTorch FSDP 的 auto_wrap_policy 通常按 TransformerBlock 自动包装。

4. DDP 和 FSDP 的适用场景

场景 推荐方案 原因
模型能放进单卡 DDP 简单、通信少、无分片 overhead
模型太大单卡放不下 FSDP 必须分片才能训练
需要与 TP/PP 混合 FSDP PyTorch 原生,生态兼容性好
追求极致显存节省 FSDP + activation checkpointing + mixed precision 组合拳

5. 面试官常见深挖追问

  • ”FSDP 的前向和反向都需要 all-gather 参数,为什么不会比 DDP 慢很多?”
    • 答:1)FSDP 的 all-gather 是逐层进行的,可以与计算重叠(communication-computation overlap);2)DDP 的梯度 all-reduce 实际上通信量与 FSDP 相当(都是 2P);3)现代网络(NVLink/IB)带宽足够高,通信 overhead 通常在 10-20% 以内。但如果网络带宽低(如以太网),FSDP 的 overhead 会更明显。
  • ”FSDP 能不能和 TP/PP 一起用?”
    • 答:可以,但需要注意层次。典型用法:最内层 TP(单机 8 卡),中间层 FSDP(跨机参数分片),最外层 DP(数据并行)。或者 FSDP 作为 DP 的替代(因为 FSDP 本身就有数据并行的语义)。关键是不能让 FSDP 和 TP 同时切同一层参数,否则分片逻辑会冲突。
  • ”如果 8 张卡用 FSDP 训练 7B 模型,单卡显存大概多少?”
    • 答:模型状态:参数 1.75GB + 梯度 1.75GB + 优化器状态 10.5GB = 14GB。激活值取决于序列长度和 batch size(如 seq=2048, batch=1 时约 5-10GB)。加上临时缓存和碎片,单卡总显存约 25-35GB。因此在 40GB(A100)或 48GB(A6000)卡上可以舒适运行,24GB 卡(3090/4090)则比较紧张。

#33. activation checkpointing 为什么能省显存?代价是什么?

#标准答案

因为训练时显存大头之一是中间激活值。activation checkpointing 的做法是不把所有中间激活都存下来,而是只保留少量 checkpoint,反向传播时再重新计算缺失部分。

所以它省显存的代价是:多做了一次前向的计算,训练时间会变长。

一句话总结:它是“用算力换显存”。


#深度解析

1. 激活值显存占用计算

对于 Transformer Layer(batch_size=B, seq_len=L, hidden_dim=d):

每层激活值 ≈ B × L × d × (常量因子)

具体构成:
- Input: B×L×d
- Q/K/V projection: 3 × B×L×d
- Attention scores: B×num_heads×L×L
- Attention output: B×L×d
- FFN intermediate: B×L×(4d) 或 B×L×(8/3 d) for SwiGLU
- Dropout mask: B×L×d

总计每层 ≈ 34 × B×L×d (标准 Transformer)

以 LLaMA-2 7B(32 层, B=4, L=4096, d=4096)为例:

  • 每层激活值:34 × 4 × 4096 × 4096 ≈ 2.3 GB
  • 32 层总激活值:约 73 GB(FP16)

2. Checkpointing 策略对比

策略 保留的激活值 显存节省 计算代价 适用场景
No Checkpointing 全部 0% 显存充足
Full Checkpointing 仅输入 ~70-80% 1.25-1.35× 显存紧张
Selective Checkpointing 每层输入 + Attention ~50-60% 1.1-1.2× 平衡选择
Layer-wise 每 N 层保留一次 可调 可调 灵活控制

3. 为什么代价是“约 25% 额外计算”?

标准训练:

  • 1 次前向 + 1 次反向 = 1 单位计算

Full Checkpointing:

  • 第 1 次前向(只保留 checkpoint)+ 反向时重算各层前向 + 反向 = 1 + 0.25 = 1.25 单位

为什么是 0.25 而不是 1.0?

  • 反向传播本身也需要前向计算
  • 重算只重算被 checkpoint 的层,其他层仍正常
  • 实际 overhead 通常在 10-30%,取决于 checkpoint 粒度

4. 与其他显存优化的正交性

优化技术 作用对象 与 Checkpointing 关系
Mixed Precision 参数/激活精度 正交,可同时使用
ZeRO/FSDP 模型状态分片 正交,解决不同问题
Gradient Accumulation 有效 batch size 正交,增加激活值
PP 层间分片 部分相关,PP 可减少每卡激活值

5. 面试官常见深挖追问

  • "Activation Checkpointing 和 Gradient Checkpointing 是同一个东西吗?"
    • 答:通常是同一个概念的不同叫法。PyTorch 中叫 torch.utils.checkpoint,DeepSpeed 中叫 activation checkpointing。核心思想一致:保留关键中间结果(checkpoint),反向时重算其他部分。有些文献区分:保留 gradient 的 checkpoint 叫 gradient checkpointing,保留 activation 的叫 activation checkpointing,但实践中往往混用。
  • "如果只有 Attention 层的激活值占显存大头,能不能只 checkpoint Attention?"
    • 答:可以,这叫 Selective Checkpointing。实践中通常只 checkpoint Transformer Block 的输入和 Attention 部分的中间结果,FFN 部分不重算。这样可以在显存节省和计算代价之间取得更好平衡。PyTorch FSDP 的 selective_activation_checkpointing 就支持这种策略。
  • "Checkpointing 和 Pipeline Parallelism 一起用会怎样?"
    • 答:两者配合效果好。PP 已经把模型按层分到不同卡上,每张卡只负责部分层,激活值本就更少。再加上 checkpointing 可以进一步减少每卡的激活值。但需要注意:PP 的 bubble 本身就有计算空闲,checkpointing 的重算可以部分填充这些空闲,有时反而能减小总体 overhead。

#34. 为什么多卡训练经常扩展不到线性加速?

#标准答案

因为一旦规模变大,系统里就不再只有纯计算,还有大量同步、通信、等待和调度开销。

最常见的原因包括:

  1. 梯度同步或参数聚合通信太重;
  2. TP/PP 切分带来的额外同步;
  3. pipeline bubble;
  4. 数据加载跟不上;
  5. 各 stage 或各卡负载不均衡。

所以大模型训练的优化重点,往往不是“再加卡”,而是“让通信别拖垮计算”。


#深度解析

1. 理想 vs 实际的加速比

线性加速的理想:N 张卡 = N 倍速度。

实际加速比(Amdahl's Law):

Speedup = 1 / (s + p/N)

s = 串行部分比例(不可并行)
p = 可并行部分比例
N = 卡数
卡数 理想加速 实际加速 效率
2 1.90× 95%
4 3.48× 87%
8 5.93× 74%
16 16× 9.14× 57%
32 32× 12.8× 40%

s = 5% 时:

结论:即使只有 5% 的串行开销,32 卡的效率也会降到 40%

2. 各类 overhead 的定量分析

Overhead 类型 来源 典型占比 如何优化
通信开销 梯度 all-reduce 10-30% 梯度压缩、重叠通信、大 batch
Pipeline bubble PP 的 fill/drain 阶段 10-25% 增加 micro-batch、减少 stage 数
数据加载 CPU→GPU 传输、预处理 5-15% 多进程 DataLoader、pin_memory
负载不均 各卡计算量不同 5-10% 均衡划分、动态调度
Kernel launch 小算子频繁启动 3-8% 算子融合、增大 tile size
同步等待 最快的卡等最慢的卡 5-15% 避免 straggler、异步训练

3. 扩展效率的实际数据

GPU 数 理论加速 实际加速 效率
1024 1024× ~600× ~59%
2048 2048× ~1000× ~49%
4096 4096× ~1600× ~39%

GPT-3 175B 训练(使用 TP+PP+DP):

4. 如何诊断扩展效率低?

Step 1: 测量单卡 throughput (tokens/s)
Step 2: 测量 N 卡 throughput
Step 3: 计算效率 = (N 卡吞吐) / (N × 单卡吞吐)
Step 4: 如果效率 < 80%:
  ├─ 用 profiler 看通信时间占比
  ├─ 检查是否有 straggler(某卡特别慢)
  ├─ 检查数据加载是否跟得上
  └─ 检查 pipeline bubble 大小

5. 面试官常见深挖追问

  • "如果 8 卡训练的加速比只有 5×(理想 8×),怎么排查?"
    • 答:1)先看通信时间占比(nvidia-smi dmon 或 nsight);2)如果通信 > 30%,可能是 batch size 太小或网络带宽不足;3)检查是否有某卡特别慢(straggler);4)检查数据加载(top 看 CPU 占用);5)如果用了 PP,计算 bubble 大小。常见根因:batch size 太小导致通信/计算比过高。
  • "通信和计算能完全重叠吗?"
    • 答:理论上可以,但实践中很难完全重叠。DeepSpeed 的 overlap_comm 和 PyTorch 的 bucket_size 都是为了让通信和计算重叠。限制因素:1)通信量太大(带宽不够);2)计算图太短(没有足够计算来掩盖通信);3)同步点强制等待(如 optimizer step 前必须等所有梯度到达)。
  • "为什么小模型反而扩展效率更低?"
    • 答:小模型单步计算量小,通信占比相对更高。例如:大模型单步计算 10s、通信 2s,效率 83%;小模型单步计算 1s、通信 0.5s,效率 67%。此外,小模型的 kernel launch overhead 占比也更高。所以扩展效率通常随模型增大而改善("大模型更适合分布式")。

#35. 为什么说 TP 特别依赖高速互联?

#标准答案

因为 TP 是在单层内部切分矩阵,意味着每一层前向和反向都可能跨卡交换中间结果。如果互联慢,层内通信开销会直接卡在主路径上,导致 GPU 算力吃不满。

所以 TP 常常更适合同机高速互联(比如 NVLink/NVSwitch)环境,而不太适合弱互联的跨机大规模切分。


#深度解析

1. TP 的通信模式分析

以 Transformer FFN 层(TP=2)为例:

输入 x (shape: B×L×d)
        │
        ▼
┌───────────────┐
│  Column Split │  W1 → [W1_0, W1_1]  每张卡 1/2
│  (切 hidden)  │
└───────┬───────┘
        │
   ┌────┴────┐
   ▼         ▼
卡 0        卡 1
h0 = x·W1_0  h1 = x·W1_1
   │         │
   └────┬────┘
        ▼
   All-Gather (把 h0, h1 拼成完整 h)
        │
        ▼
   激活函数 σ(h)
        │
        ▼
┌───────────────┐
│   Row Split   │  W2 → [W2_0; W2_1]  每张卡 1/2
│  (切 output)  │
└───────┬───────┘
        │
   ┌────┴────┐
   ▼         ▼
卡 0        卡 1
y0 = σ(h)·W2_0  y1 = σ(h)·W2_1
   │         │
   └────┬────┘
        ▼
   All-Reduce (把 y0 + y1 累加)

每层 FFN 需要 2 次 all-gather/all-reduce,Attention 层同理。

2. 不同互联带宽下的效率

假设:batch=8, seq=2048, d=4096, TP=2

每层的激活通信量:2 × B × L × d × 2 bytes = 2 × 8 × 2048 × 4096 × 2 ≈ 268 MB

互联类型 带宽 通信时间 计算时间(参考) 通信占比
NVLink 400 GB/s ~0.7 ms ~2 ms 26%
PCIe 4.0 x16 32 GB/s ~8.4 ms ~2 ms 81%
InfiniBand 50 GB/s ~5.4 ms ~2 ms 73%
以太网 10 GB/s ~26.8 ms ~2 ms 93%

结论:TP 在 NVLink 下可行,在弱互联下通信会主导总时间

3. 为什么 TP 不像 DP/PP 那样对带宽要求低?

并行方式 通信频率 通信量/步 对带宽敏感度
DP 每步一次 2P (梯度)
PP 每 stage 一次 B×L×d (激活边界)
TP 每层两次 B×L×d (层内激活) 极高

TP 的通信频率是每层的两倍,且直接在计算关键路径上,无法被计算掩盖。

4. 实际部署建议

环境 TP 最大规模 原因
单机 8×A100 (NVLink) 8 NVSwitch 全互联
单机 8×3090 (PCIe) 2-4 PCIe 带宽不足
双机 (IB) 不推荐跨机 TP IB 带宽仍远低于 NVLink
多机 (以太网) 不适合 TP 延迟和带宽都不够

5. 面试官常见深挖追问

  • "TP=8 时,8 张卡的通信是 all-reduce,还是两两之间点对点?"
    • 答:是 all-reduce(或 all-gather + reduce-scatter)。NVLink/NVSwitch 支持高效的 all-reduce(如 NCCL 的 Tree/RING 算法)。在 NVSwitch 全互联拓扑下,all-reduce 的带宽利用率可以接近线速的 80-90%。
  • "如果 TP 跨机不可避免(如单机放不下),有什么缓解方法?"
    • 答:1)尽量减少 TP 维度,增加 PP 维度(PP 的通信频率更低);2)使用通信压缩(如 FP8/INT8 传输激活值);3)重叠通信和计算(如流水线并行中的通信-计算 overlap);4)考虑用更粗的切分粒度(如只切 FFN 不切 Attention)。
  • "TP 和 ZeRO-3 都能减少单卡参数量,为什么 TP 通信更敏感?"
    • 答:ZeRO-3 的参数 all-gather 发生在层级别(每层的参数只在需要时聚合),且频率较低;TP 的 all-gather/all-reduce 发生在层内(每层的中间激活都要通信),且频率是每层两次。此外,ZeRO-3 的通信可以和计算 overlap,而 TP 的通信通常在关键路径上。

#36. FlashAttention 为什么常被说成是 IO-aware(面向 IO 的)优化?

#标准答案

因为它的关键不在于改了 attention 的数学定义,而在于重新组织计算和内存访问,让中间结果尽量在更快的存储层中处理,避免频繁把大矩阵写回高带宽显存(HBM)。

所以它的成功点是”少搬数据、少落中间矩阵”,而不是”公式更复杂”。


#深度解析

1. GPU 存储层次与带宽差距

存储层次(从快到慢):
  寄存器 (Register)      ~10 TB/s    容量:KB 级
       ↓
  SRAM (L1/L2 Cache)      ~10 TB/s    容量:10-100 KB (SM 内)
       ↓
  HBM (高带宽显存)         ~1-2 TB/s   容量:10-80 GB
       ↓
  主内存 (DRAM)            ~50 GB/s    容量:100+ GB

标准 Attention 的瓶颈:HBM 带宽不足,计算速度远快于数据搬运速度。

2. 标准 Attention 的 IO 分析

对于输入 Q, K, V ∈ R^(B×H×L×d)

标准 Attention 流程:
1. S = Q·K^T      → 读 Q, K, 写 S    (IO: 3BLHd)
2. P = softmax(S)  → 读 S, 写 P        (IO: 2BL²)
3. O = P·V         → 读 P, V, 写 O    (IO: 3BL²d)

Total HBM IO ≈ O(B·L²·d)  → 随序列长度平方增长

以 B=1, H=32, L=4096, d=128 为例:

  • S 和 P 矩阵大小:32 × 4096 × 4096 × 4 bytes ≈ 2.1 GB
  • 标准实现需要多次读写这 2.1 GB

3. FlashAttention 的核心思想:Tiling + Online Softmax

FlashAttention 将 Q/K/V 分块 (tile),块大小为 Br/Bc:

for each tile of Q (Br × d):
    初始化局部 softmax 统计量 (m, l)
    for each tile of K, V (Bc × d):
        1. 加载 Q_tile, K_tile, V_tile 到 SRAM
        2. 计算 S_tile = Q_tile · K_tile^T
        3. Online Softmax:更新局部最大值 m 和求和 l
        4. 计算 O_tile 的部分结果
        5. 丢弃 S_tile(不写入 HBM!)
    最后统一写出 O_tile 到 HBM

关键:S 和 P 矩阵完全不写入 HBM,全部在 SRAM 内完成。

4. IO 复杂度对比

实现 HBM IO 计算量 瓶颈
标准 Attention O(B·L²·d) O(B·L²·d) IO(HBM 带宽)
FlashAttention O(B·L·d) O(B·L²·d) 计算

FlashAttention 将 IO 从 O(L²) 降到 O(L),与序列长度线性相关。

5. 实际加速效果

序列长度 标准 Attention FlashAttention-1 FlashAttention-2 内存节省
1K 1.2× 1.3× ~50%
4K 2.5× ~80%
16K ~90%
64K OOM 10× ~95%

6. FlashAttention-1 vs FlashAttention-2

特性 FA-1 FA-2
forward Tiling + Online Softmax 更优的 warps 调度
backward 重算 forward 减少非矩阵乘法操作
并行度 按 batch/head 并行 额外按序列长度块并行
加速比 2-4× 2-4× (额外 1.5-2×)
支持稀疏 是 (FlashAttention-2 支持 block-sparse)

7. 面试官常见深挖追问

  • ”FlashAttention 的复杂度还是 O(n²),为什么说它更快?”
    • 答:FlashAttention 没有改变 attention 的计算复杂度(仍然是 O(L²d)),但它改变了IO 复杂度(从 O(L²d) 降到 O(Ld))。在 GPU 上,attention 的瓶颈不是计算单元(FLOPS 够),而是 HBM 带宽(数据搬太慢)。FlashAttention 通过减少 HBM 访问次数解决了真正的瓶颈。
  • ”FlashAttention 的 backward 也需要重算 forward 吗?代价多大?”
    • 答:是的,FlashAttention 在反向传播时需要重算 forward 的 S 和 P(因为它们没存下来)。代价是 backward 的计算量约为 forward 的 2 倍(标准实现 backward 也是约 2× forward,所以总体 overhead 不大)。具体来说:标准 attention backward = 2× forward;FlashAttention backward = 2× forward + 重算开销 ≈ 2.2-2.5× forward。
  • ”如果 HBM 带宽无限大,FlashAttention 还有优势吗?”
    • 答:几乎没有。FlashAttention 的核心优化就是减少 HBM 访问。如果 HBM 带宽无限,标准 attention 的 IO 不再是瓶颈,FlashAttention 的 tiling 和 online softmax 反而会因为额外操作而略慢。但现实中 HBM 带宽是硬瓶颈(过去 10 年 FLOPS 增长 100×,HBM 带宽只增长 10×),所以 FlashAttention 的优势会持续存在。

#37. 什么叫算子融合?为什么它能提速?

#标准答案

算子融合就是把原本多个相邻的小算子,合并成更少、更大的 kernel 来执行。它通常能提速,因为:

  1. 减少 kernel launch 开销;
  2. 减少中间结果写回显存再读出的次数;
  3. 更容易提升 cache 和寄存器利用率。

在大模型里,RMSNorm + bias + activation、attention 内若干步骤、甚至采样流程,都是常见融合对象。


#深度解析

1. 为什么 kernel launch 这么贵?

GPU 执行一个 kernel 的完整流程:
1. CPU 准备参数 → 2. 发起 CUDA launch → 3. GPU 调度 → 4. 执行计算

其中步骤 1-3 是固定开销(~5-10 μs),和计算量无关。

如果 100 个小算子各自 launch:
总开销 = 100 × 10μs = 1ms(纯调度!)

融合成 10 个大 kernel:
总开销 = 10 × 10μs = 0.1ms(省 90%)

2. 大模型中的典型融合场景

融合模式 原算子 融合后 收益
Norm + Residual RMSNorm + Add Fused RMSNormResidual 省 1 次读写
Linear + Bias + Act Linear + AddBias + GELU Fused MLP Block 省 2 次读写
QKV Projection 3× Linear Single QKV Gemm 省 2 次 launch
Attention 融合 Q@K^T + Scale + Softmax + @V FlashAttention 核心收益
采样融合 TopK + Softmax + Sampling Fused Sampling 减少 host-device 往返

3. 融合的限制

不是所有算子都能融合:

  • 数据依赖:如果算子 B 需要算子 A 的完整输出(非 element-wise),无法融合
  • 内存布局:不同算子要求的 tensor layout 不同(如 NCHW vs NHWC)
  • 精度要求:某些融合会引入数值误差(如 LayerNorm 的 mean/var 计算顺序)

4. 面试官常见深挖追问

  • "算子融合和编译器优化有什么关系?"
    • 答:现代 DL 编译器(如 XLA、TVM、TorchInductor)会自动做算子融合。它们分析计算图,找到可以融合的算子模式,生成融合后的 kernel。但手写融合 kernel(如 FlashAttention)通常比自动融合更高效,因为人可以针对特定模式做极致优化。
  • "为什么 attention 不融合会特别慢?"
    • 答:标准 attention 需要多次读写 HBM(Q/K/V → score → softmax → output),中间结果很大(n×n)。FlashAttention 把整个过程融合成一个 kernel,中间结果留在 SRAM,避免了大量的 HBM 访问。

#38. 如果面试官问“显存优化顺序”,一个稳妥答案怎么讲?

#标准答案

一个稳妥顺序通常是:

  1. 先降精度:BF16/FP16,必要时量化;
  2. 再切状态:ZeRO/FSDP
  3. 再压激活:checkpointing、sequence parallel、缩短序列;
  4. 再改训练方式:LoRA/QLoRA、减 batch、梯度累积;
  5. 最后才考虑 offload,因为它虽然能救命,但常常明显拖慢训练。

这个回答好的地方在于:它体现了你知道不同方法作用在哪一层,而不是把所有省显存手段混成一团。


#深度解析

1. 显存占用的层次结构

训练显存 = 模型状态 + 激活值 + 临时缓存

模型状态(长期占用):
├─ 参数 (FP16): 2P
├─ 梯度 (FP16): 2P
└─ 优化器状态 (FP32): 8P-12P

激活值(前向保存,反向释放):
└─ 取决于 batch × seq_len × layers × hidden_dim

临时缓存(动态变化):
└─ 中间计算结果、通信 buffer
组件 显存 占比
模型状态 ~70 GB ~60%
激活值 ~30 GB ~25%
其他 ~15 GB ~15%

以 7B 模型为例:

2. 为什么这个顺序是最优的?

优先级 方法 作用对象 代价 原因
1 混合精度 参数/梯度 效果无损,立即省 50%
2 ZeRO/FSDP 模型状态 通信增加 解决最大头(优化器状态)
3 Checkpointing 激活值 计算增加 20-30% 不碰模型状态
4 LoRA/QLoRA 可训练参数 效果轻微下降 只改少量参数
5 Offload 全部 速度大幅下降 最后手段

3. 常见错误顺序

错误:一上来就 offload
原因:offload 速度下降 50%+,应该先用其他方法

错误:先做 checkpointing 再做 ZeRO
原因:checkpointing 解决激活值(小头),ZeRO 解决模型状态(大头)

错误:量化训练权重
原因:训练时量化极不稳定,通常只用于推理

4. 面试官常见深挖追问

  • "如果 activation checkpointing 后还 OOM,下一步做什么?"
    • 答:检查 OOM 的来源。如果报错在 forward → 激活值仍太大,减 batch size 或 sequence length。如果报错在 optimizer.step() → 优化器状态太大,上 ZeRO/FSDP。如果报错在 backward → 梯度太大,用 gradient accumulation 拆分。
  • "为什么 offload 是最后手段?"
    • 答:因为 CPU-GPU 数据传输成为新瓶颈。即使 PCIe 4.0 带宽 32GB/s,也比 HBM 带宽(1-2TB/s)慢 30-60 倍。offload 后训练速度通常下降 50% 以上,只在"能训练"vs"不能训练"的生死关头使用。