Skip to the lesson
FixTheRobot Explore Robotics / LLM / LM10 Modern LLM Architecture and Inference / LM10-T6

LLM · Theory · LM10

LM10-T6 — Inference Efficiency and Architecture Trade-Offs

Every efficiency technique moves one cost and may spend some quality. A budget on paper tells you which combination is worth testing.

  • Lesson 6 of 6
  • Module 10: Modern LLM Architecture and Inference
  • Theory
  • Difficulty: Advanced
  • About 9 minutes to read
  • Prerequisite: LM10-T5

You now know the pieces: weights at some precision, a KV cache that grows with context and users, a decode step limited by memory traffic, and architectural options that change those numbers. This lesson puts them into one calculator and one decision procedure, adds the remaining techniques that matter in practice (exact fast attention, speculative decoding), and states what each lever obliges you to measure. The goal is not a recipe but a habit: compute the budget first, then test only the combinations that can work.

Learning objectives

After this lesson, you should be able to:

  • Build a memory and speed budget from weights, cache, batch and bandwidth.
  • Explain exact attention kernels, speculative decoding, mixture of experts and sliding windows in terms of the cost they remove.
  • Choose levers for a given constraint and state what to evaluate for each.
  • Recognise levers that trade quality and those that do not.

The idea: four costs, many levers

A deployment is limited by one of four quantities. Weight memory: the model must fit. Cache memory: the contexts of all concurrent users must fit. Bandwidth: every decode step streams weights and cache. Arithmetic: prefill, and decode at large batch, need compute. Each technique in this module reduces one of them:

Levers, what they save and what they risk
LeverReducesChanges the output?What to evaluate
Quantised weights (8 or 4 bit)weight memory, decode trafficyes, slightlytask accuracy, long-form quality
Quantised cachecache memory, decode trafficyes, slightlylong-context tasks
Grouped-query attentioncache memory, decode trafficyes, a design choice made in trainingquality of the trained model
Larger batchcost per tokennolatency per request, memory
Exact attention kernels (FlashAttention)memory traffic of attention, score-matrix memoryno (exact up to rounding)speed only
Speculative decodingdecode steps of the large modelno (distribution preserved with the right acceptance rule)speed at real acceptance rate
Mixture of expertsarithmetic per tokenyes, a different modelquality; memory still full
Sliding-window attentioncache and attention cost at long contextyes, limits direct reachlong-range tasks

The second-to-last column is the one to read first. Levers that do not change the output (batching, exact kernels, speculative decoding with the proper rule) are safe to try; they cost engineering effort but no quality. Levers that change the output need the evaluation methods of Module 9 before you rely on them.

A serving budget with four leversA bar chart of total GPU memory in gigabytes for four configurations of a 7-billion-parameter model serving 16 requests of 8,192 tokens: 16-bit weights with multi-head cache 82.7, 16-bit weights with grouped-query cache 31.2, 8-bit weights and 8-bit cache with grouped-query attention 15.6, 4-bit weights with 8-bit cache 12.1. A dashed line marks the 80 gigabyte limit of the GPU.82.7 GBMHA, 16-bit31.2 GBGQA-8, 16-bit15.6 GBGQA-8, 8-bit w+cache12.1 GBGQA-8, 4-bit w, 8-bit cache GPU limit 80 GB GPU memory for 16 requests × 8,192 tokens (weights + KV cache)
The same 7B workload under four configurations. Multi-head attention with a 16-bit cache does not fit in 80 GB; grouped-query attention makes it fit with room to spare; quantisation shrinks it further and speeds up decoding.

Exact attention kernels

Standard attention writes the score matrix (n × n per head) to memory, reads it back for the softmax, writes the probabilities and reads them again to multiply with the values. For long sequences these round trips dominate. FlashAttention (Dao et al., 2022) computes exact attention in tiles that stay in fast on-chip memory, keeping running softmax statistics, so the full score matrix is never stored. The output is the same as standard attention up to rounding; the memory for scores grows linearly, not quadratically, with length. For one layer with 32 heads in 16 bits, the stored score matrix would be 0.27 GB at 2,048 tokens, 4.3 GB at 8,192 and 68.7 GB at 32,768: the quadratic growth that exact kernels avoid.

Speculative decoding

Decode is memory-bound, so verifying several tokens in one pass costs almost the same as producing one. A small draft model proposes k tokens cheaply; the large model scores all k in a single pass and accepts the longest prefix that it agrees with, using an acceptance rule that keeps the output distribution identical to the large model’s own. If each proposed token is accepted with probability a (assumed independent), the expected number of tokens produced per large-model pass is (1 − ak+1)/(1 − a). With k = 4: 1.94 tokens at a = 0.5, 2.77 at a = 0.7 and 4.10 at a = 0.9. The gain is real only if the draft is much cheaper than the large model and agrees with it often; measure the acceptance rate on your own traffic.

Exactness is a property to verify

The mathematics: a serving budget

Let the model have P parameters stored at bw bytes each, L layers, Hkv key-value heads of width dh, cache precision bc; serve B requests of n tokens; memory bandwidth BW, usable arithmetic rate F.

memory: weights plus cache (activations ignored)
M=P⋅bw+2⋅L⋅Hkv⋅dh⋅n⋅B⋅bcM=P\cdot b_{w}+2\cdot L\cdot H_{\text{kv}}\cdot d_{h}\cdot n\cdot B\cdot b_{c}
one decode step for the whole batch: memory traffic versus arithmetic
tstep=max⁡(P⋅bw+2⋅L⋅Hkv⋅dh⋅n⋅B⋅bcBW, 2⋅P⋅BF)t_{\text{step}}=\max (\frac{P\cdot b_{w}+2\cdot L\cdot H_{\text{kv}}\cdot d_{h}\cdot n\cdot B\cdot b_{c}}{\mathrm{BW}},\,\frac{2\cdot P\cdot B}{F})
tokens per second
per−request speed=1tstep\text{per}-\text{request speed}=\frac{1}{t_{\text{step}}}
total throughput=Btstep\text{total throughput}=\frac{B}{t_{\text{step}}}
M ≤ memory
the feasibility condition; leave margin for activations, fragmentation and the framework (10 to 20%).
tstep
memory term dominates for small B and short n; the arithmetic term takes over at large B.
B
raising B raises total throughput until the arithmetic term or the memory limit binds.

Worked numbers (P = 7·109, L = 32, dh = 128, BW = 1012 B/s, F = 4·1013 FLOP/s, 80 GB GPU, B = 16, n = 8,192):

Budget for a 7B model (calculated by the code below)
ConfigurationMemoryFits 80 GB?StepPer requestTotal
16-bit weights, MHA, 16-bit cache82.7 GBno———
16-bit weights, GQA-8, 16-bit cache31.2 GByes31.2 ms32.1 tok/s513 tok/s
8-bit weights, GQA-8, 8-bit cache15.6 GByes15.6 ms64.1 tok/s1,026 tok/s
4-bit weights, GQA-8, 8-bit cache12.1 GByes12.1 ms82.7 tok/s1,323 tok/s
16-bit, GQA-8, 16-bit cache, B = 6482.7 GBno———
16-bit, GQA-8, 16-bit cache, B = 115.1 GByes15.1 ms66.3 tok/s66 tok/s

Reading the table: grouped-query attention is what makes the workload fit; quantisation then doubles the speed because the traffic halves; batching multiplies the total throughput while costing each request some speed (compare B = 1 with B = 16 at the same precision: 66 versus 513 tokens/s in total, 66 versus 32 per request). Batch 64 no longer fits at 16 bits.

A worked example: the budget calculator

This is the calculator behind the table, plus the expected-speedup formula for speculative decoding. Copy it and replace the constants with your own model, hardware and workload.

P, L, HD = 7e9, 32, 128
BW, FU, MEM = 1e12, 4e13, 80e9                  # bytes/s, usable FLOP/s, GPU memory in bytes

def plan(weight_bytes, nkv, cache_bytes, batch, ctx):
    weights = P * weight_bytes
    cache = 2 * L * nkv * HD * ctx * batch * cache_bytes
    mem = weights + cache
    step = max((weights + cache) / BW, 2 * P * batch / FU)
    return {'gb': round(mem / 1e9, 1), 'fits': mem <= MEM, 'step_ms': round(step * 1000, 1),
            'per_req': round(1 / step, 1), 'total': round(batch / step)}

for args in [(2, 32, 2, 16, 8192), (2, 8, 2, 16, 8192), (1, 8, 1, 16, 8192),
             (0.5, 8, 1, 16, 8192), (2, 8, 2, 64, 8192), (2, 8, 2, 1, 8192)]:
    print(args, plan(*args))
# (2, 32, 2, 16, 8192) {'gb': 82.7, 'fits': False, 'step_ms': 82.7, 'per_req': 12.1, 'total': 193}
# (2, 8, 2, 16, 8192) {'gb': 31.2, 'fits': True, 'step_ms': 31.2, 'per_req': 32.1, 'total': 513}
# (1, 8, 1, 16, 8192) {'gb': 15.6, 'fits': True, 'step_ms': 15.6, 'per_req': 64.1, 'total': 1026}
# (0.5, 8, 1, 16, 8192) {'gb': 12.1, 'fits': True, 'step_ms': 12.1, 'per_req': 82.7, 'total': 1323}
# (2, 8, 2, 64, 8192) {'gb': 82.7, 'fits': False, 'step_ms': 82.7, 'per_req': 12.1, 'total': 774}
# (2, 8, 2, 1, 8192) {'gb': 15.1, 'fits': True, 'step_ms': 15.1, 'per_req': 66.3, 'total': 66}

def speculative_tokens(accept, k):
    return (1 - accept ** (k + 1)) / (1 - accept)

print([round(speculative_tokens(a, 4), 2) for a in (0.5, 0.7, 0.9)])   # [1.94, 2.77, 4.1]
print([round(32 * n * n * 2 / 1e9, 2) for n in (2048, 8192, 32768)])   # [0.27, 4.29, 68.72]

Rows that do not fit still print a step time; ignore it, as the configuration is infeasible. The fifth row is a reminder that the calculator’s time estimate does not know about the memory limit, so always read fits first.

A decision procedure

  1. State the workload,Model, concurrency, context length, latency targets (time to first token, tokens per second per user), hardware.
  2. Compute the baseline,Run the budget at the highest precision and the architecture you have. Note whether it fails on memory, speed or both.
  3. Apply output-preserving levers first,Batching policy, exact attention kernels, prefix caching, speculative decoding. They cost no quality.
  4. Then quality-affecting levers,Quantisation of weights and cache, fewer key-value heads (a model choice), smaller models. Evaluate each against your task set with confidence intervals (Module 9).
  5. Re-measure on the real system,Budgets are estimates good to a factor of about two. Measure time to first token, tokens per second and percentiles at the target load.

Engineering implications and limitations

Compute before you build. A ten-line budget eliminates configurations that cannot work and tells you which lever matters; it is far cheaper than discovering an out-of-memory error in staging.

Leave headroom. Activations, fragmentation, the runtime and spikes need 10 to 20% of memory. A configuration that fits at 79 GB of 80 will fail in production.

Treat quantisation as a model change. Run the same evaluation set (Module 9) for the original and the quantised model, with intervals, including long-form and long-context cases where errors accumulate.

Log acceptance rate and cache use. For speculative decoding the acceptance rate on real traffic decides the speed-up; for the cache, occupancy and eviction rates tell you when capacity is the problem.

Do not stack levers blindly. Combinations interact: a 4-bit model with an 8-bit cache and a draft model may each be fine alone and poor together. Test the combination you ship.

Prefer simple wins. Shorter prompts, shorter outputs and a smaller model that passes your evaluation save more than most clever tricks.

For robots. On-board inference has a hard memory ceiling and a deadline. Start from the memory (weights plus cache for the longest context you allow) and the deadline, pick the smallest model that passes the task evaluation, and keep a safe fallback behaviour. The Physical AI and VLA tracks on this site cover the robot side of such systems.

Common misconceptions

“Quantisation only makes models smaller.”

It also cuts the memory traffic of decoding, which is usually what limits speed.

“Speculative decoding changes the model’s outputs.”

With the correct acceptance rule the output distribution equals that of the large model; only the speed changes.

“A mixture of experts needs less memory than a dense model of the same quality.”

It needs the memory of all experts and saves arithmetic.

“FlashAttention approximates attention.”

It computes exact attention with a different order of operations and less memory traffic.

“Bigger batches are always better.”

They raise throughput until the memory or arithmetic limit, and need cache memory for every request.

Engineering takeaways

  1. Memory M = P·bw + 2·L·Hkv·dh·n·B·bc and step time = max(memory traffic / BW, 2·P·B / F) give a serving budget before any code is deployed.
  2. In the 7B example, multi-head attention needs 82.7 GB for 16 × 8,192 tokens; grouped-query attention brings it to 31.2 GB and 8-bit weights and cache to 15.6 GB, doubling the decode speed.
  3. Levers that preserve the output (batching, exact attention kernels, prefix caching, speculative decoding) come first; levers that change it need evaluation.
  4. Speculative decoding yields (1 − a^(k+1))/(1 − a) tokens per large-model pass; it is worth it only with a cheap, well-aligned draft model.
  5. Estimates are good to about a factor of two; confirm with measurements at the real load.

References and further reading

The budget numbers were produced by the code in this lesson with round illustrative hardware figures, not the specification of a particular device. The expected-token formula for speculative decoding assumes independent acceptance with a constant probability, as in the cited analysis.

  • Dao, T. et al. (2022). FlashAttention: Fast and memory-efficient exact attention with IO-awareness. arXiv:2205.14135.
  • Leviathan, Y., Kalman, M. and Matias, Y. (2023). Fast inference from transformers via speculative decoding. arXiv:2211.17192.
  • Ainslie, J. et al. (2023). GQA: Training generalized multi-query transformer models from multi-head checkpoints. arXiv:2305.13245.
  • Shazeer, N. et al. (2017). Outrageously large neural networks: The sparsely-gated mixture-of-experts layer. arXiv:1701.06538.
  • Dao et al. (2022), FlashAttention (research paper)

Knowledge check

Three conceptual questions. Write an answer, then reveal the explanation. Your answers stay in your browser.

Question 1

A 13-billion-parameter model in 8-bit weights has 13 GB of weights. Serving needs a cache of 40 GB at the target load on a 48 GB GPU. Does it fit, and what is the first lever you would try?

Explanation

It needs 53 GB, so it does not fit in 48 GB. The first levers are on the cache: store it in 8 bits (20 GB, total 33 GB), use a model with fewer key-value heads, or reduce concurrency or context length; each is checked with an evaluation where quality is affected.

Question 2

A draft model proposes k = 3 tokens, each accepted with probability 0.8. How many tokens per large-model pass do you expect?

Explanation

(1 − 0.8⁴)/(1 − 0.8) = (1 − 0.4096)/0.2 = 2.952, so about 2.95 tokens per pass.

Question 3

Which of these can change a model’s outputs: batching more requests, an exact attention kernel, 4-bit weights, speculative decoding with the correct acceptance rule? What should you do for those that can?

Explanation

Only the 4-bit weights change the outputs (slightly). Evaluate the quantised model against the original on your task set with confidence intervals; for the others, check equality on a fixed prompt set as a regression test.

What’s next

Next, Module 11: Building LLM Applications, where the model becomes one component of a system with retrieval, tools and safeguards.

Practice this lesson

KV-Cache Memory and Behaviour

Compute KV-cache size and count the operations with and without a cache.

Next lesson

LM11-T1 — Base Versus Instruction-Tuned Models and Prompt Design

Choose a model type and write prompts and structured-output requests that are testable.

Nothing below is required to finish this lesson.