Inferensoptimering
Kunna mäta latens och throughput, använda KV-cache, batching och spekulativ avkodning.
Förkunskaper
- DTransformers — arkitekturenkrävs
- FKvantiseringkrävs
Intuition
LLM-inferens har två faser med helt olika flaskhalsar:
| Fas | Vad | Flaskhals | Åtgärd |
|---|---|---|---|
| Prefill | läser in hela prompten | beräkning (parallell över tokens) | snabbare kärnor, flash attention |
| Dekodning | genererar ett token i taget | minnesbandbredd (alla vikter läses per token) | kvantisering, MQA/GQA, spekulativ avkodning |
Därför hjälper kvantisering mest på dekodning: hälften så många byte att läsa ≈ dubbelt så snabb tokengenerering.
Två mått som inte är samma sak:
- Latens — tid till första token (TTFT) och tid per token. Vad en användare upplever.
- Throughput — tokens per sekund totalt. Vad systemet klarar.
Större batch höjer throughput och höjer latensen. Du kan inte optimera båda.
Formellt
Continuous batching är den enskilt största vinsten i en tjänst. Statisk batching väntar in en hel batch och alla måste vänta på den längsta sekvensen. Kontinuerlig batching (vLLM, TGI) låter nya förfrågningar hoppa in så fort en plats blir ledig — 2–10× högre throughput vid samma hårdvara.
PagedAttention hanterar KV-cachen i sidor i stället för sammanhängande block, vilket i praktiken eliminerar fragmentering och gör det möjligt att köra många fler samtidiga sekvenser.
Spekulativ avkodning: en liten «utkastmodell» genererar k tokens, den stora verifierar dem alla i ett framåtpass och accepterar det längsta korrekta prefixet. Vid 70 % acceptans blir det ~2× snabbare — utan att ändra utdatafördelningen (det är matematiskt exakt, inte en approximation).
Mätordning som ger resultat: mät först (var går tiden — prefill eller dekodning?), slå sedan på continuous batching, därefter kvantisering, och sist spekulativ avkodning. Att börja i fel ände är den vanligaste tidsförlusten.
Kod
import time, numpy as np
def mat_inferens(generera, prompt, n_tokens=128, upprepningar=5):
ttft, per_token = [], []
for _ in range(upprepningar):
t0 = time.perf_counter(); forsta = None
for i, _tok in enumerate(generera(prompt, max_new_tokens=n_tokens, stream=True)):
if i == 0:
forsta = time.perf_counter() - t0
total = time.perf_counter() - t0
ttft.append(forsta); per_token.append((total - forsta) / (n_tokens - 1))
return {"ttft_ms": round(np.median(ttft) * 1000, 1),
"ms_per_token": round(np.median(per_token) * 1000, 2),
"tokens_per_s": round(1 / np.median(per_token), 1)}
print(mat_inferens(generera, "Förklara attention kort."))
# {'ttft_ms': 180.4, 'ms_per_token': 22.1, 'tokens_per_s': 45.2}
Särskilj alltid TTFT från tid per token i rapporten — de har olika orsaker och olika åtgärder.
Behärskning innebär
- Mäter latens och throughput separat
- Använder batching, KV-cache och kvantisering rätt
- Vet vad som är flaskhalsen i varje fas
Logga in för att göra övningarna och bygga upp din behärskning.
Källor
- arXiv — Efficient Memory Management for LLM Serving with PagedAttention (vLLM) — arXiv (öppen åtkomst; licens per artikel)
- arXiv — Fast Inference from Transformers via Speculative Decoding — arXiv (öppen åtkomst; licens per artikel)