Skip to content

Commit 88a4184

Browse files
authored
Merge branch 'main' into ch05-qwen3
2 parents 4f87edf + 9df9e69 commit 88a4184

File tree

11 files changed

+214
-80
lines changed

11 files changed

+214
-80
lines changed

.github/workflows/check-links.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,18 @@ jobs:
2727
uv add pytest-check-links
2828
2929
- name: Check links
30+
env:
31+
CHECK_LINKS_TIMEOUT: "10"
3032
run: |
3133
source .venv/bin/activate
3234
pytest --check-links ./ \
3335
--check-links-ignore "https://platform.openai.com/*" \
3436
--check-links-ignore "https://openai.com/*" \
3537
--check-links-ignore "https://arena.lmsys.org" \
38+
--check-links-ignore "https?://localhost(:\\d+)?/.*" \
39+
--check-links-ignore "https?://127[.]0[.]0[.]1(:\\d+)?/.*" \
40+
--check-links-ignore "https://mng\\.bz/.*" \
41+
--check-links-ignore "https://github\\.com/.*" \
3642
--check-links-ignore "https://unsloth.ai/blog/gradient" \
3743
--check-links-ignore "https://www.reddit.com/r/*" \
3844
--check-links-ignore "https://code.visualstudio.com/*" \

appendix-A/01_main-chapter-code/code-part1.ipynb

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
"name": "stdout",
4747
"output_type": "stream",
4848
"text": [
49-
"2.4.0\n"
49+
"2.9.1\n"
5050
]
5151
}
5252
],
@@ -658,13 +658,13 @@
658658
"output_type": "stream",
659659
"text": [
660660
"Parameter containing:\n",
661-
"tensor([[ 0.1182, 0.0606, -0.1292, ..., -0.1126, 0.0735, -0.0597],\n",
662-
" [-0.0249, 0.0154, -0.0476, ..., -0.1001, -0.1288, 0.1295],\n",
663-
" [ 0.0641, 0.0018, -0.0367, ..., -0.0990, -0.0424, -0.0043],\n",
661+
"tensor([[ 0.0979, 0.0412, 0.1005, ..., -0.0544, -0.0804, 0.0842],\n",
662+
" [-0.0115, 0.0382, -0.0261, ..., 0.0573, 0.1094, 0.1364],\n",
663+
" [ 0.0162, -0.0050, 0.0752, ..., 0.1298, 0.1250, -0.0117],\n",
664664
" ...,\n",
665-
" [ 0.0618, 0.0867, 0.1361, ..., -0.0254, 0.0399, 0.1006],\n",
666-
" [ 0.0842, -0.0512, -0.0960, ..., -0.1091, 0.1242, -0.0428],\n",
667-
" [ 0.0518, -0.1390, -0.0923, ..., -0.0954, -0.0668, -0.0037]],\n",
665+
" [-0.0312, 0.1319, -0.0954, ..., -0.1066, -0.0970, -0.0373],\n",
666+
" [ 0.0563, -0.1373, -0.1226, ..., 0.0154, -0.0969, 0.0113],\n",
667+
" [-0.0872, -0.0098, 0.0322, ..., -0.0108, 0.1091, -0.1043]],\n",
668668
" requires_grad=True)\n"
669669
]
670670
}
@@ -1002,12 +1002,12 @@
10021002
"name": "stdout",
10031003
"output_type": "stream",
10041004
"text": [
1005-
"Epoch: 001/003 | Batch 000/002 | Train/Val Loss: 0.75\n",
1006-
"Epoch: 001/003 | Batch 001/002 | Train/Val Loss: 0.65\n",
1007-
"Epoch: 002/003 | Batch 000/002 | Train/Val Loss: 0.44\n",
1008-
"Epoch: 002/003 | Batch 001/002 | Train/Val Loss: 0.13\n",
1009-
"Epoch: 003/003 | Batch 000/002 | Train/Val Loss: 0.03\n",
1010-
"Epoch: 003/003 | Batch 001/002 | Train/Val Loss: 0.00\n"
1005+
"Epoch: 001/003 | Batch 001/002 | Train/Val Loss: 0.75\n",
1006+
"Epoch: 001/003 | Batch 002/002 | Train/Val Loss: 0.65\n",
1007+
"Epoch: 002/003 | Batch 001/002 | Train/Val Loss: 0.44\n",
1008+
"Epoch: 002/003 | Batch 002/002 | Train/Val Loss: 0.13\n",
1009+
"Epoch: 003/003 | Batch 001/002 | Train/Val Loss: 0.03\n",
1010+
"Epoch: 003/003 | Batch 002/002 | Train/Val Loss: 0.00\n"
10111011
]
10121012
}
10131013
],
@@ -1036,7 +1036,7 @@
10361036
" \n",
10371037
" ### LOGGING\n",
10381038
" print(f\"Epoch: {epoch+1:03d}/{num_epochs:03d}\"\n",
1039-
" f\" | Batch {batch_idx:03d}/{len(train_loader):03d}\"\n",
1039+
" f\" | Batch {batch_idx+1:03d}/{len(train_loader):03d}\"\n",
10401040
" f\" | Train/Val Loss: {loss:.2f}\")\n",
10411041
"\n",
10421042
" model.eval()\n",
@@ -1080,11 +1080,11 @@
10801080
"name": "stdout",
10811081
"output_type": "stream",
10821082
"text": [
1083-
"tensor([[ 0.9991, 0.0009],\n",
1084-
" [ 0.9982, 0.0018],\n",
1085-
" [ 0.9949, 0.0051],\n",
1086-
" [ 0.0491, 0.9509],\n",
1087-
" [ 0.0307, 0.9693]])\n",
1083+
"tensor([[0.9991, 0.0009],\n",
1084+
" [0.9982, 0.0018],\n",
1085+
" [0.9949, 0.0051],\n",
1086+
" [0.0491, 0.9509],\n",
1087+
" [0.0307, 0.9693]])\n",
10881088
"tensor([0, 0, 0, 1, 1])\n"
10891089
]
10901090
}
@@ -1340,7 +1340,7 @@
13401340
"name": "python",
13411341
"nbconvert_exporter": "python",
13421342
"pygments_lexer": "ipython3",
1343-
"version": "3.11.4"
1343+
"version": "3.11.11"
13441344
}
13451345
},
13461346
"nbformat": 4,

appendix-A/01_main-chapter-code/code-part2.ipynb

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@
301301
},
302302
{
303303
"cell_type": "code",
304-
"execution_count": 10,
304+
"execution_count": null,
305305
"metadata": {
306306
"colab": {
307307
"base_uri": "https://localhost:8080/"
@@ -314,12 +314,12 @@
314314
"name": "stdout",
315315
"output_type": "stream",
316316
"text": [
317-
"Epoch: 001/003 | Batch 000/002 | Train/Val Loss: 0.75\n",
318-
"Epoch: 001/003 | Batch 001/002 | Train/Val Loss: 0.65\n",
319-
"Epoch: 002/003 | Batch 000/002 | Train/Val Loss: 0.44\n",
320-
"Epoch: 002/003 | Batch 001/002 | Train/Val Loss: 0.13\n",
321-
"Epoch: 003/003 | Batch 000/002 | Train/Val Loss: 0.03\n",
322-
"Epoch: 003/003 | Batch 001/002 | Train/Val Loss: 0.00\n"
317+
"Epoch: 001/003 | Batch 001/002 | Train/Val Loss: 0.75\n",
318+
"Epoch: 001/003 | Batch 002/002 | Train/Val Loss: 0.65\n",
319+
"Epoch: 002/003 | Batch 001/002 | Train/Val Loss: 0.44\n",
320+
"Epoch: 002/003 | Batch 002/002 | Train/Val Loss: 0.13\n",
321+
"Epoch: 003/003 | Batch 001/002 | Train/Val Loss: 0.03\n",
322+
"Epoch: 003/003 | Batch 002/002 | Train/Val Loss: 0.00\n"
323323
]
324324
}
325325
],
@@ -355,7 +355,7 @@
355355
"\n",
356356
" ### LOGGING\n",
357357
" print(f\"Epoch: {epoch+1:03d}/{num_epochs:03d}\"\n",
358-
" f\" | Batch {batch_idx:03d}/{len(train_loader):03d}\"\n",
358+
" f\" | Batch {batch_idx+1:03d}/{len(train_loader):03d}\"\n",
359359
" f\" | Train/Val Loss: {loss:.2f}\")\n",
360360
"\n",
361361
" model.eval()\n",
@@ -493,7 +493,7 @@
493493
"name": "python",
494494
"nbconvert_exporter": "python",
495495
"pygments_lexer": "ipython3",
496-
"version": "3.10.16"
496+
"version": "3.11.11"
497497
}
498498
},
499499
"nbformat": 4,

ch02/05_bpe-from-scratch/bpe-from-scratch-simple.ipynb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
"- This is a standalone notebook implementing the popular byte pair encoding (BPE) tokenization algorithm, which is used in models like GPT-2 to GPT-4, Llama 3, etc., from scratch for educational purposes\n",
3737
"- For more details about the purpose of tokenization, please refer to [Chapter 2](https://github.com/rasbt/LLMs-from-scratch/blob/main/ch02/01_main-chapter-code/ch02.ipynb); this code here is bonus material explaining the BPE algorithm\n",
3838
"- The original BPE tokenizer that OpenAI implemented for training the original GPT models can be found [here](https://github.com/openai/gpt-2/blob/master/src/encoder.py)\n",
39-
"- The BPE algorithm was originally described in 1994: \"[A New Algorithm for Data Compression](http://www.pennelynn.com/Documents/CUJ/HTML/94HTML/19940045.HTM)\" by Philip Gage\n",
39+
"- The BPE algorithm was originally described in 1994: \"[A New Algorithm for Data Compression](https://github.com/tpn/pdfs/blob/master/A%20New%20Algorithm%20for%20Data%20Compression%20(1994).pdf)\" by Philip Gage\n",
4040
"- Most projects, including Llama 3, nowadays use OpenAI's open-source [tiktoken library](https://github.com/openai/tiktoken) due to its computational performance; it allows loading pretrained GPT-2 and GPT-4 tokenizers, for example (the Llama 3 models were trained using the GPT-4 tokenizer as well)\n",
4141
"- The difference between the implementations above and my implementation in this notebook, besides it being is that it also includes a function for training the tokenizer (for educational purposes)\n",
4242
"- There's also an implementation called [minBPE](https://github.com/karpathy/minbpe) with training support, which is maybe more performant (my implementation here is focused on educational purposes); in contrast to `minbpe` my implementation additionally allows loading the original OpenAI tokenizer vocabulary and merges"
@@ -253,7 +253,7 @@
253253
"id": "8c0d4420-a4c7-4813-916a-06f4f46bc3f0",
254254
"metadata": {},
255255
"source": [
256-
"- The BPE algorithm was originally described in 1994: \"[A New Algorithm for Data Compression](http://www.pennelynn.com/Documents/CUJ/HTML/94HTML/19940045.HTM)\" by Philip Gage\n",
256+
"- The BPE algorithm was originally described in 1994: \"[A New Algorithm for Data Compression](https://github.com/tpn/pdfs/blob/master/A%20New%20Algorithm%20for%20Data%20Compression%20(1994).pdf)\" by Philip Gage\n",
257257
"- Before we get to the actual code implementation, the form that is used for LLM tokenizers today can be summarized as follows:"
258258
]
259259
},

ch02/05_bpe-from-scratch/bpe-from-scratch.ipynb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
"- This is a standalone notebook implementing the popular byte pair encoding (BPE) tokenization algorithm, which is used in models like GPT-2 to GPT-4, Llama 3, etc., from scratch for educational purposes\n",
3737
"- For more details about the purpose of tokenization, please refer to [Chapter 2](https://github.com/rasbt/LLMs-from-scratch/blob/main/ch02/01_main-chapter-code/ch02.ipynb); this code here is bonus material explaining the BPE algorithm\n",
3838
"- The original BPE tokenizer that OpenAI implemented for training the original GPT models can be found [here](https://github.com/openai/gpt-2/blob/master/src/encoder.py)\n",
39-
"- The BPE algorithm was originally described in 1994: \"[A New Algorithm for Data Compression](http://www.pennelynn.com/Documents/CUJ/HTML/94HTML/19940045.HTM)\" by Philip Gage\n",
39+
"- The BPE algorithm was originally described in 1994: \"[A New Algorithm for Data Compression](https://github.com/tpn/pdfs/blob/master/A%20New%20Algorithm%20for%20Data%20Compression%20(1994).pdf)\" by Philip Gage\n",
4040
"- Most projects, including Llama 3, nowadays use OpenAI's open-source [tiktoken library](https://github.com/openai/tiktoken) due to its computational performance; it allows loading pretrained GPT-2 and GPT-4 tokenizers, for example (the Llama 3 models were trained using the GPT-4 tokenizer as well)\n",
4141
"- The difference between the implementations above and my implementation in this notebook, besides it being is that it also includes a function for training the tokenizer (for educational purposes)\n",
4242
"- There's also an implementation called [minBPE](https://github.com/karpathy/minbpe) with training support, which is maybe more performant (my implementation here is focused on educational purposes); in contrast to `minbpe` my implementation additionally allows loading the original OpenAI tokenizer vocabulary and BPE \"merges\" (additionally, Hugging Face tokenizers are also capable of training and loading various tokenizers; see [this GitHub discussion](https://github.com/rasbt/LLMs-from-scratch/discussions/485) by a reader who trained a BPE tokenizer on the Nepali language for more info)"
@@ -245,7 +245,7 @@
245245
"id": "8c0d4420-a4c7-4813-916a-06f4f46bc3f0",
246246
"metadata": {},
247247
"source": [
248-
"- The BPE algorithm was originally described in 1994: \"[A New Algorithm for Data Compression](http://www.pennelynn.com/Documents/CUJ/HTML/94HTML/19940045.HTM)\" by Philip Gage\n",
248+
"- The BPE algorithm was originally described in 1994: \"[A New Algorithm for Data Compression](https://github.com/tpn/pdfs/blob/master/A%20New%20Algorithm%20for%20Data%20Compression%20(1994).pdf)\" by Philip Gage\n",
249249
"- Before we get to the actual code implementation, the form that is used for LLM tokenizers today can be summarized as described in the following sections."
250250
]
251251
},

ch05/13_olmo3/standalone-olmo3-plus-kv-cache.ipynb

Lines changed: 55 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -206,25 +206,60 @@
206206
},
207207
"outputs": [],
208208
"source": [
209-
"def compute_rope_params(head_dim, theta_base=10_000, context_length=4096, attention_factor=1.0, rope_type=\"default\", rope_factor=1.0, rope_orig_max=8192, dtype=torch.float32):\n",
209+
"import math\n",
210+
"\n",
211+
"\n",
212+
"def compute_rope_params(head_dim, theta_base=10_000, context_length=4096, attention_factor=1.0, rope_type=\"default\", rope_factor=1.0, rope_orig_max=8192, beta_fast=32.0, beta_slow=1.0, dtype=torch.float32):\n",
210213
" assert head_dim % 2 == 0, \"Embedding dimension must be even\"\n",
211214
"\n",
212-
" # Compute the inverse frequencies\n",
213-
" inv_freq = 1.0 / (\n",
214-
" theta_base ** (\n",
215-
" torch.arange(0, head_dim, 2, dtype=dtype)[: head_dim // 2].float()\n",
216-
" / head_dim\n",
215+
" if rope_type == \"yarn\":\n",
216+
" # Compute YaRN-style frequency scaling (as per https://huggingface.co/papers/2309.00071)\n",
217+
"\n",
218+
" def find_correction_dim(num_rotations, dim, base, max_position_embeddings):\n",
219+
" \"\"\"Inverse dimension formula to find the dimension based on the number of rotations\"\"\"\n",
220+
" return (dim * math.log(max_position_embeddings / (num_rotations * 2 * math.pi))) / (2 * math.log(base))\n",
221+
"\n",
222+
" def find_correction_range(low_rot, high_rot, dim, base, max_position_embeddings):\n",
223+
" \"\"\"Find dimension range bounds based on rotations\"\"\"\n",
224+
" low = find_correction_dim(low_rot, dim, base, max_position_embeddings)\n",
225+
" high = find_correction_dim(high_rot, dim, base, max_position_embeddings)\n",
226+
" low = math.floor(low)\n",
227+
" high = math.ceil(high)\n",
228+
" return max(low, 0), min(high, dim - 1)\n",
229+
"\n",
230+
" def linear_ramp_factor(min_val, max_val, dim):\n",
231+
" if min_val == max_val:\n",
232+
" max_val += 0.001 # Prevent singularity\n",
233+
" linear_func = (torch.arange(dim, dtype=torch.float32) - min_val) / (max_val - min_val)\n",
234+
" ramp_func = torch.clamp(linear_func, 0, 1)\n",
235+
" return ramp_func\n",
236+
"\n",
237+
" # Base frequencies\n",
238+
" pos_freqs = theta_base ** (torch.arange(0, head_dim, 2, dtype=dtype) / head_dim)\n",
239+
" inv_freq_extrapolation = 1.0 / pos_freqs # No scaling (extrapolation)\n",
240+
" inv_freq_interpolation = 1.0 / (rope_factor * pos_freqs) # With scaling (interpolation)\n",
241+
"\n",
242+
" # Find the range where we blend between interpolation and extrapolation\n",
243+
" low, high = find_correction_range(beta_fast, beta_slow, head_dim, theta_base, rope_orig_max)\n",
244+
"\n",
245+
" # Get n-dimensional rotational scaling corrected for extrapolation\n",
246+
" inv_freq_extrapolation_factor = 1 - linear_ramp_factor(low, high, head_dim // 2).to(dtype=dtype)\n",
247+
" inv_freq = (\n",
248+
" inv_freq_interpolation * (1 - inv_freq_extrapolation_factor)\n",
249+
" + inv_freq_extrapolation * inv_freq_extrapolation_factor\n",
250+
" )\n",
251+
" else:\n",
252+
" # Default RoPE\n",
253+
" inv_freq = 1.0 / (\n",
254+
" theta_base ** (\n",
255+
" torch.arange(0, head_dim, 2, dtype=dtype)[: head_dim // 2].float()\n",
256+
" / head_dim\n",
257+
" )\n",
217258
" )\n",
218-
" )\n",
219259
"\n",
220260
" # Generate position indices\n",
221261
" positions = torch.arange(context_length, dtype=dtype)\n",
222262
"\n",
223-
" # Optional YaRN scaling\n",
224-
" if rope_type == \"yarn\":\n",
225-
" positions = positions / rope_factor\n",
226-
" positions = torch.clamp(positions, max=rope_orig_max - 1)\n",
227-
"\n",
228263
" # Compute the base angles (shape: [context_length, head_dim // 2])\n",
229264
" angles = positions.unsqueeze(1) * inv_freq.unsqueeze(0)\n",
230265
"\n",
@@ -642,6 +677,8 @@
642677
" \"rope_type\": \"yarn\",\n",
643678
" \"rope_factor\": 8.0,\n",
644679
" \"rope_orig_max\": 8_192,\n",
680+
" \"beta_fast\": 32.0,\n",
681+
" \"beta_slow\": 1.0,\n",
645682
" \"rms_norm_eps\": 1e-6,\n",
646683
" \"dtype\": torch.bfloat16,\n",
647684
" \"eos_token_id\": 100_257,\n",
@@ -727,6 +764,8 @@
727764
" \"rope_type\": \"yarn\",\n",
728765
" \"rope_factor\": 8.0,\n",
729766
" \"rope_orig_max\": 8_192,\n",
767+
" \"beta_fast\": 32.0,\n",
768+
" \"beta_slow\": 1.0,\n",
730769
" \"rms_norm_eps\": 1e-6,\n",
731770
" \"dtype\": torch.bfloat16,\n",
732771
" \"eos_token_id\": 100_257,\n",
@@ -810,9 +849,9 @@
810849
{
811850
"data": {
812851
"text/plain": [
813-
"tensor([[[ 0.3594, -0.6289, -0.2754, ..., 1.1016, 0.4219, 0.0381],\n",
814-
" [ 1.1719, 0.0283, 0.6055, ..., 0.4863, -0.1953, 0.2246],\n",
815-
" [ 0.4902, -0.0425, 0.6758, ..., 0.3730, -0.5781, -0.1670]]],\n",
852+
"tensor([[[ 0.3867, -0.6328, -0.2734, ..., 1.1484, 0.4258, 0.0400],\n",
853+
" [ 1.2734, 0.0040, 0.5000, ..., 0.5625, -0.2383, 0.1855],\n",
854+
" [ 0.5859, -0.0540, 0.7930, ..., 0.3262, -0.5430, -0.1494]]],\n",
816855
" dtype=torch.bfloat16, grad_fn=<UnsafeViewBackward0>)"
817856
]
818857
},
@@ -1202,8 +1241,7 @@
12021241
"name": "stdout",
12031242
"output_type": "stream",
12041243
"text": [
1205-
"Sure! Here’s a brief introduction to large language models: \n",
1206-
"Large models are advanced AI systems trained to process vast neural networks capable of understanding and generating text, learning from vast amounts of data, learning language, performing diverse tasks, assisting in many applications, and adapting various tasks.\n",
1244+
"Large language models are advanced AI systems trained on vast amounts of text to understand and generate human-like language. They can perform a wide range of tasks, from answering questions to writing essays or code. These models have transformed natural language processing and are now foundational in many modern AI applications.\n",
12071245
"\n",
12081246
"GPU memory used: 13.71 GB\n"
12091247
]

0 commit comments

Comments
 (0)