Start studying
Module 6 · LLMs Module contents
Module 6  ·  Card 16 / 22beginner

Inference

Inference is using a trained model to generate output.

Prefill processes the whole prompt in one parallel pass.

Decode then produces output tokens one at a time.

A KV cache stores past key and value vectors so they are not recomputed.

Decoding is sequential, which is why long outputs feel slow.

Learn in depth ↓
Module 06 · LLMs · 22 concepts
In depth  /  15 lines

Inference, in more detail

Inference is running a trained model to produce output, and it is where the bill lives.

It happens in two phases with very different characteristics.

Prefill processes the entire prompt in one parallel pass.

It is compute-heavy and fast, since every position is handled at the same time.

Decode then produces the answer one token at a time.

Each token needs its own pass through the whole model.

Nothing about that can be parallelised, since each token depends on the one before it.

That is why the first word appears quickly and the rest arrives at a steady trickle.

The KV cache stores the key and value vectors of everything already processed.

Without it every new token would recompute the entire history.

The cache grows with the conversation and can consume more memory than the weights.

Decoding is limited by memory bandwidth rather than arithmetic, since the weights must be read per token.

That is why batching many users together is nearly free and why providers do it aggressively.

Time to first token and tokens per second are the two numbers users actually feel.

Most inference optimisation is an attack on one of those two.

Deep dive

What is underneath Inference

Two phases with opposite bottlenecks

prefill:read T prompt tokens in one pass\text{prefill} : \text{read } T \text{ prompt tokens in one pass}
decode:produce one token, then repeat\text{decode} : \text{produce one token, then repeat}

Prefill computes the keys and values for the whole prompt at once, so it is a large matrix multiply and the hardware runs near its peak.

Decode produces one token per pass, so every weight in the model is read from memory to serve a single token.

arithmetic intensity=FLOPsbytes read\text{arithmetic intensity} = \frac{\mathrm{FLOPs}}{\text{bytes read}}

That is the whole story of serving cost. Prefill is compute-bound, decode is memory-bound, and an optimisation that helps one usually does nothing for the other.

Why decoding is bandwidth, not maths

ttoken≈2N⋅bytes per parametermemory bandwidtht_{\mathrm{token}} \approx \frac{2N \cdot \text{bytes per parameter}}{\text{memory bandwidth}}
  • NN: parameter count.

A 7-billion-parameter model in 16-bit weights reads about 14 GB per token. On an accelerator with 2 TB per second of bandwidth, that is roughly 7 ms, or 140 tokens per second.

The arithmetic in that step would take well under a millisecond. The chip spends most of its time waiting for weights.

batch B:same weights, B tokens\text{batch } B : \text{same weights, } B \text{ tokens}

Batching is therefore free throughput.

The weights are read once and serve every sequence in the batch, which is why a server's tokens per second rises almost linearly with batch size until the cache runs out of room.

The two numbers users feel

TTFT∝Tprompt,TPOT≈constant\mathrm{TTFT} \propto T_{\mathrm{prompt}}, \qquad \mathrm{TPOT} \approx \text{constant}

Time to first token is set by prefill, so it grows with prompt length. Time per output token is set by decode and is roughly flat.

A long prompt with a short answer is a prefill problem. A short prompt with a long answer is a decode problem, and they are fixed by different things.

total=TTFT+TPOT×(output tokens−1)\text{total} = \mathrm{TTFT} + \mathrm{TPOT} \times (\text{output tokens} - 1)

Streaming exists because that first term can be hidden behind the rest, and a user reads more slowly than the model writes.

One request, in order

  1. Tokenise the prompt.
  2. Prefill: one forward pass over all prompt tokens, filling the KV cache.
  3. Sample the first token from the final position's logits.
  4. Decode: one pass per token, appending each new key and value to the cache.
  5. Stop at an end token, a stop sequence, or the length limit, then free the cache.

Where the memory goes

KV bytes=2 L H dh T B×bytes\text{KV bytes} = 2 \, L \, H \, d_h \, T \, B \times \text{bytes}
  • LL: layers, HH: heads, TT: sequence length, BB: batch.

The cache grows with every token and every concurrent request, and it is usually what limits batch size rather than the weights.

grouped-query attention:Hkv≪Hq\text{grouped-query attention} : H_{kv} \ll H_q

Sharing keys and values across query heads cuts that memory several-fold, which is why nearly every recent model uses it.

Quantising the weights to 8 or 4 bits attacks the bandwidth term directly, and it speeds up decode roughly in proportion.

That is the clearest example of why the bottleneck is worth knowing before optimising.

Test yourself

One question on this card. Every option explains itself once you pick, right or wrong.

Question 1
What is the KV cache for during inference?
LLMs

22 concepts in this module, then a graded test with every answer explained.

Study this module →
↑↓ move↵ openesc close