参数到底花在哪?
本课一问:参数到底花在哪?
这一课先不碰:MoE 怎么让「总参数」和「每个 token 用到的参数」分家(C11);一个参数训练时要占几个字节(C9)。
② 从已有出发
点任一已学环节,看这一步的输入 → 输出形状、参数量,以及它解决了什么问题(数字取自 Qwen/Qwen3.8-27B 真实 config)。
贯穿例句「小明把苹果给了小王」的 5 个 token,从 embedding 一路走到 lm_head,用的是同一套参数。点上面每个环节都能看到它的参数量(由 config 现算,✓ 表示与 safetensors 实测一致)。这一课把它们放到一张账本上。
③ 先自己设计:用经典公式估一下
很多教程给的估法是:每层注意力 4d²(Q、K、V、O 四个 d × d)、FFN 8d²(两个 d × 4d),一层 12d²,再加 embedding V·d。对 Qwen3.8(L = 64,d = 5,120,V = 248,320):
- ① 朴素方案
- ② 它在哪失败
- ③ 改进方案
12 × 64 × 5,120² + 248,320 × 5,120 = 21,404,057,600
HF 上 safetensors 的实际总数:27,781,427,952。
逐个零件对着 config 数,再和 safetensors 头按张量名分项求和的结果对账:
差在哪里,逐条对得上:FFN 是 3.4d 宽的三矩阵 SwiGLU(每层 10.2d²,不是 8d²);注意力的 Q 头拼起来是 6,144 维,还多一份输出门,K/V 却因为 GQA 只有 1,024 维;48 层是 Gated DeltaNet,不是标准注意力;lm_head 不和 embedding 共享(再多 1,271,398,400);另外还有视觉塔和 MTP 模块。
④ 改进到现代做法:三张账
在上面的组件里切换视图,或者用下面这个实例直接看后两张:
试三件事:① 在「Qwen3.8 总账」里切换分母:FFN 是 61.6% 还是 63.6%,只取决于算不算视觉塔和 MTP——PipelineTracker 里写的是后者;② 看「一层里」:单层 GDN 比单层全注意力还多约 1,100 万个参数,线性注意力省的是 KV cache 和长序列计算,不是参数;③ 看「三个模型并排」:GPT-2 的 embedding 占三成,Qwen3.8 只占一成不到——模型越大,词表那一份越不显眼,FFN 越显眼。
演进图里,FFN 这一行从「4d 宽的两矩阵」一路变成「3.4d 宽的三矩阵」,这张账本就是这一行在 Qwen3.8 那一格的结果:
参数 ≠ 计算
参数占比说的是「存了多少」,不是「每生成一个 token 算了多少」。解码第 T 个 token 时,FFN 每层的矩阵乘法与 T 无关;全注意力层的 q·k 打分与加权求和却要对 T 个历史 token 各做一次:
交叉点 T = 87,040 这个数完全由 config 算出:FFN 每 token 2 × 3 × 5,120 × 17,408 × 64 FLOPs,全注意力每多一个历史 token 多 16 层 × 2 步 × 2 × 24 × 256 FLOPs,两者相除 证据等级 · 数学可证明 在写明的前提下可以严格推导出来,不依赖实验。只要前提成立,换数据、换规模仍然成立。 本条只数矩阵乘法、乘加记 2 FLOPs;组件里写明了没算进去的部分(投影、softmax、GDN 的固定状态更新、lm_head)。在这个口径下交叉点是精确的 87,040。 出处待补 。Qwen3.8 原生支持 262,144 的上下文,在那里这一部分注意力计算是 FFN 的 3 倍——这也是为什么它只让 16 层用全注意力,另外 48 层换成与 T 无关的线性注意力(C11)。
⑤ 极小真数字算一次:我们自己的模型
项目基线(d = 256,4 层,8 头 MHA,SwiGLU 中间维 688,词表 2,048,输入输出共享 embedding)可以完全手算:
- embedding:2,048 × 256 = 524,288(输出层共享,只算一次)
- 每层注意力:4 × 256 × 256 = 262,144(MHA、无偏置)
- 每层 FFN:3 × 256 × 688 = 528,384
- 每层两个 RMSNorm:2 × 256 = 512
- 最终 RMSNorm:256
合计 524,288 + 4 × (262,144 + 528,384 + 512) + 256 = 3,688,704,与 README 里训练脚本打印的数一致 证据等级 · 数学可证明 在写明的前提下可以严格推导出来,不依赖实验。只要前提成立,换数据、换规模仍然成立。 本条逐项乘法与加法;组件「三个模型并排」里的项目一栏用同一算式现算。 出处待补 。FFN 占 4 × 528,384 / 3,688,704 = 57.3%。
🔍 旧版课程在这里算错过
旧版 M2 推荐「6 层 · 384 维 · 6 头 + 8K 词表」,说是约 50M 参数的小模型。用同一个经典公式:12 × 6 × 384² + 8,192 × 384 = 10,616,832 + 3,145,728 = 13,762,560,约 14M(共享 embedding 时),差了三倍多。参数量永远自己算一遍再写进计划(R5 Q-E5)。⑥ ⚠ 常见误解
「参数最多的部件,计算也最多」✗ —— 参数与 T 无关,注意力的打分计算与 T 成正比;Qwen3.8 在 T 超过 87,040 之后,全注意力这部分的计算就超过了 FFN。
「FFN 占比是个固定常数(常说的三分之二)」✗ —— 三分之二只对「4d 宽的两矩阵 FFN + 4 个 d × d 注意力矩阵」成立;GPT-2 算上 embedding 只有 45.5%,Qwen3.8 是 61.6%(文本主干 63.6%),MoE 的 Qwen3.8-2.4T 按 config 现算约 97%。先问分母是什么。
「HF 页面上的参数总数就是参数量」✗ —— GPT-2 显示 137,022,720,其中 12,582,912 是 12 张 1,024 × 1,024 的因果掩码缓冲区,不是可学习参数;按 config 逐项现算是 124,439,808🔍 论文里又写的是 117M
GPT-2 报告 Table 2 把最小的模型写成 117M;按官方 config 逐项现算(含全部偏置与 LayerNorm)是 124,439,808,报告没有说明差在哪里。三个数各有口径:论文表格、逐项现算、safetensors 文件里的张量总数。
⑦ 证据三问
- 它解决什么问题? 决定钱和显存花在哪:想省参数先看 FFN,想省长上下文的计算先看注意力。
- 数学上为什么可能有效? 这里没有「有效」的问题,只有算术:每一项都是 config 里几个数的乘积 证据等级 · 数学可证明 在写明的前提下可以严格推导出来,不依赖实验。只要前提成立,换数据、换规模仍然成立。 本条组件对 Qwen3.8 的每一项现算都与 safetensors 实测分项逐位一致(✓);GPT-2 与项目模型的合计与 HF / README 对得上。 出处Qwen3.8-27B 官方 config 与 safetensors ↗需联网 。
- 实验上为什么最后选了它? 不适用;但「把参数花在 FFN 上」本身是实验选择——C6 讲模型该多大,C11 讲 MoE 为什么把 FFN 拆成专家。
⑧ 一句话
参数大头在 FFN,长上下文的计算大头却在注意力:数参数之前先问分母,数计算之前先问 T。
⑨ 回到主线
零件和账本都齐了。下一章不再问「块里有什么」,而是问「这 27,781,427,952 个参数怎么学出来」:C5 优化:参数怎么更新得又快又稳。
⑩ 你可能会问
- 「MoE 模型的参数怎么算?」 —— 要分「总参数」和「每个 token 激活的参数」两本账,C11 讲。
- 「训练一个约 278 亿参数的模型要多少显存?」 —— 每个参数在训练时要存参数、梯度、优化器状态,C9 从「一个参数几个字节」算起。