Zum Inhalt springen
Kurzer Hinweis: flozi00 TechHub ist ein Solo-Nebenprojekt neben einem Vollzeitjob — persönliche Lernnotizen, keine offiziellen Aussagen. Kritische Schritte selbst prüfen.

Der KV-Cache: Exakte Speicher-Mathematik, GQA vs MQA vs MLA und PagedAttention

Warum der Key-Value-Cache Ihren GPU-Speicher auffrisst: die exakte Per-Token-Formel, MHA vs MQA vs GQA vs MLA mit berechneten Beispielen, PagedAttention-Block-Mathematik, RadixAttention-Präfix-Wiederverwendung, FP8-KV-Cache und ein durchgerechnetes Kapazitätsbeispiel — alles aus den Primärquellen belegt.

9 Min. Lesezeitflozi00
aimachine-learninggpugpu-memoryoptimizationdeep-learning
Direkt zum Fachartikel
Sehen · ausprobieren · verstehen

Drei getrennte Stellschrauben im KV-Budget

Die Architektur definiert den Zustand, die Präzision die Bytes je Wert und die Zuteilung deren Speicherplätze.

KI-gestützte Lernvisualisierung · schematische Erklärung zum Artikel

Schritt 1 / 4Beim Cache-Aufbau des Modells beginnen

Grouped-query Attention lässt mehrere Query-Köpfe dieselben KV-Köpfe nutzen; Multi-query Attention teilt einen KV-Kopf. Latente Attention speichert eine andere Darstellung; die klassische Kopf-Formel ist daher nicht unverändert übertragbar.

ArchitekturAktueller SchrittBaustein anklicken, um ihn zu erklären
Attention-Architektur
MHA, GQA, MQA oder latente Attention definieren andere KV-Strukturen.
Logische KV-Nutzdaten
Gehaltene Werte und deren Darstellung bestimmen die reinen Bytes.
  1. Attention-Architektur Logische KV-Nutzdaten
    welche Werte?
Das solltest du mitnehmen

Geteilte Köpfe, Low-Bit-KV und blockweise Zuteilung lösen verschiedene Teile desselben Speicherproblems.

Reine Nutzdaten schließen Skalen, Blockreste und Laufzeit-Overhead aus. Hybride, Sliding-Window- und latente Architekturen brauchen eigene Zustandsrechnungen.

Begriffe und vollständiger Ablauf
GQA
Grouped-query Attention: Mehrere Query-Köpfe teilen sich jeweils einen KV-Kopf.
Paging
Logische Blöcke ohne eine einzige zusammenhängende Reservierung auf Speicherplätze abbilden.
Nutzdaten
Die dargestellten Zahlenwerte vor Zuteilungs- und Laufzeit-Overhead.
  1. Beim Cache-Aufbau des Modells beginnen

    Grouped-query Attention lässt mehrere Query-Köpfe dieselben KV-Köpfe nutzen; Multi-query Attention teilt einen KV-Kopf. Latente Attention speichert eine andere Darstellung; die klassische Kopf-Formel ist daher nicht unverändert übertragbar.

  2. Präzision getrennt wählen

    Der Wechsel von zwei auf ein Byte je KV-Element halbiert diese reinen Elementdaten vor Skalen und Metadaten. Quantisierte Modellgewichte ändern den Cache-Datentyp nicht automatisch.

  3. Die entstehenden Blöcke zuteilen und teilen

    Paging ordnet logische Cache-Blöcke verfügbaren physischen Plätzen zu und verringert große zusammenhängende Reservierungen. Präfixteilung nutzt passende vorhandene Blöcke für mehrere Anfragen; beide ändern den mathematischen KV-Aufbau des Modells nicht.

  4. Speicherersparnis von Lesezugriffen trennen

    Gecachte K/V vermeiden die Neuberechnung alter Projektionen. Decode mit voller Attention liest gehaltene Keys und Values weiterhin für die aktuelle Query; auch eine passende Konfiguration kann durch Bandbreite begrenzt sein.

Alle Verbindungen

  • Attention-Architektur → Logische KV-Nutzdaten: welche Werte?
  • KV-Datentyp → Logische KV-Nutzdaten: wie viele Bytes je Wert?
  • Logische KV-Nutzdaten → Blockzuteilung: Blöcke zuteilen
  • Identische kompatible Präfixe → Blockzuteilung: passende Blöcke teilen
  • Blockzuteilung → Physische Cache-Belegung: platzieren und teilen
  • Physische Cache-Belegung → Attention liest gehaltene KV: beim Decode lesen
Du bestimmst das Tempo. Pausiere jederzeit oder wähle einen Schritt aus.

KV-Cache ist neu für dich? Prefill, Decode und Cache-Wiederverwendung Schritt für Schritt ansehen, bevor es unten um die Speicherformeln geht.

Ripple-65B zeigt, warum eine Attention-Maske mit 1.024 Positionen gespeicherte K/V nicht automatisch begrenzt. Der Guide leitet ideal kompakte hybride Nutzdaten getrennt vom unkonfigurierten DynamicCache-Pfad der veröffentlichten HF-Referenz her.

Kimi K3.1 Pro wählt bis zu 2.048 Positionen für einen globalen Attention-Read, behält aber Historie für spätere Queries. Der Guide trennt MLA-Nutzdaten, Index-Keys und Sparse-Read-Kosten, statt Top-k als Cache-Eviction zu behandeln. Jede LLM-Serving-Frage — wie viele Nutzer passen auf eine GPU, warum lange Kontexte kollabieren, was FP8-KV wirklich bringt — beantwortet ein einziger Tensor: der Key-Value-Cache. Dieser Leitfaden leitet seine exakte Größe auf Byte-Ebene her und geht dann die drei Angriffsachsen (Architektur, Allokator, Datentyp) durch — mit echten Zahlen für jede Aussage.

Die eine Formel

Jede Transformer-Schicht speichert pro Token und KV-Head einen K- und einen V-Vektor — die gesamte Historie bei jedem Schritt neu zu berechnen wäre quadratisch, also wird sie einmal berechnet und bei jedem Schritt gelesen:

KV-Bytes=2×L×HKV×dhead×bdtype×s\text{KV-Bytes} = 2 \times L \times H_{\text{KV}} \times d_{\text{head}} \times b_{\text{dtype}} \times s
  • L = Schichten, H_KV = KV-Heads, d_head = Head-Dimension, b_dtype = Bytes pro Wert, s = Tokens
  • Faktor 2 = K und V werden getrennt gespeichert
  • Dieselbe Formel wie unser VRAM-Rechner; entspricht Gleichung 1 des PagedAttention-Papers (arXiv:2309.06180)

Bei gemischten lokalen und globalen Stacks sind die behaltenen Positionen pro Schichttyp getrennt zu summieren. Mellum2.1 hat 21 Schichten mit einem Fenster von 1.024 Positionen und sieben Full-Attention-Schichten. Der Guide leitet die hybride BF16-Datenmenge her und unterscheidet das logische Arbeitsfenster von Cache-Ausschnitten, temporären Tensoren und tatsächlichen Laufzeit-Allokationen.

Referenzmodell in diesem Leitfaden (dieselbe site-verifizierte Konfiguration wie in der VRAM-Anleitung): Qwen3-VL-32B — 64 Schichten, 8 KV-Heads (GQA), Head-Dimension 128.

KV-Wiederverwendung ist nicht auf autoregressives Decoding beschränkt. Qwen-Image 2.1 macht Text- und Referenzbildzustände vom Diffusionszeitpunkt unabhängig und cacht dieses feste Präfix über Denoising-Schritte. Dieselbe K/V-Byteformel gilt, aber gecachte Positionen, Wiederverwendungsachse und verbleibender Rechenaufwand unterscheiden sich.

Pro Token bei fp16:

2×64×8×128×2 B=262.144 B=256 KiB≈0,26 MB2 \times 64 \times 8 \times 128 \times 2\,\text{B} = 262.144\,\text{B} = 256 \text{ KiB} \approx 0{,}26 \text{ MB}
KontextKV-Cache (fp16)KV-Cache (fp8)
8.192 Tokens2,15 GB1,07 GB
32.768 Tokens8,59 GB4,29 GB
65.536 Tokens17,18 GB8,59 GB
262.144 Tokens68,72 GB34,36 GB

Zum Vergleich: Die fp16-Gewichte dieses Modells belegen 66,7 GB (33.357.390.064 Parameter × 2 Bytes). Bei maximalem Kontext ist der KV-Cache eines einzigen Nutzers (68,72 GB) also bereits größer als das gesamte Modell — der Schnittpunkt liegt bei rund 254.500 Tokens. Kontext ist nicht kostenlos: Er ist linearer Speicher pro Nutzer, für jeden Nutzer, immer.

Warum er auch ein Bandbreitenproblem ist

Bei kleinem Batch kann Decode eines dichten Modells speicherbandbreitenbegrenzt sein: Ein Schritt liest die Gewichte und den Cache jeder Sequenz. Auf einer H200 SXM (141 GB HBM3e bei 4,8 TB/s 1) passen beide folgenden Konfigurationen schon nach Rohkapazität. Das ideale Bandbreitenmodell liefert eine Latenz-Untergrenze:

  • Batch 1, 8k Kontext: (66,7 + 2,15) GB / 4,8 TB/s ≈ 14,35 ms → 69,7 Tok/s Bandbreiten-Obergrenze für einen Nutzer
  • Batch 16, je 8k: (66,7 + 34,36) GB / 4,8 TB/s ≈ 21,06 ms pro Schritt, bei gemeinsam gelesenem Gewichtssatz → 47,5 Tok/s pro Nutzer, 760 Tok/s aggregiert — 10,9× die aggregierte Batch-1-Obergrenze

Batching amortisiert das Lesen der Gewichte über mehrere Sequenzen. Die ideale Zeit pro Token ist für jeden Nutzer ~47 % länger als allein (21,06 statt 14,35 ms), während die aggregierte Bandbreiten-Obergrenze steigt. Beides passt vor Laufzeitreserven in 141 GB (Batch 16: 66,7 + 34,36 ≈ 101,1 GB). Das Modell lässt Attention-FLOPs, zusätzlichen Speicherverkehr, Kernels und Laufzeitreserven weg; es ist weder Benchmark noch garantierter Durchsatz.

Bei 32k Kontext, Batch 1: (66,7 + 8,59) GB / 4,8 TB/s → etwa 63,7 Tok/s als ideale Bandbreiten-Obergrenze; allein das Lesen des Caches dauert mindestens 1,79 ms pro Schritt.

Achse 1: Architektur — MHA vs MQA vs GQA vs MLA

Die Architektur bestimmt, wie viele K/V-Vektoren jeder Token kostet. Vier Familien, Per-Token-Cache beim Referenzmodell (fp16):

VarianteKV-Paare pro TokenPro Token (fp16)16 Nutzer × 32k Kontext
MHA — jeder Query-Head besitzt eigene K/V642.097.152 B (2 MiB)1.099,5 GB
MQA — ein gemeinsamer K/V-Head 2132.768 B (32 KiB)17,2 GB
GQA — ein gemeinsamer K/V pro Query-Gruppe 38262.144 B (256 KiB)137,4 GB
MLA — komprimiertes Latent statt per-Head-K/V 4—70.272 B ≈ 68,6 KiB (DeepSeek-V3, 61 Schichten)36,8 GB (DeepSeek-V3)

Diese Byte-Zahlen sind das, was die Architektur-Namen bedeuten. MQA teilt ein K/V-Head-Paar über alle 64 Query-Heads — in den Worten des Papers: „a single set of keys and values shared across heads“ — und reduziert den Cache um 64×. GQA liegt dazwischen: eine feste Zahl von KV-Gruppen, hier 8 von 64 Query-Heads, also ein 8-facher Schnitt; das Kernergebnis des Papers ist Qualität nahe MHA bei Geschwindigkeit nahe MQA, plus ein „Uptraining"-Rezept, das bestehende MHA-Checkpoints mit etwa 5 % der ursprünglichen Pretraining-Rechenleistung umwandelt. MLA ist ein völlig anderer Mechanismus: Statt K und V pro Head zu speichern, wird ein rank-512-komprimiertes Latent plus ein 64-dimensionaler entkoppelter RoPE-Key gespeichert — 576 Elemente pro Token pro Schicht in DeepSeek-V3s publizierter Konfiguration — und die vollen K/V werden während der Attention on-the-fly rekonstruiert. Das V2-Paper berichtet einen um 93,3 % kleineren Cache und 5,76× höheren maximalen Generierungs-Durchsatz gegenüber seiner 67B-MHA-Baseline.

Für die Kapazitätsplanung wählen Sie die Attention-Variante selten selbst — Sie wählen ein Modell, und die Variante kommt mit. Der nutzbare Takeaway: zu wissen, was Sie pro Token gekauft haben, aus der Tabelle oben.

Achse 2: Der Allokator — zusammenhängende Reservierung vs PagedAttention

Die zweite Achse hat mit dem Modell gar nichts zu tun. Eine Serving-Engine muss die wachsenden (k,v)-Zeilen jeder Anfrage irgendwo im VRAM unterbringen. Das naive Schema — ein zusammenhängender Puffer in Maximalgröße pro Anfrage — verschwendet enorme Speichermengen: Reservierungen werden selten gefüllt, und zusammenhängende Blöcke fragmentieren, wenn Anfragen unterschiedlicher Länge kommen und gehen.

Das PagedAttention-Paper (Kwon et al., SOSP 2023, arXiv:2309.06180) hat das gemessen: In den damaligen Standard-Systemen speicherten nur 20,4–38,2 % des für KV-Caches allokierten Speichers tatsächlich Token-Zustände — der Rest war Reservierungs-Slack und Fragmentierung. vLLMs paged Allokator, inspiriert vom virtuellen Speicher von Betriebssystemen, erreichte im selben Experiment 96,3 % effektive Nutzung: Logische Per-Anfrage-Caches werden in feste 16-Token-Blöcke zerlegt (vLLMs Standard-Blockgröße), über eine Blocktabelle pro Sequenz auf verstreute physische Blöcke abgebildet, bei Bedarf allokiert und Block für Block wieder freigegeben.

Block-Mathematik (Blockgröße 16): Eine 32.768-Token-Sequenz belegt 2.048 Blöcke; beim Referenzmodell hält jeder Block 16 × 262.144 B = 4 MiB K/V. Eine Anfrage, die bei 1.000 Tokens endet, zahlt für 63 Blöcke (1.000/16 → 62,5 → 63 mit Teil-Block), nicht für die 8,59 GB, die eine volle 32k-Reservierung festlegen würde. Der Verschnitt sinkt von „das meiste des Puffers" auf „höchstens ein teilweise gefüllter Block pro Anfrage".

Präfix-Wiederverwendung — RadixAttention und Verwandte

Paging behebt die Fragmentierung; ein zweiter Allokator-Gewinn ist das Teilen. Prompts stecken voller wiederholter Präfixe — derselbe System-Prompt für jeden Nutzer, dieselben Few-Shot-Beispiele über einen Benchmark hinweg, das gesamte vorherige Gespräch im Multi-Turn-Chat. Wenn jede Anfrage ihre eigene Kopie dieser Präfix-KV neu berechnet und speichert, zahlen Sie Rechenleistung und Speicher für dieselben Bytes immer wieder.

SGLangs RadixAttention (arXiv:2312.07104) behält fertige und laufende KV in einem Radix-Baum, verschlüsselt nach Token-Sequenzen, mit LRU-Verdrängung und referenzgezählten Knoten (die Baumstruktur selbst liegt auf der CPU). Ein neuer Prompt, der ein Präfix mit irgendetwas im Baum teilt, verwendet das KV dieses Zweigs wieder, ohne Neuberechnung: Die gemeinsamen Anteile werden automatisch gefunden, keine manuelle Präfix-Konfiguration. Das Paper berichtet bis zu 6,4× höheren Durchsatz bei präfix-lastigen Workloads gegenüber Systemen ohne automatische Wiederverwendung; der Baum-Lookup selbst verursacht vernachlässigbaren Overhead.

Präfix-Mathematik (Referenzmodell): Ein 2.000-Token-System-Prompt kostet 2.000 × 262.144 B ≈ 524 MB KV pro Gespräch bei fp16 — ohne Präfix-Sharing für jeden gleichzeitigen Nutzer neu berechnet und neu gespeichert. Mit Baum-Sharing wird er einmal berechnet und einmal gespeichert. Multi-Turn-Chat ist der Extremfall: Runde n teilt das gesamte Präfix der Runden 1…n−1, die inkrementellen KV-Kosten jeder Runde sind also nur ihre neuen Tokens.

Achse 3: Datentyp — FP8-KV-Cache

Als modellspezifisches Architektur- und Serving-Beispiel behandelt der Kolibri-1-Leitfaden die lokale/globale Cache-Berechnung zusammen mit seinem FP8-Serving-Pfad.

Die dritte Achse halbiert die Byte-Kosten pro Wert: Architektur beibehalten, Allokator beibehalten, den Cache in FP8 speichern. vLLM stellt dies als kv_cache_dtype="fp8" bereit (Optionen: auto, fp8_e4m3, fp8_e5m2; CUDA 11.8+), mit zwei Quantisierungsschemata — Per-Tensor-Skalen oder Skalen pro Attention-Head (q_scale = [num_heads], k/v_scale = [num_kv_heads]). Die vLLM-Dokumentation begründet das kapazitätsorientiert: FP8-KV verdoppelt näherungsweise die Zahl der Tokens, die in dasselbe Cache-Budget passen — das unterstützt entweder längere Kontexte oder mehr gleichzeitige Anfragen; mit FlashAttention-3 läuft die Attention vollständig quantisiert. Kalibrierung: keine (Skalen = 1,0), on-the-fly Random-Token-Kalibrierung oder Datensatz-Kalibrierung via llm-compressor (empfohlen).

Durchgerechnetes Kapazitätsbeispiel (H100 80 GB): Budget = 80 × 0,9 = 72 GB. Gewichte fp16 = 66,7 GB → 5,3 GB frei → fp16-KV: 20.162 Tokens; fp8-KV: 40.323 Tokens. Dieselbe GPU, quantisierte Gewichte (AWQ/GPTQ ≈ 18,7 GB) → 53,3 GB frei → fp16-KV: 203.399 Tokens; fp8-KV: 406.798 Tokens. Der maximale Kontext des Referenzmodells ist 262.144 Tokens: Mit fp16-Gewichten passt nicht einmal ein einziger Max-Kontext-Nutzer; quantisierte Gewichte + FP8-KV halten ihn mit Reserve.

Was Sie mitnehmen sollten

Sparse-Zugriffe bedeuten nicht automatisch komprimierte Speicherung. Step-5-Preview durchsucht Acht-Token-Proxy-Zusammenfassungen, liest aber ausgewählte originale K/V und behält die vollständige Historie seiner globalen Layer. Der Guide leitet Cache-Nutzlast, TP-Replikation und temporären Standalone-Prefill-Speicher getrennt her.

Das Cache-Layout hängt auch von der Implementierung ab. Ling-3.1-flash zeigt den Unterschied: Die Referenz speichert expandierte MLA-Keys und -Values, während ein absorbierter Serving-Pfad den gemeinsamen Latentvektor und Positions-Key behalten kann. Der Guide leitet beide Budgets her und berücksichtigt den unabhängigen KDA-Zustand.

Ein konkretes hybrides Gegenbeispiel zur Zählung aller Schichten als Attention ist LFM2.5-24B-A2B: Es besitzt zehn GQA-Caches und 30 kurze Faltungszustände. Aus seiner Konfiguration ergeben sich 20 KiB BF16-KV pro Token plus 360 KiB normaler Faltungszustand pro Sequenz. Der Architektur-Guide trennt diese logische Nutzlast von residenten Expertengewichten und Laufzeitallokationen.

  • Eine Formel: KV-Bytes = 2 × L × H_KV × d_head × b_dtype × s. Alles andere ist abgeleitet.
  • Die Architektur kommt mit dem Modell: GQA-8 → 256 KiB/Token fp16; MQA → 32 KiB; MLA → ~70 KB (DeepSeek-V3). Wissen, was Sie gekauft haben.
  • Paging schlägt Planung: Naive zusammenhängende Reservierung verschwendet bis zu ~80 % des KV-Budgets (20,4–38,2 % effektiv); PagedAttention-artige Allokatoren erreichen 96,3 %.
  • Präfix-Wiederverwendung ist gratis: Ein 2.000-Token-System-Prompt kostet ≈ 524 MB KV beim Referenzmodell — einmal über einen Radix-Baum über Nutzer geteilt, statt pro Nutzer neu berechnet.
  • FP8 halbiert die Per-Token-Kosten: von 256 KiB auf 128 KiB — Verdopplung der Kapazität für dasselbe Budget, lt. vLLM-Feature-Dokumentation.
  • KV kreuzt die Gewichte bei ~254.500 Tokens beim Referenzmodell (fp16): Darunter dominieren die Gewichte das Budget, darüber der Cache — und Gewichts-Quantisierung bringt am meisten, wenn der Cache dominiert (beide Segmente oben im Beispiel gerechnet).
  • Bandbreite ist eine Decode-Grenze: Auf einer H200 SXM bei 8k Kontext betragen die idealisierten Obergrenzen ~70 Tok/s für eine Anfrage und ~760 Tok/s aggregiert für 16. Gemessene Raten hängen von Compute, Laufzeit und Scheduling ab.
  • Weiterlesen: LLM-VRAM-Bedarf (Gewichte + KV-Cache vollständig), Inferenz-Mathematik (warum Decode speicherbegrenzt ist), Quantisierung (die andere Hälfte des Speicherproblems).

Beams hybrider Cache wächst nur in neun globalen GQA-Schichten; 43 weitere Schichten besitzen ein begrenztes Attention-Fenster von 512 Tokens. Der Guide leitet ungefähr 18,04 GiB FP8-KV-Nutzdaten bei 1.048.576 Tokens her und erklärt, weshalb das weder eine Spitzen-Speichermessung noch eine Cache-Qualitätsmessung ist.

Auch visuelle Eingaben belegen Sequenzpositionen. Nemotron 3.5 Super VL verbindet Frame-Paar-Projektion, räumliches Zusammenlegen und änderungsbasiertes Video-Pruning. Der Guide leitet die erhaltenen visuellen Positionen und ihren Backbone-KV-Beitrag über acht Blöcke her und trennt davon Encoder-Arbeit, Mamba-/MTP-Zustände und Markertokens.

Footnotes

  1. NVIDIA H200 Tensor Core GPU: 141 GB HBM3e und 4,8 TB/s maximale Speicherbandbreite. https://www.nvidia.com/en-us/data-center/h200/ ↩

  2. Shazeer, Fast Transformer Decoding: One Write-Head is All You Need, arXiv:1911.02150 (2019). ↩

  3. Ainslie et al., GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints, arXiv:2305.13245, EMNLP 2023. Llama-2-70B liefert 64 Query- / 8 KV-Heads. ↩

  4. DeepSeek-V2, arXiv:2405.04434: 93,3 % KV-Cache-Reduktion, 5,76× Generierungs-Durchsatz. Per-Token-Zahlen aus DeepSeek-V3s config.json (kv_lora_rank 512 + qk_rope_head_dim 64 = 576 Elemente, 61 Schichten, bf16 → 70.272 B/Token ≈ 68,6 KiB). Vergleich Llama-3.1-70B GQA-8: 2 × 8 × 128 = 2.048 Elemente/Schicht × 80 Schichten × 2 B = 327.680 B ≈ 320 KiB, also das 4,7-fache des DeepSeek-V3-MLA-Footprints. ↩