部署和训练的过程中冒出来的问题,每个答案都尽量对上这台 8 × A800 上测到的真实数字。可以和原理实验台对照着看:实验台负责拨动参数看现象,这一页负责把算式一步步写出来。
模型每一层的核心运算是矩阵乘向量:权重矩阵 W 乘以当前 token 的向量 x。W 存在显存里,计算核心要用它,就得把每个数从显存搬到核心里。生成一个 token 时 x 只有一个,所以每个权重恰好被用一次。结论是:每生成一个 token,所有参与计算的权重都要从显存完整读一遍。
| 数字 | 取值 | 来历 |
|---|---|---|
| 参与计算的参数 | 18B | 它是 MoE,总共 320B,路由器每个 token 只挑几个专家,加上注意力部分约 18B,其余 302B 这一步不碰 |
| 每个参数的字节数 | 1 | FP8 权重,8 位就是 1 字节;BF16 是 2 字节 |
| 同时分担的卡数 | 4 | 张量并行把每个矩阵切成 4 片,4 张卡同时各读各的 |
| 显存带宽 | 2 TB/s | A800 的 HBM2e,约每秒 2000 GB |
每步要读的总字节 = 18 × 10⁹ 个参数 × 1 字节 = 18 GB
每张卡要读的字节 = 18 GB ÷ 4 = 4.5 GB
每步时间下限 = 4.5 GB ÷ 2000 GB/s ≈ 2.3 ms
同一步的计算量 = 2 × 18 × 10⁹ = 3.6 × 10¹⁰ 次浮点运算
4 张卡的峰值算力 = 4 × 312 × 10¹² = 1.25 × 10¹⁵ 次/秒
计算耗时 ≈ 0.03 ms
算只要 0.03 毫秒,搬数据要 2.3 毫秒,差了近 80 倍。计算核心绝大部分时间在等数据,所以 decode 的速度由显存带宽决定,这就是"带宽墙"。
理论下限的意思是:假设显存带宽被 100% 用满,除了搬权重没有任何别的耗时,最快能多快。它只由硬件规格和模型大小决定,是物理上不可能突破的地板,不是对实际速度的预测。实际耗时可以拆成两部分:
实测每步时间 = 搬权重的时间(公式算的这部分) + 固定开销
| 模型与部署 | 每卡每步读取 | 理论下限 | 单流实测 TPOT | 固定开销 | 理论占实测 |
|---|---|---|---|---|---|
| Qwen3.8-27B,稠密,BF16,2 卡 | 27B × 2 ÷ 2 = 27 GB | 13.5 ms | 20.6 ms | 7.1 ms | 65% |
| Qwen3.6-35B-A3B,激活 3B,BF16,2 卡 | 3B × 2 ÷ 2 = 3 GB | 1.5 ms | 5.8 ms | 4.3 ms | 26% |
| GLM-5.3-Flash,激活 18B,FP8,TP4 × PP2 | 18B × 1 ÷ 4 = 4.5 GB | 2.3 ms | 20.1 ms | 17.8 ms | 11% |
固定开销和模型大小关系不大:每步几千个内核启动、每层一次跨卡 all-reduce、流水线两段之间的交接、采样和调度。Qwen3.8 搬权重要 13.5 ms,固定开销只是配角,所以实测和理论最接近。Qwen3.6 搬权重只要 1.5 ms,固定开销反而成了主角。GLM 在 Ampere 上走的是 Triton 回退内核,稀疏注意力和 FP8 都没有原生硬件支持,固定开销最大。CUDA Graph、内核融合、原生 FP8 硬件要解决的,正是这部分差距。
312 TFLOPS 是单张卡 BF16 的峰值算力,是 NVIDIA 给 A100 标的规格。A800 的计算部分和 A100 完全相同,只把 NVLink 从 600 GB/s 砍到了 400 GB/s。这个数不是测出来的,是从芯片结构直接乘出来的:
108 个 SM × 每个 4 个 Tensor Core × 每周期 256 次乘加 × 每次乘加 2 次运算 × 1.41 × 10⁹ 周期/秒
= 221,184 × 1.41 × 10⁹
≈ 312 × 10¹² 次/秒
1.41 GHz 就是在这台机器上用 nvidia-smi 查到的最高 SM 频率。用同样的方法验证 FP32 规格:普通计算核心 6912 个,每周期各做 1 次乘加,6912 × 2 × 1.41 × 10⁹ ≈ 19.5 TFLOPS,正好是官方标称值。312 是它的 16 倍,这就是 Tensor Core 的价值。
| 精度 | 峰值 | 走哪种电路 |
|---|---|---|
| FP32 | 19.5 TFLOPS | 普通核心 |
| TF32 | 156 TFLOPS | Tensor Core |
| FP16 / BF16 | 312 TFLOPS | Tensor Core |
| INT8 | 624 TOPS | Tensor Core |
| FP8 | 不支持 | Ampere 没有这个模式,FP8 权重只能先解成 16 位再算 |
峰值的前提是做大块稠密矩阵乘、Tensor Core 满载。实际能用掉的比例叫 MFU:这台机器上训练 d32 时 MFU 是 65%,相当于每张卡持续 200 TFLOPS 左右。作为对比,H100 的 BF16 峰值是 989 TFLOPS,并且有原生 FP8。
权重就是模型本身。训练结束后这几百亿个数就固定了,不管谁来问、问什么,走的都是同一套矩阵。不同请求之间不一样的只有三样:输入的 token、每层算出来的中间向量、各自的 KV cache。
单条请求:y = W · x x 是这条请求当前 token 的向量
16 条请求:Y = W · X X 的 16 列分别是 16 条请求各自的向量
W 的每个数只从显存搬一次,到了计算核心后分别和 16 个不同的向量相乘。搬运量几乎不变,计算量变成 16 倍,而计算本来就闲着,所以总时间几乎不变。这就是并发越高总吞吐越高的原因。
MoE 是例外。稠密模型里所有 token 用的都是全部权重;MoE 里每个 token 只挑几个专家,16 个 token 挑的专家各不相同,合起来要读的专家比单个 token 多得多。并发越高,一步里被激活的专家越多,要搬的权重越多。实测正好体现了这一点:
| 模型 | 并发 1 的 TPOT | 并发 32 的 TPOT | 变慢倍数 |
|---|---|---|---|
| Qwen3.8-27B,稠密 | 20.6 ms | 28.6 ms | 1.4 倍 |
| Qwen3.6-35B-A3B,MoE | 5.8 ms | 17.1 ms | 2.9 倍 |
| GLM-5.3-Flash,MoE | 20.1 ms | 49.0 ms | 2.4 倍 |
数据来自评测报告的压测矩阵。
TP 和 PP 是把一个模型切到多张卡上的两种切法,后面的数字是切成几份。
第 1 段:第 1 到 24 层 第 2 段:第 25 到 45 层
┌────────────────────────┐ ┌────────────────────────┐
token → │ GPU0 GPU1 GPU2 GPU3 │ ───→ │ GPU4 GPU5 GPU6 GPU7 │ → 下一个 token
│ 每层矩阵切 4 片, │ 只传一 │ 每层矩阵切 4 片, │
│ 4 卡同时算,每层合一次 │ 个向量 │ 4 卡同时算,每层合一次 │
└────────────────────────┘ └────────────────────────┘
TP4 TP4
306 GB 的权重就这样分到了 8 张卡上,每张约 38 GB,和启动日志里的数字一致。
| 张量并行 TP | 流水线并行 PP | |
|---|---|---|
| 怎么切 | 每一层的矩阵切开 | 层的先后顺序切开 |
| 卡之间怎么配合 | 同时算同一层 | 一段算完交给下一段 |
| 通信 | 每层都要合并一次,很频繁,靠 NVLink | 只在段与段之间传一次 |
| 缺点 | 卡越多通信越碎,收益递减 | 一个 token 在第一段时第二段空等,叫气泡 |
GLM 没有用 TP8 也没有用 PP8,而是各取一半:A800 的 NVLink 被砍到 400 GB/s,TP 只切到 4 来控制通信开销;PP 只分 2 段来控制气泡。两个 Qwen 模型小,只用了 TP2。
宽度是每个 token 在模型内部用多少个数来表示,也叫隐藏维度,代码里叫 n_embd。d12 里每个 token 是一个 768 维的向量,d24 是 1536 维,d32 是 2048 维。这个向量从第一层一路传到最后一层,长度始终不变,每一层都读它、改它,再传给下一层。层数是 token 要经过多少道加工,宽度是每道加工时手里的信息有多少维。
宽度决定了几乎所有参数的大小。每层里,注意力的 Q、K、V、输出四个投影矩阵各是宽度 × 宽度;MLP 先把向量放大到 4 倍宽再压回来,两个矩阵相当于 8 个宽度 × 宽度:
每层参数 ≈ 12 × 宽度²
全部矩阵参数 ≈ 12 × 层数 × 宽度²
| 模型 | 层数 | 宽度 | 公式算出 | 训练日志里的矩阵参数 |
|---|---|---|---|---|
| d12 | 12 | 768 | 84,934,656 | 84,935,088 |
| d24 | 24 | 1536 | 679,477,248 | 679,478,976 |
| d32 | 32 | 2048 | 1,610,612,736 | 1,610,615,808 |
词嵌入表也一样,是词表大小 × 宽度:32768 × 768 = 25,165,824,正好是 d12 日志里的 wte。注意力头数是宽度 ÷ 128,所以 d12、d24、d32 分别有 6、12、16 个头。
参数随宽度的平方增长:层数相同时宽度翻倍,参数变成 4 倍。d32 是 32 层 × 2048,矩阵参数 16 亿;Llama-2-7B 也是 32 层,宽度 4096,参数约 65 亿。nanochat 不单独设宽度,固定取层数的 64 倍,这就是它"只用层数一个旋钮"的原因。
| 模型 | 层数 × 宽度 | 总参数 | 其中查找表 | 参与矩阵乘的参数 | 形状最接近 |
|---|---|---|---|---|---|
| d12 | 12 × 768 | 0.29B | 0.15B | 0.11B | GPT-2 small,0.12B |
| d24 | 24 × 1536 | 1.38B | 0.60B | 0.73B | GPT-2 large,0.77B |
| d32 | 32 × 2048 | 2.82B | 1.07B | 1.68B | GPT-2 XL,1.56B |
nanochat 在注意力里加了一种叫 value embedding 的结构:每个 token 额外查一张表,把结果加到注意力的 V 上。查表只占显存、几乎不花计算,却被算进总参数,占了三分之一到一半。scaling law 的惯例只数参与矩阵乘的参数,训练耗时和推理速度也跟着这个数走,按这个算三个模型是 0.1B、0.7B、1.7B。
按能力折算,可以用评测数据包里自带的四个 GPT-2 的 CORE 分数作参照:
| 模型 | CORE | 折算 |
|---|---|---|
| GPT-2 small,0.12B | 0.114 | |
| d12 | 0.145 | 约 0.2B 的 GPT-2,在 small 和 medium 之间 |
| GPT-2 medium,0.36B | 0.185 | |
| GPT-2 large,0.77B | 0.215 | |
| d24 | 0.249 | 约 1.4B,基本等于 GPT-2 XL |
| GPT-2 XL,1.56B | 0.257 | |
| d32 | 0.346 | 超过最大的 GPT-2;沿 GPT-2 家族的趋势粗略外推,约 7B |
d24 只用一半的计算参数就追平了 GPT-2 XL,靠的是更新的架构、优化器和更好的训练数据。
账的基础是实测:8 张卡在 MFU 63% 左右时,持续算力约 1.5 PFLOP/s,一天约 1.3 × 10²⁰ 次浮点运算。训练的计算量约等于 6 × 参数量 × 训练 token 数。
| 规模 | 参数 | 训练 token | 计算量 | 8 卡耗时 | CORE |
|---|---|---|---|---|---|
| d24,已完成 | 14 亿 | 58 亿 | 2.8 × 10¹⁹ | 5.1 小时 | 0.249 实测 |
| d32,已完成 | 28 亿 | 134 亿 | 1.4 × 10²⁰ | 约 1 天,实际 4 卡跑了 49 小时 | 0.346 实测 |
| d40,估算 | 约 50 亿 | 约 260 亿 | 5.2 × 10²⁰ | 约 4 天 | 按 d24 到 d32 的实际涨幅外推,约 0.40 |
| 满负荷一个月 | 3.9 × 10²¹ | 30 天 | |||
| Llama-3.2-1B,2024 | 12 亿 | 9 万亿 | 约 5 × 10²² | 约 1.1 年 | |
| Qwen3-1.7B,2025 | 17 亿 | 36 万亿 | 约 3.7 × 10²³ | 约 7.5 年 |
两个结论。从零训练,这台机器的合理上限是 2020 到 2022 年间几十亿参数基础模型的水平,d32 已经到了"值得做"的边界,d40 是极限尝试。要得到真正能用的现代模型,正确的路径是在现成开源模型上做后训练:LoRA、SFT、偏好优化、强化学习,几张卡几小时就够。训练实录最后一节列了这些手段。