跳转至

第 0 章 GPU 系统与分布式计算基础

本章是速查表。熟悉 CUDA 和分布式训练的读者可以跳过,但建议看一眼 0.4 的四个集合通信——本册后面所有并行策略的通信代价都会还原成这四个操作。

0.1 存储层级:所有优化的起点

从快到慢、从小到大:寄存器和共享内存在计算芯片内部,延迟以纳秒计但总共只有几十 MB;HBM 就是通常说的"显存",几十上百 GB,带宽 TB/s 量级;CPU 内存更大更慢,要过 PCIe;本地盘和对象存储负责长期保存。

每往下一层,带宽掉一个数量级左右。记住这个梯度,就能理解本册大部分技术的动机:它们几乎都是在减少跨层搬运。FlashAttention 是把中间结果留在共享内存不写回 HBM;算子融合是减少 HBM 往返;量化是减少从 HBM 读的字节数;offload 是主动往下层放,用速度换容量。

0.2 算力与带宽:两个独立的预算

一张卡有两个独立的上限:每秒能做多少浮点运算(TFLOPS),每秒能从显存搬多少字节(GB/s)。

关键是它们的比值。现代 GPU 的算力增长远快于带宽增长,比值通常在每字节数百次浮点运算这个量级。这意味着:如果一个操作每读 1 字节只做几次运算,它必然把 GPU 的算力闲置着——不是你写得不好,是这个操作的性质如此。

大矩阵乘(Prefill、训练)落在算力受限一侧;逐元素算子和单 token 的 Decode 落在带宽受限一侧。分清一个操作在哪一侧,决定了优化方向是"少算"还是"少搬"。2.2 节会把这件事形式化。

0.3 GPU 之间怎样通信

同机 GPU 通过 NVLink/NVSwitch 互联,带宽几百 GB/s;跨机走 InfiniBand 或 RoCE,通常低一个数量级,且延迟明显更高。

两个维度都要看:带宽决定大张量传输的耗时,延迟决定小而频繁的同步的耗时。张量并行每层都要通信且数据量不大,它卡在延迟上,所以必须留在机内;数据并行每步一次大规模 AllReduce,它卡在带宽上,跨机尚可接受。这条区别会在第 5、7 章反复出现。

0.4 四个集合通信

  • AllReduce:所有卡的数据求和(或其他归约),每张卡都拿到完整结果。DDP 同步梯度用它。等价于 ReduceScatter + AllGather,所以实际传输量约为数据量的 2 倍。
  • ReduceScatter:求和后切开,每张卡只拿走属于自己的那一片。ZeRO/FSDP 聚合梯度用它。
  • AllGather:把各卡手上的分片拼成完整张量,每张卡都拿到完整的。FSDP 计算前恢复参数用它。
  • AllToAll:每张卡把不同的数据块发给不同的目标卡,是一次"转置"式的全交换。MoE 专家并行的核心,也是最吃网络的一个。

0.5 最低工具栈

要能读懂 PyTorch Profiler 或 Nsight 的时间线(哪段在算、哪段在通信、哪里有空洞),知道 NCCL 是做 GPU 集合通信的库、它的超时和错误日志怎么看,理解 CUDA stream 可以让计算和通信并发执行。

框架名字每年都在变,这些机制不会。

核心问答

Q:显存够了,程序为什么还慢? 容量只决定能不能跑。速度取决于算力、显存带宽、卡间通信和调度空洞,它们是四个独立的瓶颈。

Q:NVLink 和 InfiniBand 的区别对我意味着什么? 通信最频繁的并行维度必须放在机内。这一条决定了张量并行的规模上限。

Q:为什么 AllReduce 的传输量是数据量的两倍? 它实际由 ReduceScatter 和 AllGather 两步组成,各传一遍。算通信量时不要少算这个因子。

Q:框架会把这些细节藏起来吗? 能藏住正确性,藏不住性能。训练慢或扩展效率差时,最终都要回到通信量和时间线上。