结论

Weak scaling 和 strong scaling 是 HPC 里两种完全不同的扩容问题:

  • Strong scaling:总问题规模固定,加机器,看单步时间能不能同比下降。
  • Weak scaling:每台机器的问题规模固定,加机器则总问题规模一起变大,看单步时间能不能保持不变。

搬到 LLM 训练上,“问题规模”就是 global batch size,“每台机器的问题规模”就是每个 rank 的 microbatch token 数 $T$。于是两条路各撞一面墙:

  1. 固定 global batch 加卡(strong scaling)撞的是系统墙。$T$ 随卡数下降,掉到 $T_{crit}$ 以下之后 FSDP 通信无法被计算掩盖,GEMM 变小,MoE 每个 expert 分不到足够 token,pipeline 气泡占比上升。
  2. **固定每卡 token 数加卡(weak scaling)撞的是算法墙。**global batch 随卡数线性增大,超过 critical batch size 之后,固定 token 预算下 optimizer step 数不足,token efficiency 下降。
  3. **大规模训练几乎总是先 weak scale、再被迫 strong scale。**一旦 global batch 顶到当前阶段的 critical batch,继续加卡只能是 strong scaling,$T$ 下降不可避免,剩下能做的只有把 $T_{crit}$ 降下来。

一句话概括:weak scaling 的效率数字很容易做得好看,但它是拿算法预算换来的;真正难的是 strong scaling,而 strong scaling 的上限由 $T_{crit}$ 决定。

HPC 的原始定义

设总计算量为 $W$,处理器数为 $N$。

Strong Scaling 与 Amdahl 定律

$W$ 固定。若其中比例 $f$ 的工作无法并行:

$$ t(N)=f\,t(1)+\frac{(1-f)\,t(1)}{N}, \qquad S(N)=\frac{1}{f+\dfrac{1-f}{N}}. $$

$N\to\infty$ 时 $S\to 1/f$。串行部分只占 5%,加速比上限就是 20 倍,跟买多少卡无关。

Weak Scaling 与 Gustafson 定律

每个处理器的工作量固定,$W\propto N$。此时

$$ S(N)=f+(1-f)N, $$

加速比随 $N$ 线性增长。看起来漂亮,但它衡量的是“同样时间能算多大的问题”,不是“同一个问题能算多快”。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Strong scaling:总问题规模固定

  1024 卡  ┌──────────────────────────────────────┐
           │              32M tokens              │
           └──────────────────────────────────────┘

  4096 卡  ┌────────┐┌────────┐┌────────┐┌────────┐
           │   8M   ││   8M   ││   8M   ││   8M   │
           └────────┘└────────┘└────────┘└────────┘

  每卡负载 ↓,通信与同步在 step time 里的占比 ↑


Weak scaling:每卡问题规模固定

  1024 卡  ┌────────┐
           │  32M   │
           └────────┘

  4096 卡  ┌────────┐┌────────┐┌────────┐┌────────┐
           │  32M   ││  32M   ││  32M   ││  32M   │
           └────────┘└────────┘└────────┘└────────┘

  总问题规模 ↑(global batch 从 32M 变成 128M)

映射到 LLM 训练

沿用 Global Batch Size 的记号:

$$ B_{\mathrm{global}} =T_{\mathrm{micro/rank}}\times D_{\mathrm{DP}}\times A . $$

这个等式里三个量,固定哪一个就决定了在做哪种 scaling:

固定量 加卡后的变化 主要风险
Strong scaling $B_{\mathrm{global}}$ $T_{\mathrm{micro/rank}}$ 下降 通信暴露、kernel 变小、气泡变大
Weak scaling $T_{\mathrm{micro/rank}}$ $B_{\mathrm{global}}$ 上升 超过 critical batch,token efficiency 下降

需要注意的是,并行维度本身就带有 scaling 属性

1
2
3
4
5
6
7
                        加卡的两种花法

  加 DP replica(保持每卡 token 数)   →  weak scaling
      global batch 变大

  加 TP / PP / CP / EP degree          →  strong scaling
      同一批 token 用更多卡处理,每卡 token 数或每卡参数量下降

TP、CP、PP、EP 都属于“让更多卡共同处理同一批 token”,天然是 strong scaling 的手段;只有增大 $D_{\mathrm{DP}}$ 并保持 $T$ 才是 weak scaling。这也解释了一个常见现象:把 TP 从 4 开到 8,MFU 往往下降,因为它是在做 strong scaling,每卡的 GEMM 形状被切小了。

Strong Scaling 的实际衰减

把单步时间拆成随卡数下降的部分和不下降的部分:

$$ t_{\mathrm{step}}(N) \approx \underbrace{\frac{C}{N F_{\mathrm{eff}}}}_{\text{计算}} +\underbrace{t_{\mathrm{exposed}}(N)}_{\text{暴露通信 + 气泡 + optimizer}} . $$

固定 $B_{\mathrm{global}}$ 时,$C$ 是常数,第一项按 $1/N$ 缩小;而 $t_{\mathrm{exposed}}$ 不但不缩小,还会因为每卡计算窗口变短而变大。

FSDP 计算通信 overlap 里的 dense 模型阈值 $T_{crit}\approx 3.7$k tokens/GPU 为例,假设 $B_{\mathrm{global}}=32$M tokens、$A=1$、纯 DP:

GPU 数 每卡 token 数 计算 (ms) 暴露部分 (ms) Step time (ms) 理想 step time (ms) 并行效率 吞吐 (M tok/s)
1,024 32k 900 100 1,000 1,000 100% 32
4,096 8k 225 150 375 250 67% 85
8,192 4k 113 220 332 125 38% 96
16,384 2k 56 300 356 63 18% 90

$T$ 掉到 $T_{crit}$ 附近时(8,192 卡),暴露时间已经超过计算时间;再加一倍卡(16,384 卡),吞吐反而从 96M 降到 90M。这就是 strong scaling 的典型形态:存在一个卡数拐点,越过之后加卡是负收益。

拐点位置基本由 $T_{crit}$ 决定。$B_{\mathrm{global}}$ 固定时,可用卡数上限约为

$$ N_{\max}\approx\frac{B_{\mathrm{global}}}{T_{crit}} . $$

$B_{\mathrm{global}}=32$M、$T_{crit}=3.7$k 对应约 8.6k 卡,和上表的拐点一致。

Weak Scaling 的假效率

同样从 1,024 卡扩到 4,096 卡,但保持每卡 32k tokens:

GPU 数 每卡 token 数 Global batch Step time (ms) Weak scaling 效率 吞吐 (M tok/s)
1,024 32k 32M 1,000 100% 32
4,096 32k 128M 1,050 95% 122

系统指标非常好:效率 95%,吞吐接近线性。问题在于 global batch 变成了 128M,远超目前公开旗舰模型的量级(见 Global Batch Size 的横向对比)。同样的 1T token 预算下:

$$ \frac{10^{12}}{32\times10^{6}}\approx 31\text{k steps} \;\longrightarrow\; \frac{10^{12}}{128\times10^{6}}\approx 7.8\text{k steps}. $$

参数更新次数只剩四分之一,达到相同 loss 需要的 token 会更多。weak scaling 效率高不代表 time-to-quality 更好,只报告 tokens/s 或 MFU 时,这种退化完全看不出来。

这也是 MLPerf Training 用“训练到固定目标质量的时间”而不是吞吐作为指标的原因:一旦指标是 time-to-quality,靠放大 batch 换吞吐的做法就不再有收益。

和 Scaling Law 的区别

两个词长得像,讨论的完全是两件事:

自变量 因变量 关心什么
Scaling Law 参数量、训练 token 数、算力预算 validation loss 给定算力怎么分配模型和数据
Weak / Strong Scaling 并行规模(GPU 数) step time、吞吐 同一份工作能不能算得更快

两者唯一的交点是 critical batch size:它同时是 scaling law 侧的算法约束和 weak scaling 侧的扩容上限。

怎么把 Strong Scaling 的墙往后推

global batch 顶到 critical batch 之后,加卡只能 strong scale,$T$ 一定会降。能做的只有降低 $T_{crit}=\dfrac{F_{\mathrm{eff}}}{B_{\mathrm{eff}}}\cdot\dfrac{P}{P_a}$:

方向 做法 效果
提高 $B_{\mathrm{eff}}$ 把 FSDP group 收进 NVLink 域、层次化 AllGather、IB 转 NVLink 分母变大
降低 $P/P_a$ EP 搬 token 替代 FSDP 搬 expert 权重 稀疏 MoE 上收益最大
减少通信次数 reshard_after_forward=False,或让参数跨多个 accumulation microbatch 保持 unshard 用显存换通信
减少通信字节 FP8 / BF16 参数通信,把 $s_w$ 减半 等价于 $B_{\mathrm{eff}}$ 翻倍
换气泡换通信 调整 PP schedule、增大 in-flight microbatch 数 降低 $t_{\mathrm{exposed}}$ 里的气泡项

注意最后两行是有代价的:它们都在拿峰值显存换通信,而 strong scaling 的一个副作用恰好是每卡激活显存随 $T$ 下降而变小,正好腾出空间。这两件事应该一起考虑,而不是分开调。

报告扩容结果时应该说清楚的事

一条“我们扩到 N 卡,效率 90%”的结论,不说明下面四点是没有信息量的:

  1. 固定的是 $B_{\mathrm{global}}$ 还是 $T_{\mathrm{micro/rank}}$,即到底在做哪种 scaling。
  2. baseline 卡数是多少,效率是相对谁算的。加卡区间从 1k 到 2k 和从 8k 到 16k 完全不是一回事。
  3. 并行配置有没有变。若同时改了 TP/PP/EP degree,那已经不是纯粹的 strong 或 weak scaling。
  4. 有没有 validation loss–token 曲线。只有吞吐和 MFU 时,weak scaling 的算法代价被完全隐藏了。

一句话总结:strong scaling 问的是“这一批 token 能不能算得更快”,weak scaling 问的是“同样时间能不能吞更多 token”。训练系统的真实约束是先用 critical batch size 定住 weak scaling 的上限,再用 $T_{crit}$ 定住 strong scaling 的拐点,两者共同决定一个模型最多值得用多少张卡。