直觉:三本不同的账

谈大模型动辄"7B"“70B”“千亿参数”,但参数量只是其中一本账。工程上真正要算清的是三件事:

  • 参数量:模型有多大,决定权重占多少存储。
  • FLOPs:跑一次要多少计算,决定训练成本和推理延迟。
  • 显存:能不能塞进卡里,决定你需要几张 GPU。

这三本账互相关联但不等价。一个能"装下"模型权重的显卡,未必能训练它,甚至未必能高效推理它。下面把每本账拆开算。

第一本账:参数量从哪来

Transformer 的参数绝大部分集中在两类线性层。设隐藏维度为 dd,层数为 LL

注意力部分:每层有 Q、K、V 三个投影加一个输出投影,各是 d×dd \times d 的矩阵,合计约 4d24d^2

FFN 部分:标准 FFN 先升维到 4d4d 再降回,两个矩阵合计约 8d28d^2

所以每层约 12d212d^2 个参数,整个模型主干约:

N12Ld2N \approx 12 \, L \, d^2

(这里忽略了 embedding、LayerNorm、bias 等小项。)以一个 d=4096d=4096L=32L=32 的模型粗算:12×32×409626.4×10912 \times 32 \times 4096^2 \approx 6.4 \times 10^9,约 6.4B——和常见 7B 模型量级吻合。这个公式让你看到一个关键事实:参数量对 dd 是平方增长的。 宽度翻倍,参数翻四倍。

第二本账:FLOPs 与那个 6N 法则

有一条广为人知的经验估算:训练一个 NN 参数的模型,处理 DD 个 token,总计算量约

C6ND FLOPsC \approx 6 N D \ \text{FLOPs}

这个 6 从哪来?前向传播每个参数对每个 token 大致做一次乘加(2 FLOPs),即 2N2N;反向传播要算输入梯度和权重梯度两部分,约是前向的两倍,即 4N4N。加起来每 token 约 6N6N。乘以 token 数 DD 就是总量。

推理只有前向,所以推理时每生成一个 token 约 2N2N FLOPs。这条法则的实用价值在于快速估算:给定算力预算,能立刻反推能训多大模型、喂多少数据。

注意这是主干矩阵乘法的估算,没算注意力里 QKQK^\top 那块对序列长度 nn 的依赖。当序列很长时,注意力的 O(n2d)O(n^2 d) 项会变得不可忽略——这也是长上下文成本高的根源。

第三本账:显存,最容易爆的一本

显存账要分推理训练两种场景,差别巨大。

推理显存

主要两块:

  1. 权重NN 个参数 × 每参数字节数。fp16 是 2 byte,int8 是 1 byte,int4 是 0.5 byte。70B 模型 fp16 就要约 140 GB,单卡放不下;量化到 int4 约 35 GB,单张大显存卡可行。
  2. KV Cache:自回归生成时缓存历史 token 的 K、V,避免重复计算。这块常被低估。它的大小约为:

KV2×L×n×dkv×b×bytes\text{KV} \approx 2 \times L \times n \times d_{kv} \times b \times \text{bytes}

其中 2 是 K 和 V,nn 是序列长度,dkvd_{kv} 是 KV 的总维度,bb 是 batch size。KV Cache 随序列长度和 batch 线性增长,长上下文、高并发场景下它甚至会超过权重本身的占用。这正是 GQA(分组查询注意力)、MQA(多查询注意力)这类技术的动机——通过让多个 query 头共享 K、V 来压缩 dkvd_{kv},大幅缩小 KV Cache。

训练显存

训练贵得多,因为要存:

1
2
3
4
权重           参数
梯度 每个参数一份
优化器状态 Adam 要存一阶+二阶动量
激活值 反向传播要用,随 batch 和序列长度增长

前三项在微调篇里算过——用 Adam 混合精度训练,每个参数训练态要占十几个 byte。但训练显存里最"软"、也最容易爆的是激活值:前向算出的中间结果要留着给反向用,它的量级正比于 batch × 序列长度 × 层数 × 隐藏维度

1
2
3
4
5
# 极简的训练显存估算(单位 GB,仅主干,量级参考)
def train_mem_gb(N_params_billion, bytes_per_param=16):
# 权重2 + 梯度2 + Adam动量8 + fp32副本4 ≈ 16 bytes/参数
states = N_params_billion * 1e9 * bytes_per_param / 1e9
return states # 激活值另算,与 batch/seqlen 强相关

省激活值有几招:梯度检查点(gradient checkpointing) 只保存部分激活、反向时重算其余,用计算换显存;ZeRO/张量并行 把状态切到多卡。

把三本账连起来看

理解了三本账,很多工程现象就解释得通了:

  • 为什么推理能跑、训练却 OOM? 因为训练多了梯度、优化器状态和激活值,是推理显存的好几倍。
  • 为什么量化首先救的是推理? 量化主要压权重和 KV Cache,对推理立竿见影;但训练时反量化和数值稳定性更复杂。
  • 为什么长上下文这么贵? 注意力 FLOPs 的 O(n2)O(n^2) 项和 KV Cache 的 O(n)O(n) 增长同时发力,一个吃算力,一个吃显存。
  • 为什么更宽的模型涨得快? 参数量 d2\propto d^2,FLOPs N\propto N,连锁放大。

踩坑

1. 别用参数量直接估显存需求。 "70B 模型需要 70GB"是错的——推理 fp16 要约两倍参数量的字节,训练还要再翻几倍。

2. 忘了 KV Cache 是高并发部署的头号杀手。 算推理容量时,权重是固定开销,KV Cache 才决定你能同时服务多少长对话。

3. 6ND 是数量级估算,不是精确值。 它忽略了注意力对序列长度的依赖、激活函数、归一化等,用来做能力规划够用,别拿去对账。

4. MoE 打破了"参数量=计算量"的直觉。 混合专家模型总参数量很大,但每个 token 只激活一部分专家,FLOPs 远小于按总参数算的值——这正是 MoE 的卖点:用激活稀疏性把参数量和计算量解耦。

小结

千亿模型的账不是一本而是三本:参数量 12Ld2\approx 12Ld^2 决定模型多大,6ND6ND 决定训练算多久,而显存要分推理(权重 + KV Cache)和训练(再加梯度、优化器、激活值)两套来算。 真正卡住部署的往往不是参数量本身,而是被忽视的 KV Cache 和训练激活值。会算这三本账,你才能在拿到一个模型规格时,立刻判断它要几张卡、跑多快、能不能微调。