singhpratech commited on
Commit
260098f
·
verified ·
1 Parent(s): e58f45c

Upload tiny_llm_from_scratch.ipynb with huggingface_hub

Browse files
Files changed (1) hide show
  1. tiny_llm_from_scratch.ipynb +193 -63
tiny_llm_from_scratch.ipynb CHANGED
@@ -2,7 +2,7 @@
2
  "cells": [
3
  {
4
  "cell_type": "markdown",
5
- "id": "9ff84951",
6
  "metadata": {},
7
  "source": [
8
  "# Tiny Storyteller: building a language model from scratch\n",
@@ -44,7 +44,7 @@
44
  },
45
  {
46
  "cell_type": "markdown",
47
- "id": "3fcb1915",
48
  "metadata": {},
49
  "source": [
50
  "# Before any code: Momo, Ella, and what we are about to build\n",
@@ -67,7 +67,8 @@
67
  "In grown-up words: Momo is the **model**. His dials are the **weights**, also called\n",
68
  "**parameters**: the numbers that get adjusted during learning. Ella's stories are the\n",
69
  "**training data**. Her \"how wrong were you\" is the **loss**. Her shelf is the **KV cache**.\n",
70
- "Each of these gets its own section below.\n",
 
71
  "\n",
72
  "## 1. What is PyTorch?\n",
73
  "\n",
@@ -82,8 +83,8 @@
82
  " one called a T4.\n",
83
  "- **A tape recorder**, called **autograd** (automatic gradients). While Momo works it writes\n",
84
  " down every step. Afterwards it reads the tape backwards and tells Momo which way to turn\n",
85
- " every dial, and by how much. No ordinary programming tool does this, and it is the reason\n",
86
- " modern AI works at all. Part 1 has a game that shows exactly how the tape is read.\n",
87
  "\n",
88
  "PyTorch was built at Meta's AI lab and is behind most famous models (the GPT family, Llama,\n",
89
  "Stable Diffusion, Whisper). **Hugging Face**, where we publish at the end, is the public\n",
@@ -138,7 +139,7 @@
138
  "say, 92 percent. One token is picked.\n",
139
  "\n",
140
  "**Step 5, repeat.** \"Paris\" is added to the words so far and the whole journey runs again for\n",
141
- "the next token, until Momo picks a special \"I'm done\" token. You see words appear one by one\n",
142
  "on screen because that is literally how they are made.\n",
143
  "\n",
144
  "## 5. How attention looks things up: the story circle\n",
@@ -150,7 +151,9 @@
150
  "- a **key** card: \"here is what I am\" (\"France\" says: I am a country),\n",
151
  "- a **value** card: \"here is what I will tell you if you pick me\" (France's actual meaning).\n",
152
  "\n",
153
- "The newest animal holds up its query card and compares it with everyone's key card. A good\n",
 
 
154
  "match scores high, a poor match scores low. The scores are squashed into percentages\n",
155
  "(softmax again) and the animal collects a blend of everyone's value cards, weighted by those\n",
156
  "percentages. \"capital\" might take 70 percent from \"France\", 20 percent from \"of\", and crumbs\n",
@@ -180,7 +183,10 @@
180
  "token keeps its cards there. A model's **context window** (how much text it can hold at\n",
181
  "once) is partly how big the shelf is allowed to grow.\n",
182
  "\n",
183
- "Part 5 shows the shelf in twelve lines of code.\n",
 
 
 
184
  "\n",
185
  "## 7. The strange names, decoded\n",
186
  "\n",
@@ -233,7 +239,7 @@
233
  },
234
  {
235
  "cell_type": "markdown",
236
- "id": "a93c6c86",
237
  "metadata": {},
238
  "source": [
239
  "## Live flow diagram\n",
@@ -248,7 +254,7 @@
248
  {
249
  "cell_type": "code",
250
  "execution_count": null,
251
- "id": "c19f30be",
252
  "metadata": {},
253
  "outputs": [],
254
  "source": [
@@ -373,7 +379,7 @@
373
  },
374
  {
375
  "cell_type": "markdown",
376
- "id": "754198a6",
377
  "metadata": {},
378
  "source": [
379
  "## 0. Setup\n",
@@ -383,7 +389,7 @@
383
  {
384
  "cell_type": "code",
385
  "execution_count": null,
386
- "id": "68b59dbf",
387
  "metadata": {},
388
  "outputs": [],
389
  "source": [
@@ -393,7 +399,7 @@
393
  {
394
  "cell_type": "code",
395
  "execution_count": null,
396
- "id": "1d0052fe",
397
  "metadata": {},
398
  "outputs": [],
399
  "source": [
@@ -410,7 +416,7 @@
410
  },
411
  {
412
  "cell_type": "markdown",
413
- "id": "511c964a",
414
  "metadata": {},
415
  "source": [
416
  "## 1. Tensors and gradients: the two building blocks\n",
@@ -429,7 +435,7 @@
429
  {
430
  "cell_type": "code",
431
  "execution_count": null,
432
- "id": "aa29df50",
433
  "metadata": {},
434
  "outputs": [],
435
  "source": [
@@ -472,7 +478,7 @@
472
  },
473
  {
474
  "cell_type": "markdown",
475
- "id": "3717ba99",
476
  "metadata": {},
477
  "source": [
478
  "### How matrix multiplication actually happens\n",
@@ -494,7 +500,7 @@
494
  {
495
  "cell_type": "code",
496
  "execution_count": null,
497
- "id": "ba02b9f9",
498
  "metadata": {},
499
  "outputs": [],
500
  "source": [
@@ -551,7 +557,7 @@
551
  {
552
  "cell_type": "code",
553
  "execution_count": null,
554
- "id": "00afbdb2",
555
  "metadata": {},
556
  "outputs": [],
557
  "source": [
@@ -564,7 +570,7 @@
564
  },
565
  {
566
  "cell_type": "markdown",
567
- "id": "9ced2269",
568
  "metadata": {},
569
  "source": [
570
  "### The gradient: which way to turn each dial\n",
@@ -587,7 +593,7 @@
587
  {
588
  "cell_type": "code",
589
  "execution_count": null,
590
- "id": "0a31a332",
591
  "metadata": {},
592
  "outputs": [],
593
  "source": [
@@ -627,7 +633,7 @@
627
  },
628
  {
629
  "cell_type": "markdown",
630
- "id": "69480f68",
631
  "metadata": {},
632
  "source": [
633
  "### Momo in the foggy jungle: thorn bushes, marks, and the slope\n",
@@ -640,9 +646,9 @@
640
  "dials. One step is one dial turn.\n",
641
  "\n",
642
  "**A thorn bush is a step that made things worse.** Momo tried a direction and the mistake\n",
643
- "went up. He steps back, marks the spot with a red X, and corrects, say to the left. That\n",
644
- "correction is the gradient doing its job: after a bad step the slope under his feet points\n",
645
- "back the other way.\n",
646
  "\n",
647
  "**What the gradient adds.** A real monkey learns a thorn bush is there by walking into it.\n",
648
  "The gradient is better than that. It is the slope under the feet, felt *before* stepping.\n",
@@ -656,8 +662,9 @@
656
  "- The reading was noisy. Each step uses one batch of stories, so the slope is an estimate.\n",
657
  "\n",
658
  "**The marks on the map are real, in two forms.**\n",
659
- "- *The dials themselves.* Every step is written into the dials and nothing is forgotten.\n",
660
- " Momo does not get a map; after training he *is* the map.\n",
 
661
  "- *The optimizer's memory.* The dial-turning rule we use, **AdamW**, keeps a running average\n",
662
  " of recent slopes. That is Momo remembering \"the last ten readings all said left, so one odd\n",
663
  " reading saying right is probably a bump; keep going left\". One bush does not fool him.\n",
@@ -672,7 +679,7 @@
672
  {
673
  "cell_type": "code",
674
  "execution_count": null,
675
- "id": "f4cdba75",
676
  "metadata": {},
677
  "outputs": [],
678
  "source": [
@@ -782,7 +789,7 @@
782
  },
783
  {
784
  "cell_type": "markdown",
785
- "id": "0fc03ef8",
786
  "metadata": {},
787
  "source": [
788
  "### How does Momo feel the slope without walking? The blame game\n",
@@ -805,14 +812,17 @@
805
  "numbers are the gradient, found for all dials in one backward trip.\n",
806
  "\n",
807
  "Grown-up words: the tape is **autograd**, reading it backwards is **backpropagation**, and\n",
808
- "\"multiply by how hard I push\" at each step is the **chain rule**. Press each stage below. The\n",
 
 
 
809
  "slow-way check lets you see that the backward trip tells the truth."
810
  ]
811
  },
812
  {
813
  "cell_type": "code",
814
  "execution_count": null,
815
- "id": "6c9e4319",
816
  "metadata": {},
817
  "outputs": [],
818
  "source": [
@@ -913,7 +923,7 @@
913
  {
914
  "cell_type": "code",
915
  "execution_count": null,
916
- "id": "ec8003d8",
917
  "metadata": {},
918
  "outputs": [],
919
  "source": [
@@ -931,7 +941,7 @@
931
  },
932
  {
933
  "cell_type": "markdown",
934
- "id": "d1f811c6",
935
  "metadata": {},
936
  "source": [
937
  "## 2. Data: Ella's bedtime stories (TinyStories)\n",
@@ -947,7 +957,7 @@
947
  {
948
  "cell_type": "code",
949
  "execution_count": null,
950
- "id": "b3b653c1",
951
  "metadata": {},
952
  "outputs": [],
953
  "source": [
@@ -965,7 +975,125 @@
965
  },
966
  {
967
  "cell_type": "markdown",
968
- "id": "080dcf9d",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
969
  "metadata": {},
970
  "source": [
971
  "## 3. Momo's first trick: the bigram\n",
@@ -986,7 +1114,7 @@
986
  {
987
  "cell_type": "code",
988
  "execution_count": null,
989
- "id": "0309bf44",
990
  "metadata": {},
991
  "outputs": [],
992
  "source": [
@@ -1017,7 +1145,7 @@
1017
  {
1018
  "cell_type": "code",
1019
  "execution_count": null,
1020
- "id": "aa0fa0fa",
1021
  "metadata": {},
1022
  "outputs": [],
1023
  "source": [
@@ -1037,7 +1165,7 @@
1037
  {
1038
  "cell_type": "code",
1039
  "execution_count": null,
1040
- "id": "0be6fc04",
1041
  "metadata": {},
1042
  "outputs": [],
1043
  "source": [
@@ -1086,7 +1214,7 @@
1086
  },
1087
  {
1088
  "cell_type": "markdown",
1089
- "id": "e7ebebbc",
1090
  "metadata": {},
1091
  "source": [
1092
  "Momo learned *something* (the loss dropped, and he produces word-ish shapes with spaces), but\n",
@@ -1096,7 +1224,7 @@
1096
  },
1097
  {
1098
  "cell_type": "markdown",
1099
- "id": "1c63ff73",
1100
  "metadata": {},
1101
  "source": [
1102
  "## 4. A real tokenizer: how Momo decides where to bite\n",
@@ -1121,7 +1249,7 @@
1121
  {
1122
  "cell_type": "code",
1123
  "execution_count": null,
1124
- "id": "609916e1",
1125
  "metadata": {},
1126
  "outputs": [],
1127
  "source": [
@@ -1151,7 +1279,7 @@
1151
  {
1152
  "cell_type": "code",
1153
  "execution_count": null,
1154
- "id": "4ca0837a",
1155
  "metadata": {},
1156
  "outputs": [],
1157
  "source": [
@@ -1177,7 +1305,7 @@
1177
  {
1178
  "cell_type": "code",
1179
  "execution_count": null,
1180
- "id": "d939e9d0",
1181
  "metadata": {},
1182
  "outputs": [],
1183
  "source": [
@@ -1191,7 +1319,7 @@
1191
  },
1192
  {
1193
  "cell_type": "markdown",
1194
- "id": "537003ab",
1195
  "metadata": {},
1196
  "source": [
1197
  "## 5. Attention, by hand: the story circle in numbers\n",
@@ -1213,7 +1341,7 @@
1213
  {
1214
  "cell_type": "code",
1215
  "execution_count": null,
1216
- "id": "dcca4697",
1217
  "metadata": {},
1218
  "outputs": [],
1219
  "source": [
@@ -1237,7 +1365,7 @@
1237
  },
1238
  {
1239
  "cell_type": "markdown",
1240
- "id": "3d14ba96",
1241
  "metadata": {},
1242
  "source": [
1243
  "### Ella's shelf (the KV cache), in twelve lines\n",
@@ -1251,7 +1379,7 @@
1251
  {
1252
  "cell_type": "code",
1253
  "execution_count": null,
1254
- "id": "f3cef3da",
1255
  "metadata": {},
1256
  "outputs": [],
1257
  "source": [
@@ -1281,7 +1409,7 @@
1281
  },
1282
  {
1283
  "cell_type": "markdown",
1284
- "id": "e614ea56",
1285
  "metadata": {},
1286
  "source": [
1287
  "## 6. A tiny GPT: Momo's whole head\n",
@@ -1298,7 +1426,8 @@
1298
  "3. **Blocks**, repeated `n_layer` times (6 branches of the tree). Each block has:\n",
1299
  " - **multi-head attention**: the story circle, run 4 times at once with different cards;\n",
1300
  " - a **feed-forward network**: after listening to everyone, each token goes off to its own\n",
1301
- " branch and thinks alone (a small two-layer network, where most facts end up stored);\n",
 
1302
  " - **LayerNorm** (Ella keeping the numbers at a steady volume) and **residual connections**\n",
1303
  " (each block *adds* its thoughts to what came in instead of replacing it, so nothing is\n",
1304
  " lost on the way up the tree).\n",
@@ -1313,7 +1442,7 @@
1313
  {
1314
  "cell_type": "code",
1315
  "execution_count": null,
1316
- "id": "d35b8f49",
1317
  "metadata": {},
1318
  "outputs": [],
1319
  "source": [
@@ -1357,7 +1486,7 @@
1357
  {
1358
  "cell_type": "code",
1359
  "execution_count": null,
1360
- "id": "1fbd25da",
1361
  "metadata": {},
1362
  "outputs": [],
1363
  "source": [
@@ -1468,7 +1597,7 @@
1468
  },
1469
  {
1470
  "cell_type": "markdown",
1471
- "id": "6bad119f",
1472
  "metadata": {},
1473
  "source": [
1474
  "## 7. Training: Ella's bedtime lessons\n",
@@ -1497,7 +1626,7 @@
1497
  {
1498
  "cell_type": "code",
1499
  "execution_count": null,
1500
- "id": "5e1db782",
1501
  "metadata": {},
1502
  "outputs": [],
1503
  "source": [
@@ -1539,7 +1668,7 @@
1539
  {
1540
  "cell_type": "code",
1541
  "execution_count": null,
1542
- "id": "133e9333",
1543
  "metadata": {},
1544
  "outputs": [],
1545
  "source": [
@@ -1606,7 +1735,7 @@
1606
  },
1607
  {
1608
  "cell_type": "markdown",
1609
- "id": "a9476de0",
1610
  "metadata": {},
1611
  "source": [
1612
  "**How to read the numbers.** The loss is Ella's average \"how surprised were you\" per token.\n",
@@ -1617,7 +1746,7 @@
1617
  },
1618
  {
1619
  "cell_type": "markdown",
1620
- "id": "2e496a79",
1621
  "metadata": {},
1622
  "source": [
1623
  "## 8. Momo tells a story: the use case\n",
@@ -1635,13 +1764,14 @@
1635
  {
1636
  "cell_type": "code",
1637
  "execution_count": null,
1638
- "id": "f2cc11bf",
1639
  "metadata": {},
1640
  "outputs": [],
1641
  "source": [
1642
  "def tell_story(prompt, max_new_tokens=200, temperature=0.8):\n",
1643
  " model.eval()\n",
1644
- " idx = torch.tensor([tokenizer(prompt)[\"input_ids\"]], device=device)\n",
 
1645
  " out = model.generate(idx, max_new_tokens, temperature=temperature)\n",
1646
  " return tokenizer.decode(out[0].tolist(), skip_special_tokens=True)\n",
1647
  "\n",
@@ -1652,7 +1782,7 @@
1652
  },
1653
  {
1654
  "cell_type": "markdown",
1655
- "id": "ee01a9ea",
1656
  "metadata": {},
1657
  "source": [
1658
  "## 9. Put Momo's book in the library: the Hugging Face Hub\n",
@@ -1671,7 +1801,7 @@
1671
  {
1672
  "cell_type": "code",
1673
  "execution_count": null,
1674
- "id": "e392a0ac",
1675
  "metadata": {},
1676
  "outputs": [],
1677
  "source": [
@@ -1712,7 +1842,7 @@
1712
  {
1713
  "cell_type": "code",
1714
  "execution_count": null,
1715
- "id": "c5250a84",
1716
  "metadata": {},
1717
  "outputs": [],
1718
  "source": [
@@ -1733,7 +1863,7 @@
1733
  },
1734
  {
1735
  "cell_type": "markdown",
1736
- "id": "6db272e7",
1737
  "metadata": {},
1738
  "source": [
1739
  "## Loading it back later\n",
@@ -1744,7 +1874,7 @@
1744
  {
1745
  "cell_type": "code",
1746
  "execution_count": null,
1747
- "id": "0970216e",
1748
  "metadata": {},
1749
  "outputs": [],
1750
  "source": [
@@ -1765,7 +1895,7 @@
1765
  },
1766
  {
1767
  "cell_type": "markdown",
1768
- "id": "334dcc17",
1769
  "metadata": {},
1770
  "source": [
1771
  "## What we built, in one paragraph\n",
 
2
  "cells": [
3
  {
4
  "cell_type": "markdown",
5
+ "id": "b2fe09d4",
6
  "metadata": {},
7
  "source": [
8
  "# Tiny Storyteller: building a language model from scratch\n",
 
44
  },
45
  {
46
  "cell_type": "markdown",
47
+ "id": "c4f48f79",
48
  "metadata": {},
49
  "source": [
50
  "# Before any code: Momo, Ella, and what we are about to build\n",
 
67
  "In grown-up words: Momo is the **model**. His dials are the **weights**, also called\n",
68
  "**parameters**: the numbers that get adjusted during learning. Ella's stories are the\n",
69
  "**training data**. Her \"how wrong were you\" is the **loss**. Her shelf is the **KV cache**.\n",
70
+ "Ella plays two roles on purpose: the teacher while Momo learns (training), and the memory\n",
71
+ "while Momo writes (generation). Each of these gets its own section below.\n",
72
  "\n",
73
  "## 1. What is PyTorch?\n",
74
  "\n",
 
83
  " one called a T4.\n",
84
  "- **A tape recorder**, called **autograd** (automatic gradients). While Momo works it writes\n",
85
  " down every step. Afterwards it reads the tape backwards and tells Momo which way to turn\n",
86
+ " every dial, and by how much. Ordinary programs do not do this, and it is the reason modern AI\n",
87
+ " is practical at all. Part 1 has a game that shows exactly how the tape is read.\n",
88
  "\n",
89
  "PyTorch was built at Meta's AI lab and is behind most famous models (the GPT family, Llama,\n",
90
  "Stable Diffusion, Whisper). **Hugging Face**, where we publish at the end, is the public\n",
 
139
  "say, 92 percent. One token is picked.\n",
140
  "\n",
141
  "**Step 5, repeat.** \"Paris\" is added to the words so far and the whole journey runs again for\n",
142
+ "the next token, until Momo picks a special \"the story is over\" token or reaches the length limit. You see words appear one by one\n",
143
  "on screen because that is literally how they are made.\n",
144
  "\n",
145
  "## 5. How attention looks things up: the story circle\n",
 
151
  "- a **key** card: \"here is what I am\" (\"France\" says: I am a country),\n",
152
  "- a **value** card: \"here is what I will tell you if you pick me\" (France's actual meaning).\n",
153
  "\n",
154
+ "Every animal holds up its query card and compares it with the key cards of the animals\n",
155
+ "before it (during training all of them do this at the same time; when writing, only the\n",
156
+ "newest one needs to). A good\n",
157
  "match scores high, a poor match scores low. The scores are squashed into percentages\n",
158
  "(softmax again) and the animal collects a blend of everyone's value cards, weighted by those\n",
159
  "percentages. \"capital\" might take 70 percent from \"France\", 20 percent from \"of\", and crumbs\n",
 
183
  "token keeps its cards there. A model's **context window** (how much text it can hold at\n",
184
  "once) is partly how big the shelf is allowed to grow.\n",
185
  "\n",
186
+ "Part 5 shows the shelf in twelve lines of code. Two honest notes: the shelf is emptied at the\n",
187
+ "start of every new story (it is a memory *within* one piece of writing, not between stories),\n",
188
+ "and Momo's own `generate` in Part 6 does not use it, to keep the code short. It redoes the\n",
189
+ "whole journey for every word, which is fine for 200-word stories.\n",
190
  "\n",
191
  "## 7. The strange names, decoded\n",
192
  "\n",
 
239
  },
240
  {
241
  "cell_type": "markdown",
242
+ "id": "4d7312e3",
243
  "metadata": {},
244
  "source": [
245
  "## Live flow diagram\n",
 
254
  {
255
  "cell_type": "code",
256
  "execution_count": null,
257
+ "id": "cdae01ca",
258
  "metadata": {},
259
  "outputs": [],
260
  "source": [
 
379
  },
380
  {
381
  "cell_type": "markdown",
382
+ "id": "94499493",
383
  "metadata": {},
384
  "source": [
385
  "## 0. Setup\n",
 
389
  {
390
  "cell_type": "code",
391
  "execution_count": null,
392
+ "id": "0fe52b75",
393
  "metadata": {},
394
  "outputs": [],
395
  "source": [
 
399
  {
400
  "cell_type": "code",
401
  "execution_count": null,
402
+ "id": "cf74d97b",
403
  "metadata": {},
404
  "outputs": [],
405
  "source": [
 
416
  },
417
  {
418
  "cell_type": "markdown",
419
+ "id": "30cd04b6",
420
  "metadata": {},
421
  "source": [
422
  "## 1. Tensors and gradients: the two building blocks\n",
 
435
  {
436
  "cell_type": "code",
437
  "execution_count": null,
438
+ "id": "7fd75d97",
439
  "metadata": {},
440
  "outputs": [],
441
  "source": [
 
478
  },
479
  {
480
  "cell_type": "markdown",
481
+ "id": "6d9343cc",
482
  "metadata": {},
483
  "source": [
484
  "### How matrix multiplication actually happens\n",
 
500
  {
501
  "cell_type": "code",
502
  "execution_count": null,
503
+ "id": "88849be7",
504
  "metadata": {},
505
  "outputs": [],
506
  "source": [
 
557
  {
558
  "cell_type": "code",
559
  "execution_count": null,
560
+ "id": "c1522ad3",
561
  "metadata": {},
562
  "outputs": [],
563
  "source": [
 
570
  },
571
  {
572
  "cell_type": "markdown",
573
+ "id": "59188275",
574
  "metadata": {},
575
  "source": [
576
  "### The gradient: which way to turn each dial\n",
 
593
  {
594
  "cell_type": "code",
595
  "execution_count": null,
596
+ "id": "4e4aef04",
597
  "metadata": {},
598
  "outputs": [],
599
  "source": [
 
633
  },
634
  {
635
  "cell_type": "markdown",
636
+ "id": "b4ec1642",
637
  "metadata": {},
638
  "source": [
639
  "### Momo in the foggy jungle: thorn bushes, marks, and the slope\n",
 
646
  "dials. One step is one dial turn.\n",
647
  "\n",
648
  "**A thorn bush is a step that made things worse.** Momo tried a direction and the mistake\n",
649
+ "went up. In the widget he steps back and marks the spot with a red X. Real training is blunter: it\n",
650
+ "never steps back. Momo stays where he landed, reads the slope again, and the slope now points\n",
651
+ "back downhill. The correction comes from the next reading, not from undoing the step.\n",
652
  "\n",
653
  "**What the gradient adds.** A real monkey learns a thorn bush is there by walking into it.\n",
654
  "The gradient is better than that. It is the slope under the feet, felt *before* stepping.\n",
 
662
  "- The reading was noisy. Each step uses one batch of stories, so the slope is an estimate.\n",
663
  "\n",
664
  "**The marks on the map are real, in two forms.**\n",
665
+ "- *The dials themselves.* Every step is written into the dials. There is no separate map;\n",
666
+ " after training Momo *is* the map. (Later lessons can partly overwrite earlier ones, which\n",
667
+ " is why the stories are shuffled and why the last steps are tiny.)\n",
668
  "- *The optimizer's memory.* The dial-turning rule we use, **AdamW**, keeps a running average\n",
669
  " of recent slopes. That is Momo remembering \"the last ten readings all said left, so one odd\n",
670
  " reading saying right is probably a bump; keep going left\". One bush does not fool him.\n",
 
679
  {
680
  "cell_type": "code",
681
  "execution_count": null,
682
+ "id": "73a8941e",
683
  "metadata": {},
684
  "outputs": [],
685
  "source": [
 
789
  },
790
  {
791
  "cell_type": "markdown",
792
+ "id": "a6a84861",
793
  "metadata": {},
794
  "source": [
795
  "### How does Momo feel the slope without walking? The blame game\n",
 
812
  "numbers are the gradient, found for all dials in one backward trip.\n",
813
  "\n",
814
  "Grown-up words: the tape is **autograd**, reading it backwards is **backpropagation**, and\n",
815
+ "\"multiply by how hard I push\" at each step is the **chain rule**. One detail the game leaves\n",
816
+ "out: when one step feeds *two* later steps (our residual connections do this), the two blames\n",
817
+ "are added together. And the game's mistake is a squared gap; the real Momo uses cross-entropy.\n",
818
+ "Same game, different first step. Press each stage below. The\n",
819
  "slow-way check lets you see that the backward trip tells the truth."
820
  ]
821
  },
822
  {
823
  "cell_type": "code",
824
  "execution_count": null,
825
+ "id": "acb78f06",
826
  "metadata": {},
827
  "outputs": [],
828
  "source": [
 
923
  {
924
  "cell_type": "code",
925
  "execution_count": null,
926
+ "id": "39d72d64",
927
  "metadata": {},
928
  "outputs": [],
929
  "source": [
 
941
  },
942
  {
943
  "cell_type": "markdown",
944
+ "id": "24e1da8f",
945
  "metadata": {},
946
  "source": [
947
  "## 2. Data: Ella's bedtime stories (TinyStories)\n",
 
957
  {
958
  "cell_type": "code",
959
  "execution_count": null,
960
+ "id": "ebb5d3e6",
961
  "metadata": {},
962
  "outputs": [],
963
  "source": [
 
975
  },
976
  {
977
  "cell_type": "markdown",
978
+ "id": "b9bf532d",
979
+ "metadata": {},
980
+ "source": [
981
+ "### Ella's own stories about Momo\n",
982
+ "\n",
983
+ "TinyStories is full of Lily, Tom and their mums. If we want Momo and Ella to show up when the\n",
984
+ "model writes, the model has to *read* about them. So we add a few hundred short stories about\n",
985
+ "our two characters, built from sentence pools in the same simple style (every story has an\n",
986
+ "opening, Ella's introduction, a small problem, Ella helping, a resolution and an ending). We\n",
987
+ "repeat them three times so they are not drowned out by the 20,000 other stories. This is\n",
988
+ "exactly how a real model is taught a company's own documents: mix them into the training text."
989
+ ]
990
+ },
991
+ {
992
+ "cell_type": "code",
993
+ "execution_count": null,
994
+ "id": "40a20bc2",
995
+ "metadata": {},
996
+ "outputs": [],
997
+ "source": [
998
+ "# Momo and Ella stories, built from sentence pools. Same code as scripts/momo_stories.py in the repo.\n",
999
+ "import random\n",
1000
+ "\n",
1001
+ "PLACES = [\"by the river\", \"under the big mango tree\", \"in the green jungle\", \"at the waterfall\",\n",
1002
+ " \"on the sunny hill\", \"near the little pond\", \"in the tall grass\", \"by the old rock\"]\n",
1003
+ "THINGS = [\"a shiny red ball\", \"a yellow banana\", \"a big green leaf\", \"a round grey stone\",\n",
1004
+ " \"a blue feather\", \"a little drum\", \"a brown coconut\", \"a soft pink flower\",\n",
1005
+ " \"a long stick\", \"a red kite\"]\n",
1006
+ "FRIENDS = [\"Pip the parrot\", \"Tilly the turtle\", \"Bo the bear cub\", \"Lulu the little lion\"]\n",
1007
+ "FOODS = [\"bananas\", \"mangoes\", \"sweet berries\", \"coconuts\", \"crunchy leaves\"]\n",
1008
+ "\n",
1009
+ "OPENINGS = [\n",
1010
+ " \"Once upon a time, there was a little monkey named Momo.\",\n",
1011
+ " \"Momo was a little monkey who lived {place}.\",\n",
1012
+ " \"One day, Momo the monkey woke up very early.\",\n",
1013
+ " \"Momo was a small monkey with a big smile.\",\n",
1014
+ " \"In the jungle there lived a little monkey called Momo.\",\n",
1015
+ " \"Every morning, Momo the monkey jumped out of his tree.\",\n",
1016
+ "]\n",
1017
+ "ELLA_INTRO = [\n",
1018
+ " \"His best friend was Ella, a big grey elephant.\",\n",
1019
+ " \"Ella the elephant was his best friend. Ella never forgot anything.\",\n",
1020
+ " \"He loved his friend Ella. Ella was an elephant, and she remembered everything.\",\n",
1021
+ " \"Ella the elephant was big and kind and very wise.\",\n",
1022
+ " \"His friend Ella was an elephant with a long trunk and a good memory.\",\n",
1023
+ "]\n",
1024
+ "# Each scene: (problem, Ella helps, resolution). They always go together.\n",
1025
+ "SCENES = [\n",
1026
+ " (\"Momo wanted to play with {thing}, but he could not find it. He looked {place}. It was not there. He felt sad.\",\n",
1027
+ " \"Ella came slowly. \\\"Do not worry, Momo,\\\" she said. \\\"I remember. You left it {place2}.\\\"\",\n",
1028
+ " \"Momo ran and found {thing} right where Ella said. He hugged her trunk.\"),\n",
1029
+ " (\"Momo climbed very high to get {thing}. Then he looked down and felt scared. \\\"I cannot get down!\\\" he cried.\",\n",
1030
+ " \"Ella walked under the tree and lifted her trunk. \\\"I am here,\\\" she said. \\\"You are safe. Come down slowly.\\\"\",\n",
1031
+ " \"Momo climbed down step by step and jumped into Ella's arms.\"),\n",
1032
+ " (\"It started to rain. Momo got wet and cold. He hid {place} and shivered.\",\n",
1033
+ " \"Ella held a big leaf over Momo like an umbrella. \\\"Stay dry, my friend,\\\" she said.\",\n",
1034
+ " \"The rain stopped. The sun came out. Momo and Ella walked home together.\"),\n",
1035
+ " (\"Momo met {friend} {place}. {friend_short} had {thing} and did not want to share. Momo felt sad.\",\n",
1036
+ " \"Ella walked over and said, \\\"Let us all play together. Sharing makes everyone happy.\\\"\",\n",
1037
+ " \"Momo and {friend_short} became friends and played with {thing} all day.\"),\n",
1038
+ " (\"Momo tried to count his {food}. \\\"One, two, three...\\\" Then he forgot the next number.\",\n",
1039
+ " \"Ella said, \\\"After three comes four. I will count with you.\\\" They counted together.\",\n",
1040
+ " \"Momo counted all the way to ten. Ella was very proud.\"),\n",
1041
+ " (\"Momo had a bad dream. He woke up scared and ran to find Ella.\",\n",
1042
+ " \"Ella sat with Momo until he felt better. \\\"Being scared is okay,\\\" she said. \\\"I am right here.\\\"\",\n",
1043
+ " \"Momo fell asleep next to Ella and had happy dreams.\"),\n",
1044
+ " (\"Momo wanted to tell a story, but he did not know how to start. He sat down {place} and thought and thought.\",\n",
1045
+ " \"Ella said, \\\"Start with 'Once upon a time'. Then say what happens next. One word at a time.\\\"\",\n",
1046
+ " \"Momo told his first story. It was about {thing}. Ella clapped her big ears.\"),\n",
1047
+ " (\"Momo saw a big shadow {place}. He thought it was a monster. He hid behind {thing}.\",\n",
1048
+ " \"Ella laughed softly. \\\"That shadow is only me,\\\" she said. Momo peeked out and laughed too.\",\n",
1049
+ " \"They played shadow games until the sun went down.\"),\n",
1050
+ " (\"Momo was sad because he could not swim like {friend}. He sat {place} with his feet in the water.\",\n",
1051
+ " \"Ella said, \\\"Try again, little one. Every time you try, you learn a little more.\\\" She held him up with her trunk.\",\n",
1052
+ " \"Momo kicked and kicked. Soon he could swim all by himself.\"),\n",
1053
+ " (\"Momo and Ella went {place} to look for {food}. They looked and looked, but they found none.\",\n",
1054
+ " \"Ella thought for a moment. Elephants never forget. \\\"I know a secret place,\\\" she said.\",\n",
1055
+ " \"They found lots of {food} and ate them together under the stars.\"),\n",
1056
+ " (\"Momo broke {thing} that belonged to {friend}. He hid it and felt bad all day.\",\n",
1057
+ " \"Ella said, \\\"A true friend says sorry. Go and tell {friend_short}.\\\"\",\n",
1058
+ " \"Momo said sorry. {friend_short} smiled and said, \\\"We can fix it together.\\\"\"),\n",
1059
+ " (\"Momo wanted to be big like Ella. He stood on {thing} and stretched, but he was still small.\",\n",
1060
+ " \"Ella smiled. \\\"You are small, but you can climb and jump and I cannot,\\\" she said. \\\"We are different, and that is good.\\\"\",\n",
1061
+ " \"Momo climbed to the top of the tree and threw {food} down to Ella. They both laughed.\"),\n",
1062
+ "]\n",
1063
+ "ENDINGS = [\n",
1064
+ " \"The end.\",\n",
1065
+ " \"Momo was happy. Ella was happy. The end.\",\n",
1066
+ " \"And they were best friends forever. The end.\",\n",
1067
+ " \"\\\"Thank you, Ella,\\\" said Momo. \\\"You always remember.\\\" The end.\",\n",
1068
+ " \"That night, Momo dreamed about his friend Ella. The end.\",\n",
1069
+ "]\n",
1070
+ "\n",
1071
+ "\n",
1072
+ "def make_story(rng: random.Random) -> str:\n",
1073
+ " friend = rng.choice(FRIENDS)\n",
1074
+ " place, place2 = rng.sample(PLACES, 2)\n",
1075
+ " slots = dict(place=place, place2=place2, thing=rng.choice(THINGS), friend=friend,\n",
1076
+ " friend_short=friend.split(\" the \")[0], food=rng.choice(FOODS))\n",
1077
+ " problem, helps, resolution = rng.choice(SCENES)\n",
1078
+ " parts = [rng.choice(OPENINGS), rng.choice(ELLA_INTRO), problem, helps, resolution, rng.choice(ENDINGS)]\n",
1079
+ " return \" \".join(p.format(**slots) for p in parts)\n",
1080
+ "\n",
1081
+ "\n",
1082
+ "def momo_stories(n: int = 1000, seed: int = 0) -> list[str]:\n",
1083
+ " rng = random.Random(seed)\n",
1084
+ " return [make_story(rng) for _ in range(n)]\n",
1085
+ "\n",
1086
+ "momo = momo_stories(1000, seed=0)\n",
1087
+ "stories = stories + momo * 3 # 20,000 TinyStories + 3,000 Momo stories (1,000 unique)\n",
1088
+ "import random; random.Random(42).shuffle(stories)\n",
1089
+ "print(f\"{len(stories):,} stories in total, {len(momo):,} unique Momo stories\")\n",
1090
+ "print(\"-\" * 60)\n",
1091
+ "print(momo[0])"
1092
+ ]
1093
+ },
1094
+ {
1095
+ "cell_type": "markdown",
1096
+ "id": "1b3fc1b7",
1097
  "metadata": {},
1098
  "source": [
1099
  "## 3. Momo's first trick: the bigram\n",
 
1114
  {
1115
  "cell_type": "code",
1116
  "execution_count": null,
1117
+ "id": "d7c45f72",
1118
  "metadata": {},
1119
  "outputs": [],
1120
  "source": [
 
1145
  {
1146
  "cell_type": "code",
1147
  "execution_count": null,
1148
+ "id": "3a50e68a",
1149
  "metadata": {},
1150
  "outputs": [],
1151
  "source": [
 
1165
  {
1166
  "cell_type": "code",
1167
  "execution_count": null,
1168
+ "id": "942d14ad",
1169
  "metadata": {},
1170
  "outputs": [],
1171
  "source": [
 
1214
  },
1215
  {
1216
  "cell_type": "markdown",
1217
+ "id": "55fb61d0",
1218
  "metadata": {},
1219
  "source": [
1220
  "Momo learned *something* (the loss dropped, and he produces word-ish shapes with spaces), but\n",
 
1224
  },
1225
  {
1226
  "cell_type": "markdown",
1227
+ "id": "b287c96b",
1228
  "metadata": {},
1229
  "source": [
1230
  "## 4. A real tokenizer: how Momo decides where to bite\n",
 
1249
  {
1250
  "cell_type": "code",
1251
  "execution_count": null,
1252
+ "id": "6cc8a788",
1253
  "metadata": {},
1254
  "outputs": [],
1255
  "source": [
 
1279
  {
1280
  "cell_type": "code",
1281
  "execution_count": null,
1282
+ "id": "9edae39b",
1283
  "metadata": {},
1284
  "outputs": [],
1285
  "source": [
 
1305
  {
1306
  "cell_type": "code",
1307
  "execution_count": null,
1308
+ "id": "07134162",
1309
  "metadata": {},
1310
  "outputs": [],
1311
  "source": [
 
1319
  },
1320
  {
1321
  "cell_type": "markdown",
1322
+ "id": "435e5e35",
1323
  "metadata": {},
1324
  "source": [
1325
  "## 5. Attention, by hand: the story circle in numbers\n",
 
1341
  {
1342
  "cell_type": "code",
1343
  "execution_count": null,
1344
+ "id": "98f928a1",
1345
  "metadata": {},
1346
  "outputs": [],
1347
  "source": [
 
1365
  },
1366
  {
1367
  "cell_type": "markdown",
1368
+ "id": "dd9059e3",
1369
  "metadata": {},
1370
  "source": [
1371
  "### Ella's shelf (the KV cache), in twelve lines\n",
 
1379
  {
1380
  "cell_type": "code",
1381
  "execution_count": null,
1382
+ "id": "807c906b",
1383
  "metadata": {},
1384
  "outputs": [],
1385
  "source": [
 
1409
  },
1410
  {
1411
  "cell_type": "markdown",
1412
+ "id": "e7557457",
1413
  "metadata": {},
1414
  "source": [
1415
  "## 6. A tiny GPT: Momo's whole head\n",
 
1426
  "3. **Blocks**, repeated `n_layer` times (6 branches of the tree). Each block has:\n",
1427
  " - **multi-head attention**: the story circle, run 4 times at once with different cards;\n",
1428
  " - a **feed-forward network**: after listening to everyone, each token goes off to its own\n",
1429
+ " branch and thinks alone (a small two-layer network; research suggests many facts end up\n",
1430
+ " stored here);\n",
1431
  " - **LayerNorm** (Ella keeping the numbers at a steady volume) and **residual connections**\n",
1432
  " (each block *adds* its thoughts to what came in instead of replacing it, so nothing is\n",
1433
  " lost on the way up the tree).\n",
 
1442
  {
1443
  "cell_type": "code",
1444
  "execution_count": null,
1445
+ "id": "40b8d767",
1446
  "metadata": {},
1447
  "outputs": [],
1448
  "source": [
 
1486
  {
1487
  "cell_type": "code",
1488
  "execution_count": null,
1489
+ "id": "d79f1d74",
1490
  "metadata": {},
1491
  "outputs": [],
1492
  "source": [
 
1597
  },
1598
  {
1599
  "cell_type": "markdown",
1600
+ "id": "4e8831e7",
1601
  "metadata": {},
1602
  "source": [
1603
  "## 7. Training: Ella's bedtime lessons\n",
 
1626
  {
1627
  "cell_type": "code",
1628
  "execution_count": null,
1629
+ "id": "882b3bdb",
1630
  "metadata": {},
1631
  "outputs": [],
1632
  "source": [
 
1668
  {
1669
  "cell_type": "code",
1670
  "execution_count": null,
1671
+ "id": "481c902a",
1672
  "metadata": {},
1673
  "outputs": [],
1674
  "source": [
 
1735
  },
1736
  {
1737
  "cell_type": "markdown",
1738
+ "id": "944ca70e",
1739
  "metadata": {},
1740
  "source": [
1741
  "**How to read the numbers.** The loss is Ella's average \"how surprised were you\" per token.\n",
 
1746
  },
1747
  {
1748
  "cell_type": "markdown",
1749
+ "id": "387f64a3",
1750
  "metadata": {},
1751
  "source": [
1752
  "## 8. Momo tells a story: the use case\n",
 
1764
  {
1765
  "cell_type": "code",
1766
  "execution_count": null,
1767
+ "id": "b545d4c1",
1768
  "metadata": {},
1769
  "outputs": [],
1770
  "source": [
1771
  "def tell_story(prompt, max_new_tokens=200, temperature=0.8):\n",
1772
  " model.eval()\n",
1773
+ " ids = tokenizer(prompt)[\"input_ids\"] or [tokenizer.eos_token_id] # empty prompt: start from the story marker\n",
1774
+ " idx = torch.tensor([ids], device=device)\n",
1775
  " out = model.generate(idx, max_new_tokens, temperature=temperature)\n",
1776
  " return tokenizer.decode(out[0].tolist(), skip_special_tokens=True)\n",
1777
  "\n",
 
1782
  },
1783
  {
1784
  "cell_type": "markdown",
1785
+ "id": "455a433e",
1786
  "metadata": {},
1787
  "source": [
1788
  "## 9. Put Momo's book in the library: the Hugging Face Hub\n",
 
1801
  {
1802
  "cell_type": "code",
1803
  "execution_count": null,
1804
+ "id": "00878bab",
1805
  "metadata": {},
1806
  "outputs": [],
1807
  "source": [
 
1842
  {
1843
  "cell_type": "code",
1844
  "execution_count": null,
1845
+ "id": "45371319",
1846
  "metadata": {},
1847
  "outputs": [],
1848
  "source": [
 
1863
  },
1864
  {
1865
  "cell_type": "markdown",
1866
+ "id": "9c85c1d9",
1867
  "metadata": {},
1868
  "source": [
1869
  "## Loading it back later\n",
 
1874
  {
1875
  "cell_type": "code",
1876
  "execution_count": null,
1877
+ "id": "dd50896e",
1878
  "metadata": {},
1879
  "outputs": [],
1880
  "source": [
 
1895
  },
1896
  {
1897
  "cell_type": "markdown",
1898
+ "id": "c107a885",
1899
  "metadata": {},
1900
  "source": [
1901
  "## What we built, in one paragraph\n",