A modern LLM is a stack of identical transformer blocks (decoder-only variety), 30 to 120+ of them. Each block has the same structure:

flowchart TB
    IN["x  (input vector)"] --> N1["Norm"]
    N1 --> ATT["Attention<br/>tokens talk to each other"]
    ATT --> ADD1(("+"))
    IN ==>|"residual shortcut"| ADD1
    ADD1 --> N2["Norm"]
    N2 --> MLP["MLP<br/>each token thinks alone"]
    MLP --> ADD2(("+"))
    ADD1 ==>|"residual shortcut"| ADD2
    ADD2 --> OUT["x′  (output vector)"]

As equations (this is the “pre-norm” layout most modern models use):

The vector for each token flows up through the blocks, getting refined at each step. Think of the residual stream as a shared bus that each block reads from and writes small updates to.

8a. Self-attention

The important bit

The problem it solves: to understand a token, you often need information from other tokens. In “The trophy didn’t fit in the suitcase because it was too big,” what “it” refers to depends on context. Attention is the mechanism that lets each token gather relevant info from other tokens.

How it works. For every token’s vector , we compute three different vectors using three learned matrices:

VectorNameThink of it as
query”What am I looking for?“
key”What do I contain / advertise?“
value”What info do I hand over if you attend to me?”

Then for a sequence, stacking all tokens into matrices , , :

Breaking down the attention formula, one symbol at a time

PieceNameWhat it does
, , query, key, value matricesOne row per token. tokens → rows
K transposedFlip so rows become columns (so the multiply lines up)
raw scoresDot product of every query with every key → an grid. Entry = “how relevant is token to token ?“
scale factor is the length of each key vector. Dividing by its square root keeps the scores from getting huge
causal maskA grid of s and s that blocks looking at the future
normalizerTurns each row of scores into weights between 0 and 1 that sum to 1
weighted averageEach token’s output = weighted mix of all the value vectors

Step by step:

flowchart LR
    X["Token vectors X"] --> QKV["Make Q, K, V<br/>(3 matrix multiplies)"]
    QKV --> S["Scores<br/>Q·Kᵀ"]
    S --> SC["Scale<br/>÷ √d_k"]
    SC --> MK["Mask<br/>hide the future"]
    MK --> SM["Softmax<br/>rows sum to 1"]
    SM --> OUT["Weighted sum<br/>of V"]
  1. : dot product of every token’s query with every token’s key. This gives an matrix of raw relevance scores.

  2. : scaling so the dot products don’t get huge and push softmax into saturated, near-zero-gradient territory.

  3. (the causal mask): when predicting the next token, a token may only look at itself and earlier tokens, never the future (otherwise it would just copy the answer during training). Future positions get added so softmax makes them :

  4. softmax: turns each row of scores into weights that sum to 1. (Full formula in Sampling.)

  5. : each token’s output is the weighted average of all the value vectors, using those weights.

So attention is a learned, content-based, soft lookup. Each token asks a question (query), every earlier token offers a key, the best matches contribute their values.

Multi-head attention. Instead of one attention operation, run of them in parallel (e.g. 32 or 64 heads), each with its own smaller . Concatenate the results and mix with another matrix :

Different heads specialize in different things. Researchers have found heads that track syntax, heads that copy the previous occurrence of a token (induction heads, central to in-context learning), heads that attend to the previous token, and so on.

Cost note

The score matrix means attention cost grows quadratically with sequence length ( tokens → scores). That’s the main reason long context is expensive, and why a lot of engineering (FlashAttention, grouped-query attention, sliding windows) exists to cut the cost.

Try it

Watch attention run on real text, step by step, in 3D: Transformer Explainer and LLM Visualization.

8b. The MLP

After attention mixes information between tokens, the MLP (multi-layer perceptron, also called the feed-forward network) processes each token’s vector independently:

StepWhat happens
Expand the vector to a larger dimension (typically ~4× wider)
Apply the non-linearity (see Common activation functions)
Project back down to the original size

A gated variant like SwiGLU has a similar total size.

If attention is “communication between tokens,” the MLP is “computation within a token.” A big chunk of the model’s factual knowledge appears to be stored in these layers, acting like a fuzzy key-value memory. About two thirds of a transformer’s parameters live in the MLPs.

8c. Residual connections and normalization

Residual connection: each sublayer’s output is added to its input rather than replacing it:

This lets gradients flow straight back through the network during backprop (fixing the vanishing gradient problem that made deep nets impractical), and it makes each layer an incremental refinement instead of a total rewrite.

Normalization (LayerNorm / RMSNorm): rescales the vector at various points to keep numbers in a stable range. Without it, activations blow up or shrink across dozens of layers and training falls apart. Modern models usually apply it before each sublayer (“pre-norm”).


← 7. Embeddings · Contents · 9. Stacking it up and producing output →