上一讲第 10 讲:视频理解 下一讲第 12 讲:自监督学习

第 11 讲:大规模分布式训练

Large Scale Distributed Training —— 先钻进 GPU 内部看清张量核心与存储层级,再把镜头拉远到由两万四千块 GPU 组成的数据中心级"超级计算机";然后系统讲解在这台机器上训练一个巨型神经网络所需的算法:数据并行、全分片数据并行(FSDP)、混合分片并行(HSDP)、激活检查点、上下文并行、流水线并行与张量并行,以及始终指引所有调参决策的北极星指标——模型算力利用率(MFU)

本讲概览:

本讲回答两个问题:训练到底跑在什么硬件上,以及如何写出能在成千上万块 GPU 上训练一个网络的算法。老师以 Llama3-405B 作为贯穿全讲的实例——不是因为它最强,而是因为它足够开放,技术报告披露了大量训练基础设施的细节,让我们得以窥见当今大规模 LLM 的真实训练方式。硬件部分从 H100 芯片的内部结构讲到 Meta 那台 \(24{,}576\) 卡、\(24\,\mathrm{EFLOPs}\) 的"整机";算法部分从数据并行的数学出发,一路讲到 FSDP、激活检查点、多维并行与 MFU。老师的结论很直白:单块 GPU 是一台通用并行计算机,GPU 集群是一台拥有数万个计算单元的巨型并行机器,而我们的任务是把整个数据中心当作一台计算机来编程

一、开场:大规模训练是深度学习的新常态

这一讲的话题相当令人兴奋,因为今天实践中所有神经网络的训练都是这样完成的。无论是初创公司、工业界还是学术界,"大规模"已经是当今深度学习的常态——而这在过去十年间发生了根本变化:CS231n 开课之初,把模型放在一块 GPU 上训练是常态,多卡训练反而不常见;如今的新常态是几十、几百、几千甚至几万块设备同时训练一个模型。这要求我们发展新的算法、新的计算思维方式。

全讲的贯穿案例是 Llama3-405B:它未必是最强或最有趣的模型,但它接近业界最强水平,而且公开了大量实现细节——模型架构、训练方式、系统基础设施等。作为对比,业界标杆 GPT-4 的论文(2023 年)里有一句标志着行业风向转变的著名声明:

"鉴于大模型所处的竞争格局与安全问题,本报告不再包含关于架构的任何进一步细节,包括模型规模、硬件、训练算力、数据集构建、训练方法等。"——此后近三年,各家最强模型对细节讳莫如深,"你能知道它是 Transformer 就算走运了"。而 Meta 在 2024 年 4 月开源的 Llama3 却分享了训练集群等大量细节(数据集讲得少,系统基础设施讲得多)。(Llama4 已于上个月 2025 年 4 月发布,尚无论文,老师表示期待几个月后读到它。)

本讲的两部分内容由此确定:其一,GPU 硬件——这些模型究竟跑在什么上面;其二,如何在大量 GPU 上训练——需要哪些算法。

二、GPU 硬件剖析:从图形协处理器到张量核心

2.1 GPU 是什么

GPU(Graphics Processing Unit,图形处理器)最初是为计算机图形学开发的专用协处理器,后来被证明是极佳的通用并行处理器。图形学天然需要并行:屏幕上要生成海量像素,要处理大量基本几何图元——自然而然就是"一大堆计算同时做"。2000 年代初,研究者开始"曲解"这些显卡去做通用并行编程;到 2000 年代末至 2010 年代,NVIDIA 顺势把 GPU 做成、卖成真正的通用并行处理器。老师在这里开了个应景的玩笑:这间教室叫黄仁勋礼堂(Huang auditorium)——NVIDIA 的创始人和 CEO。NVIDIA 值得称道之处在于极早认出了深度学习的潜力(2010 年代初就投入大量资源让硬件贴合深度学习训练),此后十余年 GPU 一直是大规模训练的主力。

2.2 拆开一块 H100:显存、SM 与"良率筛bin"

深入芯片内部(课件给的是 NVIDIA H100 的 die shot,当今深度学习训练的主力;新一代产品刚发布但还没什么人真正用过)。中心是计算核心,四周环绕着 80 GB 的 HBM(High-Bandwidth Memory,高带宽显存),两者通过总线以约 \(3\,\mathrm{TB/s}\) 的速度交换数据。再往计算核心里看,有一块小得多的 约 50 MB 的 L2 缓存——远小于 80 GB 显存,但离计算单元极近、访问极快。真正的核心是 132 个流式多处理器(Streaming Multiprocessor,SM):相互独立的并行核心。可以把 SM 大致类比为 CPU 核心,但并不严格对等:GPU 核心并行度更高、时钟更慢、分支预测等能力更弱,很难做精确的苹果对苹果比较。

有同学数了幻灯片上的小方块会发现其实画了 144 个——多出来的 12 个去哪了?答案是 binning(分级筛选):芯片晶体管太多,无论工艺投入多大,总有一部分制造缺陷,没有一块是完美的。于是厂商按"理论上 144 个、实际承诺至少 132 个可用"来设计,只点亮确保完好的 132 个——这样才能卖出更多良率不足满血的芯片。

2.3 SM 内部:FP32 核心与张量核心

单独看一个 SM:首先有 256 KB 的 L1 缓存与寄存器堆——于是 H100 内部形成完整的三级存储层级:L1 256 KB → L2 50 MB → HBM 80 GB。老师调侃道:"你以为你在学深度学习?其实你在学计算机体系结构。"存储层级对深度学习和一切高性能计算都至关重要:离计算核心越近的存储越小越快,越远的越大越慢;写底层 GPU kernel 的人要花大量精力在层级之间搬运数据。

每个 SM 里有 128 个 FP32 核心——通用浮点算术单元,每个核心每时钟周期能算一次标量的 \(ax + b\)(一乘一加)。合计一个 SM 每周期经 FP32 核心可做 256 次浮点运算。而真正"魔法发生的地方"是标红的 4 个张量核心(tensor core)——老师指出这名字其实起错了,它们本质是矩阵核心:专用电路,只干一件事——矩阵乘法。

深入

把张量核心的账算清楚。H100 的每个张量核心每时钟周期完成一次固定尺寸的小矩阵乘:\(A\) 为 \(16\times 4\),\(B\) 为 \(4\times 8\),加上 \(16\times 8\) 的偏置矩阵——即计算矩阵版的 \(AX + B\)。这次小矩阵乘的运算量:\(16\times 4\times 8 = 512\) 次乘加 \(= 1024\) 次浮点运算(每次乘、每次加各记一次)。乘上每 SM 的 4 个张量核心,得到每 SM 每周期 4096 次浮点运算;对比 FP32 核心通道的 256 次,相差 16 倍。设备的吞吐量大头全部来自张量核心——想让代码真正吃满 GPU,就必须吃满张量核心。

混合精度与一个常见坑。张量核心以混合精度方式工作:输入通常是 16 位(FP16/BF16 等),乘法在低精度下进行,累加(加法)用 32 位高精度完成,输出也是 32 位。这带来一个很实际的后果:在 PyTorch 层面如果忘了把模型 cast 成 16 位,计算会落到 FP32 核心上,速度比预期慢约 20 倍。这看似琐碎,一旦在代码里踩中就变得非常"刻骨铭心"。

拓展

FP16、BF16 与损失缩放(loss scaling)。课上提到"16 位输入、32 位累加"但没展开格式细节。FP16 用 5 位指数 + 10 位尾数,动态范围窄(最小正规数约 \(6\times 10^{-5}\)),深层网络里小梯度容易下溢,因此经典混合精度训练要配合损失缩放(把损失放大 2 的幂使梯度移入可表示区间,更新前再缩回)并保留一份 FP32 主权重(master weights)。BF16 用 8 位指数 + 7 位尾数,范围与 FP32 相同、精度略低,几乎不需要损失缩放,因此成为现代大模型训练的主流(H100 的 \(989.4\,\mathrm{TFLOPs}\) 峰值即 BF16 口径)。更新的 H100/B200 还支持 FP8(E4M3/E5M2),DeepSeek-V3 等已在超大规模训练中验证了 FP8 的可行性,B200 更进一步提供 FP4。

2.4 十二年一千倍:从 K40 到 B200

老师展示了一张随时间增长的设备峰值吞吐图(横轴 2013 年至今,纵轴每设备 TFLOPs):他读博时人手一块的 K40(2013)整卡只有 \(5\,\mathrm{TFLOPs}\) 的 FP32 算力;到 2016、2017 年的 V100,发生了质变——它是第一块引入张量核心的设备;此后各代产品的张量核心越来越多、越来越大、占芯片面积比例越来越高。最新正式发布的 B200 理论上达到约 \(83.3\,\mathrm{TFLOPs}\) 的 FP32 与约 \(5000\,\mathrm{TFLOPs}\)(\(5\,\mathrm{PFLOPs}\))的张量核心混合精度算力(注意区分:是 \(5000\,\mathrm{TFLOPs}\) 的算力,不是 5000 个张量核心)。

退一步看:这是单块手持尺寸设备在 12 年里 1000 倍的算力增长——老师手里掂过 K40,还没机会掂 B200,但"它们感觉是同一种物理对象:差不多大、差不多重、长得也像,只是今天的比 12 年前快 1000 倍,这太疯了"。为什么过去十年 AI 变得这么强?一个主要答案就在这里:出现了一种被利用起来的算力来源,十年涨了一千倍。世界上任何东西变化 1000 倍都值得高度关注,因为它必然引发技术能力的重大变化。而更疯的是:我们还不止用一块 GPU——今天用几千、几万、有时几十万块 GPU 同时训练一个模型,叠加在单设备 1000 倍之上。

三、GPU 集群:把数据中心当作一台计算机

3.1 层级结构与带宽衰减

从单卡拉远,存储层级的规律在集群尺度上延续——离得越远,带宽越低:

3.2 物理现实:空间、机柜与散热

课堂问答让这些数字变得可感。为什么要有机柜?——总得把机器放在什么地方:机柜是数据中心几十年来的标准单元(标准尺寸、标准硬件),GPU 服务器虽然更大更耗电,但数据中心不可能一夜之间推倒重建。占多大空间?——一个机柜约 6~8 英尺高(讲台大小、比老师略高),一个 pod 是 192 个这样的柜子,再乘 8;而且这是低估:机柜要排成排留出走人的通道,除计算机柜外还有专门的网络设备机柜(海量数据需要飞来飞去)和存储机柜(训练数据总得有地方放、能送进显卡)。发热有多大?——玩游戏的同学生深有体会:桌面上一块 4090 或 5080 打游戏就能把房间加热到想开窗;一块游戏卡尚且如此,把几万块堆进数据中心,散热需求相当严肃(风冷、水冷,厂商在散热硬件上"可以走得很远")。老师总结道:这些东西不是漂浮在"云"里的神兽,而是某人真实建造、真实堆放在某个房间里的原子——想象它们的样子很有意思。

3.3 一台 24 EFLOPs 的"整机"

由此而来的思维转变是:不再把数据中心看成一块块独立的设备或服务器,而是把整个数据中心当作一台大计算机来编程。这台"整机"(Llama3 集群口径)拥有:

"这是很多 FLOPs——但我保证五年后你再回看,就不会觉得多了,这甚至更疯。"于是问题变成:如何在这台巨型超算上、一次连续训练几个月,喂饱一个能吞下海量数据的巨型神经网络?这就是当今深度学习的基本范式。至于训练时长:过去十年的经验法则是最大的模型训练以月计——这更多是人的因素而非技术因素(进度、计划、团队协作都很难支撑超长训练);GPT-4.5、GPT-5 这个级别的模型,老师猜测可能已逼近一年。另有同学问"到了大集群,小单元间还能保持高吞吐吗?"——能,而这正是系统设计的秘密与难点:能拿到快互连时就尽量利用,扩展到慢互连时又能优雅回落(后面 HSDP 与多维并行会反复回到这一点)。

3.4 硬件生态:TPU、AMD 与 Trainium

NVIDIA 是当今最主导的训练硬件,但并非唯一。Google TPU(Tensor Processing Unit)是最大的竞争者:已经历六代,可从 Google Cloud 租到的 v5p 规格与 H100 同一量级;TPU 同样组成 pod,v5p 的 pod 最多 \(8{,}960\) 个芯片(课上是 V2 pod 的照片:256 片、4 个一人高的机柜——可以想象近 9,000 片的 v5p pod 有多大)。Google 的 Gemini 几乎可以肯定训练于 TPU("他们当然不说,但如果不是我会非常震惊")。TPU 里有不少与 GPU 截然不同、非常迷人的设计取舍,可惜课上没时间展开。区别在于:TPU 买不到——要么去 Google 上班,要么在 Google Cloud 租。其他追赶者:AMD 的 MI325X 纸面参数与 H100 相当但影响力远不及;AWS 自研的 Trainium,老师没用过,但知道 Anthropic 的部分训练在用它。总体格局:NVIDIA 与 TPU 在易用性、性能和市场份额上明显领先,其余各家在追。

拓展

互连技术的名字。课上那句"卡间 900 GB/s、pod 内 50 GB/s"背后的真实名字:单机八卡内部的通道是 NVLink/NVSwitch(H100 世代为 \(900\,\mathrm{GB/s}\) 的全互连 fabric);pod 内跨机柜的 50 GB/s 通常由 InfiniBand 或 RoCE(RDMA over Converged Ethernet)的光互连提供(如 \(400\,\mathrm{Gbps} \approx 50\,\mathrm{GB/s}\) 口径,NVIDIA 的 Quantum 交换机与 Meta 自研的 Minipack3 网络都属于此类)。近两年的趋势是把"一台超级计算机"的边界继续下移:NVIDIA GB200 NVL72 用机柜级 NVLink 把 72 壳 GPU 直接连成一台逻辑机,风冷也相应让位于液冷。互连之所以关键,正如本讲反复强调的:GPU 算力的增长快于互连带宽的增长,通信越来越成为扩展的瓶颈。

四、并行训练总览:五个并行维度

第二部分:如何为这台机器写算法。基本策略是拆分计算。计算机本质上只做两件事:计算(从输入比特算出输出比特)与通信(把比特从一处搬到另一处)。整个游戏就是:如何利用集群中多尺度的存储层级,把通信与计算重叠(overlap)起来,同时把计算切开并行,让几万块 GPU、几百万个计算单元在训练巨型网络时时刻刻都有有用的工作可做,并以正确的方式把各自的结果汇总起来。

老师喜欢的思考框架:当今大规模训练(以 Transformer 为主流架构)中共有五个并行维度。Transformer 是 L 层的堆叠,每层作用在一个三维张量上——batch(小批次)\(\times\) sequence(序列)\(\times\) dim(特征维度):若干序列组成一个 minibatch,每个 token 又是 dim 维向量。这给出四个可切的轴:

名字五花八门,但本质上都是"在 Transformer 计算的四个轴上找不同的切法"。下面依次展开,其中 DP/FSDP/HSDP 讲得最细——那是同学们实践中最可能用到的。

五、数据并行(DP)

5.1 数学原理:梯度是线性的

训练永远在 minibatch 上进行:对 batch 中每个样本算损失,梯度通常是各样本损失的平均。而大多数网络里,各样本的损失与梯度计算相互独立——天然可并行。设 \(M\) 块 GPU、每卡放 \(N\) 个样本(宏批 macrobatch 共 \(M\times N\) 个),\(x_{i,j}\) 表示第 \(i\) 卡的第 \(j\) 个样本,总损失与梯度为:

$$L(W) = \frac{1}{MN} \sum_{i=1}^{M} \sum_{j=1}^{N} \ell(x_{i,j},\, W)$$
$$\nabla_W L = \frac{1}{M} \sum_{i=1}^{M} \left[ \frac{1}{N} \sum_{j=1}^{N} \nabla_W \ell(x_{i,j},\, W) \right]$$

因为梯度是线性的,求和与求平均的顺序可以重排:蓝色方括号内的内层项就是一次普通的 \(N\) 样本前向反向,可以在不同 GPU 上并行完成;外层再对 \(M\) 个设备取平均。这不是近似——数学上与单卡训练完全等价,只是代数上聪明地换了求和顺序。

5.2 五步流程

  1. 各自加载不同的 minibatch。每卡持有网络权重、优化器状态、梯度的独立副本,并加载各自不同的 \(N\) 个样本。老师特别警告:他自己的代码和学生代码里都出现过所有 GPU 加载了同一个 minibatch 的 bug——那完全没用,千万别犯。
  2. 独立前向:各卡对自己的 minibatch 算本地损失,完全无需通信。
  3. 独立反向:各卡对自己的损失算关于全部权重的本地梯度,同样无需通信。
  4. All-Reduce 梯度:这里才是麻烦的开始。每卡要把自己的梯度广播给所有卡,同时从所有卡收集梯度——这就是 all-reduce(全归约)操作,通常以关于卡数的对数时间完成。结束后每卡都持有全局平均后的完全相同的梯度。
  5. 本地更新:各卡在本地副本上做权重更新;因为起点权重相同、应用的梯度相同(在算术确定性的假设下),更新后各卡权重仍然一致。

一个关键细节:每层都存在两版梯度——本地梯度(我的 minibatch 的损失对权重之导数)与全局梯度(整个 macrobatch 损失对权重之导数)。反向传播只需要本地上游梯度就能逐层算下去;只有当需要全局版本时才必须通信。

5.3 用反向传播掩盖通信

第 3、4 步在实践中同时发生:当计算单元忙着算倒数第二层的反向时,网络同时在对最后一层的梯度做 all-reduce——"算第 \(L\) 层反向、传第 \(L+1\) 层梯度"这样交替推进(chunk along),理想情况下反向传播结束时梯度恰好已经归约完毕,可以立即更新、无需等待。这非常重要:通信相对慢,整个技巧就在于把通信开销藏进计算里。有同学问"第 4/5 步会不会成为瓶颈?"——答案是"看情况":取决于设备速度、模型大小、minibatch 大小、互连速度;大规模分布式训练的答案永远是 it depends,必须针对自己的场景做基准测试

5.4 课堂问答:同步还是异步?

有同学提出一个妙想:"为什么不让各副本各自走 \(M\) 步、偶尔再平均?"——这确实是曾经流行过的一族算法:异步 SGD(asynchronous SGD):多个模型副本各自独立更新,隔一段时间平均一次。Google 在开发 TPU pod 之前(2010 年代早期的一些网络)就是这么训练的。但它更不稳定、难以调试和复现,效果往往略差。看起来更"可扩展",但实践法则 是:如果能做同步更新,就做同步——更容易调试、理解和推理,效果也通常更好。不过老师个人预测:异步方法未来几年可能回潮,因为它对分布式训练天然更友好——没有一个"上帝视角"的驱动器能统筹一切,所有计算总要发生在某处,异步更契合这种去中心化的现实。

5.5 软件栈:谁来调度重叠?

问答:"通信与计算的重叠要自己写代码吗,还是硬件自动做?"——必须写代码。硬件只懂底层小矩阵乘这类东西,任何通信调度都要靠软件。好消息是常见场景 PyTorch 已内置:DistributedDataParallel(DDP)类会在你原有的 PyTorch 代码之上相对透明地完成这一切。这里有个有趣的不对称:单卡内部用 CUDA(NVIDIA 的类 C 语言)编程时,硬件确实会自动处理很多异步传输;集群层面则必须靠软件编排。整个系统是异构的:底层 GPU kernel 用 CUDA 写,再包上 C++/Python 封装供调用——PyTorch 本质上就是"一堆能做各种有趣事情的 GPU kernel + 让它们好用的封装"。

深入

算一笔通信账(扩展效率示例)。以 80 亿参数、BF16 训练的模型为例:梯度张量约 \(16\,\mathrm{GB}\)。环形 all-reduce 中每卡收发约 \(2(M-1)/M \times V\) 的数据量,\(M = 8\) 时为 \(1.75 \times 16\,\mathrm{GB} =\) \(28\,\mathrm{GB}\)

这就解释了后面的一切设计:通信量大的并行方式要圈在快互连里(机内/机柜内),跨慢互连只走通信量小的并行方式。另外把本地 batch 砍半,计算时间减半而通信量不变,通信占比翻倍——所以老师说"本地 batch 尽量撑满显存几乎总是对的"。

六、显存瓶颈与 FSDP:把模型状态切开来

6.1 显存账本:每个参数要养活 4~5 个标量

数据并行是人们最早并行化训练的方式,但很快撞上模型规模的瓶颈:每卡都保存整套模型状态的独立副本。现在每个权重实际上要维护4~5 个标量:权重本身、它的梯度,以及优化器状态——用 Adam 的话是每个参数的 \(\beta_1\) 与 \(\beta_2\) 统计量,有时还有权重的指数滑动平均(EMA)。按 16 位训练的下界算(2 字节/数):

$$4\ \text{个数} \times 2\ \text{字节} = 8\ \text{字节/参数} \;\Rightarrow\; 10\ \text{亿参数} \approx 8\,\mathrm{GB}\ \text{显存}$$

H100 整卡只有 80 GB——纯数据并行最多训约 100 亿参数的模型,这远远不够。我们不想被"GPU 显存大小的暴政"规定能训多大的模型。修法其实很直接:除了切数据,也把模型权重切开分到各卡

6.2 FSDP:全分片数据并行

Fully Sharded Data Parallelism(FSDP)概念上很简单:把每层视为一个权重矩阵 \(W_i\),每个 \(W_i\) 指定唯一的"属主 GPU(owner)";属主不仅保管该权重分片,也负责保管它的全局梯度和优化器状态。训练仍然是数据并行:各卡加载各自 minibatch、做完整的前向反向、聚合梯度、更新——只是权重现在是散装的,于是需要额外的通信编排:

反向传播中同时有三件事在飞:① 广播第 \(L\) 层权重;② 算第 \(L\) 层反向;③ 把第 \(L+1\) 层梯度发给属主并更新。稳态下三者完全重叠:算第 \(L\) 层反向时,正在聚合并更新第 \(L+1\) 层、预取第 \(L-1\) 层权重。逐层回退到网络开头时,梯度都已传完、所有属主都已更新完毕;与此同时 CPU 上的 DataLoader 也在异步准备下一个 batch。这些系统就是并行化机器——卡内、卡间一切能重叠的都尽量重叠,让张量核心尽可能密集地忙碌。

6.3 HSDP:混合分片数据并行

FSDP 能走很远,但还有更讲究的变体:Hybrid Sharded Data Parallelism(HSDP)——把 GPU 概念上排成二维网格,同时用两条并行轴:

为什么值得搞两维?两种并行的通信量不同:FSDP 组内一次前向反向要传三倍模型权重量的数据(前向权重一倍 + 反向重发权重一倍 + 梯度一倍);而组间 DP 只需 all-reduce 梯度,即一倍权重量。于是可以把它映射到集群层级:通信量大的 FSDP 圈在机内(8 卡、900 GB/s 快互连),通信量小的 DP 跨服务器/机柜(慢互连)——每个服务器持一份完整模型,服务器之间只传梯度。这是本讲第一个"依据已知网络拓扑设计算法"的例子。至于"该怎么取 K 和 M"——老师的原话是"这些旋钮没法调(impossible to tune),很难说清",又取决于具体场景。

FSDP 的显存收益可以用一个例子体会:1,000 亿参数的模型需 800 GB 状态存储——单卡放不下;分片到 80 张 GPU 上每卡只需 10 GB,就绰绰有余了。DP/FSDP/HSDP 是同一族算法的三档:副本数递减、单卡显存占用递减、通信编排递复杂。
拓展

FSDP 与 ZeRO 的关系。FSDP 是 PyTorch 对微软 ZeRO(Zero Redundancy Optimizer)思想的实现:ZeRO-1 只切优化器状态,ZeRO-2 加切梯度,ZeRO-3 再加切参数(对应完整的 FSDP),分层削减冗余。工程上还有 DeepSpeed、FSDP2/完全分片分布式优化器等实现。另一个有用的数字:混合精度 + Adam 的完整状态其实是 每参数约 16 字节(FP32 主权重 \(4\) + 一阶矩 \(4\) + 二阶矩 \(4\) + BF16 权重 \(2\) + BF16 梯度 \(2\))——课上"有些数会用更高精度保存"的含糊说法,指的就是主权重与优化器矩通常保持 FP32。

七、激活检查点:用计算换显存

FSDP 解决了模型状态的显存,但下一个膨胀的是激活(activations)本身。回到 Llama3-405B:126 层、模型维度 \(16{,}384\)、序列长 \(4{,}096\)——光是前向过程中间隐藏状态的存储量就非常可观,模型和序列一大就会迅速把 GPU 显存吃光。对策是激活检查点(activation checkpointing,也叫梯度检查点):不保存全部激活,反向时重算

把每层看成"前向算激活 + 反向吃(上游梯度 \(\times\) 激活)算梯度"的模块,设网络共 \(N\) 层:

$$\text{计算 } \mathcal{O}(N^2/C),\ \text{显存 } \mathcal{O}(C);\quad \text{取 } C = \sqrt{N} \;\Rightarrow\; \text{计算 } \mathcal{O}(N\sqrt{N}),\ \text{显存 } \mathcal{O}(\sqrt{N})$$

这是用计算换显存的标准折中,也是训练更大模型的重要工具。老师的评价很实在:"激活检查点很讨厌(sucks)——它让一切都变慢,但确实能让你训大得多的模型。"

八、实用扩展路线图与北极星指标 MFU

8.1 一条能走很远的配方

有了 DP、FSDP、HSDP、激活检查点,老师给出一条实用扩展配方(他强调这是在场同学实践中最可能用到的部分——"我不觉得这间教室里谁有一万卡的集群;如果你有,下课来找我,我很想和你交朋友"):

  1. 裸数据并行 DP:约 128 卡以内、10 亿参数以内的模型直接用;并把每卡本地 batch size 尽量撑满 GPU 显存——这几乎永远是对的。
  2. 模型超过约 10 亿参数(取决于显存与互连):切换到 FSDP,可以向上扩展不少。
  3. 撞上激活显存瓶颈:打开激活检查点(代价是变慢),可扩展到数百卡
  4. 约 256~512 卡量级(视集群拓扑):FSDP 通信变得太贵,切到 HSDP——可支撑数百亿参数、约一千卡、较长序列的训练。
  5. 超过约一千卡、500 亿参数、序列长过万:才需要动用进阶策略——上下文并行、流水线并行、张量并行

随之而来的焦虑是:"全局 batch、本地 batch、HSDP 维度、FSDP 维度、重算比例……旋钮这么多,我该调哪个?"答案是优化一个核心指标——MFU(Model Flops Utilization,模型算力利用率):"每当你在 GPU 并行的大海里迷航,MFU 就是你的指路明灯。"

8.2 先谈 HFU:硬件算力利用率

H100 的张量核心理论峰值是 \(989.4\,\mathrm{TFLOPs}\)(BF16)——但实际能拿到多少?HFU(Hardware Flops Utilization)\(= \text{实际吞吐} \,/\, \text{理论峰值}\)。测起来不难:老师展示了他在 H100 上跑的一个几行 PyTorch 的基准——循环做稠密矩阵乘、计时,横轴矩阵尺寸从 512 到 32,000。结果是:矩阵一大(约 \(8{,}000\times 8{,}000\) 起),简单循环就能拿到约 80% HFU,相当不错。但 HFU 的问题在于它没算模型要做的其他事:数据加载、数据增广、也许还有别的模型在旁边跑……GPU 干的活不止是赤裸裸的前向反向。

8.3 MFU:真正要最大化的东西

\(\mathrm{MFU} = \dfrac{\text{模型前向反向实际消耗的算力}}{\text{GPU 理论峰值} \times \text{训练一步的实测时长}}\),只把"花在你的模型前向反向上的 FLOPs"计入分子。计算步骤:

  1. 依据模型架构(层数、层尺寸)算出一次前向反向在给定 minibatch 上的 FLOPs;
  2. 查设备理论峰值,相除得到"理论最快一步时长";
  3. 实测训练循环的真实一步时长(它还包含数据加载、增广、通信、检查点重算等一切开销);
  4. 两者相除,得到 0~1 之间的 MFU。

老师现场演示:单卡 H100 上跑一个"超宽 MLP + ReLU + 巨大 batch"的基准,约得 50% MFU。经验阈值:如今 MFU \(\gt 30\%\) 就算不错;远低于 30% 说明某处有巨大瓶颈、有东西不对劲;\(\gt 40\%\) 已非常出色,基本是业界最强水平。来自论文的实数:Llama3-405B 的最终训练阶段在 \(8{,}000\sim 16{,}000\) 卡上同时训练,MFU 约在 \(38\%\sim 43\%\)(高 30 到低 40)——在 H100 上很难再高多少。有趣的是新设备反而可能 MFU 更差:H100 之前的 A100 世代有时能做到 50% 以上,原因正是上文那笔账——算力涨得比通信快:A100→H100 计算峰值约 3 倍提升,显存带宽只有约 2 倍,算力与互连之间的鸿沟在拉大。

深入

用 MFU 估算训练时长:以 Llama3-405B 为例。大模型界通行的估算是训练总计算量 \(C \approx 6ND\)(\(N\) 为参数量、\(D\) 为训练 token 数:前向约 \(2ND\),反向约两倍)。Llama3-405B:\(N = 405\times 10^{9}\),\(D \approx 15.6\times 10^{12}\):

$$C \approx 6 \times 405\times 10^{9} \times 15.6\times 10^{12} \approx 3.8\times 10^{25}\ \text{FLOPs}$$

在 \(16{,}384\) 张 H100 上:峰值合计 \(16{,}384 \times 989.4\,\mathrm{TFLOPs} \approx 1.62\times 10^{19}\,\mathrm{FLOPs/s}\)。按 \(\mathrm{MFU} = 40\%\) 计,有效算力 \(6.49\times 10^{18}\,\mathrm{FLOPs/s}\),训练时长 \(\approx 3.8\times 10^{25} / 6.49\times 10^{18} \approx 5.8\times 10^{6}\) 秒 \(\approx\) 68 天,约两个多月。这与老师"最大模型以月计"的经验法则、与论文披露的 MFU 38%~43% 相互印证。反过来看,若 MFU 从 40% 掉到 20%,训练直接从两个月变四个月——这就是为什么"所有旋杆都往 MFU 最大化去调"。

九、进阶并行策略:CP、PP、TP

老师说明:以下三招主要服务于万卡级集群,多数同学暂时用不到("有万卡的同学请下课来找我"),课件可课后细看,因此讲得稍快,但每个都要覆盖。

9.1 上下文并行(CP):切序列轴

让不同 GPU 处理长序列的不同片段。对 Transformer 的很大一部分这很容易:LayerNorm、FFN/MLP、残差连接本来就沿序列维度逐位置独立计算,切开后照算即可(MLP 里因为有权重,梯度需要像 DP 那样做 all-reduce,略麻烦但直接)。真正麻烦的是注意力:它计算序列中每一对 token 之间的全对交互。QKV 投影仍然平凡可切,但核心注意力矩阵很难并行。两条经典路线:

实际例子仍看 Llama3 预训练的两阶段:第一阶段序列长 8K、完全不用 CP;第二阶段把序列拉到约 13 万(128K),同时启用 16 路 CP——每条 13 万长的序列由 16 块 GPU 并行处理,相当于"每卡分到不足一个样本",batch 被切成了 \(1/16\)。

9.2 流水线并行(PP):切层轴

直觉上最自然的切法:把 \(L\) 层分成几段,各段放不同 GPU。问题在于层间是串行依赖:前向要等上一段的激活,反向要等上游的梯度。画出时间图(纵轴 GPU 1~4,横轴时间):GPU1 前向 → 把激活传 GPU2 → … → GPU4(幸运儿,前向反向一口气做完)→ 梯度再逐级传回。显然极差:\(N\) 卡流水线,每卡只有约 \(1/N\) 的时间在干有用功——8 路 PP 的 MFU 上限只有约 12%。GPU 干等的那段时间有个可爱的名字:气泡(bubble)

压缩气泡的办法是同时注入多个微批(microbatches):不再一次只推一个 batch,而是让多个 batch 同时在流水线中穿行——GPU1 做完蓝批前向就做黄批,同时蓝批的激活已传给 GPU2 开工……反向同理级联。PP 的 MFU 上限有干净的表达式(\(p\) 为流水线深度、\(m\) 为微批数):

$$\mathrm{MFU}_{\max} = \frac{m}{m + p - 1}\text{,}\quad \text{气泡占比} = \frac{p - 1}{m + p - 1}$$

代入老师的例子:\(p=8\)、\(m=1\) 时为 \(1/8 \approx\) \(12\%\)(即"\(1/N\)");\(p=4\)、\(m=4\) 时为 \(4/7 \approx\) \(57\%\)——"图中非白色部分的占比",相当不错。微批越多 MFU 越好,但每个在飞的微批都要存激活,于是又得开激活检查点——"更多还是更少的流水线深度?更多还是更少的微批?更激进的重算?再叠一层数据并行?"答案依旧是:调它们,去最大化 MFU

9.3 张量并行(TP):切维度轴

Transformer 里反复做的就是 \(XW = Y\)。TP 的做法是把单个权重矩阵本身切开分到多卡——注意这与 FSDP 不同:FSDP 按"层"为粒度把不同层分给不同属主,TP 是把同一个权重矩阵切块。每卡拿一个分块 \(W_k\),对完整的输入 \(X\) 做分块矩阵乘,各自算出输出的一个切片。问题:一层算完后要把各卡的输出激活gather 起来才能进入下一层。

深入

两层一通信的经典技巧。若连续两层 \(Y = X\cdot W^{(1)}\cdot W^{(2)}\),可以只在两层的首尾通信一次:把 \(W^{(1)}\) 按切成 \([W_1^{(1)},\ \ldots,\ W_p^{(1)}]\),把 \(W^{(2)}\) 按切成上下堆叠的 \(W_k^{(2)}\),则由分块矩阵乘法:

$$Y = \sum_{k=1}^{p} \left( X \cdot W_k^{(1)} \right) \cdot W_k^{(2)}$$

第 \(k\) 卡持有第 \(k\) 组列块与行块,独立算出部分积 \(Y_k\),最后各卡把 \(Y_k\) 相加(all-reduce)即得完整输出——"坐下来找个安静的地方推一遍,一切都会神奇地成立,这就是分块矩阵乘的魔法与神秘"。妙在Transformer 的 FFN 恰好是两层 MLP,这个"两层一通信"的技巧与它严丝合缝,所以大型 Transformer 普遍在 MLP 上使用这种张量并行。

十、多维并行:全都要

"哪种并行最好?"——真实答案是全都要:实践中采用 N 维并行(ND parallelism)。HSDP 已经是二维的例子;当前最强的实践是四维并行。回到 Llama3:其最大规模训练跑在 \(16{,}384\) 块 GPU 上,同时使用 8 路张量并行 \(\times\) 16 路上下文并行 \(\times\) 16 路流水线并行 \(\times\) 8 路数据并行(\(8\times 16\times 16\times 8 = 16{,}384\))。不同并行机制的通信需求各不相同——只要精心地把各条并行轴沿着集群拓扑排布(通信量大的轴放在快互连上、通信量小的轴跨慢互连),就能利用集群中参差的多级带宽,把整台"数据中心计算机"吃满。

全讲收束于三句话总结:单块 GPU 是一台通用化的并行计算机;GPU 集群是一台拥有数万乃至数十万块 GPU 的巨型并行机器,要当作一个整体来编程;为此我们学习了切分计算的多种并行机制、省显存的一个技巧(激活检查点),以及设计这些流水线时永远要优化的指路明灯——模型算力利用率 MFU。"下次你出门用几万块 GPU 训练时,希望你还记得这些——并且告诉我一声,好让我借你的几万块 GPU 用用。"

拓展

MoE 训练与最新超大模型实践。本讲的机制之外,当代超大模型还有两条值得关注的实践线。其一是混合专家(MoE):第 9 讲提过的"路由器 + 多专家 MLP"结构让参数量与计算量解耦,但训练时必须引入专家并行(expert parallelism)——把不同专家放在不同 GPU 上,token 按路由结果跨卡分发,这实际上又增加了一条并行轴(DeepSeek 系还用"细粒度专家 + 共享专家 + 无辅助损失的负载均衡"来缓和路由不均)。Llama4(老师提到的 2025 年 4 月发布)也已改用 MoE 架构。其二是训练经济学与工程韧性:DeepSeek-V3 以 6710 亿总参数/370 亿激活参数的 MoE、FP8 混合精度与精细的计算-通信重叠,把预训练成本压到约 558 万美元(2,048 张 H800、约两个月);而以月计的训练意味着硬件故障是常态而非例外——Llama3 报告披露,仅 54 天的主训练快照期内就发生了四百多次训练中断(多数源于硬件),全靠自动检测、检查点续训与回滚机制才把训练跑完。异步/去中心化优化器的回潮(老师在问答里的预言)、超长上下文阶段训练等,也都是这一领域正在发生的方向。

本讲要点回顾

上一讲第 10 讲:视频理解 下一讲第 12 讲:自监督学习