用户在聊天框里问了一句话,等了一会儿,答案一个字一个字地冒出来。这两三秒花在了哪里,又是谁决定的?在下面这个手算例子里,九成以上的时间花在逐个生成 token 的 decode 上;而 decode 有多快,主要看 GPU 每秒能从显存(HBM)读多少字节,不是它每秒能做多少次乘法。 这个系列就从这个数字出发,一层层往下追到芯片和工厂,再走回产品。
待审核草稿。 这一篇还没有经过站主审阅,事实、取舍和措辞都可能修改;引用前请回到文中链接的一手资料核对。
九层地图:从晶圆到产品
从下往上读。“先看哪个数”是排查时的第一个问题,不是说这一层只受这一个数限制。
| 层 | 做什么 | 通常先看哪个数 | 读哪篇 |
|---|---|---|---|
| 1 制造与封装 | 在晶圆上做出 die,测试、切割,再和 HBM 一起封装 | 每片晶圆能出多少个好 die;先进封装与 HBM 的产能 | 芯片怎么造出来 |
| 2 芯片 | CPU 管控制和数据准备,GPU / 加速器算大矩阵 | 峰值 FLOP/s(注明精度、dense 还是 sparse)与显存带宽之比 | CPU 架构、GPU 架构、NVIDIA 各代 GPU |
| 3 服务器、互联、机柜 | 把 GPU、CPU、网卡连起来:PCIe、NVLink、InfiniBand / Ethernet;供电与散热 | 每张卡的卡间带宽,分清节点内和节点间,分清 GB/s 和 Gb/s | NVIDIA 各代 GPU、多卡训练 |
| 4 集群软件与调度 | 驱动、CUDA runtime、容器,Kubernetes / Slurm 把 GPU 分给任务 | 分出去的 GPU 有多少时间真在算:排队时间、空闲率 | CUDA、Kubernetes |
| 5 kernel 与库 | cuBLAS 做矩阵乘,cuDNN 提供常见 DNN 算子,NCCL 做集合通信(collective communication),Triton 写自定义 kernel | 达到峰值的百分比;算术强度落在屋脊点哪一边 | CUDA、性能、attention kernel |
| 6 框架 | PyTorch 把模型代码变成一串 kernel;编译器做融合;分布式训练切分状态 | 单步耗时、MFU(实际算力占峰值的比例)、CPU 发射 kernel 的开销 | 框架、训练框架、张量并行 |
| 7 训练与推理系统 | serving engine 排队、组 batch、管 KV cache;训练系统管数据、checkpoint 和恢复 | TTFT、token 间隔(ITL)、满足延迟目标时的 tokens/s | 一次请求怎样跑完、vLLM 与 SGLang、推理导读 |
| 8 模型 | 参数量和结构决定每个 token 要算多少、读多少 | 权重字节数;每个 token 的 KV 字节数 | KV cache、精度与显存 |
| 9 产品 | 用户看到的回答、延迟和账单 | 延迟目标,每次请求的成本 | 现代 AI 系统 |
表里的库名各有官方文档:cuBLAS、cuDNN、NCCL(集合通信,可走 PCIe、NVLink、InfiniBand 和 socket)、Triton。调度这一层,Slurm 分配节点、排队和启动作业;Kubernetes 靠厂商的 device plugin 把 GPU 报成 nvidia.com/gpu 这类资源,写在容器的 limits 里申请。
一台服务器里,带宽一级比一级少
拿一台具体的机器看第 3 层。据 NVIDIA DGX H100 用户手册,它有 2 颗 Intel Xeon 8480C(各 56 核)、2 TB 内存、8 张 H100、卡间 NVLink 900 GB/s,以及 8 张单口 ConnectX-7 InfiniBand 卡。下面把各条链路换算成每个方向的带宽再比:
| 链路 | 每个方向的带宽 | 出处与换算 | 约为 HBM 的 |
|---|---|---|---|
| HBM(单卡 H100 SXM5) | 3,352 GB/s | H100 架构白皮书 V1.04(产品页写 3.35 TB/s);读写共用,不分方向 | 1 |
| NVLink(每卡) | 450 GB/s | Hopper 架构博客:18 条链路共 900 GB/s,每条每方向 25 GB/s | 1/7 |
| PCIe Gen5 x16 | 64 GB/s | 同一博客:共 128 GB/s,每方向 64 GB/s | 1/52 |
| InfiniBand NDR(一个端口) | 50 GB/s | ConnectX-7 数据手册:400 Gb/s,除以 8 位 | 1/67 |
厂商常把双向加起来报(900、128),网络则按比特报(400 Gb/s)。不换算就比,会差出 2 倍甚至 16 倍。换算以后能看到:每往外走一层,带宽就少好几倍,从 HBM 到网卡差了近两个数量级。所以通信最频繁的切分更适合放在带宽最高的那一层,见多卡训练和张量并行。
手算一次聊天请求
下面全是教学假设,只为让数量级可以手算,不是任何产品的实测:
| 假设 | 取值 |
|---|---|
| 模型 | 8B 参数的 dense 模型,BF16(每参数 2 字节),权重 $B_W=16$ GB |
| 结构 | 32 层,hidden size 4096,8 个 KV head,head dim 128;每 token 的 KV 是 $2\times32\times8\times128\times2$ 字节 = 128 KiB |
| 请求 | prompt 2,000 tokens(system prompt、历史和问题),输出 300 tokens,单独一个请求 |
| GPU | 峰值 $F=1{,}000$ TFLOP/s(dense BF16),显存带宽 $BW=3$ TB/s |
| 实际效率 | prefill 达到峰值算力的 $\eta_F=50\%$;decode 达到峰值带宽的 $\eta_B=70\%$ |
| GPU 以外 | 网络和网关 40 ms,套模板加 tokenize 2 ms,排队 50 ms |
GPU 一行取了整数,和 H100 SXM5 同一量级:按白皮书 V1.04(封面注明已含最终频率和 TFLOPS),它的 dense BF16(FP32 累加)是 989.4 TFLOPS,显存 3,352 GB/s。产品页上的 BF16 1,979 TFLOPS 注明“with sparsity”,是 2:4 稀疏数字;2022 年架构博客里的 1,000 TFLOPS、3,000 GB/s 是当时标明的初步规格。口径怎样对齐,见 NVIDIA 各代 GPU。
一个 $N$ 参数的 decoder 每处理 1 个 token,前向大约做 $2N$ 次浮点运算(Kaplan 等,2020,§2.1)。这里还有一项随上下文增长的 attention 运算 $2n_{\rm layer}n_{\rm ctx}d_{\rm model}$;按平均上下文 1,000 算,约为 $2N$ 的 1.6%,先忽略。于是:
$$ t_{\rm prefill}\approx\frac{2NP}{\eta_F F},\qquad t_{\rm token}\approx\frac{B_W+B_{\rm KV}}{\eta_B\,BW}. $$
$P$ 是 prompt 长度,$B_{\rm KV}$ 是这一步要读的 KV 字节数。代进去:
- Prefill:$2\times8\times10^9\times2000=3.2\times10^{13}$ 次运算,除以 $0.5\times10^{15}$ FLOP/s,得 64 ms。同一时间里只需把 16 GB 权重读一遍,约 7.6 ms,所以算力是瓶颈。
- Decode 每一步:只做 $1.6\times10^{10}$ 次运算,按 50% 峰值只要 0.032 ms;但要把 16 GB 权重和最多 0.3 GB KV 都读一遍,按 2.1 TB/s 约 7.8 ms,所以带宽是瓶颈。
换一个角度看:prefill 每读 1 字节做约 2,000 次运算,decode 只做约 1 次;这块教学 GPU 的“屋脊点”是 $10^{15}/(3\times10^{12})\approx333$ FLOP/字节(H100 SXM5 按上面的规格是 $989.4/3.352\approx295$)。高于它受算力限制,低于它受带宽限制。Pope 等(2022)也指出(§2 讲显存开销的一段):“At small batch sizes and sequence lengths, the time to load weights dominates”,即 batch 和序列都小时,读权重的时间占主导。
| 阶段 | 在哪一层 | 教学估计 | 主要受什么限制 |
|---|---|---|---|
| 网络、网关、鉴权 | 产品、服务 | 40 ms | 网络往返 |
| 套模板、tokenize | CPU | 2 ms | CPU |
| 排队 | serving engine | 50 ms | 负载与调度 |
| Prefill 2,000 tokens,得到第 1 个 token | GPU | 64 ms | 算力 |
| 首 token 时间(TTFT) | 约 156 ms | ||
| Decode 余下 299 个 token | GPU | 299 × 7.8 ms ≈ 2.3 s | HBM 带宽 |
| 合计 | 约 2.5 s | decode 约占 94% |
如果 32 个差不多的请求一起 decode,权重每步只读一次,大家共用:每步读 16 GB 权重加 32 份 KV(按每份最多 0.3 GB 算,约 9.6 GB),共约 25.6 GB,一步约 12.2 ms。每个用户的 token 间隔从 7.8 ms 变成 12.2 ms,但总吞吐从约 129 tokens/s 涨到约 2,600 tokens/s,大约 20 倍。这时 KV 已经占了每步读取量的 38%;Pope 等也指出,batch 和序列一长,读 KV 的时间会超过读权重。这就是 serving engine 要组 batch、又要精打细算 KV 的原因,见一次请求怎样跑完和 KV cache。
| 改一个条件 | 会看到什么 | 不能据此推出什么 |
|---|---|---|
| 输出从 300 改成 30 tokens | 总时间约 0.38 s,prefill 和排队的占比明显上升 | 短回答的产品一定受算力限制 |
| 权重换成 1 字节一个参数(如 FP8) | decode 每步读约 8.3 GB,约 4 ms | 质量不变,或 kernel 一定能跑到同样的带宽利用率 |
| batch 从 1 加到 32 | 吞吐约 20 倍,单个用户反而变慢 | batch 越大越好;KV 显存和带宽会先用完 |
| prompt 从 2,000 加到 20,000 | 按 $2N$ 算 prefill 约 640 ms,KV 约 2.6 GB | $2N$ 公式还够用;此时 attention 项约多出 16%,不能再忽略 |
沿着一步 decode 往下走,再走回来
产品 用户等的是“下一个字什么时候出来”
↓
推理引擎 把 32 个请求排进同一步,找到各自的 KV 位置
↓
框架 PyTorch 跑一次前向;CUDA Graph 减少 CPU 逐个发射 kernel 的开销
↓
kernel 矩阵乘(cuBLAS 等)、attention kernel;多卡切分时还有 NCCL 通信
↓
GPU SM 从 HBM 读出 16 GB 权重和 KV
↓
芯片 HBM 堆栈和 GPU die 封装在同一块 interposer 上
↓
工厂 die 面积受单次曝光视场限制;HBM 和先进封装的产能有限
再往回走:H100 SXM5 的 3,352 GB/s,来自 5 个 HBM3 堆栈和 5,120 位宽的显存接口(白皮书 V1.04、Hopper 架构博客)。在一张这样的卡上,单请求、BF16 的 8B 模型,每步至少要 $16\ {\rm GB}/3.352\ {\rm TB/s}\approx4.8$ ms,即使带宽 100% 用满,单个用户也快不过每秒约 210 个 token。想再快,要么少读(量化、更小的模型),要么多卡分摊权重,要么换更多、更快的 HBM 堆栈;最后一条又回到封装和产能。每秒 token 数是产品体验,也是成本:同一步里能塞进多少用户,决定了每个 token 摊到多少 GPU 时间。
这一组怎么读
- 芯片怎么造出来:晶圆、制程、封装与 HBM:节点名说明什么,一片晶圆的良率账与 chiplet,CoWoS 和 HBM,出货为什么受逻辑 die、封装、HBM 三样产能共同限制
- CPU 架构:流水线、缓存、SIMD 与 NUMA:分支预测和缓存怎样减少等待,SIMD/AMX、NUMA 与 Grace,CPU 在 AI 服务器里怎样喂数据、发起 GPU 工作
- GPU 架构:SM、warp、内存层级与 Tensor Core:warp 分叉与延迟隐藏,各级存储的带宽,Tensor Core 的峰值怎么算,FP8/FP4 的块缩放,NVLink
- NVIDIA 各代 GPU:每一代改了什么、为什么:读规格表先对齐什么,Volta 到 Rubin 的对比(含官方页面之间的出入),70B 模型要几张卡
- CUDA:线程、内存与 kernel:vector add、访存合并、shared memory 分块、occupancy、stream,以及 cuBLAS、CUTLASS 和 Triton
- 性能:roofline、算术强度与 MFU:三种操作在屋脊的哪一侧,batch 和 KV 怎样影响 decode,MFU 口径,all-reduce 时间,profiling 顺序
- 框架这一层:从一行 PyTorch 到 GPU 上的 kernel:dispatcher、ATen 与 autograd,eager 的开销,torch.compile、XLA 与 TensorRT,分布式 API 和推理引擎(inference engine)在哪一层
- Kubernetes 与 GPU 集群:把卡分给任务:device plugin 与 DRA,MIG/time-slicing/MPS,成组调度与拓扑,和 Slurm 的对比,推理扩容与冷启动(cold start)
- 复习题:面试题和自检
读完这一组,可以接着读量化:少存几位,换来什么、丢掉什么(待审核草稿):权重、激活和 KV cache 各压到几位,省下多少显存和带宽,精度损失怎样测。
本页术语 3
- 集合通信 collective communication
- 多个进程之间的规约、广播、收集这类操作,分布式训练全靠它
- 推理引擎 inference engine
- 负责高吞吐生成或模型服务的执行系统
- 冷启动 cold start
- 用户或内容缺少历史证据,模型只能靠先验