训练 Infra 01:算力、显存、带宽的三角,与一张集群带宽地图
从 H20 的机器平衡点讲起,解释为什么它是推理卡却在做训练,为什么 96GB 显存直接买通了 TP1 的并行设计,以及 NVLink/RoCE/NFS 三级带宽如何决定 EP8 与 DP40 的分工。
训练 Infra 01:算力、显存、带宽的三角
本节属于大模型训练 Infra 实战课。教材项目是 40 卡 H20 上的 Qwen3.6-35B-A3B 后训练,所有数字都是真实实测值。
训练 infra 的所有决策——并行怎么切、batch 怎么设、为什么 MFU 只有 8%——最终都能还原成同一个问题:数据在哪一层硬件之间流动,那一层的带宽够不够。
所以第 1 节我们把硬件栈从卡内一路捋到跨机,建立一张"带宽地图"。后面七节全部是在这张地图上做文章。
1. 一块 GPU 的三角:算力 / 显存 / 带宽
直觉
把 GPU 想成一个工厂:
- 算力(FLOPs) = 车间里工人的干活速度
- 显存容量(GB) = 仓库能囤多少原料
- 显存带宽(TB/s) = 仓库到车间的传送带速度
决定这块卡适合什么活的,不是三者的绝对值,而是它们之间的比例。工人极快但传送带慢,工人就整天在等料;仓库巨大但工人不多,就适合囤大件慢慢干。
H20 是后者。
H20 到底是一块什么卡
| H20 | H100 SXM | A100 80G SXM | H800 | |
|---|---|---|---|---|
| bf16 稠密算力 | 约 148 TFLOPs | 约 989 TFLOPs | 约 312 TFLOPs | 约 989 TFLOPs |
| 显存 | 96 GB HBM3 | 80 GB | 80 GB | 80 GB |
| 显存带宽 | 约 4.0 TB/s | 约 3.35 TB/s | 约 2.0 TB/s | 约 3.35 TB/s |
| NVLink(双向) | 900 GB/s | 900 GB/s | 600 GB/s | 400 GB/s |
H20 的出身一目了然:它是出口管制版的 H100——算力砍到 H100 的约 15%,但显存反而更大、带宽反而更高、NVLink 一刀未动。
这不是均衡设计,是"戴着镣铐设计"的产物。理解这一点,是理解后面所有取舍的前提。
公式:机器平衡点(machine balance)
判断一块卡偏科在哪,只需要一个数:
balance = 峰值算力 / 显存带宽 单位:FLOPs/byte
含义是:一段计算,如果它每从显存搬 1 个字节能做的浮点运算数(即"运算强度",arithmetic intensity)超过这个 balance,它就是算力受限(compute-bound);低于它,就是带宽受限(memory-bound)。这就是 Roofline 模型的核心。
代入三块卡:
H20 : 148e12 / 4.00e12 ≈ 37 FLOPs/byte
A100 : 312e12 / 2.00e12 ≈ 156 FLOPs/byte
H100 : 989e12 / 3.35e12 ≈ 295 FLOPs/byte
现在把两种典型负载摆进来:
训练中的大矩阵乘(比如 49K 序列打包成的 GEMM):运算强度轻松上几百甚至上千 FLOPs/byte,在三块卡上都远远越过各自的 balance → 全部是 compute-bound → 比拼的是算力,H20 只有 H100 的 15%。
推理 decode(batch 很小):每生成 1 个 token,基本要把激活参数完整读一遍。每读 2 字节(bf16)大约做 2 次运算,运算强度约 1 FLOPs/byte → 深度 memory-bound → 比拼的是带宽,H20(4.0 TB/s)反而比 H100(3.35 TB/s)还快。
一个公式就解释了 H20 的江湖定位:它是推理卡。
拿它做训练,就是在用它的短板干活。所以后面第 6 节测出 MFU 只有 8-10% 时不用太自责——那个数字里有多少是 H20 的锅、多少是 MoE 和长序列的锅,我们会一项一项拆开。
项目实例:96GB 显存如何"买通"了整个并行设计
教材项目的配置是 TP=1 / PP=1 / EP=8 / DP=40,序列 49K,micro batch=1,full recompute,实测峰值显存 85.6GB。
注意 85.6 这个数。
在 H100(80GB)上,这套配置直接 OOM。 你会被迫上 TP=2,或者做更激进的 offload。而 TP 会引入每层两次 all-reduce 的通信开销,拓扑复杂度、调试难度、故障面立刻全部上升。
也就是说:H20 用多出来的 16GB 显存,换掉了 TP 的通信成本和全部工程复杂度。
大显存弱算力的卡,正确用法就是"用显存换简单"——把并行度做低、把单卡装得满满的、接受算力上限。这套配置是教科书式地顺着这块卡的性格来的。
集群总账记一下,第 6 节算 MFU 要用:
40 卡 × 148 TFLOPs = 5.92 PFLOPs 峰值算力
2. 节点内互联:NVLink vs PCIe
直觉
显存墙之外的第二堵墙是通信墙。GPU 之间交换数据走哪条路,决定了哪种并行策略"付得起"。
- NVLink 4 + NVSwitch:每卡 900 GB/s 双向,节点内 8 卡经 NVSwitch 全互联,任意两卡等距
- PCIe Gen5 x16:约 64 GB/s 单向
差距约 14 倍。于是有一条经验法则:
每层都要通信的并行(TP 的 all-reduce、EP 的 all-to-all)必须关在 NVLink 域内;每步才通信一次的并行(DP 的梯度同步)才允许跨出去。
项目实例:EP=8 恰好等于一台机器
这是整套配置里最漂亮的一步棋:EP=8,恰好是单节点的 8 张卡。
Qwen3.6-35B-A3B 是 MoE。每个 MoE 层的 token 要按路由结果分发到不同专家(一次 all-to-all),算完再收回来(第二次 all-to-all)。这是每个 MoE 层都要发生两次的通信,频率极高。
EP=8 把专家切到本机 8 卡上,意味着:
- 所有 all-to-all 流量走 900 GB/s 的 NVLink
- 如果贪心设成 EP=16(跨 2 台机器),这些流量就要走 RoCE 网卡,带宽掉 20 到 40 倍;而 all-to-all 是所有集体通信里最怕慢链路的——一条链路慢,整组一起等它
"每 4 层 1 层全注意力,其余是 GDN 线性注意力"这个混合结构不改变上面的结论。但它意味着 MoE 的 FFN 部分在计算里占比更高,all-to-all 的频率照旧——EP 域的带宽依然是生命线。
3. 节点间网络:以太网 / InfiniBand / RoCE
三种"跨机说话"的方式
普通以太网 + TCP:数据经过 CPU 内核协议栈,拷贝多、延迟高、吃 CPU。只配跑管理流量、SSH、日志。
InfiniBand(IB):原生 RDMA——网卡直接读写对端内存,绕过双方 CPU;链路层用 credit 流控从根上避免丢包。训练集群的贵族方案。
RoCE v2:把 RDMA 跑在以太网上。便宜,但要求"无损以太网"(PFC/ECN 配置正确),配不好就丢包重传、性能雪崩。是 IB 的平民替身,也是本项目集群的方案。
再加一个关键技术:GPUDirect RDMA——网卡直接读写 GPU 显存,不用先拷到主机内存。NCCL 检测到 RoCE/IB 时会自动启用。
带宽量级:单口 100/200/400 Gbps 分别是 12.5/25/50 GB/s,多网卡可聚合。但即使聚合到 100 GB/s,也比 NVLink 低一个数量级。这就是"DP 放跨机、EP 放机内"的物理依据。
项目实例:跨机流量到底是什么
5 节点 × 8 卡,eth0 走管理面,RoCE 多网卡走数据面。跨节点的主要流量是 DP=40 的梯度同步(distributed optimizer 的 reduce-scatter + all-gather,第 3、4 节细讲)。
关键的量级感在于频率对比:
| 流量 | 频率 | 走哪条路 |
|---|---|---|
| EP all-to-all | 每个 MoE 层 × 每个 micro batch,2 次 | NVLink 900 GB/s |
| DP 梯度同步 | 每个 global step 1 次(梯度累积 2) | RoCE |
| checkpoint 落盘 | 每几百步 1 次 | NFS |
低频的放慢网络,高频的放快网络。 在 120 秒一步的节奏下,跨机梯度同步只占其中一小段——所以通信不是当前的主要瓶颈,算力才是。
常见坑:多网卡选口与脏环境变量
这是第六次排障的现场。多网卡环境下 NCCL 有两条独立的路,由两个变量分别控制:
- 控制面(bootstrap / 握手)走 socket:
NCCL_SOCKET_IFNAME选网口。选错(比如选到 docker0 虚拟网卡,或选到一个不通的口),初始化直接挂,或者静默退化到慢速口 - 数据面走 RDMA:
NCCL_IB_HCA选 RoCE/IB 设备
真正咬人的坑更隐蔽:节点全局 bashrc 里残留了不一致的 NCCL 调试变量。
NCCL 的很多环境变量会改变通信算法和协议的选择。5 台机器里只要有 1 台配置不同,集体通信双方的"舞步"就对不上——结果是死锁,而且报错信息几乎为零。
教训很硬:
- NCCL 环境变量必须由启动脚本统一注入,全集群逐字节一致
- 任何人不许往系统级 bashrc 里塞训练相关的环境变量
- 启动前应该主动 dump 一次全集群的相关环境变量做 diff
这也是第 7 节"容器化隔离的价值"的引子——容器化解决的正是这一类"人为不可控的宿主机状态"。
4. NFS 共享存储:训练中的第四个角色
直觉
NFS 是"全集群共享的慢仓库":容量大、带宽低(典型 1 到几 GB/s)、延迟高、并发写弱。它承担三件事:数据集、代码、checkpoint。
读的账:数据加载
每步 80 样本 × 平均 29K token = 2.31M token
tokenized 后每 token 几个字节
→ 每步从 NFS 读约 10MB 量级
→ 摊在 120 秒里可以忽略
结论:这套负载里数据加载不是瓶颈。长序列 + 重计算的 workload 天然如此——单步算得太久,IO 有充足的时间窗口。
反过来,短序列小模型高吞吐的场景就未必了,那时要上本地缓存和流式预取。
写的账:checkpoint
35B 参数,按 Adam 训练态算:
bf16 权重 : 35e9 × 2 字节 = 70 GB
fp32 主权重 : 35e9 × 4 字节 = 140 GB
Adam 两份动量 : 35e9 × 8 字节 = 280 GB
------------------------------------------------
全量 checkpoint ≈ 490 GB,即 500 GB 量级
按 NFS 写带宽 1 GB/s 估算:
存一次 ≈ 490 秒 ≈ 8 分钟 ≈ 4 个训练步白跑
这一笔账解释了三件事:
- 为什么
save_steps不敢设密 - 为什么 Megatron 用"每个 rank 写自己分片"的 distributed checkpoint,而不是 rank0 单点写全量
- 为什么高级方案要做异步 checkpoint——先落本地盘,再后台搬 NFS
第 7 节讲 checkpoint 策略时会回到这笔账。
常见坑
- 40 个 rank 同时往 NFS 写分片 → NFS 抖动,写入耗时方差巨大,慢的那个 rank 拖住全组
- 反过来 rank0 单点写全量 → 稳定但奇慢
- NFS 客户端缓存一致性:A 节点刚写完的文件,B 节点立刻读可能读到旧内容。续训脚本里"存完马上校验/加载"的逻辑要特别小心
- 把 Python 环境装在 NFS 上 → 几百个进程同时 import,启动卡几分钟。环境放本地盘或打进镜像
5. 收官:一张带宽地图
把本节所有数字排成一个层级,每降一级大约掉一个数量级:
| 层级 | 带宽 | 上面跑什么 |
|---|---|---|
| HBM(卡内) | 约 4 TB/s | 一切计算的供料 |
| NVLink(节点内) | 900 GB/s | EP 的 all-to-all(本项目);TP 的 all-reduce(别人) |
| PCIe | 约 64 GB/s | CPU 与 GPU 之间搬运、offload |
| RoCE(跨节点) | 约 12.5-50 GB/s/口 | DP 梯度同步 |
| NFS | 约 1 GB/s | 数据集、checkpoint |
并行策略设计的本质,就一句话:让高频通信发生在高带宽层级。
回看这套配置:EP8(每层通信)关在 NVLink,DP40(每步通信)放到 RoCE,checkpoint(每几百步)扔给 NFS——每一种流量都待在了它付得起的那一层。
后面所有章节,都是这张地图的展开。
思考题
1. 假设把这套训练搬到 1 台 8×H100(80GB)上跑同样的 49K 序列 SFT:显存和算力哪个先成为约束?你会怎么改并行配置?
提示:85.6GB 峰值 > 80GB 容量,你必须省出至少 6GB。有 TP、更狠的 recompute、offload 三条路,各自的代价是什么?
2. 用 1.1 节的方法论证"H20 训练弱、推理强":
- (a) 训练时大 GEMM 的运算强度远高于 37 FLOPs/byte,说明比的是什么?
- (b) 推理 decode 时,每生成 1 个 token 至少要读一遍激活参数(3B × 2 字节 = 6GB),做约 2 × 3B = 6 GFLOPs。按 H20 的 4 TB/s 带宽,理论 decode 上限是多少 token/s?换成 H100(3.35 TB/s)呢?谁快?
下一节进入显存账:把 85.6GB 这个峰值逐项拆开算给你看,并解释那次让 39 张卡静默死锁 5 小时的优化器惰性初始化陷阱。