← All posts

Model development

Post 23 of 26

Inference and serving: latency, throughput, KV cache and quantization

Posts in this series · 26

A trained model has to be served: thousands of users send prompts and wait for answers. The GPU post noted that generation is mostly matrix-times-vector work and therefore memory-bound. This post follows that observation through to latency, throughput, memory and cost, using Llama 3 8B on one H100 (989.5 TFLOP/s BF16, 3.35 TB/s, 80 GB) as the running example, as in CS336’s inference lecture. It needs only the architecture post for the KV cache.

Two phases: prefill and decode

Serving a request has two phases with opposite characters (CS336 lecture 10):

For a 2,000-token prompt, prefill needs about 2N×2,000≈3.2×10132N \times 2{,}000 \approx 3.2 \times 10^{13} FLOPs, roughly 65 ms at 50% of peak. Decode is where time goes for long answers.

Why one sequence is slow

At each decode step the GPU must read every weight once. Llama 3 8B in BF16 is 16 GB, so a step takes at least 16/3,35016 / 3{,}350 s ≈\approx 4.8 ms: at most about 209 tokens per second for a single sequence, however fast the arithmetic units are. Reading fewer bytes is the only way to go faster: with 8-bit weights the bound is 417 tokens per second, with 4-bit 834.

Batching: throughput against latency

The weights are the same for every sequence, so a step can process many sequences while reading the weights once. Each sequence adds only its own KV cache (128 KiB per token for Llama 3 8B). At 2,048 tokens of context:

BatchTime per stepTotal tokens per second
14.9 ms205
85.4 ms1,472
327.4 ms4,349
649.9 ms6,450

A batch of 64 delivers about 30 times the throughput, but each user’s step takes twice as long. This is the central trade-off of serving (CS336 lecture 10): small batches for low latency, large batches for low cost per token. Since the trade-off differs by phase, systems often use small batches during prefill, to keep time to first token low, and large batches during decode. The site’s post on high throughput and usable latency shows how a system can post excellent throughput while users wait minutes.

Requests arrive and finish at different times. Continuous batching adds new requests to the running batch at every step and removes finished ones, instead of waiting for a whole batch to complete, which keeps the batch full.

The KV cache decides how many users fit

Large batches need memory for every sequence’s KV cache. With BF16 weights taking 16 GB, an 80 GB GPU has about 64 GB left: room for about 60 sequences of 8,192 tokens at 128 KiB per token. The KV cache, not the weights, caps the batch. That is why grouped-query attention, which shrank the cache fourfold, matters so much for serving.

Managing that memory is its own problem. Sequences grow unpredictably, and reserving each one’s maximum length in advance wastes most of the memory. PagedAttention stores each sequence’s KV cache in fixed-size blocks allocated on demand, like pages of virtual memory, and lets sequences share blocks, for example a common system prompt or the prompt behind several samples. Its system, vLLM, achieves near-zero waste in KV-cache memory and improves throughput 2 to 4 times over earlier systems at the same latency (Kwon et al., 2023, abstract). Llama 3’s team used it to more than double the throughput of rejection sampling. When memory runs out, caches can be moved to CPU memory and back, which has its own correctness hazards; see the post on making KV offload correct.

Quantization

Since decode is limited by bytes read, storing weights in fewer bits speeds it up directly and frees memory for KV cache. Weight-only quantization stores weights as 8- or 4-bit integers with a scale, and converts them back to 16-bit on the fly for the arithmetic.

The scale is chosen so the largest weight fits the integer range, which makes the choice of grouping critical. A toy matrix whose 64 output channels differ in size by a factor of 100: with one scale for the whole matrix, the smallest channel is rounded to a few integer levels and its relative error is 74%; with one scale per output channel it is 0.8%. Real quantizers use per-channel or per-group scales (often groups of 128 weights), the same principle as the FP8 block scaling used in training.

Beyond grouping, methods differ in how they decide what to protect:

Quantization trades accuracy for memory and speed, and the trade depends on the model, the bit width and the task. Evaluate a quantized model on your own evaluation set, not only on perplexity: degradation often shows first on long or reasoning-heavy outputs.

Speculative decoding

Decode leaves the arithmetic units mostly idle. Speculative decoding uses that idle compute: a small, fast draft model proposes γ\gamma tokens, and the large model checks all of them in one forward pass, accepting a prefix of them and sampling a correction where it disagrees. A careful acceptance rule makes the output distribution identical to sampling from the large model alone. If each drafted token is accepted with probability α\alpha, a step yields on average

1−αγ+11−α\frac{1 - \alpha^{\gamma + 1}}{1 - \alpha}

tokens (Leviathan et al., 2023, §3.3, Eq. 1). With α=0.8\alpha = 0.8 and γ=4\gamma = 4 that is 3.36 tokens per large-model step. The paper reports a 2–3× speed-up on T5-XXL with identical outputs. The gain depends on how often the draft agrees with the target, which varies with the task: code and formulaic text are easier to draft than open-ended prose.

Try it: serve a 70B model. Llama-class 70B in BF16 on 80 GB GPUs. How many GPUs does it need at minimum? Roughly how long does a decode step take? What changes with 4-bit weights?

Answer. Weights are 70×2=14070 \times 2 = 140 GB, so at least 2 GPUs, before any KV cache. Reading 140 GB at 3.35 TB/s takes about 42 ms; split over two GPUs reading in parallel, about 21 ms per step at best, plus communication between them: under 50 tokens per second per sequence. With 4-bit weights the model is 35 GB and fits on one GPU with room for KV cache, and each step reads a quarter as many bytes: about 10 ms, if the quantized model’s quality is acceptable on your evaluation set.

Everyday picture: a library with one narrow door. Each reader’s next sentence needs the whole encyclopedia carried through the door. Carrying it once for a whole roomful of readers (batching), printing it in smaller type (quantization), or having an assistant guess the next few sentences for checking in one trip (speculative decoding) all attack the same bottleneck: the door.

What to remember

Sources

Further reading