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.

Disaggregierte Quantisierung: Prefill- und Decode-Kosten auf zwei Formate verteilen

Ein Paper von September 2026 (arXiv:2609.26333) behandelt ein Modell nicht mehr als ein einziges Quantisierungsproblem. Prefill ist rechenbegrenzt, also beschleunigt niedrigpräzise NVFP4-Arithmetik; Decode ist bandbreitenbegrenzt, also beschleunigen 1-3-Bit-Gewichte. Disaggregierte Quantisierung spezialisiert Formate, Gewichte und Speicherplatzierung pro Phase: Das Weglassen der Aktivierungsquantisierung allein beim Decode ist kostenlose Genauigkeit, ein separat trainierter NVFP4-Prefiller hebt einen eingefrorenen 1-Bit-GGUF-Decoder um +32,5 MMLU-Pro-Punkte, und ein von der SSD gestreamter Prefiller kauft ein 1,78-faches TTFT bei 8K Kontext — bezahlt mit einem zweiten Checkpoint, der gespeichert und qualifiziert werden muss, einer SSD-Amortisation, die nur bei langen Prompts aufgeht, und einer 1-Bit-Steuer, die bestehen bleibt. Dieser Guide rechnet Roofline, Crossover-Mathematik und ein Bits-gegen-Genauigkeit-Spielzeug in echten Zellen durch.

11 Min. Lesezeitflozi00
aimachine-learningllminferencequantization

Ein Paper von September 2026 aus dem Umfeld von NVIDIA und ISTA greift eine Annahme an, die so selbstverständlich eingebacken ist, dass die meisten Quantisierungsarbeiten sie nie aussprechen: dass ein Modell eine quantisierte Repräsentation braucht1. Disaggregated Quantization: Specializing LLM Prefill and Decode (Panferov, Kleinegger, Priyadarshi, Blankevoort und Alistarh, arXiv:2609.26333, cs.LG, eingereicht am 22. September 2026) beobachtet, dass die beiden Phasen der LLM-Inferenz für Gegenteiliges bezahlen. Prefill verarbeitet den ganzen Prompt in einem Rutsch — das ist eine GEMM, begrenzt durch Arithmetik, also beschleunigen niedrigpräzise Rechenformate (NVFP4) ihn. Decode lädt bei Batch eins für jedes generierte Token sämtliche Gewichte aus dem Speicher, um ein einziges Token zu berechnen — das ist ein Speicherbandbreiten-Problem, also beschleunigen kompakte Gewichte (1-3 Bit) es. Disaggregierte Quantisierung (DQ) spezialisiert deshalb Rechenformate, Gewichte und sogar die Speicherplatzierung pro Phase statt pro Modell1.

Das Paper ist kein neuer Quantisierer. Es ist eine Beobachtung auf Serving-Ebene mit einer Leiter aus drei zunehmend aggressiven Ausbaustufen: Aktivierungsquantisierung nur beim Decode deaktivieren (kostenlose Genauigkeit); einen separaten rechennativen NVFP4-Prefill-Checkpoint auf dasselbe Antwortziel hin trainieren (schnellerer Prefill plus bessere Niedrigbit-Genauigkeit); und diesen zweiten Checkpoint von der SSD streamen, damit ein einzelnes Gerät nicht beide hält (die 1,78-fache TTFT-Behauptung). Die Schnittstelle zwischen den Phasen bleibt der KV-Cache, dessen Layer- und Head-Dimensionen unverändert bleiben — Prefill produziert Repräsentationen, zu denen die unveränderten Decode-Gewichte dann attenden1. Der Haken, den das Paper selbst benennt: Man baut, speichert, benchmarkt und qualifiziert jetzt zwei Artefakte, der SSD-Trick zahlt sich nur bei langen Prompts aus, und die +32,5-Punkte-Schlagzeile ist die Rettung einer kollabierten 1-Bit-Baseline — keine Parität mit BF16.

1. Der Roofline-Split: Warum die Phasen unterschiedliche Achsen haben

Die ganze Methode fällt aus einer einzigen Rechnung heraus. Ein linearer Stack mit P Parametern, der einen Prompt der Länge L verarbeitet, führt etwa 2·P·L Operationen aus. Beim Prefill lädt er die P Gewichte einmal pro Prompt; beim Decode mit Batch eins lädt er alle P Gewichte pro generiertem Token, um nur 2·P nützliche Operationen auszuführen. Gegen die bewegten Gewichtsbytes gemessen liegt die arithmetische Intensität bei 16·L/bw ops/byte für Prefill und 16/bw für Decode, wobei bw die Bits pro Gewicht sind — das Verhältnis der beiden ist exakt die Promptlänge.

Gerechnet gegen die Hardware des Papers, DGX Spark (128 GB unified LPDDR5x mit 273 GB/s, 1000 FP4-TOPS mit Sparsity, also 500e12 dichte Operationen/s nach der NVIDIA-Datenblattzählung)2:

python
# CELL 1: roofline split -- prefill vs decode vs weight precision
# Arithmetic intensity (AI) measured against WEIGHT bytes, per linear stack.
#   prefill: ops = 2*P*L, weight bytes = P*bw/8 once per prompt -> AI = 16*L/bw
#   decode (batch 1): ops = 2*P, weight bytes = P*bw/8 per token -> AI = 16/bw
# Machine: DGX Spark (NVIDIA spec sheet): 1000 TOPS FP4 *with sparsity*
# -> 500e12 dense ops/s; 273 GB/s LPDDR5x.
 
FP4_DENSE_OPS = 500e12
MEM_BW = 273e9
 
def ai_decode(bw): return 16.0 / bw
def ai_prefill(L, bw): return 16.0 * L / bw
 
bal_fp4 = FP4_DENSE_OPS / MEM_BW
print("CELL 1: AI = ops per weight-byte (ops/byte), DGX Spark")
print(f"machine balance point at dense FP4: {bal_fp4:.0f} ops/byte")
print()
print("weight bits | decode AI | prefill AI L=512 | L=8192 | decode is")
for bw in (16.0, 8.0, 4.5, 2.5, 1.5):
    regime = "compute" if ai_decode(bw) >= bal_fp4 else "bandwidth"
    Lx = bal_fp4 * bw / 16.0
    print(f"  {bw:4.1f}      | {ai_decode(bw):8.2f} | {ai_prefill(512, bw):16.2f} | {ai_prefill(8192, bw):6.0f} | {regime}-bound")
    print(f"             prefill turns compute-bound at L >= {Lx:.0f} tokens")

Output eines realen Laufs (Python 3):

text
CELL 1: AI = ops per weight-byte (ops/byte), DGX Spark
machine balance point at dense FP4: 1832 ops/byte
 
weight bits | decode AI | prefill AI L=512 | L=8192 | decode is
  16.0      |     1.00 |           512.00 |   8192 | bandwidth-bound
             prefill turns compute-bound at L >= 1832 tokens
   8.0      |     2.00 |          1024.00 |  16384 | bandwidth-bound
             prefill turns compute-bound at L >= 916 tokens
   4.5      |     3.56 |          1820.44 |  29127 | bandwidth-bound
             prefill turns compute-bound at L >= 515 tokens
   2.5      |     6.40 |          3276.80 |  52429 | bandwidth-bound
             prefill turns compute-bound at L >= 286 tokens
   1.5      |    10.67 |          5461.33 |  87381 | bandwidth-bound
             prefill turns compute-bound at L >= 172 tokens

Zwei Ablesungen. Erstens liegt Decode bei jeder Gewichtspräzision zwei bis drei Größenordnungen unter dem Balance-Punkt der Maschine — Gewichte zu komprimieren ist der einzige Hebel, der Decode hilft, und das bleibt wahr, egal wie grob die Gewichte werden: Bei 1,5 Bit liegt die Decode-Intensität mit 10,67 ops/byte weiterhin gegen einen Balance-Punkt von 1832. Zweitens überschreitet Prefill schon nach wenigen hundert bis wenigen tausend Token die Rechenschwelle — für reale Prompts ist FP4-Arithmetik also das, was man für die Prefill-Seite kaufen sollte, und nichts an der Decode-Seite (wo die Gewichte wohnen) repariert die Prefill-Geschwindigkeit. Das ist der ganze Widerspruch zur monolithischen Quantisierung in einer Tabelle: Ein einzelnes Format kann höchstens für eine Phase optimal sein.

2. Die billigste Stufe: Decode-Gewichte behalten, Decode-Aktivierungsquantisierung verwerfen

Die unterste Stufe behält einen Satz Gewichte und ändert nur das Rechenformat pro Phase. NVFP4 quantisiert Gewichte und Aktivierungen (W4A4), was die Tensor-Cores wollen; die nur-gewichtete Variante NVFP4A16 lässt Aktivierungen in höherer Präzision, ist genauer, kann aber die schnelle FP4-GEMM nicht nutzen. Die Beobachtung des Papers: Beim Decode bringt die Aktivierungsquantisierung nichts (Decode ist bandbreitenbegrenzt — die Arithmetik steht ohnehin still) und kostet trotzdem Genauigkeit, weil die pro-Token-Hidden-States, die die Antwort transportieren, auf dasselbe grobe E2M1-Raster gesnappt werden, für das Prefill bereits bezahlt hat. Also: Aktivierungen nur beim Prefill quantisieren, den Aktivierungsquantisierer beim Decode überspringen. Speicher, Prefill-Kosten und Decode-Tempo bleiben unverändert oder minimal besser (das Überspringen macht Decode 2-3 % schneller), und die Decode-Genauigkeit steigt auf allen sieben getesteten Qwen-3- und Gemma-3-Modellen1.

Ein Spielzeug macht den Mechanismus konkret: ein kleines dreischichtiges MLP (nur Standardbibliothek, fester Seed), dann die Gewichtsbit-Leiter mit Block-64-RTQ hochlaufen und einen statischen per-Tensor-FP4-Aktivierungsquantisierer an- und ausschalten:

python
# CELL 3: accuracy-vs-bits ladder and the decode activation-quantization tax.
# Trained-from-scratch 3-layer MLP (pure stdlib; seed fixed) on an 8-class
# cluster task -- a stand-in for a "released model". Weight quantization is
# block-64 RTQ; activation quantization is per-tensor FP4-style signed grid
# with a STATIC scale set by a running-maximum calibration pass (what NVFP4
# W4A4 does, and what format disaggregation removes on decode).
import random, math
random.seed(2026)
 
D, H, C, N = 64, 96, 8, 1500
centers = [[random.gauss(0, 1) for _ in range(D)] for _ in range(C)]
XN, YN = [], []
for i in range(N):
    c = i % C
    XN.append([random.gauss(centers[c][d], 1.0) for d in range(D)])
    YN.append(c)
 
def init(rows, cols, s): return [[random.gauss(0, s) for _ in range(cols)] for _ in range(rows)]
W1, W2, W3 = init(H, D, (2/D)**0.5), init(H, H, (2/H)**0.5), init(C, H, (2/H)**0.5)
 
def fwd(x_in, Ws, aq=None):
    h = list(x_in)
    for li, W in enumerate(Ws):
        h = [max(0.0, sum(h[k]*W[j][k] for k in range(len(h)))) for j in range(len(W))]
        if aq:
            s = aq[li]
            h = [max(-8*s, min(8*s, round(v/s)*s)) for v in h]  # FP4-ish signed grid
    return h
 
def logits_all(Ws, aq=None): return [fwd(x, Ws, aq) for x in XN]
def acc(lg): return sum(max(range(C), key=lambda j: l[j]) == YN[i] for i, l in enumerate(lg))/N
def softmax_g(l, y):
    m = max(l); es = [math.exp(v-m) for v in l]; S = sum(es)
    g = [es[j]/S for j in range(C)]; g[y] -= 1.0; return g
 
LR = 0.05
for step in range(12):
    for i in range(N):
        hs = [XN[i]]
        for W in (W1, W2, W3):
            hs.append([max(0.0, sum(hs[-1][k]*W[j][k] for k in range(len(hs[-1])))) for j in range(len(W))])
        g3 = softmax_g(hs[3], YN[i])
        g2 = [sum(g3[j]*W3[j][k] for j in range(C))*(1 if hs[2][k] > 0 else 0) for k in range(H)]
        g1 = [sum(g2[j]*W2[j][k] for j in range(H))*(1 if hs[1][k] > 0 else 0) for k in range(H)]
        for j in range(C):
            for k in range(H): W3[j][k] -= LR*g3[j]*hs[2][k]
        for j in range(H):
            for k in range(H): W2[j][k] -= LR*g2[j]*hs[1][k]
        for j in range(H):
            for k in range(D): W1[j][k] -= LR*g1[j]*hs[0][k]
    if step % 30 == 0:
        print(f"  [train] step {step}: acc {acc(logits_all([W1,W2,W3])):.4f}")
 
def rtq_block(W, bits, gs=64):
    Wq = []
    for row in W:
        rq = []
        for i in range(0, len(row), gs):
            blk = row[i:i+gs]
            r = max(abs(w) for w in blk) or 1e-9
            s = 2*r/(2**bits-1)
            rq.extend(round(w/s)*s for w in blk)
        Wq.append(rq)
    return Wq
 
# static per-tensor activation scales via running-max observer on calibration prompts
run_max = [0.0, 0.0, 0.0]
for i in range(200):
    h = XN[i]
    for li, W in enumerate((W1, W2, W3)):
        h = [max(0.0, sum(h[k]*W[j][k] for k in range(len(h)))) for j in range(len(W))]
        run_max[li] = max(run_max[li], max(h))
S = [m/6.0 for m in run_max]   # E2M1 grid saturates ~ +/-6x scale
 
print()
print("CELL 3: accuracy vs weight bits, and the decode act-quant tax")
print("weights | acts | accuracy")
BF = acc(logits_all([W1, W2, W3]))
print(f"BF16    | FP   | {BF:.4f}")
for bits in (4, 3, 2, 1):
    Wq = [rtq_block(W1, bits), rtq_block(W2, bits), rtq_block(W3, bits)]
    a_fp = acc(logits_all(Wq))
    a_aq = acc(logits_all(Wq, aq=S))
    print(f"{bits}-bit   | FP   | {a_fp:.4f}")
    print(f"{bits}-bit   | W4A4 | {a_aq:.4f}    (act-quant tax {a_fp - a_aq:+.4f})")
print(f"BF16    | W4A4 | {acc(logits_all([W1,W2,W3], aq=S)):.4f}    (act-quant alone)")

Output eines realen Laufs (Python 3, Seed 2026):

text
  [train] step 0: acc 0.9993
 
CELL 3: accuracy vs weight bits, and the decode act-quant tax
weights | acts | accuracy
BF16    | FP   | 1.0000
4-bit   | FP   | 1.0000
4-bit   | W4A4 | 0.9987    (act-quant tax +0.0013)
3-bit   | FP   | 1.0000
3-bit   | W4A4 | 0.9993    (act-quant tax +0.0007)
2-bit   | FP   | 0.9987
2-bit   | W4A4 | 0.9960    (act-quant tax +0.0027)
1-bit   | FP   | 0.1253
1-bit   | W4A4 | 0.1253    (act-quant tax +0.0000)
BF16    | W4A4 | 0.9987    (act-quant alone)

Zu lesen als Kapitel 2.2 des Papiers im Miniformat. Die Gewichtsleiter ist auf diesem leichten Spielzeug bis 2 Bit harmlos und fällt bei 1 Bit von der Klippe: Naives 1-Bit-Runden zerstört die Funktion komplett — die veröffentlichten GGUF-Decoder des Papers überleben bei 1 Bit nur, weil aggressive Vektorquantisierungs-Kodierungen (IQ1_S & Co.) plus Trainingszeitliche Wiederherstellung Arbeit leisten, die das Spielzeug nicht modelliert. Und die Aktivierungsquantisierungs-Steuer (die W4A4-gegen-FP-Lücke bei festen Gewichtsbits) wächst, je gröber die Gewichte werden — der verbleibende Spielraum schrumpft genau dann, wenn der Gewichtsfehler schon groß ist, also bestrafen grobe Gewichte und grobe Aktivierungen einander. Diese Wechselwirkung ist der Grund, warum das Weglassen der Aktivierungsquantisierung genau dort, wo sie kostenlos ist (bandbreitenbegrenzter Decode), der billigste Gewinn des Papiers ist: Die 2-Bit-Zeile des Spielzeugs gibt 0,0027 Genauigkeit an die Aktivierungsquantisierung zurück, die Decode nie bezahlen musste. Die größte Instanz desselben Effekts ist die PTQ-Validierung des Papers an Modellen bis 2,8 Billionen Parametern, wo Formatdisaggregation die Punktschätzwerte in 11 von 13 Modell-Benchmark-Kombinationen verbessert, mit 6 statistisch signifikanten Gewinnen und keinen signifikanten Verschlechterungen — ohne dass irgendetwas nachtrainiert wurde1.

3. Volle Disaggregation: Für den Prefill eigene Gewichte kaufen

Formatdisaggregation hat eine selbstauferlegte Decke: Prefill rechnet weiterhin auf einer re-quantisierten Sicht der 1-3-Bit-Decode-Gewichte („Autocast" quantisiert LUT-Gewichte plus Aktivierungen auf dem Flug nach NVFP4), die FP4-GEMM läuft also auf Eingaben, die die kompakte Kodierung bereits beschädigt hat. Die nächste Stufe gibt dem Prefill einen eigenen Checkpoint, der von Anfang an als rechennatives NVFP4 trainiert wird. QADD (quantization-aware distillation with disaggregation) trainiert beide Pfade auf ein Antwortziel in einem einzigen Forward-Backward-Pass und nutzt die SFT-Label-Maske, um Prompt-Positionen durch den Prefill-Pfad und Antwort-Positionen durch Decode zu schicken; Gradienten erreichen die Prefill-Gewichte über die Prompt-Keys und -Values, zu denen Decode später attendet1. Die Familienmittelwerte aus Tabelle 1 des Papers (Qwen 3 / Gemma 3, Genauigkeit auf Decode-lastigen und Prefill-lastigen Suiten, Geräte-GB, Speedups über BF16 auf DGX Spark) zeigen die Form des Deals für die 2-Bit-LUT2-Zeilen1:

  • 2-Bit nur-gewichtetes Decode: Decode-lastig 38,4 / 33,7, 3,82-facher / 4,15-facher Decode-Speedup, 4,66 / 5,38 GB.
  • LUT2-Autocast in beiden Phasen (nicht disaggregiert): Decode-lastig kollabiert auf 34,8 / 30,8 — Aktivierungsquantisierung beim Decode schadet — bei 1,49-fachem / 1,67-fachem Prefill-Speedup.
  • Plus Formatdisaggregation: 37,2 / 32,6 — der größte Teil des Kollapses zurückgewonnen bei unveränderten Geräte-GB.
  • Plus volle Disaggregation: 45,5 / 38,2 Decode-lastig und 76,6 / 61,3 Prefill-lastig — für LUT3/LUT2 meldet das Papier Gewinne über das nicht-disaggregierte Schema von 6,3 / 5,2 beziehungsweise 10,7 / 7,4 Decode-lastigen Punkten — aber der Gerätespeicher springt auf 8,57 / 11,43 GB: zwei Checkpoints.
  • Plus ODP: dieselbe Genauigkeit bei wieder 4,66 / 5,38 GB, der Prefill-Speedup bleibt fast unangetastet (1,47-fach / 1,58-fach).

Der Prefiller ist also nicht nur schneller Prefill; er ist eine Rettungseinrichtung für Niedrigbit-Decode. Aber Zeile vier hat einen Preis: Der Speicher hat sich fast verdoppelt, bis ODP ihn zurückgab — das Thema des nächsten Abschnitts — und jedes voll-disaggregierte Modell wird als zwei Artefakte ausgeliefert.

4. Prefiller für eingefrorene Checkpoints: +32,5 Punkte — gemessen wogegen?

Das kommerziell spitzeste Experiment lässt die Decode-Seite komplett unangetastet: veröffentlichte, vorquantisierte Qwen3.8-27B-GGUF-Checkpoints (acht Unsloth-Releases von IQ1_S bis Q3_K_XL, im llama.cpp-GGUF-Ökosystem3), jeder dequantisiert und eingefroren, mit nur einem darauf trainierten NVFP4-Prefill-Pfad1. Die Decode-Quantisierungspipeline bleibt eine Black Box — das Training braucht ihren Checkpoint, nicht ihre Daten oder ihren Algorithmus. Auf dem IQ1_S-Decoder (1 Bit) verschiebt der trainierte NVFP4-Prefiller MMLU-Pro von 29,04 auf 61,54 (+32,50 Punkte) und MMMU-Pro von 24,39 auf 59,65 (+35,26; das Abstract rundet auf 35,3), ohne die Decode-Gewichte anzutasten — die 1-Bit-Genauigkeit verdoppelt sich auf beiden Benchmarks mehr als1. Die Gewinne schrumpfen mit steigender Bitbreite — +19,71 MMLU-Pro bei IQ1_M, +7,42 bei IQ2_XXS, +2,80 bei IQ2_S, und sie drehen bei den 3-Bit-Formaten ins Negative (IQ3_S −0,63, Q3_K_XL −0,62 MMLU-Pro; bis zu −2,77 MMMU-Pro)1.

Zwei Fakten müssen zusammen reisen. Erstens ist der Mechanismus repräsentational, nicht arithmetisch: Der eingefrorene Decoder verlor Genauigkeit schon deshalb, weil seine Eingaben — die Prompt-KV-Einträge — von einem verstümmelten 1-Bit-Prefill-Verständnis des Prompts gebaut wurden; ein treues NVFP4-Prompt-Verständnis stellt wieder her, was der Decoder noch ausdrücken kann. Zweitens zählt die Baseline: BF16-Qwen3.8-27B erzielt 84,62 MMLU-Pro und 75,26 MMMU-Pro in derselben Tabelle, die gerettete 1-Bit-Pipeline liegt mit 61,54 also noch etwa 23 Punkte unter der Vollempfindlichkeit. Die +32,5 sind die Distanz von einer kollabierten 1-Bit-Baseline zu einer deutlich weniger kollabierten — ein Argument dafür, dass 1-Bit-Decode benutzbar wird, wenn der Prefill aufhört, ihn zu sabotieren, nicht dafür, dass er BF16 einholt1.

5. ODP: Der zweite Checkpoint lebt auf der SSD, und die Amortisation hat einen Crossover

Volle Disaggregation auf einem einzelnen Gerät sprengt den Speicher — hier wird die Speicherplatzierung Teil der Quantisierungsentscheidung. Offloaded disaggregated prefill (ODP) nutzt eine Phasen-Asymmetrie: Die Gewichte eines Prefill-Transformer-Blocks werden pro Prompt genau einmal berührt (während die Token Ebene für Ebene durchs Netzwerk strömen) und danach für den Rest der Runde nie wieder gebraucht. Der Prefill-Checkpoint kann also Block für Block von der SSD gestreamt werden, durch zwei rotierende Gerätepuffer, die aus dem eigenen Speicher der Decode-Gewichte herausgeschnitten werden (während des Prefills ungenutzt). Der Gewichts-Footprint auf dem Gerät fällt auf die Decode-only-Zahl zurück; der Preis ist SSD-Verkehr plus eine feste Ladezeit, die nur lange Prompts verstecken können1.

Die Amortisationsrechnung, mit den Zahlen des Papers. Ein NVFP4-Checkpoint eines 27-Milliarden-Parameter-Modells ist etwa 15,19 GB (27e9 Parameter bei 4,5 Bit pro Gewicht — 4 Datenbits plus der über 16 Elemente amortisierte FP8-Block-Scale). Der streamt einmal pro Prompt unabhängig von der Länge, während die Prefill-Rechenzeit linear in L wächst:

python
# CELL 2: ODP SSD amortization for the Qwen3.8-27B NVFP4 prefiller.
# Full disaggregation stores a SECOND checkpoint (~4.5 bpw for NVFP4 incl.
# the FP8 block scales). ODP streams it from SSD: each transformer block is
# needed exactly once per prompt, so SSD time is FIXED while prefill compute
# grows linearly in L. Crossover L*: compute time == SSD load time.
# Calibration: paper reports compute overtakes loading around 8K context on
# DGX Spark; we pin SSD at 3.5 GB/s (ordinary NVMe sustained read) and solve
# for the achieved NVFP4 throughput that makes L* = 8192.
 
P = 27e9          # Qwen3.8-27B parameters
BPW = 4.5         # NVFP4 bits per weight incl. FP8-E4M3 scale per 16 elems
ckpt_gb = P * (BPW / 8) / 1e9
SSD = 3.5         # GB/s sustained
L_star = 8192
 
load_s = ckpt_gb / SSD                       # fixed SSD cost per prompt
T_ops = 2 * P * L_star / load_s             # implied achieved FP4 throughput
print("CELL 2: ODP off the 27B NVFP4 prefiller")
print(f"checkpoint on SSD: {ckpt_gb:.2f} GB at {SSD} GB/s -> fixed load {load_s:.2f} s")
print(f"implied achieved NVFP4 throughput: {T_ops/1e12:.0f} TOPS")
print()
print("L tokens | MB SSD / token | load s | compute s | load/compute")
for L in (1024, 2048, 4096, 8192, 16384, 32768):
    mb = ckpt_gb * 1e3 / L
    cs = 2 * P * L / T_ops
    print(f"{L:8d} | {mb:15.2f} | {load_s:6.2f} | {cs:9.2f} | {load_s/cs:11.2f}")
print()
print("crossover sensitivity (L* scales with SSD bandwidth):")
for g in (1.75, 3.5, 7.0):
    print(f"  SSD {g:4.2f} GB/s -> L* = {L_star * SSD / g:6.0f} tokens")

Output eines realen Laufs (Python 3):

text
CELL 2: ODP off the 27B NVFP4 prefiller
checkpoint on SSD: 15.19 GB at 3.5 GB/s -> fixed load 4.34 s
implied achieved NVFP4 throughput: 102 TOPS
 
L tokens | MB SSD / token | load s | compute s | load/compute
    1024 |           14.83 |   4.34 |      0.54 |        8.00
    2048 |            7.42 |   4.34 |      1.08 |        4.00
    4096 |            3.71 |   4.34 |      2.17 |        2.00
    8192 |            1.85 |   4.34 |      4.34 |        1.00
   16384 |            0.93 |   4.34 |      8.68 |        0.50
   32768 |            0.46 |   4.34 |     17.36 |        0.25
 
crossover sensitivity (L* scales with SSD bandwidth):
  SSD 1.75 GB/s -> L* =  16384 tokens
  SSD 3.50 GB/s -> L* =   8192 tokens
  SSD 7.00 GB/s -> L* =   4096 tokens

Die strukturellen Fakten, die die Tabelle offenlegt. Das Laden dominiert bei 1K Token mit 8 zu 1 und ist bei 4K noch doppelt so teuer wie das Rechnen — genau deshalb meldet das Paper, dass ODP bei kurzen Prompts langsamer ist als die residente nur-gewichtete Baseline und erst ab etwa 4K Kontext davonzieht. Der Crossover liegt in den DGX-Spark-Messungen des Papiers bei 8K (TTFT 1,78-mal schneller als die nur-gewichtete IQ1_S-Baseline bei 8K in ihrem llama.cpp-Fork), und die dort implizierte erreichte FP4-Durchsatzrate — 102 TOPS, ein Fünftel des dichten Peaks — ist ein gesunder Plausibilitätsanker für die Kalibrierung. Und der Crossover ist eine Eigenschaft des Verhältnisses von SSD-Bandbreite zu erreichter Rechenleistung, nicht der Modellgröße: Halbiert man die SSD, verdoppelt sich der Crossover. Nichts davon hilft einem MoE-Modell, wie das Papier anmerkt — der Rechenanteil pro geladenem Byte ist bei aktiven Parametern gering, also bleibt das Laden bis zu extremen Kontextlängern teuer1.

6. Anti-Hype: Die Rechnung für die Phasenteilung

Das Limitationen-Kapitel und die Tabellen des Papiers beziffern die Kosten ehrlich; die Rechnung hat fünf Posten.

Zwei Artefakte speichern, qualifizieren und konsistent halten. Ein voll-disaggregiertes Deployment besitzt einen Decode-Checkpoint und einen Prefill-Checkpoint (Qwen-3-Familie, Tabelle 1: 8,57 GB gesamt für 2-Bit gegenüber 4,66 GB nur-Decode). ODP entfernt die Geräte-Residenz, nicht das Artefakt: 15,19 GB liegen auf der SSD und müssen gegen den Decoder versioniert, heruntergeladen und regression-getestet werden — und im Setup des Papers ist jede Decode-Bitbreite mit ihrem eigenen Prefiller gepaart, die Paarungsmatrix wächst also.

Der ODP-Gewinn hängt von der Promptlänge ab. Unterhalb von rund 4K Token ist die SSD-Last — 4,34 s fester Streaming-Verkehr für den 27B-Prefiller bei der obigen Kalibrierung —reine zugesetzte TTFT-Latenz. Jedes Deployment, dessen Traffic aus Chat-langen Stößen besteht, bekommt die Speicherersparnis und die Verlangsamung; die 1,78 sind eine Zahl für 8K Kontext, die aus einem Defizit unter 4K heraus erreicht wurde1.

Der Prefiller wird trainiert, nicht heruntergeladen — außer wenn er es ist. Der +32,5-Punkte-Prefiller hat einen QADD-Lauf auf Reasoning-Traces konsumiert, die vom BF16-Modell destilliert wurden (an der vollständigen Disaggregation führt kein kostenloser Weg vorbei). Die veröffentlichten Artefakte decken Qwen3.8-27B ab; jeder andere Decoder zahlt die Rechnung für seinen eigenen Trainingslauf1.

Die 1-3-Bit-Decode-Steuer überlebt die Rettung. Der gerettete IQ1_S erzielt 61,54 MMLU-Pro gegen 84,62 für BF16 in derselben Anhangstabelle — der Prefiller repariert den Schaden, den die 1-Bit-Prefill-Sicht angerichtet hat, nicht den Schaden, den die 1-Bit-Gewichte anrichten. Und oberhalb von 2 Bit kann der Prefiller subtrahieren: Die 3-Bit-Formate verlieren bis zu 2,77 MMMU-Pro-Punkte mit angehängtem NVFP4-Prefiller. Es gibt keine Bitbreite, bei der der zweite Checkpunkt bedingungslos positiv ist1.

Die Teilung setzt disaggregierte Infrastruktur voraus. Die Genauigkeitszahlen reiten auf echtem disaggregiertem Serving (vLLM plus NIXL, KV-Cache-Transfer zwischen Engines), die ODP-Zahlen auf einem angepassten llama.cpp-Fork. Alles ist bei Batch eins, single-turn gemessen: Das Paper bewertet kein hochgradig gleichzeitiges Batching und markiert Mehrfach-Turn-Chats als ungetestet — ein erneutes Prefillen von zwischengespeicherten Assistenten-Tokens durch den Prefill-Checkpoint kann andere KV-Einträge liefern als die Decode-Zeit-Repräsentationen der Tokens, und niemand hat gemessen, wie viel das ausmacht1.

7. Fazit

Disaggregierte Quantisierung ist ein Reframing auf Serving-Ebene mit ungewöhnlich sauberem Mechanismus: Die Roofline lässt die beiden Phasen Gegenteiliges wollen, und das Paper zwingt nicht länger ein Format, beiden zu dienen. Die billige Stufe — Aktivierungsquantisierung beim Decode auslassen — ist nahezu bedingungslos gut, und die PTQ-Validierung des Papiers an produktionsgroßen Modellen bis 2,8 Billionen Parameter (11 von 13 Modell-Benchmark-Kombinationen verbessert, keine signifikant verschlechtert) stützt, dass diese Stufe in disaggregiertem Serving zum Standard wird. Die teuren Stufen sind ein echter Engineering-Trade: ein zweiter, trainierter Checkpoint gegen große Niedrigbit-Genauheitsrückgewinne und FP4-Prefill-Tempo, wobei das SSD-Streaming den Speicherpreis in einen Latenzpreis verwandelt, den nur lange Prompts amortisieren. Die ehrliche Zusammenfassung des 1-Bit-Ergebnisses: Die Phasenteilung bewegt eine 1-Bit-Pipeline von kaputt zu benutzbar — und die Distanz, die zu BF16 bleibt, ist das offene Forschungsproblem, kein gelöstes.

Fußnoten

Footnotes

  1. Panferov, Andrei; Kleinegger, Maximilian; Priyadarshi, Sweta; Blankevoort, Tijmen; Alistarh, Dan — Disaggregated Quantization: Specializing LLM Prefill and Decode, arXiv:2609.26333, cs.LG, eingereicht am 22. September 2026 (Abstract und vollständiges HTML v1 verifiziert: phasenspezialisierte Formate/Gewichte/Platzierung; Batch-eins-Decode als gewichtslastig gegenüber rechengebundener langem Prefill, Kap. 1.1; QADD-Destillation in einem Durchlauf mit SFT-Masken-Routing, Kap. 2.1; NVFP4 gegen NVFP4A16 und Formatdisaggregation ohne Decode-Aktivierungsquantisierung mit 2-3 % Decode-Speedup, Kap. 2.3; volle Disaggregation trainiert separate NVFP4-Prefill-Checkpoints mit paariger Zuordnung pro Bitbreite, Kap. 2.4; ODP streamt blockweise von der SSD mit zwei aus Decode-Gewichten geschnittenen Gerätepuffern, Rechnen überholt das Laden ab etwa 8K Kontext auf DGX Spark, MoE ausgeschlossen, Kap. 2.5; Prefiller für eingefrorene Unsloth-GGUF-Decoder von Qwen3.8-27B, Kap. 2.6 und Anhang A.2 Tabelle 5: IQ1_S 29,04→61,54 (+32,50) MMLU-Pro und 24,39→59,65 (+35,26) MMMU-Pro, BF16 84,62 / 75,26, IQ3_S −0,63, Q3_K_XL −0,62, bis zu −2,77 MMMU-Pro bei 3 Bit; Tabelle 1 Familienmittelwerte Qwen 3 / Gemma 3 inkl. LUT2-Zeilen 34,8/30,8 nicht-disagg., 37,2/32,6 Format-disagg., 45,5/38,2 voll-disagg. decode-lastig, 4,66/5,38 gegen 8,57/11,43 Geräte-GB, 1,47-facher/1,58-facher ODP-Prefill-Speedup; Kap. 3.2 voll-disagg. decode-lastige Gewinne 6,3/5,2 LUT3 und 10,7/7,4 LUT2 über nicht-disaggregiert; Abstract: 32,5 und 35,3 Punkte, 1,78-fache TTFT bei 8K in llama.cpp; Kap. 3.3 und Tabelle 2: NVFP4-PTQ-Formatdisaggregation auf acht Modellen bis 2,8 Bio. Parametern inkl. Kimi-K3-2.8T, 11 von 13 Kombinationen verbessert, 6 signifikante Gewinne, keine signifikanten Verschlechterungen; Limitationen: Batch eins, single-turn, Mehrfach-Turn-Cache-Politik ungetestet; veröffentlichte Artefakte: IST-DASLab/disaggregated-quantization Code, disaggregated-llama.cpp Fork, ISTA-DASLab/Qwen3.8-27B-NVFP4-prefiller auf Hugging Face): https://arxiv.org/abs/2609.26333 ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11 ↩12 ↩13 ↩14 ↩15 ↩16 ↩17

  2. NVIDIA — DGX Spark Produktseite und Benutzerhandbuch, Hardware-Übersicht (128 GB LPDDR5x unified memory, 256-Bit-Interface, 273 GB/s Bandbreite, 4 TB NVMe-M.2-Speicher, bis zu 1.000 TOPS / 1 PFLOP FP4 mit Sparsity, NVIDIA Blackwell GB10 Superchip, 140 W TDP): https://www.nvidia.com/en-us/products/workstations/dgx-spark/ und https://docs.nvidia.com/dgx/dgx-spark/hardware.html ↩

  3. Gerganov, Georgi und Beitragende — llama.cpp: LLM inference in C/C++, das GGUF-Ökosystem quantisierter Checkpoints, aus dem die Decoder des Papers stammen (Unsloth-veröffentlichte Qwen3.8-27B-GGUF-Checkpoints, acht Formate von IQ1_S bis Q3_K_XL), und die Basis des ODP-Erweiterungs-Forks des Papers: https://github.com/ggml-org/llama.cpp ↩