Experiment: Hadamard-rotierter INT8-KV-Cache (FWHT) vs. INT8 / KIVI
Kontext
llama.cpp PR ggml-org/llama.cpp#21038
(gemerged) rotiert Q/K/V mit einer orthonormalen Hadamard-Matrix vor der
Attention und rotiert den Output zurück. Das glättet Aktivierungs-Ausreißer und
verbessert die Qualität bestehender symmetrischer Low-Bit-Cache-Quants bei
~0 Speicherkosten (QuaRot/TurboQuant-Idee). Headline-Zahlen: Qwen3 0.6B
q4_1-Cache PPL 212 → 22, q5_1 62 → 14; q8_0 unverändert.
geist löst dasselbe Ausreißer-Problem heute mit KIVI (2-bit asymmetrisch,
per-channel-K) und hat einen INT8-Modus, der K, V und Q symmetrisch
per-head quantisiert:
- Q-Quant (INT8-Modus):
src/archs/transformer/forward/attention.c:257
- K/V-Quant (INT8-Modus):
src/archs/transformer/forward/kv_store.c:69
- KIVI:
src/backends/common/kivi.h, .../forward/attention.c:36
Der INT8-Pfad ist der Kandidat: dort sind beide Seiten des Skalarprodukts
symmetrisch quantisiert, also trifft eine Rotation die Ausreißer auf Q- und
K-Seite. KIVI umgeht das strukturell (Q bleibt fp32).
Hypothese
Eine Hadamard-Rotation vor dem INT8-Quant bringt den INT8-Cache nahe an
KIVI-Qualität — bei weniger Code und weniger Laufzeit-Buchhaltung (keine
128er-Gruppen, keine per-channel scales/zeros). Falls ja: simplere Cache-Variante.
Falls nein: wegwerfen, KIVI bleibt.
Umsetzung (minimal, hinter Env-Flag)
GEIST_KV_ROT=1 (analog zum LLAMA_ATTN_ROT_DISABLE des PR), nur im INT8-Modus wirksam.
- FWHT statt Matmul. Der PR nutzt einen n×n-Matmul nur wegen Backend-Agnostik.
Auf CPU nimmt geist die Fast Walsh–Hadamard Transform in-place, O(n·log n)
Butterfly über head_dim (Gemma4: 256/512, sonst 128 — alle Zweierpotenzen).
Normierung 1/√n → Matrix ist ihr eigenes Inverses (forward = backward).
Neue Datei src/backends/common/fwht.{h,c}, ~30 Zeilen + Self-Check.
- Einfügepunkte (nach RoPE, damit Q·K erhalten bleibt — H beidseitig):
- Q rotieren direkt vor der Quantisierung in
attention.c:257.
- K und V rotieren vor dem Quant-Store in
kv_store.c:69.
- Attention-Output (Σ softmax·V_rot) mit derselben FWHT zurückrotieren, vor o_proj.
- Keine neuen Typen, kein neuer
geist_kv_mode — der Cache bleibt bit-identisch
INT8, nur der Inhalt ist rotiert. Flag aus = exakt heutiges Verhalten.
Messung
Eval-Harness (PPL + MMLU) auf mind. zwei Modellen, jeweils 3 Konfigurationen:
| Modus |
Q |
K/V |
erwartet |
| INT8 (heute) |
int8 |
int8 |
Baseline |
| INT8 + ROT |
int8 rotiert |
int8 rotiert |
Hypothese: ↑ nahe KIVI |
| KIVI (heute) |
fp32 |
2-bit |
Qualitäts-Referenz |
| FP32 |
fp32 |
fp32 |
oberer Anker |
Zusätzlich Prefill/Decode-Kosten der FWHT auf dem A76 (Pi5) messen — die
Butterfly-Pässe liegen im heißen Decode-Pfad und müssen sich im Rauschen bewegen,
sonst kippt der ganze Sinn (CPU-Effizienz). Bench-Protokoll wie üblich:
Pi5 quiesced/mean-of-10, Mac best-of-10.
Erfolgskriterium
INT8+ROT schließt ≥ ~70 % der PPL/MMLU-Lücke zwischen INT8 und KIVI und
FWHT-Overhead < ~2 % Decode auf A76 → lohnt als simplere Alternative, KIVI ggf.
ablösen/optional machen. Sonst: Ergebnis dokumentieren, Branch schließen.
Nicht-Ziele
- Kein neues Cache-Format, keine randomisierten Hadamard-Matrizen (PR-Follow-up),
kein MLA, keine Fusion in Attention-Gewichte (QuaRot-Stufe 2). Erst messen, ob
sich der Ansatz überhaupt trägt.
Experiment: Hadamard-rotierter INT8-KV-Cache (FWHT) vs. INT8 / KIVI
Kontext
llama.cpp PR ggml-org/llama.cpp#21038
(gemerged) rotiert Q/K/V mit einer orthonormalen Hadamard-Matrix vor der
Attention und rotiert den Output zurück. Das glättet Aktivierungs-Ausreißer und
verbessert die Qualität bestehender symmetrischer Low-Bit-Cache-Quants bei
~0 Speicherkosten (QuaRot/TurboQuant-Idee). Headline-Zahlen: Qwen3 0.6B
q4_1-Cache PPL 212 → 22, q5_1 62 → 14; q8_0 unverändert.
geist löst dasselbe Ausreißer-Problem heute mit KIVI (2-bit asymmetrisch,
per-channel-K) und hat einen INT8-Modus, der K, V und Q symmetrisch
per-head quantisiert:
src/archs/transformer/forward/attention.c:257src/archs/transformer/forward/kv_store.c:69src/backends/common/kivi.h,.../forward/attention.c:36Der INT8-Pfad ist der Kandidat: dort sind beide Seiten des Skalarprodukts
symmetrisch quantisiert, also trifft eine Rotation die Ausreißer auf Q- und
K-Seite. KIVI umgeht das strukturell (Q bleibt fp32).
Hypothese
Eine Hadamard-Rotation vor dem INT8-Quant bringt den INT8-Cache nahe an
KIVI-Qualität — bei weniger Code und weniger Laufzeit-Buchhaltung (keine
128er-Gruppen, keine per-channel scales/zeros). Falls ja: simplere Cache-Variante.
Falls nein: wegwerfen, KIVI bleibt.
Umsetzung (minimal, hinter Env-Flag)
GEIST_KV_ROT=1(analog zumLLAMA_ATTN_ROT_DISABLEdes PR), nur im INT8-Modus wirksam.Auf CPU nimmt geist die Fast Walsh–Hadamard Transform in-place, O(n·log n)
Butterfly über
head_dim(Gemma4: 256/512, sonst 128 — alle Zweierpotenzen).Normierung
1/√n→ Matrix ist ihr eigenes Inverses (forward = backward).Neue Datei
src/backends/common/fwht.{h,c}, ~30 Zeilen + Self-Check.attention.c:257.kv_store.c:69.geist_kv_mode— der Cache bleibt bit-identischINT8, nur der Inhalt ist rotiert. Flag aus = exakt heutiges Verhalten.
Messung
Eval-Harness (PPL + MMLU) auf mind. zwei Modellen, jeweils 3 Konfigurationen:
Zusätzlich Prefill/Decode-Kosten der FWHT auf dem A76 (Pi5) messen — die
Butterfly-Pässe liegen im heißen Decode-Pfad und müssen sich im Rauschen bewegen,
sonst kippt der ganze Sinn (CPU-Effizienz). Bench-Protokoll wie üblich:
Pi5 quiesced/mean-of-10, Mac best-of-10.
Erfolgskriterium
INT8+ROT schließt ≥ ~70 % der PPL/MMLU-Lücke zwischen INT8 und KIVI und
FWHT-Overhead < ~2 % Decode auf A76 → lohnt als simplere Alternative, KIVI ggf.
ablösen/optional machen. Sonst: Ergebnis dokumentieren, Branch schließen.
Nicht-Ziele
kein MLA, keine Fusion in Attention-Gewichte (QuaRot-Stufe 2). Erst messen, ob
sich der Ansatz überhaupt trägt.