Skip to content

Experiment: Hadamard-rotierter INT8-KV-Cache (FWHT) vs INT8/KIVI #61

Description

@geisten

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.

  1. 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.
  2. 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.
  3. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions