第 5 课:逐层解剖一个模型

前面三节课我们学了 Transformer 的原理、五大改造、Tokenization。现在把所有这些拼起来——以 Llama 2 7B 为标本,从 Embedding 到 LM Head,一层一层拆开看 tensor 形状和计算量。

🎯 学完这 6 步你将能够:
① 画出 Llama 7B 的完整架构图,标注每一层的 tensor 输入输出形状
② 手工推算 Attention 层和 FFN 层的参数量和 FLOPs
③ 从"你好"两个 token 开始,追踪它们经过 32 层后的完整变化过程
🗺 本节推理链(6 步逐层递进:从"算清每个 tensor"到"拼出一次前向的 FLOPs")
1要做显存估算和 FLOPs 核算,必须先把 整体结构 拆开算清参数量(Embedding → 32×Block → LM Head)—— 只记住"7B"一个总数,就说不清 96% 的参数压在哪里。
↓
2整体结构 的第一笔账落在 Embedding 查表 上:32000×4096 的矩阵占 131M(约 2%),这就要求先把它和后面的矩阵乘法分开——它只按 token ID 取整行,不做乘加。
↓
3向量离开 Embedding 查表 后进入 Block,第一个子层是 Attention,要回答"谁该看谁"——所有关系挤在一条 4096 维通道里学不出多样模式,因此拆成 32 头×128 维各自算注意力(4 个 4096×4096 = 67M)。
↓
432 头 的 Attention 只负责在 token 之间搬运信息,"这些信息意味着什么"没人回答,于是补上 SwiGLU(用门控控制信息通过量的前馈网络) FFN(gate/up/down 三个矩阵,135M,占每层 2/3);否则模型只是一台搬运机。
↓
5SwiGLU FFN 再强,32 层也叠不起来:少了归一化数值会逐层放大、少了残差梯度衰减到第 1 层就没了,因此每层加 2 个 RMSNorm(各 4096 参数)+ 两条 RMSNorm 与残差捷径,把主干直通下去。
↓
6RMSNorm 与残差捷径 把每层接成主干后,把上面全部串起来跑一次前向:Embedding→32×[Norm→Attn→Res→Norm→FFN→Res]→Final Norm→LM Head,于是得每层约 400M FLOPs、32 层约 12.8G(单 token 前向约 13.5 GFLOPs)、生成 100 token ≈ 1.35T——这就是推理成本的全部来源。
LlamaEmbeddingAttentionSwiGLURMSNormParameters
1
如果拆开一个 Llama 7B 模型,里面到底有几层?每层在干什么?
提示:先想清楚"哪些参数在 32 层里各来一份、哪些只在首尾出现"——把结构拆成 Embedding、Block、输出三部分,再逐块估大小,答案自然浮现。
▾
知识背景
Llama 7B 的结构:1 个 Embedding 层 + 32 个 Transformer Block + 1 个 LM Head。参数量 = 6.74B(四舍五入为"7B")。每层 Block ≈ 202M(Attention 67M + FFN 135M)。Embedding 仅 131M(约 2%)。同系列的 LLaMA-13B 在多数基准上超过了 GPT-3(175B),参数量不到它的十分之一(Touvron et al., Meta, 2023)。

Llama 2 7B 的架构由三部分组成:Embedding 层 → 32 个 Transformer Block → LM Head。每个 Block 内部又分成 Attention 和 FFN 两个子层,每个子层前后各有一个 RMSNorm。

可以把这一结构类比成一条装配线:首尾各有一个工位,中间几十个工位做完全相同的加工——Transformer 里这些"工位"叫 Block,只是重复了很多次。

🧮 Llama 2 7B 完整参数拆解
Step 1:全局架构 — 3 大部分,32 层
组件包含什么参数占比
Token Embedding32000 × 4096 的查表矩阵131.1M1.95%
32 × Transformer Block每层 = Attention + FFN + 2×RMSNorm32 × 202.4M = 6,476M96.1%
LM Head + Final RMSNorm输出投影(独立矩阵,不与 Embedding 共享)+ 最后的归一化131.1M + 4K1.95%
总计:131.1M + 6,476M + 131.1M ≈ 6.74B,与宣布的 7B 接近(差异来自模型配置细节)。
Step 2:一个 Transformer Block 的内部结构
子层操作参数
Input RMSNorm对输入做 RMS 归一化4096(仅 γ 参数)
AttentionQKV 投影(3×[4096×4096]) + O 投影([4096×4096])4 × 16.78M = 67.1M
Post-Attention RMSNorm对残差加和后的结果归一化4096
FFN (SwiGLU)gate([4096×11008]) + up([4096×11008]) + down([11008×4096])3 × 45.1M = 135.3M
每层总参数:67.1M(Attention) + 135.3M(FFN) + 8K(2×RMSNorm) ≈ 202.4M。32 层 ≈ 6.48B,绝大部分参数在 Attention 和 FFN 里。
Step 3:数据流动方向 — "你好"两个字走一遍
位置操作tensor 形状
① Tokenizer 输出"你好" → BPE 编码 → token IDs[1, 2](batch=1, seq_len=2)
② Embedding查表:每个 ID 取一行 4096 维向量[1, 2, 4096]
③ Block 1..32每层进出形状不变:Attention→残差→FFN→残差[1, 2, 4096] → 32次 → [1, 2, 4096]
④ Final RMSNorm归一化最后一层的输出[1, 2, 4096]
⑤ LM Head× W_out^T(独立输出矩阵)得到词表概率分布[1, 2, 32000]
🎯 关键认知

7B 参数的 96% 在 32 个 Transformer Block 里。每个 Block 又分配为:Attention 占 33%(67M/202M),FFN 占 67%(135M/202M)。FFN 矩阵是模型"知识存储"的主体——这也是为什么 FFN 比 Attention 大两倍。

AI 助教
👋 对 Llama 的架构有疑问?比如"为什么 FFN 比 Attention 参数多?""不同大小的模型(7B/13B/70B)每层参数一样吗?"

我会用具体数字帮你算。
2
从"你好"两个字到一堆 4096 维向量——Embedding 层到底做了什么运算?
提示:Embedding 层本质上就是一个巨大的查表操作——32000 行的矩阵,每行是一个 4096 维的向量。拿到 token ID 后,直接取对应行。
▾
知识背景
Embedding 矩阵 = V × d = 32000 × 4096 = 131M 参数。本质:一个巨大查找表——取 token ID 对应行的 4096 维向量。Weight Tying(权重绑定):让 Embedding 和 LM Head 共享同一个矩阵,省下一份参数。原论文《Attention Is All You Need》(2017) 第 3.4 节已采用;Inan et al.(2016)与 Press & Wolf(2017)分别系统讨论了它的收益与做法(GPT-2 等沿用)。但 Llama 2 并未使用——它的 LM Head 是一个独立的 131M 输出矩阵。

上一张卡片我们看完了 Llama 的整体结构(Embedding → 32 Blocks → LM Head)。现在聚焦第一站:Embedding 层的数学极其简单——矩阵查表。有一个 32000×4096 的矩阵 W_embed,token ID 为 t 时,输出就是 W_embed 的第 t 行。

这一步就像查一本字典:token ID 是页码,翻到那一页整行搬走,不需要做任何乘加——Embedding 层的运算只有取行这一步。

🧮 "你好"的 Embedding 查表,每一步的数值
Step 1:Tokenizer 输出 — "你好" → 两个 token ID
字Token ID(示意)说明
你12845常见单字 token,词表中独立存在
好6721常见单字 token,词表中独立存在
输入 tensor:[[12845, 6721]],形状 [1, 2](batch_size=1, seq_len=2)。
Step 2:Embedding 查表 — 取 W_embed 的第 12845 行和第 6721 行
Token前 4 维数值(示意)完整维度
"你"[0.032, -0.015, 0.078, -0.041, ...]4096 维
"好"[0.056, 0.023, -0.012, 0.067, ...]4096 维
输出 tensor:[[[0.032,-0.015,...], [0.056,0.023,...]]],形状 [1, 2, 4096]。
Step 3:显存计算 — Embedding 矩阵有多大?
项目计算结果
参数数量32000 × 4096131,072,000(131M)
fp16 显存131M × 2 bytes262 MB
fp32 显存131M × 4 bytes524 MB
推理时实际占用fp16 加载 + 输入 batch 查表临时内存~270 MB(含临时 buffer,估算,依实现而异)
262MB 的 Embedding 矩阵在推理时一直驻留在 GPU 显存中。对于 24GB 的消费级显卡,它占约 1%。
🎯 Embedding 矩阵与 LM Head 是两个独立矩阵

Llama 2 的 Embedding 矩阵 W_embed([32000, 4096])负责把 token ID 映射为向量;最后的输出投影 LM Head 是一块独立的 [4096, 32000] 矩阵 W_out,把最后一层的 [1, 2, 4096] 映射回 [1, 2, 32000] 词表概率。二者并不共享权重(tie_word_embeddings=False)——6.74B 这个总数里已经分别算了这两块各 131M。Weight Tying(共享)是 GPT-2 等模型的做法,可省一份参数,但 Llama 2 没有采用。

AI 助教
👋 对 Embedding 层有疑问?比如"能不能用更小的 Embedding 维度?""ALiBi 和 RoPE(按位置给词向量拧一个旋转角度)的位置编码在哪一步加进去?"

我会用具体数字帮你算。
3
一个 Attention Head 里,Q、K、V 到底是怎么从输入一步步算出来的?
提示:先想 Q/K/V 从哪来——输入分别乘三个权重矩阵得到;再想那 4096 维怎么分给 32 个头,每个头算的注意力维度是多少?
▾
知识背景
Attention 层内部包含 4 个权重矩阵:W_Q、W_K、W_V、W_O(各 4096×4096 = 16.8M → 共 67M)。流程:输入 × W_Q/W_K/W_V → 拆 32 头(每头 128 维)→ RoPE 旋转 → QK^T/√128 → Softmax → ×V → 拼接 → ×W_O。每头独立学习一种关系模式。

上一张卡片我们把"你好"变成了两个 4096 维向量。现在它们进入 Attention 层——Transformer 的核心计算单元。输入 [1, 2, 4096],经过 QKV 投影 → 注意力计算 → O 投影,输出还是 [1, 2, 4096]。

用图书馆借书来类比:Q 是手里的索书号,K 是书脊上的分类标签,V 是书页里的正文——拿 Q 去和每张 K 比对,谁最像就借走谁的 V。

🧮 完整走查:一个 Attention Block 的 5 步计算
Step 1:QKV 投影 — 输入 × 三个权重矩阵
操作计算输出形状参数量
Q = X × W_Q[1,2,4096] × [4096,4096][1, 2, 4096]16.78M
K = X × W_K[1,2,4096] × [4096,4096][1, 2, 4096]16.78M
V = X × W_V[1,2,4096] × [4096,4096][1, 2, 4096]16.78M
QKV 投影合计 3 × 16.78M = 50.3M 参数。每个投影就是一次矩阵乘法。
Step 2:拆头 — 4096 维 → 32 个头 × 128 维
张量拆分前拆分后
Q[1, 2, 4096][1, 32, 2, 128](batch, heads, seq, dim)
K[1, 2, 4096][1, 32, 2, 128]
V[1, 2, 4096][1, 32, 2, 128]
"你好"只有 2 个 token,所以 seq_len=2。每个头拿到的是 2×128 的子矩阵。
Step 3:注意力分数 — Q × K^T / √128
头编号计算注意力矩阵形状含义
Head 1Q₁ × K₁^T / √128[1, 2, 2]2个字之间的两两注意力分数
Head 1 数值例(已除以 √128 的缩放后分数,示意):Q₁[0]·K₁[0]/√128=0.43, Q₁[0]·K₁[1]/√128=0.18
Q₁[1]·K₁[0]/√128=0.15, Q₁[1]·K₁[1]/√128=0.52
[[0.43, 0.18],
[0.15, 0.52]]
"你"更关注自己(0.43),"好"也更关注自己(0.52)
√128 ≈ 11.31 是缩放因子——防止点积太大导致 softmax 梯度消失。
Step 4:Softmax + 加权求和 — 每个位置的输出是 V 的加权组合
步骤Head 1 的计算
Softmax(QK^T/√128)行1: softmax([0.43,0.18]) = [0.56, 0.44]
行2: softmax([0.15,0.52]) = [0.41, 0.59]
输出 = 注意力权重 × V位置1输出 = 0.56×V₁[0] + 0.44×V₁[1]
位置2输出 = 0.41×V₁[0] + 0.59×V₁[1]
Step 5:合并头 + O 投影 — 32 个头拼回 4096 维,再乘 W_O
操作输入形状输出形状
合并 32 个头[1, 32, 2, 128][1, 2, 4096]
O = concat × W_O[1, 2, 4096] × [4096, 4096][1, 2, 4096]
Attention 层总参数:QKV(50.3M) + O(16.78M) = 67.1M。输入/输出形状不变 [1,2,4096]→[1,2,4096]。
🎯 为什么用 32 个头?

多头注意力的关键是让不同头关注不同的语义关系。研究者发现(Clark et al., 2019),训练后的模型里某些头倾向于关注"主语-谓语"关系,另一些头关注"形容词-名词"修饰,还有些头关注位置相邻性(哪一头对应哪种关系并无固定编号,此处为示意说明)。如果只有一个头(4096 维直接做 Attention),所有关系会混在一起,模型学不出这么多样的注意力模式。32 个头 = 32 种不同的"视角"同时看同一句话。

AI 助教
👋 对 Attention 计算有疑问?比如"GQA(把多个 Query 头分成几组、每组共享同一份 K/V)是怎么减少 KV 头的?""如果不用 √d_k 缩放会怎样?"

我会用具体数字帮你走一遍。
4
一个 token 走完 32 层 Llama 2 7B,到底要算多少次浮点运算?
提示:先想一件事——每一次权重参与运算,要花几次浮点操作?把这个数乘以参数量,会得到什么?
▾
知识背景
FLOPs(Floating Point Operations,浮点运算次数:衡量计算量的单位,一次浮点乘或一次浮点加各算 1 次)是算力核算的通用货币。经验规则:前向 FLOPs ≈ 2 × 参数量——因为每个权重在一次前向里做一次「乘 + 加」= 2 FLOPs。训练再按 3 倍算(前向 2N + 反向 4N = 6N),就是 Kaplan et al.《Scaling Laws for Neural Language Models》(arXiv:2001.08361, 2020)与 Hoffmann et al.《Training Compute-Optimal Large Language Models》(Chinchilla, arXiv:2203.15556, 2022)反复使用的 C ≈ 6ND 口径。痛点:光知道「7B」这一个数,算不出它的单 token 计算量——而这条 2N 规则把它变成能口算的估算器。

上一张卡片我们逐步跑完了 Attention 的 5 步计算;这一张换个问法——不再问「怎么算」,而是问「一共要算多少次」。要把一个 token 走完 32 层的计算量压成一个数,只需要一条经验规则:一次前向里,每个权重都恰好做一次「乘 + 加」,也就是 2 次浮点运算(FLOP,Floating Point Operation,一次浮点乘或浮点加)。先把三种口径说清(同一颗权重,按数哪些运算区分):
① 只数乘法(乘一次算 1):前向 ≈ 1N = 6.7 GFLOPs;
② 只计前向、乘和加都数(每权重 2 FLOPs):前向 ≈ 2N = 13.5 GFLOPs;
③ 前向 + 反向(反向约是前向的 2 倍):训练 ≈ 6N = 40.4 GFLOPs。
本课前向采用口径 ②、训练采用口径 ③,两者口径统一(②×3 = ③)。

把这条规则套到参数量上,就得到本课要记住的 2N 规则:前向 FLOPs ≈ 2 × 参数量。它就像一条「流水线计件工资」的口算公式——每个权重是一名工人,每过一次前向固定领 2 次浮点操作,把工人总数(参数量)乘 2 就是这一趟的总工时。

🧮 从 2N 到 6ND:一条能口算的算力公式
Step 1:2N 从哪来——每个权重 2 次浮点操作
操作每个权重做什么FLOPs
乘权重 w 乘上激活 x1
加把乘积累加进这一路的输出1
合计一次前向里每个权重固定贡献2
所以一个 [4096, 4096] 矩阵(16.78M 参数)单独跑一次就要 2 × 16.78M ≈ 33.6M FLOPs。
Step 2:套到 Llama 2 7B——单 token 的前向 / 反向 / 训练
阶段计算结果
参数量 N—6.74B
单 token 前向2 × N = 2 × 6.74e913.5 GFLOPs
单 token 反向4 × N = 4 × 6.74e927.0 GFLOPs
单 token 训练(前向 + 反向)6 × N = 6 × 6.74e940.4 GFLOPs
6.74B 参数本身就横跨 32 层(32 × 202.38M ≈ 6.48B),所以 2N 已经把「走完全部 32 层」的账算进去了——不必再单独乘 32。
Step 3:训练总算力 C = 6ND 的来历
项计算结果
每 token 训练 FLOPs2N(前向)+ 4N(反向)= 6N40.4 GFLOPs
训练 1T token6 × 6.74e9 × 1e124.04 × 10²² FLOPs
训练 2T token6 × 6.74e9 × 2e128.09 × 10²² FLOPs
把 6N 换成 6ND(D = 训练 token 数),就是训练总算力公式 C = 6ND。
Step 4:一个例子——1000 token 的输入要多少算力
场景计算结果
prefill 1000 token(一次前向过 1000 个 token)1000 × 2 × 6.74e913.5 TFLOPs
生成 100 token100 × 2 × 6.74e91.35 TFLOPs
示意口径:这里只乘 2N,忽略了 attention 的 O(L²) 项——短上下文(几百 token)下它相对很小,上下文极长时才会显著长大。
🎯 关键认知:2N 是一个可以口算的估算器

记住 2N 这一条,看到任何模型都能立刻估出它的单 token 前向算力:Llama 2 7B ≈ 13.5 GFLOPs、13B ≈ 26 GFLOPs、70B ≈ 140 GFLOPs。训练时换成 6N,再乘训练 token 数,就得到总训练算力 C = 6ND——这是各大团队规划预算时用的口径。它忽略 attention 的 O(L²) 项,短上下文下误差很小;上下文极长时这一项才会盖过 2N。

AI 助教
👋 对 FLOPs 和 2N 规则有疑问?比如「为什么是 2N 而不是 N?」「训练为什么是 6N?」「上下文很长时 attention 那一项有多大?」

我会用具体数字帮你算。
5
FFN 的中间维是 11008——这个怪数字到底是怎么定出来的?
提示:先看标准 FFN 用几个矩阵、中间维取多少;再看 SwiGLU 用几个矩阵。要让两者的参数量相当,中间维该怎么变?
▾
知识背景
FFN(Feed-Forward Network,前馈网络:每个 Block 里负责「记忆」的子层)的中间维惯例取 4d——标准 FFN 用 2 个矩阵,中间维是模型维度 d 的 4 倍(原论文 d_model=512 → 中间维 2048)。SwiGLU(Swish-Gated Linear Unit,用 SiLU 做门控的 GLU 变体,由 Shazeer《GLU Variants Improve Transformer》, arXiv:2002.05202, 2020 提出)改用 3 个矩阵(gate/up/down)。3 个矩阵要凑出与标准 FFN 相同的参数量,中间维就必须缩到 2/3——这正是 11008 的来历。

上一张卡片我们用 2N 规则算出了单 token 的算力,也看到参数量几乎都压在 FFN 里;现在回到「这些参数从哪来」这一侧,把 FFN 那个 11008 拆开看。它不是随手取的整数,而是「参数量守恒」倒推出来的结果。先看两种更省事的做法,恰好都不成立:一是不升维(中间维取 d),两个矩阵只有 2 × 4096² ≈ 33.6M,是 4d 版本 134.2M 的约 1/4;二是省掉一个矩阵(gate/up/down 只留两个),配 11008 只剩 2 × 4096 × 11008 ≈ 90.2M,比守恒点 135.3M 少 45.1M/层。而 FFN 正是每层参数的大头(约 2/3),这两刀都会直接砍在「知识存储」的容量上。

道理就像把一份工作量分给不同人数:标准 FFN 是 2 个人干活(2 个矩阵),SwiGLU 是 3 个人干(3 个矩阵)——想让总工作量不变,每个人(每个矩阵的中间维)就得按比例缩到原来的 2/3。

🧮 从「2 个矩阵」到「3 个矩阵」:11008 的推导
Step 1:标准 FFN 的账——2 个矩阵,中间维 4d
矩阵形状参数
W1(升维)[d, 4d]4d²
W2(降维)[4d, d]4d²
合计2 × d × 4d = 8d²8 × 4096² = 134.2M
d = 4096 时,标准 FFN 每层 8d² = 134.2M 参数——这就是 SwiGLU 要「对齐」的目标。
Step 2:SwiGLU 有 3 个矩阵,中间维要缩到 8/3·d
矩阵形状参数
gate_proj[d, d_ff]d·d_ff
up_proj[d, d_ff]d·d_ff
down_proj[d_ff, d]d_ff·d
合计3 × d × d_ff待定
令 3·d·d_ff = 8d²,解得 d_ff = 8/3·d = 8/3 × 4096 ≈ 10922.7。
Step 3:实际取 11008——向上对齐到 256 的整数倍
步骤计算结果
2/3 规则8/3 × 409610922.7
除以 25610922.7 / 25642.67
向上取整再乘回43 × 25611008
每层 FFN 参数3 × 4096 × 11008135.3M
对齐到 256 的整数倍(43 × 256 = 11008)是为切分粒度留余量——这一点属工程惯例,需人工核实(不要把它理解成"256 = 头数 × 每头维度",那是 4096)。
Step 4:算一笔对比账——为什么不能随便改这个数
方案每层 FFN 参数与 11008 之差32 层合计
3 矩阵 × 11008(实际)3 × 4096 × 11008 = 135.3M基准4.33B
3 矩阵 × 16384(若用 4d)3 × 4096 × 16384 = 201.3M+66.0M6.44B
2 矩阵 × 11008(少一个矩阵)2 × 4096 × 11008 = 90.2M−45.1M2.89B
取 4d 会让 32 层多花 2.11B 参数;少一个矩阵又会少 45.1M/层、参数量不再守恒。11008 正好卡在「3 个矩阵 × 2/3 中间维」这一点上。
🎯 关键认知:11008 是「参数量守恒」倒推出来的

它 = 4096 × 8/3 再向上对齐到 256 的整数倍,目的只有一个:让 SwiGLU 的 3 个矩阵加起来(3·d·d_ff ≈ 8d²)与标准 FFN 的 2 个矩阵(2·d·4d = 8d²)持平。同一套账换个模型照样套——把 d 换掉重算即可;不同实现会在此基础上调(如 Llama 3 8B 用 14336,比 8/3·d 更大,以换取更强表达力)。

AI 助教
👋 对 FFN 中间维有疑问?比如「为什么是 8/3 而不是 4?」「11008 为什么对齐到 256 的倍数?」「Llama 3 为什么用 14336?」

我会用具体数字帮你算。
6
人人都说「7B 模型」——这个 7,000,000,000 到底是怎么一块一块加出来的?
提示:别盯着总数看。先把模型拆成首尾两张表 + 中间 32 层,每层再拆成 Attention 和 FFN 两块——数一数每一块是几×几的矩阵,再把它们加起来,总数自己就浮出来了。
▾
知识背景
Llama 2 由 Meta 于 2023 年 7 月发布(Touvron et al., 2023)。7B 版本公布的配置是:hidden_size(隐藏层维度,每个 token 向量的长度)=4096、32 层、32 个注意力头、FFN(Feed-Forward Network,每层负责「记忆」的前馈子层)中间维 11008、词表 32000;官方标称参数量 6.74B,四舍五入就叫「7B」。痛点:做显存估算时只知道「7B」这一个总数远远不够——你会算不清这 6.74B 到底压在哪些矩阵上、哪一块动一下总账就跟着动。

上一张卡片我们把 32 层 Block 接成了一条主干;现在走到整条流水线的最后一步——把 [1, 2, 4096] 的隐藏向量变成下一个词的预测,这一步靠 LM Head(把隐藏向量投影成词表概率分布的输出层)。

这一节不数 tensor 形状,而是回答一个更实在的问题:所谓「7B」,就是把这些矩阵一笔一笔乘出来再加总——首尾各一张 32000×4096 的大表,加上中间 32 层的 Attention 和 FFN。可以把它类比成装修算总价:首尾两张表是门和窗(各算一张),32 层 Block 是 32 间房,每间房里再分「Attention 区」和「FFN 区」,把单间用料乘以 32 再加门窗,就是总数。

🧮 把 6.74B 一块一块乘出来加总
Step 1:先摆出 Llama 2 7B 的全部超参
参数值含义
hidden_size(d)4096每个 token 的向量长度
num_hidden_layers32Block 层数
num_attention_heads32注意力头数
num_key_value_heads32等于头数 → 用的是 MHA(Multi-Head Attention,多头注意力:每个 Q 头都配一份独立的 K、V,不降维)
intermediate_size11008FFN 中间维
vocab_size32000词表大小
官方参数量6.74B本文要逐块加出来的目标数
注意:Llama 2 的 7B 用的是 MHA(kv 头 = 32,K/V 不降维);改用 GQA(Grouped-Query Attention,分组查询注意力:多个 Q 头共享一组 K、V)的是 34B / 70B。
Step 2:每层 Attention — 4 个 4096×4096 矩阵
矩阵形状参数
W_q4096 × 409616.78M
W_k4096 × 409616.78M
W_v4096 × 409616.78M
W_o4096 × 409616.78M
合计4 × 4096×4096 = 4 × 16.78M67.11M
4096 × 4096 = 16,777,216 ≈ 16.78M。因为是 MHA,K、V 也保持满维 4096,所以是 4 个同样大的矩阵。
Step 3:每层 FFN — SwiGLU 的 3 个矩阵
矩阵形状参数
gate_proj4096 × 1100845.09M
up_proj4096 × 1100845.09M
down_proj11008 × 409645.09M
合计3 × 4096×11008 = 3 × 45.09M135.27M
SwiGLU(门控前馈网络:用一个 gate 分支控制信息通过量)用三个矩阵,所以 FFN 比 Attention 更「胖」。
Step 4:每层合计,乘 32 层
账目计算参数
每层 Attention—67.11M
每层 FFN—135.27M
每层合计67.11M + 135.27M202.38M
32 层202.38M × 326,476.01M
Step 5:再加上首尾两张词表,对账 6.74B
账目计算参数
32 层 Block202.38M × 326,476.01M
Embedding32000 × 4096131.07M
LM Head32000 × 4096131.07M
RMSNorm32×2×4096 + 40960.27M
总计6,476.01M + 131.07M + 131.07M + 0.27M6,738.42M ≈ 6.74B
两张表占比(131.07M + 131.07M) / 6,738.42M≈ 3.9%
若共享省下131.07M / 6,738.42M≈ 1.9%
6.74B 不是估的:它 = 32 层的 Attention + FFN,加上首尾两张各 131.07M 的词表,再加可忽略的 RMSNorm。
🎯 关键认知

「7B」不是一个大概的数字,而是每一块矩阵乘出来加总的结果:32 层的 Attention + FFN 吃掉了约 96%,首尾两张词表各占 1.95%。其中 LM Head(把隐藏向量投影成词表概率的输出层)和 Embedding 是两张独立的大表——Llama 2 没有做 weight tying(权重绑定:让输入查表和输出投影共用同一份矩阵);如果共享,就能省下 131.07M ≈ 1.9% 的参数。这也解释了工程上为什么要权衡「词表大小」和「是否共享」:词表越大,首尾两张表越贵。

AI 助教
👋 对「7B 到底怎么算出来」有疑问?比如「MHA 换成 GQA 会少多少参数?」「weight tying 省下的 1.9% 值不值?」「Llama 3 8B 的 8.03B 怎么来的?」

我会用具体数字帮你算。