这是 DeepMind Scaling Book 系列的第 12 部分(额外章节)。

关于 GPU 的一切 (How to Think About GPUs)

How To Scale Your Model Part 12 (Part 11: Conclusion | The End)

在 Google 我们热爱 TPU,但 GPU 也很棒。本章深入探讨 GPU 的世界——每个芯片如何工作,它们如何联网,以及这对 LLM 意味着什么,特别是与 TPU 相比。虽然有来自 NVIDIA, AMD, Intel 等的众多 GPU 架构,但在这里我们将重点关注 NVIDIA GPU。本节建立在第 2 章第 5 章的基础上,因此鼓励你先阅读它们。

GPU 是什么? (What Is a GPU?)

现代 ML GPU(例如 H100, B200)基本上是一堆专门用于矩阵乘法的计算核心(称为 Streaming MultiprocessorsSMs)连接到一根快速内存(称为 HBM)。

Figure: abstract layout of an H100 or B200 GPUs Figure: H100 或 B200 GPU 的抽象布局示意图。H100 有 132 个 SM,而 B200 有 148 个。我们使用术语“Warp Scheduler”来宽泛地描述一组 32 个 CUDA SIMD 核心以及向它们分派工作的调度器。注意这看起来多像 TPU!

每个 SM,像 TPU 的 Tensor Core 一样,都有一个专用的矩阵乘法核心(不幸的是也叫 Tensor Core [1]),一个向量算术单元(叫 Warp Scheduler [2]),和一个快速的片上缓存(叫 SMEM)。与 TPU 不同(TPU 最多有 2 个独立的“Tensor Cores”),现代 GPU 有超过 100 个 SM(H100 上有 132 个)。这些 SM 中的每一个都远不如 TPU Tensor Core 强大,但整个系统更灵活。每个 SM 或多或少是完全独立的,因此 GPU 可以同时执行数百个单独的任务 [3]。

让我们更详细地看一下 H100 SM:

Figure: H100 SM diagram Figure: H100 SM 示意图,显示 4 个 subpartitions,每个包含一个 Tensor Core, Warp Scheduler, Register File, 和一组 CUDA Cores。底部的 ‘L1 Data Cache’ 是 256kB SMEM 单元。

  • CUDA Cores: 每个子分区包含一组用于 SIMD/SIMT 向量算术的 ALU,称为 CUDA Cores。每个 ALU 通常每个周期可以执行 1 个算术运算,例如 f32.add。每个子分区包含 32 个 fp32 核心。
  • Tensor Core (TC): 每个子分区都有自己的 Tensor Core,这是一个专用的矩阵乘法单元,就像 TPU MXU 一样。Tensor Core 代表了 GPU 的绝大多数 FLOPs/s(例如,在 H100 上,我们有 990 bf16 TC TFLOP/s,而 CUDA 核心只有 66 TFLOPs/s)。

CUDA 核心比 TPU 的 VPU 更灵活:GPU CUDA 核心使用称为 SIMT (Single Instruction Multiple Threads) 的编程模型,相比之下 TPU 使用 SIMD (Single Instruction Multiple Data) 模型。

CUDA 核心调度也更灵活:SM 运行有点像多线程 CPU,因为它们可以并发地“调度”许多程序(warps)(每个 SM 最多 64 个),但每个 Warp Scheduler 在每个时钟周期只执行单个程序。

内存 (Memory)

除了计算单元,GPU 还有内存层次结构:

  • Registers: 每个子分区有自己的寄存器文件,包含 16,384 个 32-bit 字。
  • SMEM (L1 Cache): 每个 SM 有自己的 256kB 片上缓存,称为 SMEM。
  • L2 Cache: 所有 SM 共享一个相对较大的 ~50MB L2 缓存。
  • HBM: 主 GPU 内存,用于存储模型权重、梯度、激活等。

GPU 规格摘要 (Summary of GPU specs)

GPU Generation Clock Speed SMs/chip SMEM capacity/SM L2 capacity/chip HBM capacity/chip
V100 Volta 1.25GHz/1.38HGz 80 96kB 6MB 32GB
A100 Ampere 1.10GHz/1.41GHz 108 192kB 40MB 80GB
H100 Hopper 1.59GHz/1.98GHz 132 256kB 50MB 80GB
H200 Hopper 1.59GHz/1.98GHz 132 256kB 50MB 141GB
B200 Blackwell ? 148 256kB 126MB 192GB
GPU Generation HBM BW/chip FLOPs/s/chip (bf16/fp16) FLOPs/s/chip (fp8/int8) FLOPs/s/chip (fp4)
V100 Volta 9.0e11
A100 Ampere 2.0e12 3.1e14 6.2e14
H100 Hopper 3.4e12 9.9e14 2.0e15
H200 Hopper 4.8e12 9.9e14 2.0e15
B200 Blackwell 8.0e12 2.3e15 4.5e15 9.0e15

芯片层面的 GPU vs. TPU (GPUs vs. TPUs at the chip level)

  • GPU 更模块化。TPU 有 1-2 个大 Tensor Cores,而 GPU 有数百个小 SM。
  • 历史上,单个 GPU 更强大(也更贵)
  • TPU 有更多快速缓存内存。TPU 有比 GPU SMEM 多得多的 VMEM。

网络 (Networking)

网络是 GPU 和 TPU 差异最大的领域之一。TPU 连接在 2D 或 3D 环面中,而 GPU 使用更传统的分层树状交换网络。

节点层面 (At the node level)

GPU 节点是一个小单元,通常有 8 个 GPU(GB200 最多 72 个),通过全对全、全带宽、低延迟的 NVLink 互连连接。

Figure: NVLink nodes Figure: 从 Pascall (P100) 开始的节点即 NVLink 域图。

对于 Hopper 一代 (NVLink 4.0),每个 NVLink 链路具有 25GB/s 的全双工带宽,给我们每个 GPU 18 * 25=450GB/s 的全双工带宽进入网络。

NVLink Gen NVSwitch Gen GPU Generation NVLink Bandwidth (GB/s, full-duplex) NVLink Ports / GPU Node GPU to GPU bandwidth (GB/s full-duplex) Node size (NVLink domain) NVSwitches per node
3.0 2.0 Ampere 25 12 300 8 6
4.0 3.0 Hopper 25 18 450 8 4
5.0 4.0 Blackwell 50 18 900 8/72 2/18

节点之外 (Beyond the node level)

在节点级别之外,GPU 网络的拓扑结构不那么标准化。NVIDIA 发布了一个参考 DGX SuperPod 架构,使用 InfiniBand (IB) 将更大的 GPU 组连接起来。

Figure: H100 SuperPod Figure: 参考 1024 H100 DGX SuperPod 示意图,有 128 个节点。

我们有多少带宽? InfiniBand 网络(称为“scale out network”)的总体拓扑是 Fat Tree (胖树),电缆和交换机保证节点级别以上的全对分带宽。这意味着如果我们将节点分成两半,每个节点可以同时向另一个分区中的节点输出 400GB/s。

Level GPUs Switches per Unit Switch Type Bandwidth per Unit (TB/s, full-duplex) GPU-to-GPU Bandwidth (GB/s, full-duplex) Fat Tree Bandwidth (GB/s, full-duplex)
Node 8 4 NVL 3.6 450 450
Leaf 256 8 IB 12.8 50 400
Spine 1024 16 IB 51.2 50 400

集体通信在 GPU 上是如何工作的? (How Do Collectives Work on GPUs?)

我们使用 NCCL (NVIDIA Collective Communication Library) 库。

节点内集体通信 (Intra-node collectives)

AllGather 或 ReduceScatter: 在节点级别,你可以像 TPU 一样在环周围执行它们,在每一跳使用完整的 GPU 到 GPU 带宽。

\[T_\text{AG or RS comms} = \frac{\text{bytes}}{\text{GPU egress bandwidth}}\]

AllToAlls: 节点内的 GPU 具有全对全连接,这使得 AllToAlls 非常容易。

\[T_\text{AllToAll comms} = \frac{B \cdot (N - 1)}{W \cdot N^2} \approx \frac{B}{W \cdot N}\]

网络内归约 (In network reductions): 自 Hopper 一代以来,NVIDIA 交换机支持 SHARP,允许网络交换机本身执行归约操作。理论上,这应该将 AllReduce 的成本减半。

跨节点集体通信 (Cross-node collectives)

当我们超越节点级别时,成本有点微妙。

\[T_\text{total} = \max(T_\text{comms at node}, T_\text{comms in scale-out network}) = \max\left[\frac{\text{bytes}}{W_\text{GPU egress}}, \frac{\text{bytes}}{W_\text{node egress}}\right]\]

一般来说,节点外 AllGather 或 ReduceScatter 的成本大约是 $B / W_\text{node egress}$,在 H100 DGX SuperPod 上是 $B / \text{400e9}$。

GPU 上 LLM Scaling 的 Rooflines (Rooflines for LLM Scaling on GPUs)

数据并行 (Data Parallelism)

对于纯数据并行或 FSDP 没有网络内归约,我们需要:

\[\frac{B}{X} > \frac{C}{W_\text{collective}}\]
  • 节点内,我们需要每个 GPU token batch size > $\text{990e12} / \text{450e9} = 2200$。
  • SU 内或 spine 级别,BS > $\text{990e12} / \text{400e9} = 2475$。

张量并行 (Tensor Parallelism)

张量并行需要在激活上进行 AllGather 和 ReduceScatter。

\[Y < \frac{F \cdot W_\text{collective}}{C}\]

在节点内,这给我们大约 $F / 2200$ 或节点外 $F / 2475$。对于 LLaMA-3 ($F=28000$),这大约是 11 路 TP(或者向下取整,大约 8 路,这是节点的大小)。

专家并行 (Expert Parallelism)

对于混合专家 (MoE) 模型,如果 $F < 8 * C / W_\text{node}$,专家并行可以跨越 1-2 个节点,成本与 TP 相似(略低);或者如果 $F > 8 * C / W_\text{node}$,我们可以进行大量的专家并行(直到 $E$ 个节点),成本相对较低。

流水线并行 (Pipeline Parallelism)

流水线并行的总体通信成本很小。

\[T_\text{per-layer comms} \approx 1.5 \cdot \frac{2BD}{W \cdot N_\text{layers}}\]

从通信的角度来看,流水线基本上是免费的。

总结:GPU 上 LLM 扩展的要点 (TLDR of LLM scaling on GPUs)

  • 数据并行或 FSDP (ZeRO-1/3) 需要每个 GPU 约 2500 tokens 的本地批量大小
  • 张量并行在计算受限的情况下最多可达约 8 路,这主要限制我们在单个 NVLink 域内(即单节点)。
  • 任何跨越多节点的模型并行形式都可以进一步降低 FSDP 的成本,因此我们经常希望混合 PP + EP + TP 来跨越许多节点并降低 FSDP 成本。
  • 如果能处理零气泡流水线的代码复杂性并保持较大的批量大小,流水线并行效果很好。

脚注

[1] 令人困惑的命名。 [2] 实际上包含 Dispatch Unit, Register File, CUDA Cores 等。 [3] 通过 CUDA Streams。

来源

GPUs - Part 12