{ "cells": [ { "cell_type": "markdown", "id": "7d22be6a", "metadata": {}, "source": [ "# 06 - The Transformer block\n", "\n", "A GPT is just a stack of identical **Transformer blocks**, one on top of the next. You can picture each block as a short team meeting with two phases:\n", "\n", "1. **multi-head self-attention**, where everyone shares information (each token gathers context from the others),\n", "2. a **feed-forward network**, where everyone goes back to their desk and thinks it over alone.\n", "\n", "Two supports keep the meeting orderly: **residual connections** (keep the original notes and just add edits on top) and **LayerNorm** (keep everyone's numbers on a similar scale). And because attention on its own has no sense of word order, we first stamp each token with its **position**. We will build every piece in NumPy and run one full block's forward pass." ] }, { "cell_type": "code", "execution_count": 1, "id": "4dc377e4", "metadata": { "execution": { "iopub.execute_input": "2026-07-01T09:08:58.173507Z", "iopub.status.busy": "2026-07-01T09:08:58.173301Z", "iopub.status.idle": "2026-07-01T09:08:58.221299Z", "shell.execute_reply": "2026-07-01T09:08:58.220808Z" } }, "outputs": [], "source": [ "import numpy as np\n", "np.random.seed(1337)\n", "def softmax(x, axis=-1):\n", " x = x - x.max(axis=axis, keepdims=True); e = np.exp(x); return e / e.sum(axis=axis, keepdims=True)\n", "\n", "B, T, C = 4, 16, 64 # batch, time, embedding dim\n", "n_head = 4" ] }, { "cell_type": "markdown", "id": "079258f1", "metadata": {}, "source": [ "
Line by line: what each line does\n", "\n", "
" ] }, { "cell_type": "markdown", "id": "68225a11", "metadata": {}, "source": [ "## Positional encoding\n", "\n", "Attention is **order-blind**. It is just a weighted sum, so if you shuffled the tokens it would return the same outputs (shuffled the same way); it has no idea which token came first. But order carries meaning, since \"dog bites man\" and \"man bites dog\" are very different. So before anything else we stamp each token with its position, adding a position signature onto its embedding (the embedding being the list of numbers that represents the token).\n", "\n", "The classic method uses **sinusoids**, which are simply waves of different speeds. Think of a car's mileage counter: a fast-spinning ones wheel, a slower tens wheel, and a slower-still hundreds wheel. Read together, the mix of fast and slow wheels gives every position a unique fingerprint, and nearby positions get similar fingerprints. (A GPT actually learns its own table of position signatures instead of using fixed waves, but both achieve the same thing.)" ] }, { "cell_type": "code", "execution_count": 2, "id": "437e3be0", "metadata": { "execution": { "iopub.execute_input": "2026-07-01T09:08:58.222674Z", "iopub.status.busy": "2026-07-01T09:08:58.222582Z", "iopub.status.idle": "2026-07-01T09:08:58.399218Z", "shell.execute_reply": "2026-07-01T09:08:58.398783Z" } }, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "def positional_encoding(T, C):\n", " pos = np.arange(T)[:, None]\n", " i = np.arange(C)[None, :]\n", " angle = pos / np.power(10000, (2 * (i // 2)) / C)\n", " pe = np.where(i % 2 == 0, np.sin(angle), np.cos(angle))\n", " return pe # (T, C)\n", "\n", "pe = positional_encoding(T, C)\n", "import matplotlib.pyplot as plt\n", "plt.figure(figsize=(6,3)); plt.imshow(pe, aspect=\"auto\", cmap=\"RdBu\")\n", "plt.xlabel(\"embedding dim\"); plt.ylabel(\"position\"); plt.title(\"sinusoidal positional encoding\"); plt.colorbar(); plt.show()" ] }, { "cell_type": "markdown", "id": "09c1c89e", "metadata": {}, "source": [ "
Line by line: what each line does\n", "\n", "
" ] }, { "cell_type": "markdown", "id": "71edb611", "metadata": {}, "source": [ "## LayerNorm\n", "\n", "As signals pass through many layers, the numbers can drift, either ballooning very large or shrinking towards nothing, and training then falls apart. **LayerNorm** is the fix. For each token it takes that token's list of numbers and rescales it to have an average of 0 and a **standard deviation** of 1. (Standard deviation is just a measure of how spread out a set of numbers is; forcing it to 1 keeps the spread consistent, rather like grading on a curve.) It then applies two learned dials, `gamma` and `beta`, so the model can stretch or shift the result if that helps.\n", "\n", "The cell shows it working: numbers that started with an average of 0.44 and a spread of 5.02 come out at an average of 0 and a spread of 1. This is done for each token on its own and has nothing to do with the rest of the batch, which is what separates it from an older method called BatchNorm, and why it behaves the same whether you process one sequence or a thousand." ] }, { "cell_type": "code", "execution_count": 3, "id": "0895632a", "metadata": { "execution": { "iopub.execute_input": "2026-07-01T09:08:58.400332Z", "iopub.status.busy": "2026-07-01T09:08:58.400258Z", "iopub.status.idle": "2026-07-01T09:08:58.402466Z", "shell.execute_reply": "2026-07-01T09:08:58.402079Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "before: mean=0.44 std=5.02\n", "after : mean=0.00 std=1.00 (per-row normalized)\n" ] } ], "source": [ "def layer_norm(x, gamma, beta, eps=1e-5):\n", " mu = x.mean(axis=-1, keepdims=True)\n", " var = x.var(axis=-1, keepdims=True)\n", " return gamma * (x - mu) / np.sqrt(var + eps) + beta\n", "\n", "z = np.random.randn(2, 5) * 5 + 3\n", "zn = layer_norm(z, 1.0, 0.0)\n", "print(\"before: mean=%.2f std=%.2f\" % (z.mean(), z.std()))\n", "print(\"after : mean=%.2f std=%.2f (per-row normalized)\" % (zn.mean(), zn.std()))" ] }, { "cell_type": "markdown", "id": "e37194ab", "metadata": {}, "source": [ "
Line by line: what each line does\n", "\n", "
" ] }, { "cell_type": "markdown", "id": "m6lna", "metadata": {}, "source": [ "### Watch LayerNorm flatten a token\n", "\n", "LayerNorm's job is one sentence: take a token's row of numbers and rescale it to mean 0, standard deviation 1. The cell above printed the overall stats; here it is per row, before and after, with row 0 drawn as bars. However spread out a row starts, it lands on the same scale." ] }, { "cell_type": "code", "execution_count": 4, "id": "m6lnb", "metadata": { "execution": { "iopub.execute_input": "2026-07-01T09:08:58.403522Z", "iopub.status.busy": "2026-07-01T09:08:58.403453Z", "iopub.status.idle": "2026-07-01T09:08:58.449067Z", "shell.execute_reply": "2026-07-01T09:08:58.448690Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "before row 0: mean=-0.06 std=3.23\n", "before row 1: mean=+0.95 std=6.29\n", "after row 0: mean=+0.00 std=1.00\n", "after row 1: mean=+0.00 std=1.00\n" ] }, { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# LayerNorm rescales EACH row to mean 0, std 1 -- per row, then row 0 as bars.\n", "for r in range(z.shape[0]):\n", " print(f\"before row {r}: mean={z[r].mean():+.2f} std={z[r].std():.2f}\")\n", "for r in range(zn.shape[0]):\n", " print(f\"after row {r}: mean={zn[r].mean():+.2f} std={zn[r].std():.2f}\")\n", "\n", "fig, ax = plt.subplots(1, 2, figsize=(7, 2.6))\n", "idx = np.arange(z.shape[1])\n", "ax[0].bar(idx, z[0], color=\"#d9822b\"); ax[0].axhline(0, color=\"k\", lw=.5)\n", "ax[0].set_title(\"row 0 before (mean %.1f, std %.1f)\" % (z[0].mean(), z[0].std()))\n", "ax[1].bar(idx, zn[0], color=\"#2b8dd9\"); ax[1].axhline(0, color=\"k\", lw=.5)\n", "ax[1].set_title(\"row 0 after (mean 0, std 1)\")\n", "plt.tight_layout(); plt.show()" ] }, { "cell_type": "markdown", "id": "m6lnc", "metadata": {}, "source": [ "
Line by line: what each line does\n", "
    \n", "
  • The two loops print each row's mean and standard deviation, first for the raw z, then for the normalized zn.
  • \n", "
  • Row 1 starts wildly spread (std over 6); after LayerNorm every row reads mean 0.00, std 1.00.
  • \n", "
  • The left bars are row 0 raw -- off-centre and uneven; the right bars are the same row after -- centred on 0 with a consistent spread.
  • \n", "
  • gamma and beta (here 1 and 0) then let the model rescale and shift if it wants, but the starting point is always this clean, fixed scale.
  • \n", "
\n", "
" ] }, { "cell_type": "markdown", "id": "0150e5e9", "metadata": {}, "source": [ "## Multi-head attention\n", "\n", "A single attention head can only look for one kind of relationship at a time. **Multi-head attention** runs several heads in parallel so the model can look for several at once: perhaps one head links each verb to its subject, another tracks quotation marks, and another watches for the previous line break. It is like a panel of specialists, each reading the sentence for their own purpose and then pooling their notes.\n", "\n", "Mechanically, we slice the embedding into `n_head` equal pieces, run a separate attention head (exactly the one from notebook 05) on each piece in parallel, glue the results back together (concatenate them), and pass them through one more projection `Wo` that lets the heads mix. The output has the same shape as the input, so it drops straight into the block." ] }, { "cell_type": "code", "execution_count": 5, "id": "27e9fe80", "metadata": { "execution": { "iopub.execute_input": "2026-07-01T09:08:58.450130Z", "iopub.status.busy": "2026-07-01T09:08:58.450074Z", "iopub.status.idle": "2026-07-01T09:08:58.452795Z", "shell.execute_reply": "2026-07-01T09:08:58.452497Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "multi-head output: (4, 16, 64)\n" ] } ], "source": [ "def multi_head_attention(x, Wq, Wk, Wv, Wo, n_head):\n", " B, T, C = x.shape\n", " hs = C // n_head\n", " def proj(W): return (x @ W).reshape(B, T, n_head, hs).transpose(0, 2, 1, 3) # (B,nh,T,hs)\n", " q, k, v = proj(Wq), proj(Wk), proj(Wv)\n", " scores = (q @ k.transpose(0, 1, 3, 2)) / hs**0.5 # (B,nh,T,T)\n", " scores = np.where(np.tril(np.ones((T, T))) == 0, -np.inf, scores)\n", " attn = softmax(scores, axis=-1)\n", " out = attn @ v # (B,nh,T,hs)\n", " out = out.transpose(0, 2, 1, 3).reshape(B, T, C) # concat heads\n", " return out @ Wo # output projection\n", "\n", "Wq = np.random.randn(C, C)*0.02; Wk = np.random.randn(C, C)*0.02\n", "Wv = np.random.randn(C, C)*0.02; Wo = np.random.randn(C, C)*0.02\n", "x = np.random.randn(B, T, C)\n", "print(\"multi-head output:\", multi_head_attention(x, Wq, Wk, Wv, Wo, n_head).shape)" ] }, { "cell_type": "markdown", "id": "2223c3bd", "metadata": {}, "source": [ "
Line by line: what each line does\n", "
    \n", "
  • def multi_head_attention(x, Wq, Wk, Wv, Wo, n_head):: run several attention heads at once and combine them.
  • \n", "
  • hs = C // n_head: whole-number division: 64 features split across 4 heads = 16 each.
  • \n", "
  • def proj(W): return (x @ W).reshape(B, T, n_head, hs).transpose(0, 2, 1, 3): one helper used three times: project, then reshape carves the 64-wide result into 4 heads of 16, and transpose reorders the axes to (batch, head, time, hs) so every head can work independently.
  • \n", "
  • q, k, v = proj(Wq), proj(Wk), proj(Wv): queries, keys, values, all carved into heads.
  • \n", "
  • scores = (q @ k.transpose(0, 1, 3, 2)) / hs**0.5: notebook 05's scaled query-key scores, now with a head axis riding along: 4 separate (T,T) grids per sequence.
  • \n", "
  • scores = np.where(np.tril(...) == 0, -np.inf, scores): the causal mask, applied to every head at once.
  • \n", "
  • out = attn @ v then .transpose(...).reshape(B, T, C): blend values per head, then undo the carving so the 4 heads' 16-number outputs sit side by side as 64 again (\"concatenate\").
  • \n", "
  • return out @ Wo: one final projection lets the heads' findings mix with each other.
  • \n", "
\n", "
" ] }, { "cell_type": "markdown", "id": "m6mhaa", "metadata": {}, "source": [ "### How `C` splits into heads\n", "\n", "The reshape inside `multi_head_attention` is the one line that trips people up. All it does is cut each token's projected vector into `n_head` equal slices, run attention on every slice in parallel, then glue the results back and mix them with `Wo`. Here are the shapes at each step, and a picture of the split." ] }, { "cell_type": "code", "execution_count": 6, "id": "m6mhab", "metadata": { "execution": { "iopub.execute_input": "2026-07-01T09:08:58.453873Z", "iopub.status.busy": "2026-07-01T09:08:58.453818Z", "iopub.status.idle": "2026-07-01T09:08:58.476937Z", "shell.execute_reply": "2026-07-01T09:08:58.476669Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "C = 64 -> 4 heads of head_size = 16\n", "\n", "x @ Wq : (4, 16, 64) (B, T, C)\n", "reshape + move heads up : (4, 4, 16, 16) (B, n_head, T, head_size)\n", "per-head attention q@k.T: (4, 4, 16, 16) one T x T map per head\n", "glue heads back : (4, 16, 64) then a final @ Wo mixes them\n" ] }, { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Trace the shapes through one multi-head pass, then draw the head split.\n", "hs = C // n_head\n", "print(f\"C = {C} -> {n_head} heads of head_size = {hs}\\n\")\n", "print(\"x @ Wq :\", (x @ Wq).shape, \" (B, T, C)\")\n", "qh = (x @ Wq).reshape(B, T, n_head, hs).transpose(0, 2, 1, 3)\n", "print(\"reshape + move heads up :\", qh.shape, \" (B, n_head, T, head_size)\")\n", "print(\"per-head attention q@k.T:\", (B, n_head, T, T), \" one T x T map per head\")\n", "print(\"glue heads back :\", (B, T, C), \" then a final @ Wo mixes them\")\n", "\n", "fig, ax = plt.subplots(figsize=(7, 1.5))\n", "colors = plt.cm.Set2(np.linspace(0, 1, n_head))\n", "for hi in range(n_head):\n", " ax.barh(0, hs, left=hi * hs, color=colors[hi], edgecolor=\"white\")\n", " ax.text(hi * hs + hs / 2, 0, f\"head {hi}\\n[{hi*hs}:{hi*hs+hs}]\", ha=\"center\", va=\"center\", fontsize=8)\n", "ax.set_xlim(0, C); ax.set_ylim(-0.5, 0.5); ax.set_yticks([])\n", "ax.set_xlabel(f\"the {C} projected dims per token, sliced into {n_head} heads of {hs}\")\n", "ax.set_title(\"multi-head = split the projection into parallel heads\")\n", "plt.tight_layout(); plt.show()" ] }, { "cell_type": "markdown", "id": "m6mhac", "metadata": {}, "source": [ "
Line by line: what each line does\n", "
    \n", "
  • x @ Wq: project every token, still (B, T, C) -- nothing split yet.
  • \n", "
  • .reshape(B, T, n_head, hs).transpose(...): cut the C numbers into n_head slices of head_size, and move the head axis up so each head is an independent (T, head_size) block.
  • \n", "
  • Each head then runs the exact attention from notebook 05 on its own slice, giving one T x T map per head.
  • \n", "
  • The outputs are glued back into (B, T, C) and passed through Wo, which lets the heads' findings mix.
  • \n", "
  • The coloured bar is the split: dims 0-15 are head 0, 16-31 head 1, and so on -- parallel heads, each watching for a different kind of relationship.
  • \n", "
\n", "
" ] }, { "cell_type": "markdown", "id": "70e6e3ec", "metadata": {}, "source": [ "## Feed-forward network\n", "\n", "Attention let the tokens talk to each other; now each token thinks on its own. The feed-forward network is a small two-layer MLP (multi-layer perceptron, from notebook 04) applied to every token independently. It **expands** the vector to width `4*C`, four times wider, giving it room to compute richer features; passes it through a **nonlinearity** (here GELU, a smooth on/off gate that roughly keeps positive values and suppresses negative ones); and then **projects it back** down to width `C`.\n", "\n", "That nonlinearity is essential. Without a bend in it, stacking layers would collapse into a single straight-line layer that cannot learn curves or rules. This sub-layer holds most of the model's numbers, and much of what we would loosely call its \"knowledge\" lives here." ] }, { "cell_type": "code", "execution_count": 7, "id": "c0e0c8cc", "metadata": { "execution": { "iopub.execute_input": "2026-07-01T09:08:58.477985Z", "iopub.status.busy": "2026-07-01T09:08:58.477928Z", "iopub.status.idle": "2026-07-01T09:08:58.480332Z", "shell.execute_reply": "2026-07-01T09:08:58.480027Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "feed-forward output: (4, 16, 64)\n" ] } ], "source": [ "def gelu(x):\n", " return 0.5 * x * (1 + np.tanh(np.sqrt(2/np.pi) * (x + 0.044715 * x**3)))\n", "\n", "def feed_forward(x, W1, b1, W2, b2):\n", " return gelu(x @ W1 + b1) @ W2 + b2\n", "\n", "W1 = np.random.randn(C, 4*C)*0.02; b1 = np.zeros(4*C)\n", "W2 = np.random.randn(4*C, C)*0.02; b2 = np.zeros(C)\n", "print(\"feed-forward output:\", feed_forward(x, W1, b1, W2, b2).shape)" ] }, { "cell_type": "markdown", "id": "9b9838aa", "metadata": {}, "source": [ "
Line by line: what each line does\n", "
    \n", "
  • def gelu(x):: the gentle on/off gate. The exact formula is a standard fast approximation; what matters is the shape: very negative inputs → near 0 (off), positive inputs → near x (passed through), with a smooth bend instead of a hard corner.
  • \n", "
  • def feed_forward(x, W1, b1, W2, b2):: the per-token \"think about it\" network.
  • \n", "
  • gelu(x @ W1 + b1) @ W2 + b2: the whole thing in one line: widen (64 → 256), bend with GELU, narrow back (256 → 64). b1/b2 are bias vectors added to every token by broadcasting.
  • \n", "
  • W1 = np.random.randn(C, 4*C)*0.02; b1 = np.zeros(4*C): weights start small-random, biases start at zero.
  • \n", "
\n", "
" ] }, { "cell_type": "markdown", "id": "m6gea", "metadata": {}, "source": [ "### See the GELU gate, and the width change\n", "\n", "The feed-forward network does two things worth seeing. Every token passes through GELU, the \"smooth on/off gate\" the text mentions -- so here it is, plotted against the blunt ReLU. And it briefly widens each token from `C` to `4*C` and back, which is where its extra room to compute lives." ] }, { "cell_type": "code", "execution_count": 8, "id": "m6geb", "metadata": { "execution": { "iopub.execute_input": "2026-07-01T09:08:58.481216Z", "iopub.status.busy": "2026-07-01T09:08:58.481165Z", "iopub.status.idle": "2026-07-01T09:08:58.508811Z", "shell.execute_reply": "2026-07-01T09:08:58.508483Z" } }, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "feed-forward width per token: 64 -> 256 (expand + GELU) -> 64 (contract)\n", "W1: (64, 256) W2: (256, 64)\n" ] } ], "source": [ "# GELU vs ReLU, then the expand-then-contract widths of the feed-forward net.\n", "xs = np.linspace(-4, 4, 200)\n", "plt.figure(figsize=(6, 3))\n", "plt.plot(xs, gelu(xs), label=\"GELU (used here)\", color=\"#5b5bd6\", lw=2)\n", "plt.plot(xs, np.maximum(xs, 0), label=\"ReLU (for comparison)\", color=\"#aaa\", ls=\"--\")\n", "plt.axhline(0, color=\"k\", lw=.5); plt.axvline(0, color=\"k\", lw=.5)\n", "plt.legend(); plt.title(\"GELU keeps positives, softly suppresses negatives\")\n", "plt.xlabel(\"input\"); plt.ylabel(\"output\"); plt.show()\n", "\n", "print(f\"feed-forward width per token: {C} -> {4*C} (expand + GELU) -> {C} (contract)\")\n", "print(f\"W1: {W1.shape} W2: {W2.shape}\")" ] }, { "cell_type": "markdown", "id": "m6gec", "metadata": {}, "source": [ "
Line by line: what each line does\n", "
    \n", "
  • xs = np.linspace(-4, 4, 200): a range of inputs to feed the activation.
  • \n", "
  • plt.plot(xs, gelu(xs)): GELU's smooth S-curve -- it passes large positives through almost unchanged and eases negatives toward zero, with a soft dip near -1 rather than ReLU's hard corner.
  • \n", "
  • The dashed ReLU (max(x, 0)) is drawn for contrast: same idea, blunt instead of smooth.
  • \n", "
  • The prints show the width change: each token goes 64 -> 256 -> 64. The wide middle (four times C) is the room the network computes richer features in before shrinking back.
  • \n", "
\n", "
" ] }, { "cell_type": "markdown", "id": "0f93f646", "metadata": {}, "source": [ "## Assemble the block (pre-norm, with residuals)\n", "\n", "Now we wire the two sub-layers together. Modern GPTs use the **pre-norm** arrangement: apply LayerNorm first, then the sub-layer, then add the result back to the input. That \"add back\" is the **residual** (or skip) connection, and it is worth pausing on:\n", "\n", "```\n", "x = x + MultiHeadAttention(LayerNorm(x))\n", "x = x + FeedForward(LayerNorm(x))\n", "```\n", "\n", "Read each line as \"keep `x`, and add an improvement on top.\" Each sub-layer only has to learn a small edit to the running representation, rather than rebuilding it from scratch. Just as important, the `x +` gives the gradients a clean route straight back through the whole stack during the backward pass; without residuals, deep Transformers simply do not train, because the gradient fades to nothing before it reaches the early layers.\n", "\n", "Stacking the block three times below returns the same shape it took in, which is the whole point: identical blocks can be stacked, and a real GPT simply stacks more of them." ] }, { "cell_type": "code", "execution_count": 9, "id": "c91bc971", "metadata": { "execution": { "iopub.execute_input": "2026-07-01T09:08:58.509810Z", "iopub.status.busy": "2026-07-01T09:08:58.509755Z", "iopub.status.idle": "2026-07-01T09:08:58.513045Z", "shell.execute_reply": "2026-07-01T09:08:58.512786Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "after 3 blocks: (4, 16, 64) (shape preserved -> blocks are stackable)\n", "finite: True\n" ] } ], "source": [ "def transformer_block(x, params):\n", " p = params\n", " # sub-layer 1: attention, with a residual connection\n", " a = multi_head_attention(layer_norm(x, p['g1'], p['b1']), p['Wq'], p['Wk'], p['Wv'], p['Wo'], n_head)\n", " x = x + a\n", " # sub-layer 2: feed-forward, with a residual connection\n", " f = feed_forward(layer_norm(x, p['g2'], p['b2']), p['W1'], p['ff_b1'], p['W2'], p['ff_b2'])\n", " x = x + f\n", " return x\n", "\n", "params = dict(\n", " g1=np.ones(C), b1=np.zeros(C), g2=np.ones(C), b2=np.zeros(C),\n", " Wq=Wq, Wk=Wk, Wv=Wv, Wo=Wo,\n", " W1=W1, ff_b1=b1, W2=W2, ff_b2=b2,\n", ")\n", "# token embeddings + positional encoding go in; same shape comes out\n", "h = x + positional_encoding(T, C)\n", "for _ in range(3): # stack 3 blocks\n", " h = transformer_block(h, params)\n", "print(\"after 3 blocks:\", h.shape, \" (shape preserved -> blocks are stackable)\")\n", "print(\"finite:\", np.isfinite(h).all())" ] }, { "cell_type": "markdown", "id": "0a498581", "metadata": {}, "source": [ "
Line by line: what each line does\n", "
    \n", "
  • def transformer_block(x, params):: wire the two sub-layers together; params is a dictionary holding every weight, so p['Wq'] fetches the query projection, etc.
  • \n", "
  • a = multi_head_attention(layer_norm(x, ...), ...): read inside-out: normalize, then attend.
  • \n", "
  • x = x + a: add the attention result back onto x. That x + is the residual: keep the original, add an edit on top.
  • \n", "
  • f = feed_forward(layer_norm(x, ...), ...) then x = x + f: the same normalize → think → add-back pattern for the second sub-layer.
  • \n", "
  • params = dict(g1=np.ones(C), b1=np.zeros(C), ...): bundle all the pieces: LayerNorm dials (set to \"no change\"), the four attention grids, the two feed-forward grids and biases.
  • \n", "
  • h = x + positional_encoding(T, C): stamp positions onto the tokens before the first block.
  • \n", "
  • for _ in range(3): h = transformer_block(h, params): stack three blocks. Same shape out as in, every time -- which is exactly what lets you stack them.
  • \n", "
  • np.isfinite(h).all(): a health check: no infinities or NaNs anywhere after 3 blocks.
  • \n", "
\n", "
" ] }, { "cell_type": "markdown", "id": "m6resa", "metadata": {}, "source": [ "### Residuals: keep `x`, add a small correction\n", "\n", "Both block lines read `x = x + something`. That \"+ x\" is the residual connection. Measure the size (root-mean-square) of each piece and you can see what it buys: each sub-layer adds only a small correction on top of `x`, and the block's output stays on the same scale as its input." ] }, { "cell_type": "code", "execution_count": 10, "id": "m6resb", "metadata": { "execution": { "iopub.execute_input": "2026-07-01T09:08:58.514076Z", "iopub.status.busy": "2026-07-01T09:08:58.514019Z", "iopub.status.idle": "2026-07-01T09:08:58.516794Z", "shell.execute_reply": "2026-07-01T09:08:58.516453Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "block input x : rms = 1.213\n", "attention correction a : rms = 0.014 <- added: x = x + a\n", "feed-forward corr. f : rms = 0.027 <- added: x = x + f\n", "block output x+a+f : rms = 1.214 (same scale as the input)\n", "\n", "The corrections are small on purpose: small initial weights make each block\n", "start as ALMOST the identity (output ~ input). The residual is what preserves\n", "the scale, so you can stack many blocks and still train them.\n" ] } ], "source": [ "# Measure the size of each quantity a block produces (rms = typical magnitude).\n", "def rms(t): return float(np.sqrt((t ** 2).mean()))\n", "\n", "x0 = x + positional_encoding(T, C) # block input\n", "a = multi_head_attention(layer_norm(x0, params[\"g1\"], params[\"b1\"]), Wq, Wk, Wv, Wo, n_head)\n", "x1 = x0 + a # first residual add\n", "f = feed_forward(layer_norm(x1, params[\"g2\"], params[\"b2\"]), W1, b1, W2, b2)\n", "x2 = x1 + f # second residual add\n", "\n", "print(f\"block input x : rms = {rms(x0):.3f}\")\n", "print(f\"attention correction a : rms = {rms(a):.3f} <- added: x = x + a\")\n", "print(f\"feed-forward corr. f : rms = {rms(f):.3f} <- added: x = x + f\")\n", "print(f\"block output x+a+f : rms = {rms(x2):.3f} (same scale as the input)\")\n", "print(\"\\nThe corrections are small on purpose: small initial weights make each block\")\n", "print(\"start as ALMOST the identity (output ~ input). The residual is what preserves\")\n", "print(\"the scale, so you can stack many blocks and still train them.\")" ] }, { "cell_type": "markdown", "id": "m6resc", "metadata": {}, "source": [ "
Line by line: what each line does\n", "
    \n", "
  • rms(t): the root-mean-square, a single number for \"how big are these values typically\".
  • \n", "
  • x0: the block's input (token embeddings plus positions), rms about 1.2.
  • \n", "
  • a and f: the attention and feed-forward outputs -- both much smaller than x0, so x = x + a and x = x + f nudge the signal rather than overwrite it.
  • \n", "
  • The output stays on the same scale as the input, which is exactly why cell above could stack three blocks and stay finite.
  • \n", "
  • Small corrections at the start (from small weights) mean the block begins near the identity and training gently grows it -- the residual is what makes that possible.
  • \n", "
\n", "
" ] }, { "cell_type": "markdown", "id": "a0657c2d", "metadata": {}, "source": [ "## The wall we have just hit, on purpose\n", "\n", "We have built the entire forward pass of a Transformer by hand. Notice what we did not do: the backward pass. Differentiating multi-head attention, LayerNorm, the residuals, and the feed-forward stack by hand, the way we did for the bigram in notebook 03, would be hundreds of careful and error-prone lines, and a single wrong sign would break the whole thing silently.\n", "\n", "This is exactly the moment autograd (notebook 04) earns its place. In Part 2 we rebuild all of this in **PyTorch**, where every operation we just wrote already knows how to compute its own gradient. The concepts are the same, the code is a fraction of the length, and it actually trains.\n", "\n", "Next: notebook 07, PyTorch and autograd." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (.venv)", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.12" } }, "nbformat": 4, "nbformat_minor": 5 }