CS 601.471/671 · NLP: Self-supervised Models · Fall 2026

Handout #11 — Self-Attention and Next-Token Prediction

Session 11 (Tue, Oct 6) · Transformer Architecture slides · Course page

Attention lets each token retrieve information from other token positions. The important change from a fixed-window MLP is not just a larger context: the way information is combined now depends on the input itself. This reading develops that operation, then follows it into a next-token predictor.

Scope
Slides 1–51. Slide 51 is the bridge to Handout #12, which develops the mask. Here we identify why it is needed. §9.3 is an optional tutorial extension. §9.4 guides the assigned at-home reading of slides 112–125, completed alongside Handout #12.
Time
65–85 minutes for the core reading and checks; 20–30 more for the optional lab and code reading. Allow additional time for the assigned implementation reading in §9.4 and Handout #12 §7.
By the end
Compute one attention output; track batches and heads; explain scaling, positional information, residuals, and shifted targets; diagnose future-token leakage.
Assumes
Handout #10's embedding lookup and next-token loss, matrix multiplication, softmax, and normalization and residual connections.
Reading pathRead §1–§7, including the worked example in §7.4, then try §10’s cumulative practice. Complete §9.4’s assembly worksheet with slides 112–125 at home, then continue with Handout #12 §7. Boxes labeled “Optional depth,” §8’s lab, and §9.1–§9.3’s nanoGPT/tutorial exercises are optional extensions. All sequence positions in both handouts are numbered from 0.
Slide-to-reading map
SlidesReading
1–17§1–§3: retrieval, numbers, scaling, batches
18–23§4: heads and fused projections
24–28§5: FFN, residuals, normalization
29–35§6: depth, output head, positions
36–42§7.1: generation
43–51§7.2–§7.3: training and the leakage problem
At-home reading and extensions§9.4: assigned slides 112–125. §8 and §9.1–§9.3: optional attention lab and code readings

1Content-dependent retrieval

A fixed-window MLP gives each relative position a fixed block of weights. In attention, position $i$ instead computes a different set of mixing weights for every input. For “The trophy did not fit in the suitcase because it was too large,” a useful representation of “it” may need information about “trophy.” The architecture provides a route to retrieve that information, even across many intervening positions. Learning a useful route still requires suitable training data and parameters.

Write the input as rows $X\in\mathbb R^{T\times D}$. Each position publishes three vectors:

$$Q=XW_Q,\qquad K=XW_K,\qquad V=XW_V.$$

A query describes what a position seeks; a key describes how that position can be matched; a value contains the information it can contribute. All three are learned projections of the same input in self-attention. The matrices are shared across token positions. They are not separate parameters for “trophy,” “suitcase,” or position 8.

Separating keys from values lets the model match on one set of features and retrieve another. For example, keys could encode features useful for locating a noun, while values supply information about its number or meaning. This is an interpretation of their roles, not a guarantee that a particular trained dimension has a human-readable label.

A token vector changes meaning across layersThe input to the first attention block comes from token and position embeddings. In later blocks it is a contextual representation. Two occurrences of the same token can then have different keys and values because earlier layers have processed different contexts.

2Compute one query's answer

For query row $q_i$, first score every key, then normalize across keys, then combine the values:

$$s_{ij}=\frac{q_i k_j^\top}{\sqrt{d_k}},\qquad a_{ij}=\frac{e^{s_{ij}}}{\sum_{r=0}^{T-1} e^{s_{ir}}},\qquad y_i=\sum_{j=0}^{T-1} a_{ij}v_j.$$

We use $s$ for raw scores and $a$ for normalized attention weights, so the two quantities do not get confused. $d_k$ is the query/key width. Values may have a different width $d_v$; compatible queries and keys must have the same width.

2.1 A complete numerical retrieval

Choose $d_k=2$, $q=[1,0]$, and keys $k_0=[\sqrt2\log2,0]$, $k_1=[0,1]$, $k_2=[0,-1]$. The scaled scores are $[\log2,0,0]$. Their exponentials are $[2,1,1]$, so the weights are $[1/2,1/4,1/4]$.

Key positionWeightValueWeighted contribution
00.50$[2,0]$$[1,0]$
10.25$[0,2]$$[0,0.5]$
20.25$[4,4]$$[1,1]$

Adding contributions gives $y=[2,1.5]$. The output need not equal any individual value. Before dropout, it is a convex combination of the values: nonnegative weights sum to one. Later projections, residual additions, and FFNs are not constrained to this convex hull.

Try changing the retrieval scores

These controls edit already-scaled scores for the three values above.

2.2 How the routing learns

Raising one score increases its own weight and reduces the others, because they compete for a fixed total. The value path passes information forward; the query/key path learns how to route it. Both paths receive gradients from the final language-model loss.

Optional depth · The softmax derivative

For one query row, $a_j=e^{s_j}/\sum_r e^{s_r}$. Differentiating numerator and denominator gives $\partial a_j/\partial s_r=a_j(\mathbf1[j=r]-a_r)$. The diagonal term is $a_j(1-a_j)$; off-diagonal terms are $-a_ja_r$. A saturated row has small derivatives, explaining why excessive score magnitudes can make routing hard to change.

A large attention weight alone is not a complete explanation of a prediction: a value can be small, point in an unhelpful direction, or be offset by another head or the residual stream. To test a causal claim about model behavior, changing or removing the relevant input and observing the prediction is more informative than inspecting a weight alone.

Check 1 · Match versus information

If $v_2$ changes to $[0,0]$ while queries and keys stay fixed, what changes? What if we instead add 10 to every score?

Reveal the answer

The weights stay $[0.5,0.25,0.25]$ but the output becomes $[1,0.5]$. Adding a common score shift changes neither weights nor output, since the factor $e^{10}$ cancels in softmax.

Practice · Why not just pick the best key?

Adapted from Spring 2025 Homework 6, §2.1, p. 4. Numbers and explanations are adapted for this handout.

Replace softmax in §2.1 by a one-hot vector selecting the largest score. For scores $[\log2,0,0]$, what output do you obtain? If the top-scoring key stays the same after a small query change, does the output change? Which learning paths remain?

Reveal the answer

Hard selection returns $v_0=[2,0]$, instead of the soft mixture $[2,1.5]$. Within a region where the winner is unchanged, the output is constant with respect to the scores. Ordinary derivatives provide no useful routing gradient to Q/K; at winner-switching boundaries the operation is discontinuous. The selected value still receives a gradient, so it is too broad to say that the whole model cannot backpropagate. Softmax supplies a differentiable routing path as well as a value path.

3Scaling and batching without mixing examples

3.1 Why divide by the square root?

Suppose query and key coordinates are independent, zero-mean, with variance $\sigma^2$. Each product has variance $\sigma^4$, and summing $d_k$ independent products gives variance $d_k\sigma^4$. Dividing by $\sqrt{d_k}$ gives variance $\sigma^4$. This is an initialization-scale argument; trained coordinates need not satisfy the assumptions exactly.

For two scores $[0,8]$, softmax is approximately $[0.000335,0.999665]$. Dividing by $\sqrt{64}=8$ instead gives $[0,1]$ and probabilities $[0.268941,0.731059]$. The second distribution has more room for score changes to alter its weights. Scaling limits dimension-driven saturation; it does not prohibit a trained head from becoming selective.

3.2 The full matrix operation

$$Y=\operatorname{softmax}_{\text{keys}}\!\left(\frac{QK^\top}{\sqrt{d_k}}\right)V.$$

Rows are queries, columns are keys. Every row sums to one; columns generally do not. For a batch, transpose only the final two dimensions of $K$. Each batch item has its own attention matrix:

TensorShapeExample: $B=2,T=3,d_k=4,d_v=5$
$Q,K$$B\times T\times d_k$$2\times3\times4$
$V$$B\times T\times d_v$$2\times3\times5$
$QK^\top$, weights$B\times T\times T$$2\times3\times3$
$Y$$B\times T\times d_v$$2\times3\times5$
Check 2 · Find the wrong axis

Adapted from Spring 2025 Quiz 2, Q3.5–7, p. 6. Numbers and explanations are adapted for this handout.

For scores shaped [2,3,3], why is softmax(dim=-1) correct? What would dim=0 do?

Reveal the answer

The final axis enumerates keys for each query. Dimension 0 normalizes across the two examples, coupling their weights and making an example's output depend on its batch companion. Neither queries nor separate examples should compete for a row's probability mass.

4Multiple heads: separate routing decisions

One head produces one distribution over positions for each query. Two heads can retrieve two different mixtures at the same position. For example, one might emphasize a subject and another a nearby modifier. Heads are jointly trained; they are not independent language models voting on a final answer, and useful specialization is not guaranteed.

With model width $D$ and $H$ heads, take $d_h=D/H$. Each head has query, key, and value width $d_h$. Concatenating $H$ outputs recovers width $D$; an output projection $W_O\in\mathbb R^{D\times D}$ mixes the head features.

$$Y=\operatorname{Concat}(Y^{(1)},\ldots,Y^{(H)})W_O.$$

At $D=8,H=2$, each head returns 4 features. Ignoring biases, the three projection families contain $3D^2=192$ parameters and $W_O$ adds $D^2=64$, totaling 256. Changing the head count while holding $D$ fixed changes head width but not this parameter count.

Optional depth · Can a mixture preserve two separate signals?

Adapted from Spring 2025 Homework 6, §2.2, parts 2–3, p. 5; the homework credits John Hewitt for this question family. Numbers and explanations are adapted for this handout.

Suppose two retrieved values are $v_a=[4,0]$ and $v_b=[0,6]$, known to occupy different coordinate directions. Their equally weighted mixture is $\bar v=[2,3]$. Multiplying its first coordinate by two and discarding the second recovers $v_a$; doing the reverse recovers $v_b$. Mixing need not destroy separable information.

In general, using column vectors for this derivation, let $v_a$ lie in a subspace with orthonormal basis $a_1,\ldots,a_m$, and $v_b$ lie in an orthogonal subspace. Then $P_A=\sum_r a_ra_r^\top$ projects onto the first subspace, and $2P_A\bar v=v_a$ for $\bar v=(v_a+v_b)/2$.

If the values share the same coordinate direction, recovery can be ambiguous: $[4,0]$ with $[0,0]$ and $[2,0]$ with $[2,0]$ both average to $[2,0]$. Multiple heads provide separate mixtures, but do not guarantee orthogonal features or lossless recovery.

Equal attention to two desired keys requires equal scores for those keys and negligible weight elsewhere. With finite scores, ordinary softmax gives every unmasked key positive weight. The homework's very large negative scores therefore give an approximate two-value average; masking all other keys can make it exact. The same distinction applies to copying a single value.

4.1 Two heads answer the same query differently

Reuse §2.1’s values $v_0=[2,0]$, $v_1=[0,2]$, $v_2=[4,4]$. At the same query position, let two heads’ separate projections produce the following scaled scores. For this example their value projections produce the same values; their routing differs.

HeadScaled scores for keys 0, 1, 2WeightsRetrieved output
1$[\log8,0,0]$$[0.8,0.1,0.1]$$[2,0.6]$
2$[0,\log8,0]$$[0.1,0.8,0.1]$$[0.6,2]$

For head 1, the sum is $0.8[2,0]+0.1[0,2]+0.1[4,4]=[2,0.6]$. Head 2 instead computes $0.1[2,0]+0.8[0,2]+0.1[4,4]=[0.6,2]$.

Concatenation gives $[2,0.6\;|\;0.6,2]$: four features, with each head’s answer still separately available. Here $H=2,d_h=2,D=4$. Choosing $W_O=I_4$ preserves these four features; a learned $4\times4$ map can mix them. Averaging the two answers would instead give only $[1.3,1.3]$, merging the two routing decisions. Concatenation is not averaging.

Head 1 emphasizes position 0; head 2 emphasizes position 1. Both still include position 2 because finite unmasked softmax scores give positive weights. This is a possible learned behavior, rather than a promise that every trained head specializes this way.

4.2 Fused projection is the same algebra

Store $W_{QKV}=[W_Q\;W_K\;W_V]\in\mathbb R^{D\times3D}$. One multiplication $XW_{QKV}$ returns three adjacent feature groups. Split them, then reshape and transpose to [B,H,T,d_h]. This combines operations; it does not force $Q=K=V$.

From fused projection to separate headsB by T by D input is projected to three D-wide groups, then split into queries, keys, values and rearranged into B by H by T by head width.Input X[B, T, D]→Q | K | V[B, T, 3D]→Each of Q, K, V[B, H, T, D/H]one linear mapsplit, reshape, transpose
Original shape diagram. The head axis becomes a separate batch-like axis for parallel attention operations.

Attention weights now have shape [B,H,T,T]. Arithmetic for the score/value products stays proportional to $BT^2D$ at fixed width, but explicitly storing all heads' weights takes $BHT^2$ entries. Similar arithmetic cost does not imply identical activation memory.

Check 3 · Rank and head width

For $T=6,D=8,H=2$, what is the maximum rank of a head output matrix and of the concatenated, projected output?

Reveal the answer

A head is $6\times4$, so rank is at most $\min(6,4)=4$. The combined output is $6\times8$, so rank is at most $\min(6,8)=6$. Separate heads can contribute different column spaces, allowing the combined rank to exceed one head’s rank. In general the head bound is $\min(T,d_h)$, and the combined bound is $\min(T,D)$. These are upper bounds, not promises of full rank. $W_O$ cannot raise the rank of its input.

5Build a block: mix positions, then transform features

Attention mixes information across positions. The feedforward network transforms the resulting features independently at each position, with shared parameters:

$$\operatorname{FFN}(x)=f(xW_1+b_1)W_2+b_2,\quad W_1\in\mathbb R^{D\times D_{ff}},\quad W_2\in\mathbb R^{D_{ff}\times D}.$$

The FFN can expand to $D_{ff}=4D$, apply a nonlinear activation, then return to width $D$. “Position-wise” does not mean context-free: its input already contains information retrieved by attention. It means the FFN itself does not communicate between rows. A linear-only pair would collapse to a single linear map; the intervening nonlinearity matters.

5.1 Two arrangements you should recognize

The post-norm block in slides 25–26 computes:

$$U=\operatorname{LN}(X+\operatorname{MHA}(X)),\qquad Y=\operatorname{LN}(U+\operatorname{FFN}(U)).$$

A pre-norm version computes:

$$U=X+\operatorname{MHA}(\operatorname{LN}(X)),\qquad Y=U+\operatorname{FFN}(\operatorname{LN}(U)).$$

Both keep the residual width equal to $D$. LayerNorm normalizes across features within a token, not across sequence positions or batch items. In pre-norm, each update has an explicit identity path: $d(x+g(\operatorname{LN}(x)))/dx=I+J_{g\circ\operatorname{LN}}$. This helps gradient flow through a deep stack, but does not guarantee stable training under every initialization or learning rate. Revisit Handout #8 for the underlying optimization ideas.

Check 4 · Which operation communicates?

If you change one row of a block input, which operations can directly change another row? Would replacing LayerNorm by a normalization across token positions preserve that answer?

Reveal the answer

Attention can change another row. The shared FFN, feature-wise LayerNorm, and residual addition cannot directly do so. Normalizing across positions would couple rows and, in a causal model, could leak future-token information even if attention were masked.

6Depth, positions, and a vocabulary head

Stacking blocks lets later layers retrieve and transform features that earlier layers built. After $L$ blocks, the shape is still [B,T,D]. Apply a vocabulary projection to obtain [B,T,Vocab] logits. If input and output embeddings are tied, the logits for row $h_i$ are $h_iE^\top$ with $E\in\mathbb R^{Vocab\times D}$. Tying is a parameter-sharing choice, not a requirement of attention.

6.1 A precise statement about order

Unmasked self-attention without position information is permutation equivariant: reordering input rows reorders output rows the same way. It is not invariant: outputs do move. Shared FFNs and token-wise normalization preserve this property. For example, swapping rows 0 and 2 swaps their contextual outputs but does not add a signal saying which row originally came first.

Optional depth · Why the permutation claim holds

Let $P$ be a permutation matrix acting on rows. Shared projections give $Q'=PQ$, $K'=PK$, and $V'=PV$. Thus $S'=PSP^\top$, where $S=QK^\top/\sqrt{d_k}$. Reordering a row’s entries simply reorders its softmax, while reordering rows changes which query it belongs to, so $A'=PAP^\top$. Finally $Y'=A'V'=PAP^\top PV=PY$, since $P^\top P=I$. A shared row-wise FFN or normalization also commutes with $P$.

This argument requires the absence of fixed position signals and an unchanged ordering mask. If token rows move while position vectors remain assigned to indices, the combined inputs are not just $PX$.

Thus an unrestricted block cannot tell that a row was originally “first” just from its array index. Adding position vectors $p_i$ makes $x_i=E[w_i]+p_i$. The same token at two positions now starts with different vectors. Learned absolute embeddings add $T_{max}D$ trainable parameters; fixed sinusoidal encodings do not. In the sinusoidal scheme, even/odd feature pairs use sine and cosine at different frequencies.

The mask also introduces structureA causal mask treats earlier and later indices differently, so the unrestricted permutation proof does not apply unchanged. The mask supplies an ordering constraint. Explicit position encodings still give the model a direct signal for positions or distances; mask structure and positional embeddings play different roles.
Check 5 · Same token, different position

Without position information, two identical input rows have identical queries. Under unrestricted attention, must their outputs match? What changes if they have different causal masks?

Reveal the answer

Yes: they see the same keys and values with the same scores, so their mixtures match. With different causal masks, their allowed key sets differ and outputs need not match. Adding different positional vectors also breaks the identical-query premise.

7One predictor, two execution modes

7.1 Generation appends one token at a time

Given a prompt, use the logits at its final real position to predict the next token. Sample from softmax, or select the largest logit for greedy decoding; append the chosen token and repeat. Stop at EOS or a chosen length bound. The vocabulary projection is shared across positions. Generation is sequential because the next input depends on the token just chosen.

Extending the prompt changes the next-position prediction. In a correctly causal model, earlier positions' representations do not change merely because a later token was appended, with positions and other settings fixed. That property will justify caching in Handout #12. No cache is needed to understand the generation algorithm; a naive implementation recomputes the growing prefix.

7.2 Training supplies all gold prefixes together

For the cat sat on the mat <eos>, use:

Input position012345
Inputthecatsatonthemat
TargetcatsatonthematEOS

Output at input position $i$ predicts the token at $i+1$. The input token at $i$ is legitimate context. The target at $i+1$ is not. This is teacher forcing: training uses the observed prefix rather than a prefix sampled by the model. All target positions are known, so their losses can be computed together:

$$\mathcal L=-\frac1N\sum_{b,i\;\text{scored}}\log p_\theta(w_{b,i+1}\mid w_{b,\le i}).$$

Backpropagation updates embeddings, Q/K/V and output projections, FFNs, and trainable normalization and position parameters. Queries, attention weights, and intermediate representations are activations, not independently optimized parameter tables. The softmax function itself has no trainable parameters.

7.3 Why shifting the targets is insufficient

The target “cat” also appears in the input, one column to the right. With unrestricted attention, the “the” query can access the “cat” key and value. A low training loss could then reflect learning to read the answer from the future, a route unavailable during generation. The same problem recurs at every position except the last.

A causal model must enforce that every output at $i$ depends only on inputs at positions $j\le i$. Enforce this in every block: masking only the final block is insufficient because an earlier block could already have copied future information into an allowed row. Handout #12 derives the mask and tests this dependence directly.

Check 6 · Leakage audit

A two-block model has unrestricted attention in block 1 and causal attention in block 2. Is the output at position 0 safe? Does removing the loss at position 1 fix it?

Reveal the answer

No. Block 1 can copy input 1 into representation 0; block 2 can attend to representation 0 and use that future information. Removing a loss does not remove its corresponding input or the information path. Restrict all attention blocks and keep other operations token-wise.

7.4 One sequence, from embeddings to loss

Follow the observed token stream A B C A. The three input rows are A B C at positions 0, 1, 2; their targets are B C A. Take vocabulary order $[A,B,C]$, width $D=2$, and one head with $d_k=1,d_v=2$. These are fixed toy parameters, not a trained language model.

Arithmetic simplificationThis teaching block uses $U=X+Y_{attn}$ and $H=U+\operatorname{ReLU}(U)W_2$, with $W_1=I_2$, $W_2=\tfrac12I_2$, and identity attention output projection. It omits normalization, biases, and dropout to expose the arithmetic. A full pre-norm or post-norm Transformer inserts normalization as shown in §5; the numbers would then change. Each query here reads only its permitted prefix; #12 derives the masking operation.

1 · Embed tokens and add positions. The lookup rows are $E[A]=[1,0]$, $E[B]=[0,1/2]$, $E[C]=[1/2,1/2]$. Position rows are $p_0=[0,0]$, $p_1=[0,1/2]$, $p_2=[1/2,1/2]$. Therefore:

$$X=E[\text{inputs}]+P=\begin{bmatrix}1&0\\0&1\\1&1\end{bmatrix}.$$

2 · Project Q/K/V. Choose $W_Q=[1,0]^\top$, $W_K=[\log2,0]^\top$, and $W_V=I_2$. Then $Q=[1,0,1]^\top$, $K=[\log2,0,\log2]^\top$, and $V=X$. Since $d_k=1$, the scale is 1.

3 · Retrieve from the prefix. For row 0, only key 0 is allowed; for row 1, keys 0–1; for row 2, keys 0–2. The raw scores and normalized weights are:

$$S=QK^\top=\begin{bmatrix}\log2&0&\log2\\0&0&0\\\log2&0&\log2\end{bmatrix},\qquad A=\begin{bmatrix}1&0&0\\1/2&1/2&0\\2/5&1/5&2/5\end{bmatrix}.$$

Raw future scores exist in $S$ but are excluded before normalization. Row 2, for example, has exponentials $[2,1,2]$ and retrieves $\tfrac25[1,0]+\tfrac15[0,1]+\tfrac25[1,1]=[0.8,0.6]$.

4 · Add the residual and apply the FFN. Every entry of $U$ is nonnegative, so $\operatorname{ReLU}(U)=U$ and the second residual produces $H=1.5U$.

Position$X_i$$Y_{attn,i}=(AV)_i$$U_i=X_i+Y_{attn,i}$$\operatorname{FFN}(U_i)$$H_i$
0$[1,0]$$[1,0]$$[2,0]$$[1,0]$$[3,0]$
1$[0,1]$$[0.5,0.5]$$[0.5,1.5]$$[0.25,0.75]$$[0.75,2.25]$
2$[1,1]$$[0.8,0.6]$$[1.8,1.6]$$[0.9,0.8]$$[2.7,2.4]$

5 · Project to vocabulary logits and score the next token. Use an untied head $W_{vocab}=\begin{bmatrix}1&0&-1\\0&1&-1\end{bmatrix}$. Each row $[h_0,h_1]$ gives logits $[h_0,h_1,-h_0-h_1]$. Softmax now normalizes over vocabulary entries, rather than key positions.

Input positionLogits for $[A,B,C]$Next-token targetTarget probabilityLoss (nats)
0$[3,0,-3]$B (stream position 1)0.047313.05095
1$[0.75,2.25,-3]$C (stream position 2)0.004275.45569
2$[2.7,2.4,-5.1]$A (stream position 3)0.574310.55459

For each row, $\ell_i=-\log p_i(\text{target})=\operatorname{logsumexp}(z_i)-z_{i,\text{target}}$. The mean loss over the three scored rows is approximately 3.02041 nats. A large loss is expected for these arbitrary parameters. During generation, row 2’s logits would predict a new token after A B C; training instead scores the observed next token A.

Trace check · Two softmaxes, two axes

Which softmax decides where information comes from, and which decides which token to predict? If the final observed A changes to B while the three input tokens stay fixed, which computations change?

Reveal the answer

Attention softmax produces each row of $A$ over keys; vocabulary softmax produces token probabilities from logits. Changing only the final target changes row 2’s scored class and its loss, not $X$, Q/K/V, attention, hidden rows, logits, or predicted probabilities. That target is outside the three-token input.

8Optional lab: verify attention before building an LM

Download 11_attention.py and run python 11_attention.py with PyTorch installed. This original lab has no training loop: it isolates retrieval, fused projections, and the order symmetry. It verifies the retrieval answer $[2,1.5]$, the two-head example, and §7.4’s full numerical trace, and checks row sums, shapes, projection equivalence, permutation equivariance, and future dependence.

def attention(q, k, v):
    scores = q @ k.transpose(-2, -1) / math.sqrt(q.size(-1))
    weights = scores.softmax(dim=-1)
    return weights @ v, weights

Notice that transpose(-2,-1) works for both three-dimensional batches and four-dimensional head tensors. .T does not express that operation for arbitrary batch rank.

Lab edits · Make and explain a failure
  1. Replace softmax(dim=-1) by softmax(dim=-2). Which assertion catches it, and what is now normalized?
  2. Add different position vectors before mha. Compare mha(x[:,perm] + positions) with the permuted output of mha(x + positions). Why does the old equality no longer follow?
  3. Set all values to the same vector. Can changing scores change the output before $W_O$?
Reveal the answers

1. The row-sum check catches the wrong normalization; queries now compete within each key column. In the one-query example, the wrong softmax also gives all weights 1 and output $[6,6]$. 2. Token rows move but position vectors stay assigned to indices, so the combined inputs are not simply permuted versions of one another. 3. No: $\sum_j a_jv=v$. Routing cannot create information absent from the values.

8.1 Optional code exercise: name the tensor axes

Practice · Write the two contractions

Adapted from Spring 2025 Homework 7, §1, self-attention exercise, p. 4. Numbers and explanations are adapted for this handout.

For $Q,K\in\mathbb R^{B\times T\times d_k}$ and $V\in\mathbb R^{B\times T\times d_v}$, fill in the two einsum expressions. Let b name the batch, i a query position, j a key position, and d/e the key/value features.

scores = torch.einsum("...", q, k) / math.sqrt(q.size(-1))
weights = scores.softmax(dim=-1)
y = torch.einsum("...", weights, v)
Reveal the answer
scores = torch.einsum("bid,bjd->bij", q, k) / math.sqrt(q.size(-1))
y = torch.einsum("bij,bje->bie", weights, v)

The first expression sums over key features d while retaining both position axes. The second sums over key positions j while retaining query positions and value features. Batch b remains in both outputs; examples do not mix. Shapes are [B,T,T] and [B,T,d_v]. Compare these outputs with the matrix-multiplication lab using torch.testing.assert_close. The source uses a named scale factor; here division by $\sqrt{d_k}$ makes its convention explicit.

9Implementation readings and at-home assembly

Optional nanoGPT reading · §9.1–§9.2Open nanoGPT/model.py at revision 3adf61e (330 lines). Find CausalSelfAttention.forward, MLP, and Block.forward. The next handout reads the mask and loss paths in the same file.

9.1 Identify the head axis

model.py · CausalSelfAttention.forward · verbatim excerpt

        q, k, v  = self.c_attn(x).split(self.n_embd, dim=2)
        k = k.view(B, T, self.n_head, C // self.n_head).transpose(1, 2) # (B, nh, T, hs)
        q = q.view(B, T, self.n_head, C // self.n_head).transpose(1, 2) # (B, nh, T, hs)
        v = v.view(B, T, self.n_head, C // self.n_head).transpose(1, 2) # (B, nh, T, hs)

C is our $D$, nh is $H$, and hs is $d_h$. The projection fuses all three families; the reshape separates heads. The output later transposes back and joins head features, as in §4.

9.2 Recognize pre-norm

model.py · Block.forward · verbatim excerpt

    def forward(self, x):
        x = x + self.attn(self.ln_1(x))
        x = x + self.mlp(self.ln_2(x))
        return x

This is §5's pre-norm arrangement. Inside MLP, trace the expansion to 4 * config.n_embd, GELU, and contraction back to $D$. The implementation also includes dropout; our lab disables that complication.

Code edit · One axis breaks head layout

In a local copy, remove the three .transpose(1, 2) calls and force the manual attention branch. With $B=2,T=3,C=8,H=2$, what shape does the score matrix have instead of [2,2,3,3]? Predict the failure, then run it.

Reveal the answer

Each Q/K tensor remains [2,3,2,4], giving scores [2,3,2,2]. The operation mixes heads at each token instead of tokens within each head. The manual causal mask is [1,1,3,3], so masking fails on incompatible final dimensions. Restore the transposes; reshaping alone does not exchange axes.

Excerpts: nanoGPT, Copyright (c) 2022 Andrej Karpathy, MIT License. License and permission notice.

9.3 Optional workshop: improve the course tutorial with an equivalence check

Read, predict, then editContinue the JHU-CLSP tutorial at revision 92c7e31e from Handout #10's data-pipeline exercise. Follow AttnHead → Attn → TransformerBlock → Transformer. Compare that explicit module structure with nanoGPT's fused-head implementation above.

lab_1_pretraining_a_small_language_model.py · Attn.forward · verbatim excerpt

        out = torch.cat([h(x) for h in self.heads], dim=-1)

The tutorial evaluates separately parameterized heads and concatenates their outputs. Its blocks use pre-norm residuals, RMSNorm, and a gated FFN. These last two choices are optional architectural variations: the core reasoning about shapes and information flow from §4–§5 still applies. For a gated FFN, two $D\to D_{ff}$ maps produce features and gates; elementwise multiplication combines them before a $D_{ff}\to D$ map. RMSNorm rescales features by their root-mean-square rather than subtracting their mean first.

Code task · Fuse heads without changing the function

For the companion experiment with $D=8,H=2$, replace the separate head projections by one fused QKV projection. Copy existing weights and biases rather than reinitializing them. Compare outputs on [2,4,8] inputs, with the same causal rule and output projection. Why is equal parameter count insufficient to establish equivalence?

Reveal the answer

Stack all heads' Q rows, then all K rows, then all V rows, giving a [24,8] PyTorch weight and a 24-element bias. After projection, split the three width-8 groups, reshape each to [2,4,2,4], and transpose to [2,2,4,4]. Scale by $\sqrt4$, attend within each head, then rejoin heads and apply the copied output projection. Both implementations have 288 parameters including biases: 216 in Q/K/V and 72 in the output map. Equal counts alone allow completely different weights or head layouts.

10_11_jsalt_checks.py performs this conversion and verifies numerical agreement with torch.testing.assert_close. This establishes that the edit preserves the function. It does not establish a speedup: that requires timing under a specified device, batch size, and sequence length.

9.4 Assigned at-home reading: turn the implementation slides into a build plan

Use slides 112–125, “Writing our own Transformer”, as assigned reading to complete at home. Use the worksheet below to trace how the components fit together. They build an encoder–decoder; the tutorial builds a decoder-only LM. First assemble the shared modules, then use #12's architecture section to reason about the additional cross-attention path.

SlidesBuild questionEvidence to collect
113, 123: copies and stacksAre repeated layers distinct modules?Compare parameter object identities across two layers.
114–115: embedding and positionWhat enters row $i$?Trace IDs $[B,T]$ to vectors $[B,T,D]$; check that position vectors broadcast across the batch.
116–117: attentionWhich axis holds keys?Trace $[B,H,T,T]$ weights; compare separate and fused projections.
118–119: FFN and residualsCan each branch be added to its input?Verify matching $[B,T,D]$ outputs; identify pre-norm versus post-norm from the operation order.
120–121: encoder and decoderWhere do Q/K/V come from?Draw source self-attention, target self-attention, and rectangular cross-attention separately.
122, 124–125: head and full modelDo outputs fit the chosen loss?Trace $[B,T,D]$ to logits $[B,T,V]$; inspect initialization and the target shift.
Assembly check · Two different kinds of sharing

Explain why sharing projection weights across token positions is compatible with independently parameterized layers. Then test whether the input embedding and output-head weights are tied; does having the same shape prove they share parameters?

Reveal the answer

One layer applies its same projection to all token rows, but another layer can own a different projection. Position sharing and layer sharing refer to different axes of reuse. Equal shapes do not imply tied parameters: compare the actual parameter objects. The companion checker confirms distinct layers and separate embedding/head weights in the pinned tutorial, checks output shape, and verifies that changing future inputs leaves prefix logits unchanged.

For the causal-mask implementation and cached decoding, continue with #12's assigned at-home implementation reading. Slides 112–125 are required reading to complete at home; §9.4 and #12 §7 provide guidance for that reading. The additional code experiments remain optional.

10Practice set: put the pieces together

Try these without opening the answers. Use zero-based positions throughout.

A · Trace shapes and separate the softmaxes

For $B=2,T=6,D=8,H=2$ and vocabulary size 20, give the shapes of per-head Q/K/V, attention weights, concatenated head outputs, and vocabulary logits. Which axis does each softmax normalize? Compare one head’s rank bound with the combined output’s.

Reveal the answer

Q/K/V: $[2,2,6,4]$; weights: $[2,2,6,6]$; concatenated outputs: $[2,6,8]$; logits: $[2,6,20]$. Attention normalizes the final key axis (length 6); vocabulary probabilities normalize the final class axis (length 20). For one example, a head’s $6\times4$ output has rank at most 4; the combined $6\times8$ output has rank at most 6.

B · Repeated tokens and shifted targets

The stream is A B A C. Use its first three tokens as inputs. Write the positions and targets. Must the two A input rows have identical Q/K/V after adding learned position embeddings? Which keys may the prediction at input position 1 use?

Reveal the answer

Input positions are $[0,1,2]$, inputs A B A, and targets B A C. The target stream positions are $[1,2,3]$. The A token lookup is shared, but adding $p_0$ versus $p_2$ can change the input rows and their projections; equality is not required. The prediction at position 1 may use keys 0 and 1, including its current B, while predicting the A at stream position 2.

C · Catch leakage across layers

A two-block decoder masks only block 2, uses position-wise FFNs and feature-wise LayerNorm, and shifts labels correctly. Propose two length-4 inputs and an output comparison that can expose leakage at positions 0–1. Why can block 2’s mask fail to protect them?

Reveal the answer

Compare A B C A with A B A C, keeping positions fixed and disabling dropout. A causal model’s logits at positions 0–1 must agree. Unrestricted block 1 can carry the changed suffix into prefix rows; block 2 may read those allowed but already contaminated rows. Mask every block. A successful comparison on one pair is useful evidence, not a proof for all possible inputs.

D · Change a target without changing context

In §7.4, change only the final target A to B. Use row 2’s logits to compute its new loss and the new three-row mean. Explain why its attention weights stay unchanged.

Reveal the answer

B’s logit is 0.3 below A’s, so its negative log probability is 0.3 larger: about 0.85459 nats. The mean rises by $0.3/3=0.1$ to about 3.12041 nats. A target label changes which probability is scored; it does not participate in the forward pass.