Part one of a five-part walkthrough of what happens between your prompt and the next token.
Every part uses one reference model, Qwen2.5-0.5B, so the numbers line up from start to finish.
See the whole series →
Part 1 of 5 — How an LLM generates one token
PART ONE · ONE TOKEN, END TO END · reference model Qwen2.5-0.5B
Everything a model does to generate one token.
Type “The apple is sweet” and the model generates one token. To continue, it runs the same pipeline again with that token added to the context. This page takes one pass apart: CPU work in blue, GPU work in green, a diagram for each stage, and two 3-D benches that show the tensor moving through the model.
Blue is the host - i.e. the CPU. Green is the device - i.e. the GPU. The top green row is the forward pass through depth; the bottom green row is the head that turns 896 numbers into vocabulary scores. Click any block to jump to its explanation.
CPU / hostGPU / devicetemperaturethe surviving row, and the token it becomes
B
Ten stops, one token
Each stop names the tensor it produces and its shape. Following those shapes keeps the operations tied to concrete data.
0CPU
A string arrives
The tokenizer receives a byte sequence. After tokenization, the model answers one question: given the vocabulary entries so far, which entry comes next?
At this point nothing explicitly marks sweet as an adjective or says that the sentence may end. Those relationships have to emerge from the computations that follow.
in: "The apple is sweet" · out: bytes[18]
1CPU
Tokenizer. Tokenize, then look up ids
Byte-pair encoding merges frequent adjacent pairs until nothing in its learned merge list applies. The result is a list of vocabulary entries, and each entry has a fixed integer id — position in the dictionary, nothing more.
The leading space is part of the token: ␣apple and apple are different ids. A rare word can split into several entries; Numidroid might use five tokens where apple uses one.
This is branchy string manipulation over a hash table. There is nothing here a GPU is good at, so it stays on the host. What crosses to the device is a few hundred bytes of integers.
out: ids = [785, 23268, 374, 10226] · int32[4]
2GPU
Embedding Vectors. Ids become vectors
The embedding table has one row per vocabulary entry, each row 896 numbers long. Turning an id into a vector is not a multiplication — it is a row copy. Id 23268 means “fetch row 23268”.
d_model is the width of the pipe that runs the length of the model: 896 for Qwen2.5-0.5B, 4096 for Llama 3 8B. Every hidden state, every residual, every attention output is this wide.
Common trap. Position is not added here. In these models nothing distinguishes “apple as word 2” from “apple as word 200” at this stage — RoPE injects order later, inside each attention layer.
out: X [4 × 896] · table is [151936 × 896] ≈ 136M params
3GPU
One token maps to one row in the Embedding Table
Each row is one token. The 896 numbers along a row are that token's features — 896 is the width of a row, the size of the vector, not a count of columns of anything. This convention lets one set of kernels serve a four-token prompt and a four-thousand-token one: the shape changes, the code does not.
Adding a batch dimension in front gives [batch, tokens, d_model], and that is the tensor shape you will see printed in every debugger from here to the end of the model.
Common trap. “Column” invites the picture of each token sliding down its own private lane. It doesn't. Attention makes row 3 a function of rows 0–3 at every single layer. Depth is the sequential axis; rows are coupled.
shape: [n_tokens, d_model] = [4, 896]
4GPU
The Neural Network: Twenty-four layers of edits
The tensor now passes through 24 identical-in-shape, different-in-weights blocks. Once it is inside, stop calling it an embedding: it is a hidden state, and specifically a residual stream that each sublayer reads and writes back into.
One block contains four main operations: normalize, attend, add the result to the residual stream; normalize again, run the MLP, and add that result back. Each sublayer modifies the residual stream instead of replacing it.
Attention is the only place rows talk. With a causal mask, row 3 may look at rows 0–3 and no further, which is exactly what makes the model a next-token predictor rather than a fill-in-the-blank one.
in [4 × 896] → out [4 × 896], 24 times
5GPU
Final RMSNorm: Normalize once more, then keep one row
After layer 24, a final RMSNorm sets the scale of the hidden states before the LM head. Omitting it changes the logit scale and therefore changes the effect of temperature.
Four rows went in, but only row 3 — the final prompt token — is read by the LM head for this generation step. Rows 0–2 were computed through all 24 layers; their final hidden states are not read out.
That waste is only waste at generation time. During training every row predicts its own successor, so one forward pass yields n training signals instead of one.
out: h [1 × 896] — 896 numbers now carry the whole prompt
6GPU
LM head and output logits: 896 numbers become 151,936 scores
The LM head multiplies the final 896-number hidden state by a [896 × 151,936] matrix. The result is one logit for each vocabulary entry.
Logits are unbounded scores and are meaningful only relative to one another. A logit of 57.29 says little alone; its position among the other 151,935 scores determines its probability after softmax.
In Qwen2.5-0.5B this LM head matrix is the embedding table transposed — the same 136M parameters used at both ends. Llama 3 keeps them separate. Either way it is one of the largest single tensors in a small model.
out: z [151,936] — one score per token id
7GPU
Temperature: a divide, before the softmax
Every logit is divided by T. Dividing by a small number less than 1 stretches the gaps between scores, so after the softmax the leader takes almost everything. Dividing by a large number squashes the gaps and the distribution flattens.
T does not add noise — it reshapes the distribution the sampler will draw from. Ordering never changes. T → 0 is argmax — no randomness at all; T = 1 leaves the model's own distribution alone.
Top-k and top-p are separate scissors, usually applied around this step: keep the best k entries, or the smallest set whose probability sums past p, and zero the rest before renormalizing. The bench below lets you move all three.
z' = z / T · shape unchanged
8GPU
Softmax, then choose one: argmax or sampling
Softmax exponentiates each logit and divides by the sum of all exponentiated logits. The result is a probability distribution over 151,936 vocabulary entries that sums to 1. Because softmax is monotonic, the ranking stays the same.
Argmax chooses the highest-probability entry every time. Sampling assigns each entry a segment of the interval from 0 to 1, sized by its probability, then draws a random point on that interval. The leading token wins most often, but lower-probability tokens can still be selected.
out: token_id = 323 — a single integer
9CPU
Token id generated: back to the host, then around again
The id goes back to the CPU and through the dictionary in reverse: 323 becomes " and". Streaming decoders buffer here, because byte-level Byte Pair Encoding (BPE) means one id can be an incomplete UTF-8 sequence — the reason an emoji sometimes lands a beat late.
The same id is embedded on the device as row 4, and the pipeline runs again with one more token of context. Autoregressive generation repeats this loop until a stopping condition is reached.
What real decoding does. It does not re-run rows 0–3. The prompt is processed once — prefill, all rows in parallel, compute-bound. After that each step is decode: exactly one new row, with every earlier key and value read from the KV cache. It is memory-bandwidth-bound, and it is why the first token feels slow and the rest stream.
loop: [4 × 896] → [5 × 896] → [6 × 896] …
C
Move the knobs
Twelve plausible continuations of “The apple is sweet”, with hand-picked logits. Everything downstream of the logits is the real arithmetic — divide, filter, exponentiate, normalize, draw.
Divides every logit by the temperature T, then softmax exponentiates the gaps between them into odds. T below 1 divides by a fraction, so gaps grow and the leader pulls away; T above 1 shrinks gaps and the field closes up. Order never changes.
Keep only the k highest scores, then renormalize.
Keep the smallest set of tokens whose probability passes p.
Nothing drawn yet.
D
Bench one: the loop, running
One token's journey, on repeat. Prompt text enters on the blue host slab, becomes token rows on the green device, travels through 24 layers, collapses to one readout row, fans out into logits, passes through temperature and sampling, and returns as the selected token. Drag to orbit; scroll to zoom.
bench 01 continuous —
E
Bench two: one step at a time
The same scene under manual control. Play advances stage by stage and stops; the stepper moves one stage; the dial scrubs anywhere in between so you can hold the tensor mid-flight.
bench 02 stepped —
0 — A string arrives
Bytes on the host. Nothing has been split, embedded or scored yet.
F
The whole flow
One turn, end to end. Blue
runs on the host, green on the device, and
red marks a value rather than a step.
Tokenizer→Embedding→24 Transformer Layers→Final RMSNorm→LM-Head→Logits→Temperature→Softmax→Argmax or Sample→Token-Id