Skip to content
The Generation Loop

01.02 · Walkthrough · Free

The Generation Loop

Trace the autoregressive generation loop: forward pass → sample token → append → repeat. Read Karpathy's generate function in nanoGPT.

This video is hosted by Klay so it plays even when YouTube blocks embedding.

Curated for this lesson

The Generation Loop

The Generation Loop

Best explanation of The Generation Loop from Andrej Karpathy.

Autoregressive generation is a small loop: run the model on the current tokens, read the final-position logits, choose the next token, append it, and repeat until a stop condition. The same shape appears in simple nanoGPT code and in production serving, with caching, batching and scheduling around it.

What this lesson answers

  • how does autoregressive text generation loop work
  • what does nanoGPT generate function actually do
  • why does KV cache change decode performance

Notes

The generation loop is the autoregressive inference algorithm that repeatedly computes next-token logits, selects one token, appends it to the context, and feeds the longer sequence back in: given tokens , run , sample or choose , then set and repeat until EOS or . In Karpathy’s nanoGPT, this is the core of `GPT.generate`: crop context to `block_size`, run `logits, _ = self(idx_cond)`, take `logits = logits[:, -1, :]`, optionally divide by `temperature`, optionally `top_k` filter, compute `probs = F.softmax(logits, dim=-1)`, draw `idx_next = torch.multinomial(probs, num_samples=1)`, then concatenate `idx = torch.cat((idx, idx_next), dim=1)`.

Example: suppose the prompt is token ids , vocabulary size , and the model’s last-position logits are . With temperature , , so multinomial sampling might draw token . Append it: , run the model again, and suppose the next logits are with probabilities , so token is drawn and appended. After two generated tokens, the sequence is ; the loop stops if token is EOS, or continues until `max_new_tokens` is reached.

1. Greedy decoding replaces sampling with ; for , greedy always picks token . 2. Temperature rescales logits: ; with , and , making outputs less random. 3. Top- keeps only the largest logits; with for , keep tokens , set others to , and get probabilities . 4. Without KV cache, step recomputes attention over the full prefix, costing roughly attention work across the generated sequence; with KV cache, each new step attends one query to cached keys, costing . 5. Context windows force cropping: if `block_size=4` and current tokens are $[10,42,7,1,2]`, nanoGPT feeds only `[42,7,1,2]` as `idx_cond`, so tokens before the window no longer affect logits.

In real serving systems, this same loop is split into a prefill phase and a decode phase: prefill processes the full prompt, then decode repeatedly runs one-token forward passes using the KV cache. In vLLM, see `LLMEngine.step()` scheduling requests, model execution through worker/model runner paths such as `vllm/worker/model_runner.py`, and sampling logic in `vllm/model_executor/layers/sampler.py`. In HuggingFace TGI, the loop is implemented around batching, prefill, decode, and token selection in the server code, especially `text-generation-inference/server/text_generation_server/models/` and generation/token selection utilities. In TensorRT-LLM, the runtime generation loop appears in executor/session paths such as `tensorrt_llm/runtime/generation.py`, `tensorrt_llm/runtime/model_runner.py`, and C++ executor backends that repeatedly launch optimized decode kernels.

Karpathy’s nanoGPT version is intentionally simple because it stores the whole growing tensor `idx` and calls the model each iteration; for prompt length and `max_new_tokens=2`, it performs two full forward calls over lengths and . Production systems instead maintain per-request state: `tokens=[10,42,7,1,2]`, `kv_cache` tensors per layer, stop flags, RNG state, and sampling parameters. The algorithmic shape is unchanged: . The engineering challenge is batching many such loops whose requests have different prompt lengths, generation lengths, and stopping times.

Common questions

What is the generation loop in a language model?
It is the repeated inference path used to produce text. The model receives the current token sequence, returns logits for possible next tokens, a decoding rule selects one token, and that token is added to the sequence. The updated sequence then becomes the input for the next step.
Why do we only use the last-position logits?
In autoregressive decoding, each position predicts the following token from the prefix up to that position. During generation you already have the prompt and any generated tokens, so the only prediction you need is the next token after the current end of the sequence. Earlier logits are not used for selection.
How do production servers change the basic loop?
They keep the same algorithmic structure but avoid waste around it. The prompt is processed first, then decoding proceeds token by token using cached keys and values. Serving systems also batch requests, track per-request state, apply sampling rules, and handle requests that stop at different times.