4.1.10 · D2Transformer Architecture

Visual walkthrough — Encoder vs decoder vs encoder-decoder

2,178 words10 min readBack to topic

This page builds the whole story of Encoder vs Decoder vs Encoder-Decoder from a single idea: who is allowed to look at whom. Everything else — BERT, GPT, T5, translation, generation — falls out of that one choice.

We start from zero. No prior notation is assumed. Every symbol is earned before it is used.


Step 1 — The row of tokens and their three vectors

WHAT. We line up the input as a sequence of tokens. A token is just one chunk of text (a word or word-piece). We write the sequence as

  • — the tokens in order, position first.
  • — how many tokens there are (the length).

Each token is turned into a list of numbers (a vector). From that vector we compute three new vectors by multiplying with three learned number-grids (matrices) :

  • — the embedding vector of token (its raw meaning as numbers).
  • — the query: "what is token looking for?"
  • — the key: "what does token advertise about itself?"
  • — the value: "what does token hand over if you attend to it?"

WHY three? Because looking is a matching game. A query from one token is compared against the keys of others; wherever query and key match well, that token's value gets pulled in. Splitting the roles (asking / advertising / delivering) is what lets attention be selective. See Self-Attention Mechanism.

PICTURE.

Figure — Encoder vs decoder vs encoder-decoder

Step 2 — Scoring: how strongly should look at ?

WHAT. For token looking at token , we measure how well the query matches the key using the dot product:

  • — the raw score (a single number) for " attending to ".
  • — the dot product: multiply the vectors component-by-component, add it all up.
  • large positive they point the same way strong relevance; near zero unrelated.

WHY the dot product and not something else? We need a single number that grows when two vectors agree in direction. The dot product is exactly that: it is large when the query and key are aligned. It answers the question "how relevant is to ?" cheaply, with one multiply-and-add.

Then we scale by :

  • — the length (number of components) of each key vector.
  • — the shrink factor.

WHY divide by ? Adding up products makes the score grow roughly like just by chance. If scores get huge, the next step (softmax) collapses to "all attention on one token" and the gradient dies. Dividing by keeps the numbers in a healthy range.

PICTURE.

Figure — Encoder vs decoder vs encoder-decoder

Step 3 — Softmax: turning scores into a peek-budget

WHAT. Each token has a fixed amount of "attention" (total ) to spread over the tokens it may look at. Softmax converts the raw scores into that spread:

  • — the exponential; it makes every value positive and blows up big scores.
  • numerator — the un-normalised weight for token .
  • denominator — the sum over all tokens is allowed to see; dividing forces the weights to add to .
  • — the final attention weight: the fraction of 's peek-budget spent on .

WHY softmax? We want a set of positive numbers that sum to — a probability distribution — so "attention" behaves like a budget. Softmax is the smooth, differentiable way to do this, and the exponential rewards the best-matching token most.

The new representation of token is the budget-weighted blend of values:

  • — mix each value by its weight; tokens with big dominate the blend.
  • — token 's new, context-aware vector.

PICTURE.

Figure — Encoder vs decoder vs encoder-decoder

Step 4 — The mask: the ONE knob that makes three architectures

WHAT. The word "all " in the softmax denominator hides a choice. We control which are allowed by adding a mask matrix before softmax:

  • — token may look at token (score unchanged).
  • — token may not; because , that weight becomes exactly zero.

Two choices of give us two rules (see Attention Masking):

WHY and not just -weighting afterwards? If we zeroed weights after softmax, the denominator would still have counted the forbidden tokens and the budget wouldn't sum to . Injecting before softmax removes them cleanly, so the remaining weights still add to exactly .

WHY causal at all? When a decoder generates word , words do not exist yet. Letting position peek right would be cheating — training on answers it won't have at generation time. The lower-triangular mask enforces "left-only". This is Causal Language Modeling; the all-ones mask powers Masked Language Modeling.

PICTURE.

Figure — Encoder vs decoder vs encoder-decoder

Step 5 — Encoder-only: everyone peeks at everyone (BERT)

WHAT. Set everywhere. Now token blends values from tokens — past and future. Stack such layers; each refines the blend:

  • — token 's vector after layer .
  • — all tokens from the previous layer feed into the next.
  • — total number of stacked layers.

WHY bidirectional? To understand, a word needs its whole surroundings. "bank" in "river bank" versus "bank account" only disambiguates if it sees words on both sides at once. See BERT.

PICTURE.

Figure — Encoder vs decoder vs encoder-decoder

Step 6 — Decoder-only: peek left only (GPT)

WHAT. Use the causal mask. Position blends only . To predict the next token:

  • — all tokens before position .
  • — depends only on (never the future).

The whole-sequence probability factors by the chain rule:

  • — multiply the per-step probabilities.
  • Each factor is one causal prediction; multiplying them gives the joint probability, exactly like .

WHY this shape? Autoregressive Generation: generate one token, append it, feed it back, repeat. The left-only rule is what makes training match generation. See GPT.

PICTURE.

Figure — Encoder vs decoder vs encoder-decoder

Step 7 — Encoder-decoder: two rows joined by cross-attention (T5)

WHAT. Now run both rules together. The source goes through a bidirectional encoder; the target goes through a causal decoder — but the decoder adds a third kind of attention, cross-attention, that lets it read the encoder's outputs:

Here the roles are split across rows:

  • — query from the decoder (what the output word is asking for). is the decoder's causal self-attention output at step .
  • — key from the encoder (what each source word offers).
  • — value from the encoder (the source information delivered).

WHY cross-attention? In translation the decoder must look at the whole source while still not peeking at its own future. Self-attention (causal) handles the growing target; cross-attention (unmasked, over the source) handles the input. See Cross-Attention, Sequenceto-Sequence Models, and T5.

One decoder layer, in order: (1) causal self-attention on , (2) cross-attention into the encoder, (3) a feed-forward mix. Prediction:

PICTURE.

Figure — Encoder vs decoder vs encoder-decoder

Step 8 — Degenerate and edge cases (never leave a gap)

WHAT / WHY / PICTURE, four corner cases:

  1. (single token). Softmax over one item gives . In any architecture the token just returns its own value — nothing to attend to. Causal and bidirectional coincide here.
  2. First decoder position (, causal). The mask allows only , so position attends to itself alone: . A decoder's very first step has no left context — it leans entirely on the prompt/cross-attention.
  3. All scores equal. If every is the same, softmax gives uniform weights — attention degenerates to a plain average. This is the "no preference" baseline before training sharpens it.
  4. Empty source in encoder-decoder (). No keys/values exist, so cross-attention has nothing to sum over — the decoder collapses to a pure decoder-only model. This shows the three architectures are one family: turn the source off and encoder-decoder is a decoder.
Figure — Encoder vs decoder vs encoder-decoder

The one-picture summary

Everything above is one pipeline — score, scale, mask, softmax, blend — with only the mask changed, plus an optional cross-attention bridge.

Figure — Encoder vs decoder vs encoder-decoder
Recall Feynman retelling — say it like a story

Line up the words. Give each word three name-tags: a question (query), a label (key), and a gift (value). To update a word, hold up its question and compare it against every label you're allowed to read — the closeness score is just a dot product. Divide the scores by so they don't explode, then softmax them into a budget of attention that adds to one. Blend the gifts by that budget: that's the word's new, context-rich vector.

Now the only real choice: who may you read? If everyone may read everyone, you understand (BERT-style encoder). If you may only read to your left, you can generate one word at a time without cheating on the future (GPT-style decoder). If you want to translate, run both: an encoder reads the whole source, and a left-only decoder writes the target while a cross-attention bridge lets each output word peek at the entire source. Turn the source off and the translator becomes a plain generator — proof they're all the same machine wearing different masks.

Recall Quick self-test

Why divide the score by ? ::: Scores grow like by chance; dividing keeps softmax from saturating and gradients from dying. Why put in the mask before softmax, not zero the weight after? ::: So the softmax denominator never counts forbidden tokens — the remaining weights still sum to exactly . What single thing turns an encoder into a decoder? ::: The mask: all-zeros (bidirectional) → lower-triangular (causal). In encoder-decoder cross-attention, where do , , come from? ::: from the decoder, and from the encoder outputs. What happens to cross-attention if the source is empty? ::: Nothing to attend to — the model reduces to decoder-only.