Transformer Blocks
Attention lets tokens exchange information, but that is only part of a transformer. We will put it together with per-token processing, normalisation, and residual connections, explaining the job of each component.
10 sections · 9 questions · 4 coding challenges
The arrow keys move between sections too.
Could Every Position Consult the Others Directly?
BOTIE
Vaswani and colleagues introduced the Transformer in 2017 for sequence transduction, including translation. It made attention the main means of exchanging information across positions, without the recurrent or convolutional layers used by many earlier systems.
A block first lets positions gather information through attention. A feed-forward stage then transforms each position's updated representation. Residual connections and normalisation help these stages work together in a trainable stack. The block is useful because it separates communication between positions from processing within a position. A language generator additionally restricts which positions can be consulted, so training does not reveal the next token's answer.
Sources for this history
How Do We Build a Model Around Attention?
Consider the sentence: The cat lay on the blanket because it was tired. To make sense of it, we need to connect the final words with something mentioned earlier. Reading each word in isolation would leave out that connection.
We already have an operation that lets tokens gather information from other tokens: attention. Now we need to place it inside a larger component that can preserve information, combine what it gathers, and pass the result onward. That component is a transformer block.
Give every token a place to keep information
Each token receives a vector, a row of numbers that the model can update. Position information accompanies that row so the model can distinguish the order of the tokens. These rows are the information being processed, not separate little models.
Token
- cat
- was
- tired
Its representation
- Row for cat
- Row for was
- Row for tired
Now assemble the block in the order information travels
The numerical example follows those connections through one small block. Change the last token and check that earlier rows cannot change through access to the future.
Its randomly initialized parameters expose the architecture. Learning useful representations requires training, which the next-token lesson explains.
Explore the full example
Change the last token from cat to dog. Follow its row through the block, then check that the earlier rows remain unchanged. Read the attention tables by row: each row says which positions that position reads.
Calculating the example…
Part 1. Two Jobs Inside the Block
1. Gather context, then process the result
Attention and the feed-forward network do different work. Attention lets each token row gather information from other positions. The feed-forward network then transforms the coordinates within each row, using the same weights at every position.
Why both? Attention compares a row with the rows it is allowed to read and combines their value vectors in proportion to the shares it computes, which sum to one across the positions read. In the live block the row for cat reads <start>, the and itself, and the first head gives those three positions shares of 0.3988, 0.3307 and 0.2705. What the row receives is a mixture in those proportions, and a mixture can only contain what went into it. Making something new out of the gathered content is the second job. The feed-forward network widens the row into a larger intermediate one, replaces every negative intermediate value with zero, and narrows the result back to the row’s width. The zeroing gives the network a changing slope, so what it answers is not simply another weighted sum of the row it read.
The same weights serve every position because the network’s question is the same wherever a row came from. Where a token sits is already written into its row by the position step, so the network reads the position out of the row rather than needing a separate set of weights for each place. That is also what lets one block read a longer prefix with the same parameters. The live example reads three tokens, and a fourth token would meet the same expansion and contraction matrices.
Separate heads give attention several independently learned comparison spaces. They are not assigned grammatical roles in advance. A head might learn a useful relationship, but its role must be investigated rather than inferred from its name.
2. Preserve a route for the incoming representation
Each branch produces a contribution that is added to its input. These residual additions preserve a direct route for information and gradients. The branch can learn an adjustment without needing to recreate the entire incoming representation.
The cat row through both additions
Follow the third row of the live tables at the default prompt. After the position step the row for cat reads 0.6632, -0.7264, 0.2649, 1.1782. Attention’s contribution to it, which is the difference between the second and fourth tables, is 0.1897, -0.1005, -0.1018, -0.2512, and the feed-forward contribution in the fifth table is -0.5318, -0.1214, -0.1309, 0.3195. Each addition works coordinate by coordinate, and the second coordinate shows the pattern.
-0.7264 + (-0.1005) = -0.8269
-0.8269 + (-0.1214) = -0.9483The first sum is the second entry of the row after attention and the second sum is the second entry of the row that leaves the block, exactly as the fourth and sixth tables print them. The inputs shown are rounded to four places, so on another coordinate the last digit of a sum can differ from the table by one. Nothing in the second addition removed what the first had put there, and nothing in either removed the row the position step produced. That surviving row is the route the residual additions preserve.
Layer normalization standardizes coordinates within each token row. Our block normalizes before attention and before the feed-forward network. This is a pre-normalization arrangement; the original Transformer paper placed normalization after its residual additions.
Each addition can change the scale of a row, so a branch reads a standardized copy and meets values on the same scale whatever the earlier additions did. The copy is only what the branch reads. Its contribution is added to the un-normalized row, so the direct route is never rescaled inside the block, and the row is normalized once more only before the vocabulary projection in Part 3.
Part 2. Calculating One Decoder Block
3. Write the connections in their execution order
Let X contain the positioned token rows. LN means layer normalization, applied independently to each row. Attention is causal self-attention: each query can read its own position and earlier positions. The first addition produces H.
H = X + Attention(LN(X))
F = ReLU(LN(H) W₁ + b₁) W₂ + b₂
Y = H + FThe first feed-forward matrix expands the row into a wider intermediate representation. ReLU replaces negative intermediate values with zero. The second matrix returns to the model width so its contribution can be added to H. This implementation uses zero biases.
The SDK's attention projections store output units as matrix rows. The two feed-forward matrices shown here use input coordinates as rows, so they multiply on the right without a transpose. Their shapes, rather than their letters, determine the multiplication.
4. Check the dimensions before adding
The live block uses four coordinates per token, two attention heads, and eight intermediate feed-forward coordinates. For one token row, the transformations have these shapes:
Input row: (1, 4)
Expansion W₁: (4, 8)
Intermediate row: (1, 8)
Contraction W₂: (8, 4)
Branch output: (1, 4)
Residual output: (1, 4)The final row can enter another block with the same model width. A vocabulary projection after the final block turns these hidden coordinates into next-token scores.
Check yourself
Questions on Parts 1 and 2
Question 1 of 5
The feed-forward network uses a different set of weights at each position in the sequence.
Part 3. From a Block to a Language Model
5. Follow a NumPy forward pass
The reference decoder combines embeddings, sinusoidal positions, one pre-normalized block, final row normalization, and a vocabulary projection. It exposes its intermediate arrays so the causal relationship can be checked.
import numpy as np
from oop_ml.numpy.modern import CausalLanguageModel
model = CausalLanguageModel(n_vocab=7, n_model=4, n_heads=2)
trace = model.respond_to(np.array([0, 1, 2]))
print(trace.attention)
print(trace.logits)The check the live tables let you make
Set the last token to dog. The rows for <start> and the keep their values exactly in every table, not only to the displayed digits, because the causal mask stops those two positions reading the third one and so nothing they read has changed. The third row is the only one that moves. In the first head its shares across <start>, the and the last token go from 0.3988, 0.3307 and 0.2705 with cat to 0.1624, 0.4041 and 0.4335 with dog, and the third row of every later table follows.
This object implements inference with fixed seeded parameters. It does not implement whole-decoder training, cross-attention, padding masks, or a key/value cache. The attention primitive itself already supports differentiation; composing a complete training pipeline is a further step.
6. Distinguish the architecture from the learned behavior
Stacking blocks creates repeated opportunities to gather and transform information. Training determines which representations and comparisons are useful. Randomly initialized blocks have the structure of the computation but have not learned grammar, facts, or instruction following.
A decoder-only language model is one transformer arrangement. Encoders can use unmasked attention, and encoder-decoder models add cross-attention to another sequence. The causal decoder here is the arrangement we need for the next lessons.
The original paper introduces the attention-based encoder-decoder architecture. Our one-block causal example uses the pre-normalization variant described above. Attention Is All You Need.
Continue with Next-Token Prediction.
Check yourself
Questions on Part 3
Question 1 of 4
Which of these does the reference decoder leave unimplemented?
More than one of these may hold. Submit when you have them all.
Try it with Botie
Build with Botie
Write and run Python