Systems & Serving

LLM Inference Optimization Techniques

LLM inference optimization is one of the most active areas in applied AI right now — everyone wants text generation that's faster, more accurate, and cheaper to run. Here are 10 techniques that help get there, from caching tricks and attention variants to quantization and disaggregated serving.

1

KV Caching

The simplest and most foundational optimization: stop recomputing what you've already computed.

During each step of autoregressive text generation, an LLM compares the last token's Query vector against the Key vectors of every preceding token, including itself. This produces attention weights, which are used to compute a weighted sum over the corresponding Value vectors — the attention output for that token.

For example, when generating the token that follows "The capital of the U.K. is", the model:

This repeats at every step of generation. Recomputing Key and Value vectors for the entire sequence at each step gets expensive fast as the sequence grows — which is exactly the problem a KV cache solves.

Instead of recalculating Key and Value vectors for the whole sequence every time, the KV cache stores each token's K and V vectors once. At each new step, the model only computes (and appends) the new token's Key and Value, reusing everything else from the cache.

WITHOUT KV CACHE — recompute K,V for every token, every step The capital of U.K. is → all 5 recomputed to predict "London" WITH KV CACHE — reuse cached K,V, compute only the new token The capital of U.K. is London ← only the new token is computed

Green/cyan = cached and reused. Red = recomputed. The KV cache trades HBM memory for a large cut in redundant computation.

This massively reduces inference compute — but at the cost of GPU high-bandwidth memory (HBM). There's no free lunch. Still, KV caching is one of the simplest, highest-leverage techniques for improving inference speed.

2

Efficient Attention Mechanisms

Since the KV cache eats into HBM, shrinking it is its own optimization target.

Traditional Multi-Head Attention (MHA) gives every attention head its own Key and Value vectors. Several attention variants reduce the number of K/V vectors in use — and therefore the KV cache size:

MHA MQA GQA MLA 3 heads, 3 full KV sets 3 heads, 1 shared KV 2 groups, 2 shared KV pairs latent compressed KV latent

MHA vs MQA vs GQA vs MLA — fewer distinct Key/Value sets means a smaller KV cache. (Source)

3

Continuous Batching

Processing requests one at a time wastes GPU compute — batching fixes that, but how you batch matters.

Handling LLM requests sequentially is inefficient, since requests arrive at different times and have variable input/output lengths. Batching requests together improves overall throughput and reduces idle GPU compute — but there's more than one way to do it:

In static and dynamic batching, the entire batch must finish before a new request can join. Continuous batching removes that constraint, keeping GPU utilization consistently high.
4

Optimized Kernels

Decode is memory-bound — the bottleneck is moving data, not computing on it.

During inference, the Decode phase is memory-bound: the GPU spends more time moving data from memory (HBM) to its compute cores than actually computing. A kernel is a function that runs on the GPU performing parallel operations, and it can be optimized to keep data in fast on-chip memory (SRAM/registers) rather than repeatedly re-reading it from slow HBM.

Kernel fusion merges multiple individual operations into a single kernel to avoid unnecessary data movement across memory. FlashAttention is the best-known example, fusing the operations of attention computation into one kernel.

Standard attention computation moves data back and forth repeatedly: Query and Key are read from HBM and multiplied to form an attention score matrix, which is written back to HBM, re-read to apply softmax, written back again, then read once more to multiply by the Value matrix — with the final output written back to HBM one last time.

FlashAttention avoids all of this by never materializing the full attention matrix in HBM. It splits the Query, Key, and Value matrices into smaller tiles that fit in on-chip SRAM, and performs attention one tile at a time — computing attention scores and softmax on-chip, and writing only the final output back to HBM.

HBM (slow, large) Q, K, V matrices full Q / K / V final output only On-chip SRAM (fast, small) Q tile K tile V tile attention score + softmax computed on-chip, per tile tile output loop over Q/K/V tile blocks No N×N attention matrix ever touches HBM

FlashAttention tiles Q/K/V into on-chip SRAM, computing attention block by block and writing only the final output back to HBM — minimizing slow memory round-trips.

5

Quantization

Store and compute in fewer bits, and both memory footprint and throughput improve.

Quantization stores and computes LLM parameters, activations, and the KV cache in lower-precision formats such as INT8 (8 bits) or INT4 (4 bits) instead of full-precision FP32 or 16-bit FP16/BF16. This shrinks memory requirements and increases throughput by reducing how much data moves from HBM to the compute cores — at the cost of a slight accuracy drop.

Llama 3 70B memory footprint by precision FP32 280 GB FP16 140 GB INT8 70 GB INT4 35 GB single H100 GPU: 80 GB memory → only INT8 & INT4 fit on one GPU

At FP32, a 70B-parameter model needs 280 GB — more than a single 80 GB H100 GPU. Quantizing to INT4 brings that down to 35 GB, small enough to fit on one GPU.

Quantized models are commonly labeled using the convention W(x)A(y), describing how much the weights (W) and activations (A) have been quantized:

W4A16W8A8W4A4

You'll also see model names suffixed with -GPTQ or -AWQ — the two most common quantization techniques:

6

Prefix / Prompt Caching & RadixAttention

Many requests share the same opening tokens — compute that shared prefix once.

LLM inference has two distinct phases:

Prefix (or prompt) caching reuses the computed KV cache for a shared prefix of the input prompt across multiple requests, cutting redundant Prefill computation and shortening TTFT. Consider a long system prompt like "System: You are a helpful assistant..." — without prefix caching, every request recomputes Prefill for the entire system prompt plus the user's question. With it, the system prompt's KV cache is computed once and reused; each request only computes Prefill for its own unique question.

RadixAttention, introduced with the SGLang serving framework, implements prefix caching efficiently using a radix tree: each path from the root represents a token sequence, and shared prefixes across requests become shared branches. For a new request, the algorithm walks the tree, matching tokens as far as possible and reusing the KV cache along that path — computing Prefill only for the tokens unique to that request.

7

Pruning

Not every parameter earns its keep — pruning removes the ones that don't.

Pruning removes parts of a model that contribute little to its accuracy, making it smaller and cheaper to run inference on. It comes in three flavors:

  1. Unstructured pruning — sets low-magnitude individual parameters to zero.
  2. Structured pruning — removes entire sections of the model, such as neurons, attention heads, or fully-connected layers.
  3. Semi-structured (N:M) pruning — sets N of every M consecutive weights to zero. NVIDIA GPUs from Ampere onward have hardware support for 2:4 sparsity, giving roughly a 2x boost in matrix multiplication throughput.
8

PagedAttention

Borrowed from operating systems: don't demand one giant contiguous block of memory.

PagedAttention, introduced in the vLLM serving framework, manages the KV cache's memory more efficiently by borrowing an idea from how operating systems handle memory paging.

Instead of reserving one large contiguous chunk of GPU memory for the KV cache upfront, PagedAttention stores it dynamically across many small, fixed-size, non-contiguous blocks called pages. A per-sequence block table maps logical token positions to their physical memory blocks, and the attention kernel consults this table to locate the right KV pairs on demand.

Logical sequence tok 0-3 tok 4-7 tok 8-11 tok 12-15 Block table Physical GPU memory (non-contiguous pages) page page page free page

A block table maps each logical chunk of the sequence to a physical page, which can live anywhere in GPU memory — just like OS virtual memory paging.

9

Speculative Decoding

Use a fast, small model to guess ahead — then let the big model verify the guesses in one pass.

Speculative decoding accelerates inference with large LLMs by pairing them with a smaller model from the same family, sharing the same tokenizer and vocabulary. The smaller model — the Draft model — runs faster than the larger Target model simply because it has fewer parameters. The process works like this:

  1. Drafting — for a given prompt, the Draft model generates K tokens ahead of time.
  2. Target forward pass — those K draft tokens, plus the original prompt, are fed to the Target model. In a single forward pass, it produces a probability distribution for the next token at every drafted position, plus one more beyond it (K + 1 predictions total). Because Decode is memory-bound, this single pass costs about as much as generating just one token normally would.
  3. Verification — each drafted token is checked against the Target model's prediction at that position. It's accepted if they match (under greedy decoding) or if the Target model finds it likely enough via rejection sampling (under probabilistic decoding). At the first token where verification fails, that token and every token after it are discarded, the Target model supplies a replacement, and drafting resumes from that position.
Example: 5 drafted tokens, verified against the target model ✓ D1 ✓ D2 ✓ D3 ✗ D4 D5 (discarded) replacement Result: 3 accepted draft tokens + 1 resampled replacement = 4 tokens from one target pass, instead of 4 separate memory-bound decode steps.

If all K draft tokens are accepted, the output is K+1 tokens in one pass (best case). If the very first draft token is rejected, the result is just 1 resampled token — identical to normal decoding (worst case, no loss).

10

Prefill-Decode Disaggregation

Prefill and Decode want different things from hardware — so give them different hardware.

Prefill is compute-bound and determines TTFT; Decode is memory-bound and determines TPOT (also called inter-token latency). These are fundamentally different problems, and optimizing both on the same GPU is difficult — especially for prefill-heavy requests where long prompts produce short outputs, and low TTFT and low TPOT are both required at once.

Prefill-decode disaggregation is a serving architecture that solves this by moving the two inference stages onto separate, dedicated GPU pools: one pool optimized for high compute (e.g. the H100) handles Prefill, while a pool optimized for high memory throughput (e.g. the H200, which offers much faster and larger memory at similar core compute) handles Decode.

The main overhead in this architecture is transferring the KV cache between the Prefill pool and the Decode pool — a cost that can be reduced with faster interconnects such as NVLink or InfiniBand.