前几天我那句「一层 12d²」被一份 config.json 打脸,改成「16d² 起步」,今天又拿真 config 核了一遍,发现还是不准。这回把账彻底摊开重写。
一个 transformer 层就两块肉
- FFN(SwiGLU 三个矩阵):
3 × d × m,m = intermediate_size - 注意力(GQA):
d × head_dim × (2·n_q + 2·n_kv)—— Q 和 O 各吃一份n_q × head_dim,K 和 V 各吃一份n_kv × head_dim
归一化那点参数(每层 2 × d)加进去连零头都算不上,手算直接扔。
关键:别记 d² 的系数,先记 m 是 d 的几倍
令 r = m / d,FFN 就是 3r · d²。
注意力折算成 d² 是 2 · head_dim · (n_q + n_kv) / d,我核过的模型基本都落在 2 ~ 2.5。
所以:
每层 ≈ (3r + 2.3) · d²,r 是主角,注意力是零头。
三份真 config 的账
Qwen2.5-1.5B:d=1536,m=8960,12 头 / 2 kv 头 / head_dim 128,28 层,词表 151936,权重绑定
- FFN:3 × 1536 × 8960 = 41,287,680 / 层
- attn:Q 2,359,296 + K 393,216 + V 393,216 + O 2,359,296 = 5,505,024 / 层
- 每层 46.79M ÷ d²(=2,359,296) = 19.8 d²(因为 r = 5.83!)
- × 28 层 = 1,310,281,728
- 词表 151,936 × 1536 = 233,373,696(绑定只算一份)
- 合计 1,543,655,424 → 官方口径 1.54B,对上 ✓
Llama-3.2-1B:d=2048,m=8192(r=4),32 头 / 8 kv / head_dim 64,16 层,词表 128256 绑定
- 每层 = 12 + 2.5 = 14.5 d²,× 16 层 + 词表 ≈ 12.36 亿 ✓(官方 1.236B)
Gemma-3-27B:d=5376,m=21504(r=4),32 头 / 16 kv / head_dim 128
- 每层 = 12 + 2.29 = 14.3 d²
我之前为什么一直算歪
因为我一直默认 FFN = 4d。实际 r 从 3.5(Llama3-70B 那种)到 5.83(Qwen 小模型)都有,而且规律是反的:模型越小 FFN 越肥,越大越抠。拿一个固定系数横跨整个尺寸段,误差能到 1.5 倍。所谓 16d²,其实是 MHA 时代(head_dim = d / 头数)的巧合数,GQA + 固定 head_dim 之后那个巧合就不成立了。
新口诀(三步)
- 先算
r = m / d,FFN =3r · d² - 注意力按 2 ~ 2.5 d² 补,kv 头越少越贴近 2
- 小模型必须单独加词表:
vocab × d,绑定算一份、不绑定算两份。1.5B 这档词表占总量 15%,27B 只占 5%
一层拆到底的真实比例(1.5B 这例):FFN 75% / 注意力 10% / 词表 15%。
以后谁再问我这模型多大,我就这三步,不拍脑袋了。