Skip to content

Commit a92ede0

Browse files
committed
Fix notebook content accuracy
1 parent 4d44342 commit a92ede0

30 files changed

Lines changed: 444 additions & 184 deletions

README-CN.md

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Modern LLM Notebook
22

33
<p align="center">
4-
<strong>用 23 篇可运行 Jupyter Notebook,从零实现现代 LLM 系统。</strong>
4+
<strong>用 26 篇可运行 Jupyter Notebook,从零实现现代 LLM 系统。</strong>
55
</p>
66

77
<p align="center">
@@ -26,7 +26,7 @@
2626
</a>
2727
<img alt="Python" src="https://img.shields.io/badge/Python-3.9%2B-3776AB">
2828
<img alt="PyTorch" src="https://img.shields.io/badge/PyTorch-2.0%2B-EE4C2C">
29-
<img alt="Notebooks" src="https://img.shields.io/badge/Notebooks-23-orange">
29+
<img alt="Notebooks" src="https://img.shields.io/badge/Notebooks-26-orange">
3030
<img alt="Languages" src="https://img.shields.io/badge/Languages-English%20%7C%20Chinese-2ea44f">
3131
</p>
3232

@@ -50,7 +50,7 @@ Modern LLM Notebook 是一套以 Jupyter Notebook 为主线的现代大语言模
5050
黑盒调用,而是用 PyTorch 亲手实现核心组件:Tokenizer、Embedding、Attention、Transformer Block、
5151
训练循环、MoE、LoRA、RLHF、解码、KV Cache、长上下文、VLM、评测、蒸馏和 On-Policy Distillation。
5252

53-
仓库现在同时维护中文与英文两套 Notebook。英文版位于 `notebooks-en/`,覆盖完整 23 章;
53+
仓库现在同时维护中文与英文两套 Notebook。英文版位于 `notebooks-en/`,覆盖完整 26 章;
5454
网页阅读器在首页和 Notebook 侧边栏都支持语言切换(也可以在 URL 里用 `?lang=en`),课程目录、Notebook 内容和运行输出都按语言展示。
5555

5656
这个项目的定位是**教学型参考实现**。它不是模型权重仓库,不是生产推理框架,也不是托管 API
@@ -143,7 +143,7 @@ jupyter notebook notebooks/part1-foundation/01-tokenizer-basics.ipynb
143143
语言说明:
144144

145145
- 中文版 Notebook:`notebooks/`
146-
- 英文版 Notebook:`notebooks-en/`23/23 全量覆盖)
146+
- 英文版 Notebook:`notebooks-en/`26/26 全量覆盖)
147147

148148
推荐环境:
149149

@@ -185,8 +185,8 @@ python scripts/execute_notebooks_en_no_kernel.py
185185

186186
| 模块 | 状态 |
187187
|:---|:---|
188-
| 中文 Notebook | 23/23 完整覆盖 |
189-
| 英文 Notebook | 23/23 完整覆盖,并已写入运行输出 |
188+
| 中文 Notebook | 26/26 完整覆盖 |
189+
| 英文 Notebook | 26/26 完整覆盖,并已写入运行输出 |
190190
| 网页阅读器 | React / Vite,支持首页和侧边栏语言切换 |
191191
| 静态站点 | 通过 GitHub Pages 发布 |
192192
| 质量检查 | 英文覆盖、语法、输出语言、网页构建 |
@@ -201,7 +201,7 @@ python scripts/execute_notebooks_en_no_kernel.py
201201

202202
## 课程路线
203203

204-
课程分为 5 个部分,共 23 个自包含 Notebook。
204+
课程分为 5 个部分,共 26 个自包含 Notebook。
205205

206206
```text
207207
Modern LLM Notebook
@@ -216,6 +216,7 @@ Modern LLM Notebook
216216
217217
├── Part 2: Training
218218
│ ├── 从 GPT-2 到现代模型
219+
│ ├── Model config
219220
│ ├── Mixture of Experts
220221
│ ├── Training and loss
221222
│ ├── Scaling laws
@@ -237,7 +238,8 @@ Modern LLM Notebook
237238
└── Part 5: Production
238239
├── Evaluation
239240
├── Distillation
240-
└── On-policy distillation
241+
├── On-policy distillation
242+
└── RAG
241243
```
242244

243245
每个 Notebook 都尽量自包含。你可以顺序学习,也可以直接跳到感兴趣的主题,不依赖前面 Notebook
@@ -255,14 +257,14 @@ Modern LLM Notebook
255257
| 04 | [Position Encoding](notebooks/part1-foundation/04-position-encoding.ipynb) | 模型如何感知词的顺序? | 正弦位置编码、输入组装 |
256258
| 05 | [Attention & Transformer Block](notebooks/part1-foundation/05-transformer-block.ipynb) | Attention 如何搬运上下文信息? | MHA、残差、归一化 |
257259
| 06 | [Mini-GPT](notebooks/part1-foundation/06-mini-gpt.ipynb) | GPT 风格模型如何组装起来? | Decoder-only 模型、LM head |
258-
| 07 | [Model Config](notebooks/part1-foundation/07-model-config.ipynb) | 真实模型的 config.json 里每个字段是什么意思? | vocab_size、hidden_size、layers、heads |
259-
| 08 | [BERT Encoder](notebooks/part1-foundation/08-bert-encoder.ipynb) | Encoder-only 模型为什么能双向读文本? | MiniBERT、MLM head |
260+
| 07 | [BERT Encoder](notebooks/part1-foundation/07-bert-encoder.ipynb) | Encoder-only 模型为什么能双向读文本? | MiniBERT、MLM head |
260261

261262
### Part 2: Training
262263

263264
| # | Notebook | 核心问题 | 实现重点 |
264265
|:---:|:---|:---|:---|
265-
| 09 | [从 GPT-2 到现代模型](notebooks/part2-training/09-gpt2-to-modern-models.ipynb) | GPT-2 之后,现代模型在架构上改了什么? | RMSNorm、SwiGLU、RoPE、GQA、QK-Norm、MLA |
266+
| 08 | [从 GPT-2 到现代模型](notebooks/part2-training/08-gpt2-to-modern-models.ipynb) | GPT-2 之后,现代模型在架构上改了什么? | RMSNorm、SwiGLU、RoPE、GQA、QK-Norm、MLA |
267+
| 09 | [Model Config](notebooks/part2-training/09-model-config.ipynb) | 真实模型的 config.json 里每个字段是什么意思? | vocab_size、hidden_size、layers、heads |
266268
| 10 | [Mixture of Experts](notebooks/part2-training/10-moe.ipynb) | 稀疏专家路由如何工作? | Router gate、top-k experts、无辅助 loss 负载均衡 |
267269
| 11 | [Training & Loss](notebooks/part2-training/11-training-loss.ipynb) | 语言模型如何从预测错误中学习? | 训练循环、loss、梯度、Multi-Token Prediction |
268270
| 12 | [Scaling Laws](notebooks/part2-training/12-scaling-laws.ipynb) | 模型大小、数据量和算力如何权衡? | FLOPs 估算、Chinchilla 直觉 |

README.md

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Modern LLM Notebook
22

33
<p align="center">
4-
<strong>Build modern LLMs from scratch through 23 runnable Jupyter Notebooks.</strong>
4+
<strong>Build modern LLMs from scratch through 26 runnable Jupyter Notebooks.</strong>
55
</p>
66

77
<p align="center">
@@ -26,7 +26,7 @@
2626
</a>
2727
<img alt="Python" src="https://img.shields.io/badge/Python-3.9%2B-3776AB">
2828
<img alt="PyTorch" src="https://img.shields.io/badge/PyTorch-2.0%2B-EE4C2C">
29-
<img alt="Notebooks" src="https://img.shields.io/badge/Notebooks-23-orange">
29+
<img alt="Notebooks" src="https://img.shields.io/badge/Notebooks-26-orange">
3030
<img alt="Languages" src="https://img.shields.io/badge/Languages-English%20%7C%20Chinese-2ea44f">
3131
</p>
3232

@@ -173,7 +173,7 @@ jupyter notebook notebooks-en/part1-foundation/01-tokenizer-basics.ipynb
173173
Language note:
174174

175175
- Chinese notebooks live in `notebooks/`
176-
- English notebooks live in `notebooks-en/` (complete 23/23 translation coverage)
176+
- English notebooks live in `notebooks-en/` (complete 26/26 translation coverage)
177177

178178
Recommended environment:
179179

@@ -217,8 +217,8 @@ python scripts/execute_notebooks_en_no_kernel.py
217217

218218
| Area | Status |
219219
|:---|:---|
220-
| Chinese notebooks | Complete 23/23 |
221-
| English notebooks | Complete 23/23 with executed outputs |
220+
| Chinese notebooks | Complete 26/26 |
221+
| English notebooks | Complete 26/26 with executed outputs |
222222
| Web reader | React / Vite app with language switching |
223223
| Static site | Published through GitHub Pages |
224224
| Quality checks | English coverage, syntax, output-language checks, and web build |
@@ -233,7 +233,7 @@ python scripts/execute_notebooks_en_no_kernel.py
233233

234234
## Curriculum
235235

236-
The curriculum is organized as five parts and 23 self-contained notebooks.
236+
The curriculum is organized as five parts and 26 self-contained notebooks.
237237

238238
```text
239239
Modern LLM Notebook
@@ -248,6 +248,7 @@ Modern LLM Notebook
248248
249249
├── Part 2: Training
250250
│ ├── From GPT-2 to modern models
251+
│ ├── Model config
251252
│ ├── Mixture of Experts
252253
│ ├── Training and loss
253254
│ ├── Scaling laws
@@ -269,7 +270,8 @@ Modern LLM Notebook
269270
└── Part 5: Production
270271
├── Evaluation
271272
├── Distillation
272-
└── On-policy distillation
273+
├── On-policy distillation
274+
└── RAG
273275
```
274276

275277
Each notebook is designed to be runnable on its own. You can follow the full sequence or jump to a
@@ -287,13 +289,14 @@ topic without depending on hidden runtime state from earlier notebooks.
287289
| 04 | [Position Encoding](notebooks-en/part1-foundation/04-position-encoding.ipynb) | How does the model know word order? | Sinusoidal encoding, input assembly |
288290
| 05 | [Attention & Transformer Block](notebooks-en/part1-foundation/05-transformer-block.ipynb) | How does attention move information? | MHA, residuals, normalization |
289291
| 06 | [Mini-GPT](notebooks-en/part1-foundation/06-mini-gpt.ipynb) | How does a GPT-style model fit together? | Decoder-only model, LM head |
290-
| 08 | [BERT Encoder](notebooks-en/part1-foundation/08-bert-encoder.ipynb) | Why can encoder-only models read bidirectionally? | MiniBERT, MLM head |
292+
| 07 | [BERT Encoder](notebooks-en/part1-foundation/07-bert-encoder.ipynb) | Why can encoder-only models read bidirectionally? | MiniBERT, MLM head |
291293

292294
### Part 2: Training
293295

294296
| # | Notebook | Primary question | Implementation focus |
295297
|:---:|:---|:---|:---|
296-
| 09 | [From GPT-2 to Modern Models](notebooks-en/part2-training/09-gpt2-to-modern-models.ipynb) | What changed architecturally after GPT-2? | RMSNorm, SwiGLU, RoPE, GQA, QK-Norm, MLA |
298+
| 08 | [From GPT-2 to Modern Models](notebooks-en/part2-training/08-gpt2-to-modern-models.ipynb) | What changed architecturally after GPT-2? | RMSNorm, SwiGLU, RoPE, GQA, QK-Norm, MLA |
299+
| 09 | [Model Config](notebooks-en/part2-training/09-model-config.ipynb) | What does each field in a real config.json mean? | vocab_size, hidden_size, layers, heads |
297300
| 10 | [Mixture of Experts](notebooks-en/part2-training/10-moe.ipynb) | How does sparse expert routing work? | Router gate, top-k experts, aux-free load balancing |
298301
| 11 | [Training & Loss](notebooks-en/part2-training/11-training-loss.ipynb) | How does a language model learn from prediction errors? | Training loop, loss, gradients, Multi-Token Prediction |
299302
| 12 | [Scaling Laws](notebooks-en/part2-training/12-scaling-laws.ipynb) | How do model size, data, and compute trade off? | FLOPs estimates, Chinchilla intuition |
@@ -325,6 +328,7 @@ topic without depending on hidden runtime state from earlier notebooks.
325328
| 23 | [Evaluation](notebooks-en/part5-production/23-evaluation.ipynb) | How do we tell whether a model is better? | Win-rate matrices, RAGAS, judge metrics |
326329
| 24 | [Distillation](notebooks-en/part5-production/24-distillation.ipynb) | How does a small model learn from a large one? | Soft labels, temperature, logit distillation |
327330
| 25 | [On-Policy Distillation](notebooks-en/part5-production/25-opd.ipynb) | How can distillation reduce exposure bias? | OPSD, KL estimator taxonomy |
331+
| 26 | [RAG](notebooks-en/part5-production/26-rag.ipynb) | How does retrieval-augmented generation connect external knowledge to a model? | Chunking, embedding retrieval, reranking, generation |
328332

329333
## Quality Bar
330334

notebooks-en/part1-foundation/03-embedding.ipynb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,7 @@
376376
"\n",
377377
"Weight decay is a constraint the optimizer applies during each parameter update: first shrink the parameter proportionally (w <- w - lr x lambda x w), then subtract the current gradient direction. This is equivalent to adding a lambda*||w||^2/2 penalty to the loss, applying a stronger pull-back force on large weights to prevent parameter values from diverging.\n",
378378
"\n",
379-
"A common intuition is: each row of the Embedding matrix is a token's semantic vector. If we pull the row vector toward the origin (i.e., decay each component's absolute value), the semantic vector's \"length\" is artificially shortened -- and semantics shouldn't have强弱之分. Following this logic, Embedding weights should be excluded from weight decay.\n",
379+
"A common intuition is: each row of the Embedding matrix is a token's semantic vector. If we pull the row vector toward the origin (i.e., decay each component's absolute value), the semantic vector's \"length\" is artificially shortened -- and semantics shouldn't have an artificial strong/weak ranking. Following this logic, Embedding weights should be excluded from weight decay.\n",
380380
"\n",
381381
"But this intuition lacks experimental support. Actual open-source code does the opposite.\n",
382382
"\n",
@@ -999,4 +999,4 @@
999999
},
10001000
"nbformat": 4,
10011001
"nbformat_minor": 5
1002-
}
1002+
}

notebooks-en/part2-training/08-gpt2-to-modern-models.ipynb

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
"\n",
3535
"Take Post-Norm as an example. Post-Norm places normalization after the residual addition: after computing Attention, add the residual, then apply Norm. With few layers, this is easy to understand and works fine. But as layers get deeper, every time the gradient passes through a layer it also passes through normalization, and its scale gets repeatedly altered. Pre-Norm moves normalization before the sublayer, making the residual path more like a direct highway, and deep training is typically more stable.\n",
3636
"\n",
37-
"Activation functions follow a similar pattern. ReLU's rule is simple: positive numbers pass through, negative numbers become 0. It's easy to understand and implement, but the gradient is 0 in the negative region, which can lead to \"neurons that don't learn for a long time.\" Modern LLMs more commonly use GELU or SwiGLU - smoother or gated activations that don't simply cut information with a single一刀 (single一刀).\n",
37+
"Activation functions follow a similar pattern. ReLU's rule is simple: positive numbers pass through, negative numbers become 0. It's easy to understand and implement, but the gradient is 0 in the negative region, which can lead to \"neurons that don't learn for a long time.\" Modern LLMs more commonly use GELU or SwiGLU - smoother or gated activations that don't simply cut information with a single hard cutoff.\n",
3838
"\n",
3939
"LLaMA (2023) combines these modern components systematically: Pre-Norm + RMSNorm, SwiGLU, RoPE. Later models like Mistral, LLaMA 3, Qwen, and DeepSeek continue to refine around inference efficiency and long context, with improvements like GQA, MLA, QK-Norm, and more.\n",
4040
"\n",
@@ -250,7 +250,7 @@
250250
"rms_values = [f\"{v:.4f}\" for v in x_rmsnorm.tolist()]\n",
251251
"print(f\"RMSNorm result: {rms_values}\")\n",
252252
"print(f\" mean={x_rmsnorm.mean():.4f}, RMS={rms_after:.4f}\")\n",
253-
"print(f\"\\n-> Different values, but both achieve \"standardization\"\")\n",
253+
"print('\\n-> Different values, but both achieve \"standardization\"')\n",
254254
"print(f\"-> LayerNorm forces mean=0, RMSNorm doesn't (but in practice it's often good enough)\")"
255255
]
256256
},
@@ -1852,7 +1852,17 @@
18521852
"source": [
18531853
"## Exercises\n",
18541854
"\n",
1855-
"To be added"
1855+
"**Exercise 1: RMSNorm vs LayerNorm edge cases**\n",
1856+
"\n",
1857+
"Change the RMSNorm hand-calculation input to `[1, -1, 1, -1]` and `[10, 10, 10, 10]`. Observe the LayerNorm and RMSNorm outputs. Write two conclusions: which one forces mean 0, and which one only controls RMS?\n",
1858+
"\n",
1859+
"**Exercise 2: Estimate SwiGLU parameter count**\n",
1860+
"\n",
1861+
"Assume `hidden_size=4096` and a regular FFN uses `intermediate_size=11008`. Estimate the linear-layer parameter count for a ReLU/GELU FFN and a SwiGLU FFN. Explain why SwiGLU often adjusts the intermediate dimension to control parameter size.\n",
1862+
"\n",
1863+
"**Exercise 3: KV Cache savings from GQA**\n",
1864+
"\n",
1865+
"Assume `num_attention_heads=32`, `num_key_value_heads=8`, `head_dim=128`, and sequence length 4096. Calculate how many K/V scalars a standard MHA layer and a GQA layer cache, then report the savings ratio."
18561866
]
18571867
}
18581868
],
@@ -1869,4 +1879,4 @@
18691879
},
18701880
"nbformat": 4,
18711881
"nbformat_minor": 4
1872-
}
1882+
}

notebooks-en/part2-training/10-moe.ipynb

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -742,7 +742,7 @@
742742
"\n",
743743
"| Metric | What to check | Warning sign |\n",
744744
"|:---|:---|:---|\n",
745-
"| `task_loss` | Is the main task being learned? | Loss not decreasing or剧烈 jittering |\n",
745+
"| `task_loss` | Is the main task being learned? | Loss not decreasing or severe jittering |\n",
746746
"| `expert_usage` | Selection ratio per expert | One expert consistently at 80%+ |\n",
747747
"| `imbalance` | Gap between busiest and idlest expert | Gap persistently large |\n",
748748
"| `router_entropy` | Is the router becoming too rigid too early? | Low entropy, meaning selection is too peaked |\n",
@@ -937,7 +937,17 @@
937937
"source": [
938938
"## Exercises\n",
939939
"\n",
940-
"To be added."
940+
"**Exercise 1: Observe router collapse**\n",
941+
"\n",
942+
"Change router top-k from 2 to 1, then try increasing or decreasing the softmax temperature. Record each expert's usage count and decide whether a few experts are being overused.\n",
943+
"\n",
944+
"**Exercise 2: Implement a simple capacity limit**\n",
945+
"\n",
946+
"Give each expert a maximum number of accepted tokens, for example `capacity = ceil(num_tokens / num_experts * 1.25)`. Tokens beyond capacity can be skipped or routed to their second-choice expert. Compare expert usage with and without the capacity limit.\n",
947+
"\n",
948+
"**Exercise 3: Calculate active parameters**\n",
949+
"\n",
950+
"Assume 8 experts, each with 100M parameters, plus 300M parameters in the router and shared layers. Each token activates only 2 experts. Compute total parameters and per-token active parameters, then explain why MoE can have many parameters but relatively low per-token compute."
941951
]
942952
}
943953
],
@@ -954,4 +964,4 @@
954964
},
955965
"nbformat": 4,
956966
"nbformat_minor": 5
957-
}
967+
}

0 commit comments

Comments
 (0)