← ATTENTION & TRANSFORMERS / COURSE MAP
LESSON 07 / THE COMPLETE ARCHITECTURE

Encoder, decoder, or both?

Choose an architecture by following the available information, the output you need, and the objective used to train it.

On this page Explore the sections +
Before you begin Prerequisites & learning goal +

Builds on: Lesson 6: attention blocks, residual addition, layer normalization, and position-wise FFNs.

Your goal: Trace all three transformer families and choose a sensible starting point for classification, generation, or conditional sequence generation.

We can assemble the same ingredients in several ways. The words encoder and decoder are easiest to understand as descriptions of information flow and purpose, rather than as mysterious types of neural computation.

Ask three questions. What information is available when a prediction must be made? Does the output describe an existing input, or does it extend a sequence? If it generates a sequence, is there a separate source representation it should read?

1. An encoder contextualizes an available input

Our transformer encoder embeds the source tokens, adds positions, and applies blocks with bidirectional self-attention. Each non-padding token can incorporate information from all real source positions. The encoder returns a memory tensor of shape (B, S, D).

Those memory vectors are internal representations, not automatically class labels, vocabulary distributions, or a single sentence embedding. A task head turns them into the output required by a training objective.

For token labeling, a shared linear layer can map each vector to label scores. For sentence classification, one can use a designated summary token or a padding-aware pooling operation, followed by a classifier. For retrieval, one can train representations with an appropriate similarity objective. Merely averaging an arbitrary encoder’s outputs does not guarantee a good semantic embedding space.

BERT is a familiar encoder-family example. Its pretraining includes masked-token prediction using bidirectional context. This is different from asking a causal language model to predict a token from only its prefix; both the allowed information and the training objective differ.

2. A decoder-only model extends a prefix

An autoregressive model factorizes a sequence probability as:

$$ p(y_1,\ldots,y_T)=\prod_{t=1}^{T}p(y_t\mid y_1,\ldots,y_{t-1}). $$
READ THE EQUATION

Factor a sequence’s probability into next-token probabilities, each conditioned on the earlier tokens.

TermWhat it is and doesWhat it controls
\(y_1,\ldots,y_T,T\)Output tokens in order and sequence length.The complete sequence whose probability is evaluated.
\(p\)A probability assigned by the model.How much probability mass it gives a sequence or next token.
\(\prod_{t=1}^{T},t\)Product symbol: multiply one conditional probability at each position t.Combines next-token factors into a sequence probability.
Vertical conditioning barRead as given, not division.Specifies which earlier tokens the model may use.
\(y_1,\ldots,y_{t-1}\)Prefix before the token being predicted; the first step uses a start convention.Prevents conditioning on future target tokens.

Check: If a two-token sequence has first-token probability 0.5 and second-token conditional probability 0.2, its probability is 0.1. The product describes the training objective’s factorization, not a claim that all choices are independent.

A decoder-only transformer embeds the prefix, applies causal self-attention blocks, and maps the hidden states to vocabulary logits. It has no separate encoder memory and therefore no encoder–decoder cross-attention sublayer.

At training time, shifted targets let us evaluate many next-token losses in parallel. At generation time, we use the final prefix position’s logits to select the next symbol. Then that symbol becomes part of the next input prefix. Greedy choice, sampling, and beam search are different decoding policies applied to model outputs; they are not different attention mechanisms.

You can condition such a model by placing context or instructions in the prefix. That is why a separate encoder is not a strict requirement for tasks such as translation or summarization. The training formulation and the available checkpoint matter.

3. An encoder–decoder keeps source and target streams separate

For conditional generation, write:

$$ p(y\mid x)=\prod_t p(y_t\mid y_{
READ THE EQUATION

Predict each target token using both the earlier target prefix and the available source.

TermWhat it is and doesWhat it controls
\(x,y\)Source sequence and target sequence. These are whole streams in this equation, not scalar numbers.What is provided and what must be predicted.
\(p(y\mid x)\)Conditional probability of the target given the source.The sequence-to-sequence prediction objective.
\(\prod_t,y_t\)Multiply one probability factor for each target token.Builds the full target likelihood from local next-token decisions.
\(y_{Shorthand for all target tokens before position t.Autoregressive target context; no future target is included.
\(\mid y_{Condition on that prefix and the source.Adds source information to the decoder’s own prefix information.

Check: When translating, the first output token can use the entire supplied source but no previous target words. A later output can use that same source and the words already generated.

The encoder reads x once and creates source memory. The decoder builds target-side states from the prefix. Each decoder block can then retrieve source information through cross-attention.

Our decoder block has three sublayers: causal self-attention, cross-attention, and the FFN. Each has a pre-norm input and a residual update. For the cross-attention operation, target-side states supply Q, while encoder memory supplies K and V.

Source and target can differ in length, vocabulary, or even modality. An image encoder can supply visual features to a text decoder. An audio encoder can supply acoustic representations. The source representation must fit the cross-attention projections; it need not consist of the same kind of tokens as the target.

VISUAL WALKTHROUGHALL STEPS
Three architectures, different information contracts
1 / Encoder only: describe the available input
ENCODER / READ THE SOURCEDECODER / PREDICT THE NEXT TOKENSOURCE IDs → EMBEDDING+ POSITIONBIDIRECTIONAL SELF-ATTENTION+ FFN, RESIDUALS, NORMSMEMORY [B,S,D]TARGET PREFIX → EMBEDDING+ POSITIONCAUSAL SELF-ATTENTION+ RESIDUAL, NORMFFN + RESIDUAL, NORMNO ENCODER MEMORYVOCABULARY LOGITS [B,T,V]TASK HEAD: LABELS OR EMBEDDINGS

Use bidirectional source representations with a task head. The full input is available. The faded target stream is not part of this architecture.

2 / Decoder only: extend a prefix
ENCODER / READ THE SOURCEDECODER / PREDICT THE NEXT TOKENSOURCE IDs → EMBEDDING+ POSITIONBIDIRECTIONAL SELF-ATTENTION+ FFN, RESIDUALS, NORMSMEMORY [B,S,D]TARGET PREFIX → EMBEDDING+ POSITIONCAUSAL SELF-ATTENTION+ RESIDUAL, NORMFFN + RESIDUAL, NORMNO ENCODER MEMORYVOCABULARY LOGITS [B,T,V]

Use causal self-attention and a vocabulary head. There is no separate source-memory stream. Context, when needed, can be represented in the prefix itself.

3 / Encoder–decoder: generate while reading a source
ENCODER / READ THE SOURCEDECODER / PREDICT THE NEXT TOKENSOURCE IDs → EMBEDDING+ POSITIONBIDIRECTIONAL SELF-ATTENTION+ FFN, RESIDUALS, NORMSMEMORY [B,S,D]TARGET PREFIX → EMBEDDING+ POSITIONCAUSAL SELF-ATTENTION+ RESIDUAL, NORMCROSS-ATTENTION + FFNQ FROM TARGET; K,V FROM MEMORYVOCABULARY LOGITS [B,T,V]SOURCE AND TARGET MAY DIFFER IN LENGTH.

Encode the source into memory. The decoder uses causal target self-attention and an additional cross-attention operation over that memory. Source availability and target causality are separate rules.

One operation at a time. Use the arrows or step buttons; nothing advances automatically.

4. Implement the decoder block

This extends the encoder-style block from lesson 6 with a second attention sublayer. Read the arguments to each call before reading the variable names. They tell you which stream is being queried.

PYTHON
NumPy / inspect the operations
class DecoderBlock:
    def __init__(self, width: int = 32, heads: int = 4, inner: int = 64, seed: int = 20) -> None:
        self.self_attn = MultiHead(width, heads, seed)
        self.cross_attn = MultiHead(width, heads, seed + 1)
        self.ffn = ffn_parameters(width, inner, seed + 2)

    def __call__(self, y: FloatArray, memory: FloatArray, target_visible: BoolArray, source_visible: BoolArray) -> FloatArray:
        normalized = layer_norm(y)
        y = y + self.self_attn(normalized, normalized, target_visible)[0]
        y = y + self.cross_attn(layer_norm(y), memory, source_visible)[0]
        return y + feed_forward(layer_norm(y), *self.ffn)

Typed Python · Shapes are documented alongside the code. Open the full file for imports and dependencies, or step through a concrete example.

The memory tensor remains the encoder output throughout the decoder block. The target state y is updated after each sublayer. In our model, source memory has already passed through a final encoder normalization; the target stream uses a separate normalization before forming cross-attention queries.

Repeated decoder blocks would have their own parameters. “Stacking identical blocks” means identical structure, not necessarily shared weights. Our small model uses one block per side so its complete computation remains easy to inspect.

5. The same block structure can serve different tasks

The following forward demonstrations show an encoder-only classifier and a decoder-only next-token predictor. The latter reuses our two-sublayer block with a causal mask. Its class is called EncoderBlock because that is where we introduced it, but the mask changes the information it can access. The class name alone does not make it bidirectional.

PYTHON
NumPy / inspect the operations
def architecture_demo() -> tuple[FloatArray, FloatArray]:
    source = np.array([[4, 7, 9], [6, 8, 0]])
    prefix = np.array([[1, 4, 7], [1, 6, 8]])
    width, vocabulary = 32, 12
    rng = np.random.default_rng(8)
    embedding = rng.normal(size=(vocabulary, width))
    source_mask, target_mask = attention_masks(source, prefix)
    x = embedding[source] + positions(source.shape[1], width)
    y = embedding[prefix] + positions(prefix.shape[1], width)

    # Encoder-only: pool only real source positions for classification.
    encoded = layer_norm(EncoderBlock()(x, source_mask))
    real = (source != 0)[..., None]
    pooled = (encoded * real).sum(1) / real.sum(1)
    class_logits = pooled @ rng.normal(size=(width, 3))

    # Decoder-only: same two-sublayer structure, with CAUSAL visibility.
    causal_hidden = layer_norm(EncoderBlock(seed=30)(y, target_mask))
    next_token_logits = causal_hidden @ rng.normal(size=(width, vocabulary))
    return class_logits, next_token_logits  # (2, 3), (2, 3, 12)

Typed Python · Shapes are documented alongside the code. Open the full file for imports and dependencies, or step through a concrete example.

Run architecture_demo() from either full source file. The outputs have shapes (2, 3) for three sentence classes and (2, 3, 12) for twelve vocabulary scores at each prefix position. They are random, untrained logits; the example demonstrates architecture and shape, not task performance.

The PyTorch helper creates its modules inside the function for a one-off forward demonstration. A reusable trainable model stores its modules on an nn.Module instance, as our final TinyTransformer does. Recreating layers on every training call would reset their weights and prevent learning across calls.

6. Choosing a starting point

What you needA sensible starting pointReason to consider it
Classify a complete documentEncoder + classifierAll document tokens are available for contextualization
Label each tokenEncoder + token headEach label can use surrounding input context
Build a retrieval representationEncoder + pooling and suitable trainingA fixed-size representation can be indexed and compared
Continue text or generate codeDecoder-only modelThe next-token objective matches prefix continuation
Translate or summarize a separate sourceEncoder–decoder, or a suitably trained decoder-only modelBoth can express conditioning; compare the training setup and constraints
Generate text from image or audio featuresSource encoder + decoder cross-attention is one optionCross-attention provides an explicit interface between representations

These are starting points, not exclusive capability boundaries. For example, a decoder-only model can classify through a prompted label or a learned head, and an encoder can participate in iterative or non-autoregressive generation systems. What matters is the actual computation, objective, and inference procedure.

A useful engineering distinction is reuse. An encoder–decoder can encode the source once, then repeatedly query that memory during generation. A decoder-only model can reuse prefix keys and values through caching. Neither design removes all costs associated with long context.

7. “Decoder” does not always mean causal text generation

Outside autoregressive language modeling, the same word is used for other transformations from internal representations to task outputs. DETR , for example, uses object queries to decode a set of detections. Its object-query decoder is not simply a left-to-right text generator with a vocabulary head.

When reading another paper, inspect the query source, the masks, and the output head. Do not infer causality from the word “decoder” alone. This is especially useful when moving between language and computer vision.

CHECK YOUR UNDERSTANDINGA model has no encoder, but its prompt contains a source document. Can it still generate a summary conditioned on that document?Think first. Open to check your reasoning.

Yes. A decoder-only formulation can place the source document in the prefix and generate the summary afterward. That differs structurally from cross-attending to separately encoded memory, but both can model source-conditioned output. Suitability depends on training, available models, and inference constraints.

Our choice for the final experiment

We will use an encoder–decoder for copying integer sequences. It gives us an explicit source/target separation and exercises all three kinds of attention from lesson 4. This is a pedagogical choice: copying could be formulated in other ways, but this version makes every component we have learned visible in one model.

END OF LESSON 07