Inference Lab · 8 × A800 现场版
大模型推理时,GPU 到底在忙什么
六个可以动手拨弄的"实验台",把 prefill、decode、KV cache、并行切分和训练的内存账算清楚。所有默认参数都取自你这台机器和刚部署的模型,理论值旁边尽量放上实测值,方便对号入座。
检测到你的系统偏好减少动画,页面里的动画默认暂停,可用按钮手动单步。
1. 一次生成的全景
forward pass
模型不"读句子",它一次处理一串 token。每个 token 先变成一个向量,穿过几十层相同结构的 Transformer 块,最后一层的输出变成对"下一个 token"的概率分布,采样一个,接到末尾,再来一遍。下面的动画是一步生成的路径,点一下可以单步。
layer 0/45
每一层里两件事:注意力让当前 token 去看之前所有 token 的 K、V(这就是 KV cache 存的东西),MLP 对每个 token 各自做一次大矩阵乘。MoE 模型的 MLP 由很多"专家"组成,每个 token 只激活其中几个,所以 GLM-5.3-Flash 有 320B 参数但每个 token 只算 18B。
2. Prefill 与 Decode:算力墙和带宽墙
roofline
Prefill 把整段提示词一次算完,矩阵乘的规模是"token 数 × 隐藏维度",GPU 的算力被喂饱。Decode 每步只有一个新 token,却仍要把全部激活权重从显存读一遍,算力大量闲置,时间花在搬数据上。批处理的意义就在这里:一步里同时算 16 条请求,权重只读一次。
上:prefill 一次并行 · 下:decode 逐 token,每步扫一遍权重
怎么读这组数字。 决定 decode 每步时间的是"每张卡要搬多少字节 ÷ 这张卡的显存带宽"。A800 的 HBM 是 2 TB/s,GLM-5.3-Flash 每个 token 激活 18B 参数、FP8 一字节,4 卡分摊后每卡每步读 4.5 GB,理论下限约 2.3 ms。单流实测 TPOT 是 20 ms,差了约 9 倍,这就是"内核效率"滑块的意义:Ampere 上跑的是 Triton 回退内核、流水线并行有气泡、MoE 路由和 all-reduce 都有固定开销。把滑块拉到 12% 左右,单流的理论值就和实测对上了,这个差距正是后续优化的空间。图上的红字会按你选的并发数显示对应的实测值,并发 4 时是 38 ms。逐项推导见
原理问答第 1 节。
算术强度。 每搬 1 字节能做多少次乘加,决定你撞的是哪堵墙。A800 的平衡点约 156 FLOP/字节。单条请求 decode 每字节只做 2 次运算,离平衡点差两个数量级,纯粹带宽瓶颈;并发拉到几十条以后强度线性上升,才开始接近算力墙。这就是并发曲线先陡后平的原因。
3. KV cache 与 PagedAttention
3D · 拖动旋转
注意力要看历史 token 的 K 和 V,不缓存就得每步重算整段上下文。缓存下来后,显存里除了权重,剩下的空间几乎都给了它。vLLM 把 KV cache 按固定大小的"页"管理,请求来了按需分页、结束就归还,这就是 v 的来历。下面是一张 A800 的显存,方块是页,颜色是不同请求。
KV 每 token 占多少。 GQA 模型是 2 × 层数 × KV 头数 × 头维度 × 2 字节;Qwen3.8-27B 约 262 KB/token,128K 上下文一条请求就要 34 GB。GLM-5.3-Flash 用 MLA 把 K、V 压成一个 512 维的潜向量,加上稀疏注意力索引,每 token 只有几十 KB,所以同样的显存能装 263 万 token,这是它能标 1M 上下文的物理基础。
4. 多卡怎么分工
TP · PP · EP
一个模型放不进一张卡,或者一张卡算得太慢,就要切。张量并行把每一层的大矩阵横着切给几张卡,每层算完要做一次 all-reduce 把结果合起来,靠 NVLink 撑。流水线并行把层按顺序切成几段,token 像流水线上的工件依次经过,段与段之间只传一个激活向量,但下游要等上游,产生"气泡"。专家并行把 MoE 的专家分到不同卡,token 按路由结果跳到专家所在的卡。GLM 的部署是 TP4 × PP2,用满 8 张卡。
左键拖动旋转 · 亮起的卡正在计算 · 连线是通信
为什么 GLM 选 TP4 × PP2 而不是 TP8。 TP 每层要 all-reduce,卡越多通信越碎;A800 的 NVLink 是 400 GB/s,比 A100 的 600 GB/s 又砍了三分之一。PP 的通信量小得多,但 8 卡都堆在 PP 上气泡太大。4 × 2 是在这台机器上两种代价的折中,验证者在同样的 8×A800 上试出来的。
5. 训练和推理的内存账
bytes / param
推理只需要权重和 KV cache。训练还要保存梯度、优化器状态和反向传播用的激活值,混合精度下每个参数要 16 字节起步,再加上算力是推理的 3 倍(前向 1 份,反向 2 份)。拖动参数量,看看同一个模型训练和推理各要多少张 A800。
时间线上的区别。 推理:前向一次,出一个 token。训练:前向算 loss,反向把梯度一层层传回来,优化器用梯度更新全部权重,再来下一批。反向的计算量约是前向的两倍,而且每一层的激活值都要留到反向用,序列越长激活越多,这就是长序列训练那么吃显存的原因。ZeRO / FSDP 把权重、梯度、优化器状态切到多张卡上分摊,DeepSpeed 和 FSDP 都是这个思路。
6. 把测到的指标对号入座
GLM-5.3-Flash · 8×A800 实测
| 指标 | 对应阶段 | 受什么支配 | 实测(1K 输入 / 256 输出,并发 4) |
| TTFT 首 token 延迟 | Prefill | 算力、提示词长度、排队 | 540 ms |
| TPOT 每 token 耗时 | Decode 单步 | 显存带宽、激活参数字节数、KV 长度 | 38 ms,每路 26 tok/s;单流时 20 ms,50 tok/s |
| 吞吐 tok/s | Decode 批处理 | 并发数、每步时间增长的斜率 | 99 tok/s @ 并发 4 |
| KV cache 容量 | 显存 | 显存减权重,除以每 token KV 字节 | 2,627,138 token |
| 加载时间 | 启动 | 存储读取带宽、权重体积 | 306 GB / 550 s |
| CUDA Graph 捕获 | 启动 | 把 decode 每步的几千个内核调用录成一张图重放,省 CPU 开销 | 103 s |
后面两个 Qwen 模型的完整报告出来后,可以把它们的数字填进第 2 站的模型下拉框里做对比:同样的硬件,稠密 27B、MoE 3B 激活、MoE 18B 激活三种结构的 TPOT 曲线会很不一样。