Decoder Architecture › The Generation Loop

Michael BrenndoerferUpdated June 19, 20253 min read
Language AI HandbookAll chapters
Part 16 of 67Transformer Architectures
Chapter 112Decoder Architecture › The Generation Loop
Reading section 9 of 16 · The Generation Loop · 3 minSection 9 of 16 · 3 min

Book contents

Section 9 of 16 · 3 min read

Decoder Architecture › The Generation LoopOne section · Sections in this chapter9 / 16 ↓
Reading tools Definitions & inline links

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

At inference time, the decoder generates text autoregressively. Each iteration:

  1. Processes the current sequence through all decoder blocks
  2. Takes the logits at the final position
  3. Samples or greedily selects the next token
  4. Appends that token to the sequence
  5. Repeats until a stopping condition
In[21]:
Code
def generate(model, prompt_tokens, max_new_tokens=20, temperature=1.0):
    """
    Generate tokens autoregressively.

    Args:
        model: GPTDecoder instance
        prompt_tokens: Initial token indices
        max_new_tokens: Maximum tokens to generate
        temperature: Sampling temperature (higher = more random)

    Returns:
        Complete sequence including prompt and generated tokens
    """
    tokens = list(prompt_tokens)

    for _ in range(max_new_tokens):
        # Get current sequence length
        current_len = len(tokens)
        if current_len >= model.max_seq_len:
            break

        # Forward pass
        token_array = np.array(tokens)
        logits = model(token_array)

        # Get logits for next token prediction (last position)
        next_logits = logits[-1]  # (vocab_size,)

        # Apply temperature
        if temperature != 1.0:
            next_logits = next_logits / temperature

        # Convert to probabilities
        probs = softmax(next_logits)

        # Sample next token
        next_token = np.random.choice(len(probs), p=probs)
        tokens.append(next_token)

        # Simple stop condition: token 0 is end-of-sequence
        if next_token == 0:
            break

    return np.array(tokens)


# Generate from a prompt
prompt = np.array([42, 100, 256])
generated = generate(model, prompt, max_new_tokens=10, temperature=0.8)
Out[22]:
Console
Autoregressive Generation Demo
=============================================
Prompt tokens: [42, 100, 256]
Generated tokens: [42, 100, 256, 2986, 4309, 6020, 5662, 6276, 348, 3626, 1098, 6231, 3138]
New tokens: 10

The model generated 10 new tokens from the 3-token prompt. Since this is a randomly initialized model (not trained on any text), the generated token IDs are essentially random samples from the vocabulary. A trained model would produce coherent continuations. The temperature of 0.8 makes the distribution slightly sharper than pure random sampling, biasing toward higher-probability tokens.

Let's visualize how temperature affects the sampling distribution. Lower temperatures concentrate probability mass on the highest-scoring tokens, while higher temperatures flatten the distribution:

Out[23]:
Visualization
Line plot showing three probability distributions over token indices with different temperatures. This shows how lower temperatures create sharper peaks.
Effect of temperature on token probability distribution. Temperature=0.5 (blue) sharpens the distribution, concentrating probability on high-scoring tokens. Temperature=1.0 (orange) preserves the original logit ratios. Temperature=2.0 (green) flattens the distribution, making unlikely tokens more probable.

At temperature 0.5, the top tokens dominate the distribution, making generation more deterministic. At temperature 2.0, even low-scoring tokens have non-negligible probability, introducing more randomness and diversity. The choice of temperature trades off between coherence (low temperature) and creativity (high temperature).

In practice, generation involves beam search, top-k sampling, nucleus sampling, and other decoding strategies to balance quality and diversity. The decoder architecture itself doesn't change; only the sampling logic varies.