把 Llama 2 7B 一塊一塊拆開:6.74B 參數、13.5 GFLOPs 的由來
把 Llama 2 7B 一块一块拆开:6.74B 参数、13.5 GFLOPs的来历
這篇教程逐層拆解 Llama 2 7B,計算其約 6.74B 參數及單 token 前向約 13.5 GFLOPs 的由來。文中將模型拆為 Embedding、32 個 Transformer Block 和 LM Head,指出約 96% 參數位於 Block,並推導 FFN 中間維度 11008 的由來。
2026-11-06 4
版权
版权声明:
本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《 阿里云开发者社区用户服务协议》和 《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写 侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。
简介: 本课以Llama 2 7B为标本,逐层拆解大模型:从Embedding查表、32层Transformer Block结构(含Attention与SwiGLU FFN)、到LM Head输出,手算每块参数与计算量,揭示96%参数在Block、FFN占主导等关键事实。免费在线可读,含完整源码(MIT许可)。
前四篇讲了 Self-Attention、Transformer 骨架、现代结构改造、Tokenization。这一篇把它们装回一个真实模型——以 Llama 2 7B 为标本,从 Embedding 到 LM Head 逐层拆开,每个数字都自己乘一遍。内容来自我做的一套 34 课大模型课程的第 5 课。
- 本课在线阅读(免登录、手机可看):https://zhuangzhaoyeye.github.io/llm-course/lesson-5.html
- 全部 34 课:https://zhuangzhaoyeye.github.io/llm-course/
- 源码(MIT 许可):https://github.com/zhuangzhaoyeye/llm_course
问题 1:拆开一个 7B 模型,里面到底有几层?每层在干什么?
Llama 2 7B 只有三部分:一个 Embedding 层、32 个完全相同的 Transformer Block、一个 LM Head(把隐藏向量投影成词表概率的输出层)。每个 Block 里再分 Attention 和 FFN 两个子层,每个子层前各有一个 RMSNorm。
可以把结构想成一条装配线:首尾各一个工位,中间几十个工位做一模一样的加工——这些重复的工位就是 Block。
| 组件 | 包含什么 | 参数 | 占比 |
|---|---|---|---|
| Token Embedding | 32000 × 4096 查表矩阵 | 131.1M | 1.95% |
| 32 × Transformer Block | 每层 Attention + FFN + 2×RMSNorm | 32 × 202.4M = 6,476M | 96.1% |
| LM Head + Final RMSNorm | 独立输出矩阵 + 最后归一化 | 131.1M + 0.27M | 1.95% |
三者相加 6,738.4M ≈ 6.74B,这就是「7B」的由来。一个 Block 内部:
| 子层 | 操作 | 参数 |
|---|---|---|
| Input RMSNorm | 归一化 | 4096(只有缩放参数 γ) |
| Attention | QKV 三个投影 + O 投影,各 4096×4096 | 4 × 16.78M = 67.1M |
| Post-Attention RMSNorm | 归一化 | 4096 |
| FFN(SwiGLU) | gate / up / down 三个矩阵 | 3 × 45.09M = 135.3M |
一个结论值得记住:模型 96% 的参数在 Block 里,而 Block 里 FFN 又占 67%(135.3 / 202.4)。FFN 比 Attention 大两倍,不是设计失误——它才是「知识存储」的主体。
问题 2:从「你好」到一堆 4096 维向量,Embedding 做了什么运算?
答案是:只做查表,没有乘加。
有一个 32000 × 4096 的矩阵 W_embed,token ID 是 t,输出就是第 t 行。所以:
| 字 | Token ID(示意) | 参数来源 |
|---|---|---|
| 你 | 12845 | 词表第 12845 行 |
| 好 | 6721 | 词表第 6721 行 |
输入 tensor 形状 [1, 2](batch=1,seq_len=2),查表后变成 [1, 2, 4096]。
| 项目 | 计算 | 结果 |
|---|---|---|
| 参数数量 | 32000 × 4096 | 131,072,000(131M) |
| fp16 显存 | 131M × 2 bytes | 262 MB(250 MiB) |
| fp32 显存 | 131M × 4 bytes | 524 MB(500 MiB) |
262 MB 常驻显存,对 24 GB 显卡约占 1%——看着不多,但它和 LM Head 是两张一样大的表。
这里有个容易混的点:Llama 2 没有做 weight tying(权重绑定,让输入查表和输出投影共用同一份矩阵)。GPT-2 做了,能省一半;Llama 2 的 LM Head 是独立的 [4096, 32000] 矩阵,所以 6.74B 里这两块各算了一次 131M。
问题 3:一个 Attention Head 里,Q、K、V 是怎么从输入一步步算出来的?
输入 [1, 2, 4096] 进来,经过 QKV 投影 → 拆头 → 算分数 → 加权求和 → 合并 → O 投影,出去还是 [1, 2, 4096]。
用借书打比方:Q 是你手里的索书号,K 是书脊上的分类标签,V 是书页里的正文——拿 Q 和每张 K 比,谁最像就借走谁的 V。
第 1 步,三个投影,每个都是一次矩阵乘法:
| 操作 | 计算 | 输出形状 | 参数 |
|---|---|---|---|
| Q = X × W_Q | [1,2,4096] × [4096,4096] | [1, 2, 4096] | 16.78M |
| K = X × W_K | 同上 | [1, 2, 4096] | 16.78M |
| V = X × W_V | 同上 | [1, 2, 4096] | 16.78M |
第 2 步,把 4096 维拆成 32 个头,每头 128 维:[1, 2, 4096] → [1, 32, 2, 128]。
第 3 步,每个头单独算 Q·Kᵀ/√128,得到 2×2 的注意力分数(示意值):
| 对「你」 | 对「好」 | |
|---|---|---|
| 「你」这一行 | 0.43 | 0.18 |
| 「好」这一行 | 0.15 | 0.52 |
√128 ≈ 11.31,作用是压住点积的量级,防止 softmax 变成 one-hot、梯度消失。
第 4 步,按行做 softmax:
- 「你」:[0.43, 0.18] → [0.562, 0.438]
- 「好」:[0.15, 0.52] → [0.409, 0.591]
再用这两个权重去加权 V,得到每个位置的输出。
第 5 步,32 个头拼回 [1, 2, 4096],乘 W_O 再变一次维度不变的映射。整个 Attention 层参数 = QKV 50.3M + O 16.78M = 67.1M。
为什么是 32 个头而不是 1 个?如果只有一个 4096 维的头,主谓关系、修饰关系、位置相邻这些模式会全混在一个注意力分布里;32 个头等于 32 个视角同时看同一句话,各自学一种关系。
问题 4:一个 token 走完 32 层,到底要算多少次浮点运算?
只需要一条规则:一次前向里,每个权重恰好做一次「乘 + 加」,也就是 2 FLOPs。所以前向 FLOPs ≈ 2 × 参数量。
先把三种口径说清,避免和论文对不上:
| 口径 | 数什么 | Llama 2 7B |
|---|---|---|
| 只数乘法 | 乘一次算 1 | ≈ 1N = 6.7 GFLOPs |
| 只计前向,乘加都数 | 每权重 2 FLOPs | ≈ 2N = 13.5 GFLOPs |
| 前向 + 反向 | 反向约是前向 2 倍 | ≈ 6N = 40.4 GFLOPs |
套进具体数字(N = 6.74B):
| 阶段 | 计算 | 结果 |
|---|---|---|
| 单 token 前向 | 2 × 6.74e9 | 13.5 GFLOPs |
| 单 token 反向 | 4 × 6.74e9 | 27.0 GFLOPs |
| 单 token 训练 | 6 × 6.74e9 | 40.4 GFLOPs |
注意 2N 里的 N 已经是全部 32 层的参数总和,所以不需要再乘 32。
训练总算力就是把这个式子乘以 token 数 D:C = 6ND。
| 训练规模 | 计算 | 结果 |
|---|---|---|
| 1T token | 6 × 6.74e9 × 1e12 | 4.04 × 10²² FLOPs |
| 2T token | 6 × 6.74e9 × 2e12 | 8.09 × 10²² FLOPs |
换成推理场景:prefill 1000 个 token ≈ 1000 × 2 × 6.74e9 = 13.5 TFLOPs;生成 100 个 token ≈ 1.35 TFLOPs。这里只算 2N,忽略了 attention 的 O(L²) 项——几百 token 的短上下文下它很小,上下文极长时才会盖过 2N。
问题 5:FFN 的中间维是 11008——这个怪数字怎么定出来的?
不是随手取的整数,是「参数量守恒」倒推出来的。
标准 FFN 用两个矩阵,中间维惯例取 4d,参数量 = 2 × d × 4d = 8d²。d = 4096 时是 134.2M。
SwiGLU 用三个矩阵(gate / up / down),参数量 = 3 × d × d_ff。要让两者持平:
3 · d · d_ff = 8d² → d_ff = 8d/3 = 8 × 4096 / 3 ≈ 10922.7
再向上对齐到 256 的整数倍:10922.7 / 256 ≈ 42.67 → 43 × 256 = 11008。
于是每层 FFN = 3 × 4096 × 11008 = 135.3M,正好接近标准的 134.2M。换个取值会怎样:
| 方案 | 每层 FFN 参数 | 与 11008 之差 | 32 层合计 |
|---|---|---|---|
| 3 矩阵 × 11008(实际) | 135.3M | 基准 | 4.33B |
| 3 矩阵 × 16384(若按 4d) | 201.3M | +66.0M | 6.44B |
| 2 矩阵 × 11008(少一个矩阵) | 90.2M | −45.1M | 2.89B |
按 4d 取会让 32 层多花 2.11B 参数;少一个矩阵则每层少 45.1M、参数量不再守恒。11008 正好卡在「3 个矩阵 × 2/3 中间维」这一点上。
这套账换个模型照样能算:Llama 3 8B 就把中间维放到 14336,比 8d/3 更大,用参数换表达力。
问题 6:「7B」这个数字,是怎么一块一块加出来的?
把每一块矩阵乘出来,再加总。Llama 2 7B 的超参:d = 4096、32 层、32 个注意力头、FFN 中间维 11008、词表 32000。
每层 Attention,4 个 4096×4096:
| 矩阵 | 参数 |
|---|---|
| W_q | 16.78M |
| W_k | 16.78M |
| W_v | 16.78M |
| W_o | 16.78M |
| 合计 | 67.11M |
每层 FFN,SwiGLU 的 3 个矩阵:
| 矩阵 | 形状 | 参数 |
|---|---|---|
| gate_proj | 4096 × 11008 | 45.09M |
| up_proj | 4096 × 11008 | 45.09M |
| down_proj | 11008 × 4096 | 45.09M |
| 合计 | 3 × 45.09M | 135.27M |
每层 67.11 + 135.27 = 202.38M,乘 32 层 = 6,476.01M。
最后加上首尾:
| 账目 | 计算 | 参数 |
|---|---|---|
| 32 层 Block | 202.38M × 32 | 6,476.01M |
| Embedding | 32000 × 4096 | 131.07M |
| LM Head | 32000 × 4096 | 131.07M |
| RMSNorm | 32×2×4096 + 4096 | 0.27M |
| 总计 | 相加 | 6,738.42M ≈ 6.74B |
两张表合计占 262.14M / 6,738.42M ≈ 3.9%;如果做 weight tying,能省下其中一张、约 1.9%。这也解释了工程上为什么要权衡词表大小:词表越大,首尾两张表越贵。
小结
| 问题 | 结论 | 一个数字 |
|---|---|---|
| 里面有几层 | Embedding + 32 Block + LM Head | 96% 参数在 Block 里 |
| Embedding 做什么 | 纯查表,无乘加 | 131M 参数 = 262 MB |
| Q/K/V 怎么来 | 三次投影 → 拆 32 头 → 分数 → 加权 → 合并 | 每层 67.1M |
| 多少浮点运算 | 前向 2N,训练 6ND | 单 token 前向 13.5 GFLOPs |
| 11008 怎么来 | 8d/3 向上对齐 256 | 3 × 4096 × 11008 = 135.3M |
| 7B 怎么加出来 | 逐块乘加 | 6,738.42M ≈ 6.74B |
参考与说明
- Llama 2 配置与参数量:Touvron 等,Llama 2: Open Foundation and Fine-Tuned Chat Models, 2023,https://arxiv.org/abs/2307.09288
- FLOPs 经验规则与 C = 6ND:Kaplan 等,Scaling Laws for Neural Language Models, 2020,https://arxiv.org/abs/2001.08361;Hoffmann 等,Training Compute-Optimal Large Language Models, 2022,https://arxiv.org/abs/2203.15556
- SwiGLU 与三个矩阵的取舍:Shazeer,GLU Variants Improve Transformer, 2020,https://arxiv.org/abs/2002.05202
- 多头注意力中各头分工的观察:Clark 等,What Does BERT Look At?, 2019,https://arxiv.org/abs/1906.04341
文中所有数字(Embedding 参数量、每层 Attention/FFN 参数、32 层合计、fp16 显存、11008 的推导、2N/6ND、softmax 结果)我都用 Python 独立复算过。"示意值"标明的是为演示取的数字,不是模型真实输出。
说明:这套课程由 AI 在我设计的规则下生成,再经过脚本检查和独立审查;审查发现过不少问题,都写在仓库 README 里。如果你发现错误,欢迎在仓库提 Issue,写清位置,我会逐条核实。
继续学
上一篇是第 4 课「Tokenization 机制」,讲 BPE 怎么合并、中文为什么更费 token。这一课之后是第 6 课「从 Transformer 到 LLM 全景图」。每张卡片后面还有 AI 助教,可以接着追问(每人每天有次数限制)。
- 课程:https://zhuangzhaoyeye.github.io/llm-course/
- 源码:https://github.com/zhuangzhaoyeye/llm_course ,觉得有帮助的话欢迎点个 Star
來源:阿里雲開發者社區 AI · developer.aliyun.com