Next-word prediction & the art of sampling
An LLM does one thing: given the tokens so far, it outputs a probability distribution over the next token. Everything else — chat, code, essays — falls out of running that prediction in a loop and choosing how to pick from the distribution. This lab lets you turn the knobs yourself: temperature, top-K, and top-P.
§1The autoregressive loop
"Autoregressive" means the model's own output is fed back in as input. One forward pass predicts
one token; generation is just this loop until the model emits the special
<eos> (end-of-sequence) token or hits a length cap.
Context in
The prompt plus every token generated so far, e.g. the cat sat on the
Model forward pass
One pass through the network produces a score (logit) for every token in the vocabulary — ~50,000 for GPT-2.
Softmax → probabilities
Logits become a probability distribution that sums to 1. Most mass sits on a few tokens; the rest is a long tail.
Sample one token
Greedy takes the argmax. Sampling draws randomly — shaped by temperature, top-K, and top-P.
§2Sampling lab
This is the lecture's Excel demo, made live. The model just saw
the cat sat on the and produced this distribution over what comes next.
Dashed outlines are the original probabilities; solid bars are what's left after your
settings rescale, filter, and renormalize. Then sample from it — a lot — and watch which
tokens actually get picked.
Try the classics: temperature 0.05 (≈ greedy — every draw is mat),
temperature 3 (near-uniform chaos — spaceship starts showing up),
top-K 3 (only three candidates survive no matter what), and
top-P 0.9 (the long tail is amputated but the head keeps its shape).
§2.5The last step: rolling a weighted die
Temperature, top-K and top-P all just reshape the menu — none of them actually picks.
The pick is a weighted random draw over whatever survived: lay the survivors end to end
along a line from 0 to 1, each owning a slice as wide as its probability, then draw a random
number and see where it lands. A token holding 47% of the line gets hit 47% of the time.
That is all torch.multinomial does — and it's the step do_sample=True
switches on.
There's no knob for this step because do_sample is the knob, and it's
binary: False gives you argmax and ignores temperature, top-K and top-P entirely;
True gives you this draw. Argmax is still reachable from inside sampling —
top-K 1 leaves one survivor owning the whole line, and temperature near 0 stretches
the leader across almost all of it. If you want repeatable output without giving up sampling,
the knob you actually want is the random seed: set_seed(42) makes the same prompt
and settings produce the same rolls every run.
§3Generation playground
A real (tiny!) language model running in your browser: a bigram model counted from a small corpus about cats, dogs, and mice. It predicts the next word from the current word only — but the autoregressive loop, EOS stopping, and sampling behavior are exactly what GPT-2 does at 50,000× the scale. Click any bar to force that token, or let it sample.
§4The same knobs in code
Everything you just did by hand maps one-to-one onto Hugging Face's
model.generate() — the exact call from the Colab exercise.
from transformers import AutoModelForCausalLM, AutoTokenizer, set_seed
tok = AutoTokenizer.from_pretrained("gpt2")
model = AutoModelForCausalLM.from_pretrained("gpt2")
ids = tok("The cat sat on the", return_tensors="pt").input_ids
set_seed(42) # same seed + same settings = same rolls, every run (§2.5)
out = model.generate(
ids,
max_new_tokens=40, # cap on the autoregressive loop (§1)
do_sample=True, # False → greedy argmax every step
temperature=0.8, # <1 sharper, >1 flatter (§2 slider 1)
top_k=50, # keep the 50 most likely tokens (slider 2)
top_p=0.95, # nucleus: smallest set covering 95% (slider 3)
eos_token_id=tok.eos_token_id, # the stop token
)
print(tok.decode(out[0]))
§5Test yourself
Eleven questions on everything in this chapter. Instant feedback, explanations included.
§6Key takeaways
<eos>.model.generate does under the hood.do_sample=False replaces that draw with argmax and makes the other knobs no-ops; set_seed makes the draws repeatable.