Autoregressive Models (GPT-style)

Autoregressive generative models produce data one element at a time, each conditioned on everything generated so far. GPT-style large language models are the best-known example: a decoder-only transformer trained to predict the next token. The same recipe has been applied to images (PixelCNN, Image GPT, DALL-E 1, Parti), audio (WaveNet) and code.


1. The Chain-Rule Factorization

Autoregressive Factorization Thex1 catx2 satx3 onx4 thex5 ? → "mat"p(x6 | x1..x5) p(x) = ∏ p(xₜ | x₁ … xₜ₋₁) — exact likelihood, trained with next-token cross-entropy.

Any joint distribution can be written exactly as a product of conditionals: p(x1, …, xT) = ∏t p(xt | x<t). An autoregressive model parameterizes each conditional with a neural network and trains by maximum likelihood, i.e. minimizing the cross-entropy between predicted and actual next tokens. Unlike GANs or diffusion, the likelihood is exact, which makes perplexity (exp of mean loss) a direct quality metric.

2. Decoder-Only Transformer

Decoder-Only Transformer with Causal Mask Tokens + positionsembedding N × blockmasked self-attentionMLP, residual + norm LM headlinear → vocab softmaxnext token causal mask: query i attends only to keys j ≤ i blue = allowed, dark = masked to −∞ before softmax Training: all positions predicted in parallel (teacher forcing). Inference: one token at a time, reusing a KV cache.

Text is tokenized (usually BPE or unigram subwords) and embedded. Each block applies causally masked multi-head self-attention, then an MLP, with residual connections and normalization (pre-norm with RMSNorm is common now). Positions come from learned embeddings or rotary position embeddings (RoPE). Because the mask hides future tokens, a single forward pass yields a loss at every position, so training is fully parallel even though generation is sequential.

3. A Tiny GPT in PyTorch

import torch, torch.nn as nn, torch.nn.functional as F

class Block(nn.Module):
    def __init__(self, d, h):
        super().__init__()
        self.ln1, self.ln2 = nn.LayerNorm(d), nn.LayerNorm(d)
        self.attn = nn.MultiheadAttention(d, h, batch_first=True)
        self.mlp = nn.Sequential(nn.Linear(d, 4 * d), nn.GELU(), nn.Linear(4 * d, d))
    def forward(self, x):
        T = x.size(1)
        mask = torch.triu(torch.ones(T, T, dtype=torch.bool, device=x.device), 1)  # True = blocked
        a = self.ln1(x)
        x = x + self.attn(a, a, a, attn_mask=mask, need_weights=False)[0]
        return x + self.mlp(self.ln2(x))

class TinyGPT(nn.Module):
    def __init__(self, vocab, d=128, h=4, n=4, ctx=128):
        super().__init__()
        self.ctx = ctx
        self.tok, self.pos = nn.Embedding(vocab, d), nn.Embedding(ctx, d)
        self.blocks = nn.Sequential(*[Block(d, h) for _ in range(n)])
        self.ln, self.head = nn.LayerNorm(d), nn.Linear(d, vocab, bias=False)
    def forward(self, idx):
        pos = torch.arange(idx.size(1), device=idx.device)
        return self.head(self.ln(self.blocks(self.tok(idx) + self.pos(pos))))

text = open("input.txt").read()                    # any plain-text corpus
chars = sorted(set(text)); stoi = {c: i for i, c in enumerate(chars)}
data = torch.tensor([stoi[c] for c in text])
model = TinyGPT(len(chars)); opt = torch.optim.AdamW(model.parameters(), lr=3e-4)

for step in range(3000):
    ix = torch.randint(len(data) - 129, (32,))
    x = torch.stack([data[i:i + 128] for i in ix]); y = torch.stack([data[i + 1:i + 129] for i in ix])
    loss = F.cross_entropy(model(x).view(-1, len(chars)), y.view(-1))
    opt.zero_grad(); loss.backward(); opt.step()

@torch.no_grad()
def generate(idx, n, temperature=0.8, top_k=20):
    for _ in range(n):
        logits = model(idx[:, -model.ctx:])[:, -1] / temperature
        v, _ = torch.topk(logits, top_k); logits[logits < v[:, [-1]]] = -float("inf")
        idx = torch.cat([idx, torch.multinomial(F.softmax(logits, -1), 1)], 1)
    return "".join(chars[i] for i in idx[0].tolist())

print(generate(torch.zeros(1, 1, dtype=torch.long), 300))

4. Decoding

Decoding Loop and Sampling Strategies Contextprompt + so far Modellogits for vocab Samplingtemp, top-k, top-p Append tokenstop on EOS / max Greedy / beam search: deterministic, can be repetitive. Temperature < 1 sharpens, > 1 flattens. Top-p keeps the smallest token set with cumulative probability ≥ p.

Generation cost grows with output length: each token needs a forward pass. The KV cache stores keys and values from previous positions so each step only computes the new token, turning quadratic recomputation into linear work per step, at the cost of memory proportional to context length. Speculative decoding uses a small draft model to propose several tokens that the large model verifies in one pass.

5. Strengths, Weaknesses, Pitfalls

6. A Worked Example: Loss and Perplexity

Take the four-token sequence "the cat sat down". Training feeds "the cat sat" and asks the model to predict "cat", "sat" and "down" at positions 1, 2 and 3 in a single forward pass. Suppose the model assigns probability 0.20 to "cat" after "the", 0.50 to "sat" after "the cat", and 0.25 to "down" after "the cat sat". The per-token losses are the negative logs: −ln 0.20 ≈ 1.61, −ln 0.50 ≈ 0.69, −ln 0.25 ≈ 1.39. The mean cross-entropy is about 1.23 nats, and perplexity is e1.23 ≈ 3.4. Intuitively, the model is on average as uncertain as if it were choosing uniformly among about 3.4 tokens.

Perplexity is only comparable between models that share a tokenizer and evaluation text: a tokenizer that splits words into more pieces produces more, easier predictions and a lower per-token perplexity for the same underlying quality. Compare in bits per byte or bits per character when tokenizers differ.

The same factorization explains the training-inference gap. During training every prefix comes from real data (teacher forcing). At inference the prefix comes from the model's own samples, so a single unlikely choice early on shifts every later conditional — the "exposure bias" mentioned above.

7. Sampling Strategies in Detail

Decoding Strategies on One Next-Token Distribution Logits one score per vocabulary token Temperature T divide logits by T T<1 sharper Top-k filter keep k best tokens Top-p (nucleus) smallest set with mass p Greedy / beam argmax, deterministic Sample draw from renormalised p greedy skips temperature and filtering: always take the top token

The model only outputs a distribution; the decoding rule decides what text you actually see, and it matters as much as the weights for perceived quality.

MethodHow it worksGood forFailure mode
GreedyAlways take the most likely tokenShort deterministic outputs, classification-style promptsRepetition loops, bland text
Beam searchKeep the b best partial sequences by total log-probabilityTranslation, summarizationFavours short, generic outputs in open-ended generation
TemperatureDivide logits by T before softmaxControlling diversityHigh T produces incoherence
Top-kSample only among the k most likely tokensCutting the long tailFixed k is too narrow for flat distributions and too wide for peaked ones
Top-p (nucleus)Sample from the smallest set whose probability sums to pGeneral chat and creative writingStill can drift on long generations

Common starting points are temperature 0–0.3 for extraction, code and tool calls, and temperature around 0.7 with top-p 0.9–0.95 for open-ended writing. Repetition and frequency penalties lower the logits of tokens already generated. For outputs that must parse, constrained decoding masks any token that would violate a grammar or JSON schema — see Function Calling and Structured Output.

8. Autoregressive vs Other Generative Families

AutoregressiveDiffusionGANVAE
LikelihoodExactLower boundNoneLower bound (ELBO)
SamplingOne step per tokenTens of denoising stepsOne forward passOne forward pass
Natural dataDiscrete sequences (text, code, tokens)Continuous signals (images, audio)ImagesLatent representations
Main weaknessSequential latency, no revisionMany stepsUnstable training, mode collapseBlurry samples

The families also combine. DALL-E 1 and Parti first compress images into discrete tokens with a VQ-VAE or ViT-VQGAN and then model those tokens autoregressively; latent diffusion uses a VAE for compression and diffusion for generation. Audio models such as WaveNet were autoregressive over raw samples, which is accurate but slow, and later systems moved to codec tokens to shorten the sequence.

9. Serving and Scaling Notes

10. Further Reading