~/satyajit

architectures / transformer

The encoder–decoder Transformer, from first principles

mdjsonmcp

Encoder–decoder (seq2seq) · 2017 · Transformer · 9 min

  • cross-attention
  • seq2seq
  • translation
  • transformers
  • explainer

A 1:55 narrated explainer, drawn in code. Every number and picture in it is this page's own; the sources are below.

› transcript

Hi, I'm Galette! Translation needs a reader and a writer. Here's how one Transformer is both. An encoder reads the whole source at once. A decoder writes the target one token at a time, looking back at the source through cross-attention. The encoder reads the source both ways and hands over one vector per word: the memory. The decoder reads the target so far, masked so no word sees the future. Cross-attention: queries from the decoder, keys and values from the encoder. The newest word asks which source word matters. An MLP and a softmax pick the next word, which joins the target. In the encoder, every source word sees every other. In the decoder, each target word sees only its past. Training feeds it the true target, shifted right, and predicts every word at once. Across the bridge, no mask: every target word may read the whole source. To pretrain the pair, T5 corrupts text. Pick fifteen percent of the tokens, in short spans. Replace each span with a single placeholder. The encoder reads the sentence with holes. The decoder writes only what's missing. BART instead rebuilds the whole original. Each token, source or target, passes through only half the weights: about twenty-two million multiply-adds in the base model. But it needs a separate source, and every new chat turn means encoding again. A decoder-only model trains on any text with one loss, takes its task from the prompt, and simply appends. Two stacks, joined by cross-attention. One reads the source both ways. The other writes, looking back at it. Read it all, write it out, look back. Every source is in the full article. I'm Galette. Bye!

encoder–decoder transformer (seq2seq) · t5 / bart
encoder × Ndecoder × NAdd & NormFeed-ForwardAdd & NormSelf-Attentionbidirectionalinput embedding + posderHundbelltsource · GermanAdd & NormFeed-ForwardAdd & NormCross-AttentionK,V from encoderAdd & NormMasked Self-Attentioncausal · past onlyoutput embedding + pos[BOS]thedogtarget · shifted rightLinear → Softmaxoutput: barksencoder output → K,V

The encoder reads the whole source at once and produces a set of vectors; the decoder generates the target left-to-right, and at each step its cross-attention queries that encoder output — the one wire that turns two stacks into a translator.

The Transformer of Attention Is All You Need was a translation model, and it had two halves. An encoder reads the source sentence, German say, and turns it into one vector per source token. A decoder writes the English one token at a time, and at every layer it looks back at the encoder's vectors through cross-attention. Decoder-only language models kept the second half and dropped the first; BERT kept the first and dropped the second. This page is about the whole machine, the two families that made it a general-purpose pretrained model, T5 and BART, and why it mostly lost.

The worked numbers use the paper's base model: width d=512d = 512, 8 heads, an MLP of width 2,048, 6 encoder layers and 6 decoder layers.

The problem: one sequence in, another out

A sequence-to-sequence model estimates the probability of a target y=(y1,…,yT)y = (y_1, \dots, y_T) given a source x=(x1,…,xS)x = (x_1, \dots, x_S), one token at a time:

p(y∣x)=∏t=1Tp(yt∣y<t, x)p(y \mid x) = \prod_{t=1}^{T} p\big(y_t \mid y_{<t},\, x\big)

The source is known in full before generation starts; the target is not. That asymmetry is the whole design. The source can be read in both directions at once, so the encoder uses full attention; the target must be produced left to right, so the decoder is causal.

Before 2017 both halves were recurrent. Sutskever et al. squeezed the whole source into the encoder's final hidden state, one fixed-size vector. Bahdanau et al. argued that this vector was a bottleneck for long sentences, and let the decoder attend over all of the encoder's states at every step instead. That attention is the ancestor of cross-attention; the Transformer kept it and replaced the recurrence on both sides with self-attention.

The encoder

The encoder is a stack of blocks exactly like BERT's: self-attention with no causal mask, then an MLP, each wrapped in a residual add and a LayerNorm. Source token ii attends to every source token jj, left and right, so after 6 layers each of the SS vectors describes its token in the context of the entire sentence. The output is a matrix H∈RS×dH \in \mathbb{R}^{S \times d}, often called the memory. The encoder runs once per source; nothing in it depends on the target.

The decoder: three sublayers

Each decoder block has three sublayers where an encoder block has two:

  1. Masked self-attention over the target so far. The causal mask sets every score from target position tt to a later position to −∞-\infty, so yty_t is predicted only from y<ty_{<t}.
  2. Cross-attention into the encoder's output. The queries come from the decoder's stream; the keys and values come from HH:
CrossAttn(Y,H)=softmax ⁣((YWQ)(HWK)⊤dk)HWV\text{CrossAttn}(Y, H) = \text{softmax}\!\left(\frac{(Y W_Q)(H W_K)^{\top}}{\sqrt{d_k}}\right) H W_V

The score matrix is T×ST \times S, one score for every pair of a target position and a source position, and it has no mask: every target token may read the whole source. 3. The MLP, per position, as in any Transformer block.

After the last decoder block, a linear layer and a softmax give the next-token distribution. Three attentions, three shapes:

AttentionQueries fromKeys and values fromMaskScores
Encoder self-attentionsourcesourcenoneS×SS \times S
Decoder self-attentiontargettargetcausalT×TT \times T
Cross-attentiontargetencoder outputnoneT×ST \times S

Every decoder layer cross-attends to the same HH, the output of the encoder's last layer, not to the encoder layer at the same height. When translating "der Hund bellt" the decoder that has written "the dog" sends a query from its newest position, the keys of "der", "Hund" and "bellt" answer, and the values of the best match, "bellt", flow into the stream that will produce "barks".

Teacher forcing, and what happens at inference

Training uses teacher forcing. The decoder's input is the true target shifted right by one, a start token followed by y1,…,yT−1y_1, \dots, y_{T-1}, and its output at position tt is scored against yty_t. The causal mask keeps each position from seeing the answer, so one forward pass computes all TT predictions in parallel, each conditioned on the true prefix, and the loss is the summed cross-entropy −∑tlog⁡p(yt∣y<t,x)-\sum_t \log p(y_t \mid y_{<t}, x).

At inference there is no true prefix. The encoder runs once; then the decoder generates a token, appends it to its own input, and runs again, usually with beam search (the paper used a beam of 4). Two things are cached. The decoder's self-attention keys and values grow by one entry per generated token, as in any decoder. The cross-attention keys and values, HWKH W_K and HWVH W_V, are computed once per layer from the encoder output and never change. The model is trained on true prefixes and run on its own, possibly wrong, ones; that mismatch is called exposure bias.

Where the weights and FLOPs go

Counting matrix weights only, per layer, in units of d2d^2:

With d=512d = 512, d2=262,144d^2 = 262{,}144. Six encoder layers hold 18,874,368 matrix weights, six decoder layers 25,165,824, together 44,040,192; biases and LayerNorms add 98,304 more. The paper shares one embedding matrix between the source side, the target side and the output layer, and its English-German vocabulary has about 37,000 tokens, so the table adds about 18.9 million, for about 63 million in all. The paper's Table 3 lists 65 million for the base model.

The FLOPs are where it gets interesting. A cross-attention's four matrices act on two different streams: WQW_Q and WOW_O on each target token, WKW_K and WVW_V on each source token, once. So per layer pair:

Each token touches 14d214d^2 of the 28d228d^2 weights in a layer pair: half the model. With 6 layer pairs and d=512d = 512 that is 22,020,096 multiply-adds, about 44 million FLOPs, per token, source or target. A decoder-only model of the same parameter count runs every token through all of its weights, so it costs twice as much per token. This is the observation in T5: an encoder-decoder with LL layers in each stack has about the parameters of a 2L2L-layer language model and about the compute of an LL-layer one.

T5: every task as text to text, and span corruption

T5 (Raffel et al., 2019) turned the translation machine into a general pretrained model by making every task text in, text out. A prefix names the task: "translate English to German: …", "summarize: …", "cola sentence: …". Classification becomes generating the label's word. One model, one loss, one decoding procedure.

Its pretraining objective is span corruption. Pick 15% of the tokens, in spans averaging 3 tokens, replace each span with a single sentinel token, and train the decoder to output only the missing spans, each after its sentinel. The paper's own example:

The encoder sees a sentence with holes and full bidirectional context; the decoder writes a short target, so training is cheap. T5's base model mirrors BERT-base in each stack, 12 layers of width 768, about 220 million parameters, and its other choices became common: a 32,000-token SentencePiece vocabulary, pre-norm with a LayerNorm that has no bias, and relative position biases, one learned scalar per head for each of 32 distance buckets, added to the attention logits. The released sizes ran from 60 million to 11 billion. T5 also compared architectures on the same data, and the encoder-decoder with a denoising objective came out best.

BART: corrupt anything, rebuild everything

BART (Lewis et al., 2019) is the same machine, described as a BERT-like bidirectional encoder feeding a GPT-like left-to-right decoder, trained as a denoising autoencoder. Corrupt a document with any noise, and train the decoder to reproduce the original document in full, not just the missing pieces. The paper tried token masking, token deletion, sentence permutation, document rotation and text infilling: spans with lengths drawn from a Poisson distribution with mean 3, each replaced by a single mask token, including spans of length zero, so the model must also work out how many tokens are missing. Text infilling was the most consistently strong, and the large model combined it with sentence permutation, masking 30% of tokens and permuting all sentences. Reconstructing the whole input makes BART's decoder a strong generator: it set new state-of-the-art results on abstractive dialogue, question answering and summarization, with gains of up to 6 ROUGE.

Why decoder-only took over

T5's own comparison favoured the encoder-decoder, and it uses half its weights per token. Decoder-only models won anyway, for reasons that are mostly about generality at scale rather than quality per FLOP:

A controlled study, Wang et al. (2022), found that after self-supervised pretraining alone a causal decoder generalised best zero-shot, while a non-causal model trained on masked prediction and then multitask-finetuned did best overall.

The encoder-decoder survives where the input really is a different thing from the output. Whisper encodes 30-second chunks of audio spectrogram and decodes text; the Whisper hallucination article edits that decoder's activations. Translation systems such as NLLB-200 keep it. And the encoder half is often used alone: Imagen conditioned its image diffusion on a frozen T5-XXL encoder, and Breeze TTS 2 reads its text through a bidirectional T5Gemma2TextEncoder.

The block itself is the one on the Transformer page, used twice, joined by one extra attention whose queries and keys come from different sequences.

share