Replies: 181 comments 390 replies
|
It is also something other vendors out there are championing such as nvidia (KTVC): Article: https://venturebeat.com/orchestration/nvidia-shrinks-llm-memory-20x-without-changing-model-weights More links within that reference. It would be great to hear from the developers what is ahead regarding such features! |
|
I've got something going here: unixsysdev/llama-turboquant@16e93d5 PS: Closer to optimal. |
|
Working TurboQuant Implementation Available Memory layout: |
|
I have a working implementation of TurboQuant as native KV cache types in llama.cpp with Metal GPU support. Repo: https://github.com/TheTom/turboquant_plus What's working:
Benchmarks (M5 Max 128GB):
Compression target is met. Speed gap is from the unoptimized WHT rotation (O(d^2) per block). Working on Hadamard rotation (O(d log d)) and fused flash attention dequant next. Gotcha for anyone else implementing this: Metal JIT silently falls back to CPU if you Happy to collaborate with anyone else working on this. |
Couldn't wait, so I spun something up; hopefully, it helps the final implementation. Feel free to cherry-pick :)
Working TurboQuant TQ3_0 implementation (CPU, both K+V cache) Branch: https://github.com/Aaryan-Kapoor/llama.cpp/tree/turboquant-tq3_0 Implements Algorithm 1 (TurboQuant_mse) from the paper as
Benchmarks (Qwen3.5-35B-A3B Q4_K_M, CPU, 4 threads):
Output is identical to f16 baseline on the 35B model at temperature 0. Quality degrades on very small models (0.6B) as expected - the paper's claims hold for reasonably-sized models. Usage:
Known limitations:
|
|
Got CUDA + Flash Attention turbo3 working on RTX 5090. Ported @TheTom's Metal turbo3 kernels to CUDA with full Flash Attention support for both K and V. Hardware: RTX 5090 32GB, CUDA 12.8, sm_120, WSL2 Ubuntu 24.04 NIAH: 6/6 exact retrieval Qwen3.5-27B is a hybrid architecture — only 16 of 64 layers have KV cache (the GatedAttention layers). 16 layers × 4 KV heads × 256 head_dim. What's implemented (15 files, 4 new + 11 modified): All dispatch paths: convert, set-rows, get-rows, cpy, MUL_MAT routing (turbo3 excluded from mmvq/mmq, routed through dequant-then-cublas for MUL_MAT) Build: Known limitations: |
|
anyone working on Vulkan backend? |
|
https://github.com/spiritbuun/llama-cpp-turboquant-cuda This is a fork of Tom's implementation with CUDA support. Results look promising.
As per their twitter account spiritbuun. |
|
So it's already in the main repo of llama.cpp? |
|
Is no one else seeing the obvious here? |
Engineering Findings from 8-Model TurboQuant BenchmarkWe independently implemented TurboQuant from scratch (Python/NumPy, 49 tests, distortion matches paper ±15%) and ran systematic benchmarks across 8 models from GPT-2 (124M) to Qwen2.5-7B (7.6B). Sharing findings that may be useful for the llama.cpp integration: Finding 1: K/V Norm DisparityThe paper does not discuss this. Modern LLMs have dramatically different Key vs Value vector magnitudes:
Since quantization error scales with norm squared, K needs far more bits than V. The K/V ratio predicts the optimal bit budget: Finding 2: MSE > Prod for AttentionThe paper recommends TurboQuantProd (QJL residual) for Keys. Our tests show MSE for both K and V works better in practice:
QJL adds variance that softmax amplifies. Low variance (MSE) beats unbiasedness (Prod). Finding 3: Outlier-Aware Mixed Precision~5-20% of K channels (especially Layer 0) have 10-100x larger RMS than median. Storing outlier channels at 8-bit, rest at 3-bit:
Finding 4: Compressed Storage VerifiedActual memory savings: GPT-2 89% reduction, 9x compression, zero PPL impact. RepoFull implementation, benchmarks, and data: https://github.com/scos-lab/turboquant ~2,500 LOC Python, 49 tests, MIT license. Hope these findings help with the llama.cpp integration. |
|
I've been working on extending unixsysdev's tq3_0 implementation with V cache support and flash attention. Repo here: https://github.com/animehacker/llama-turboquant What this adds on top of unixsysdev's work: Normalization fix (1/32 → 1/√32 for the asymmetric K-side WHT) 72K context with tq3_0 K+V (4.57x compression) Paper with implementation details: https://oliverchurch.com/turboquant-for-ggml-achieving-4.57x-kv-cache-compression-in-llama.cpp.html |
|
Seems like this tq3 quantization works well. When could it be used on model weights to replace the useless -q3- models? |
|
Update Mar 30th 2026: WHT + QJL + MSE is the solution! In @AmesianX 's implementation, PPL decreased after introducing QJL. At first I thought this is due to @AmesianX comments, i.e., The fix was using independent sign patterns for MSE WHT and QJL SRHT. Since the only difference is WHT (Walsh-Hadamard Transform), I implemented another version replace random rotation with WHT (https://github.com/Arclabs001/YATQ/blob/main/turboquant_wht.py) Test Setup
Perplexity Comparison (Random Rotation vs WHT)
Attention Score Metrics Comparison
Observations
Finally, why "random rotation" + QJL makes it worse but WHT + QJL makes it better is still a mystery to me. As in the paper, the author says they used random rotation. (this is infer from claude, maybe explain something) Mar 28th Hey everyone! I just finished reproducing TurboQuant (ICLR 2026) purely in torch. This repo supports real QJL by rewriting whole attention and forward process for QWen3 models. And I found the result independantly: In the same bits budget, k-bit MSE is better than k-1 bit MSE + 1 bit QJL Repo link: https://github.com/arclabs001/YATQ BackgroundTurboQuant proposes a clever way to quantize KV caches:
The paper claims QJL eliminates quantization bias, which sounds great in theory. So I implemented both stages and ran extensive tests. The Surprising PartQJL actually hurts performance in practice. Here's what I found on Qwen3-1.7B (4K context), top-1 token consistency rate drops:
MSE-only consistently wins on Top-1 token matching. The gap is huge at low bits and still noticeable at 8-bit. What's Going On?The theory says QJL = no bias. That's true! But here's the trade-off:
QJL eliminates bias but explodes variance. And for attention, variance is worse than bias! Why? Softmax is tolerant to uniform bias: But variance randomly perturbs each score, which messes up Top-K ranking: So you get "unbiased" estimates that give you the wrong Top-1 token more often. Another Thing: Both Keys and Values Don't Need QJLI also tested whether V should use QJL. Short answer: nope.
Values only do weighted sum, so softmax naturally averages out per-vector errors. QJL wastes 1 bit on useless residual info. My TakeawayFor KV cache quantization:
The implementation is open source if anyone wants to dig deeper or challenge these findings: https://github.com/arclabs001/YATQ Would love to hear thoughts from the community! Did I miss something? Are there scenarios where QJL actually shines? |
|
Why not to compress the weights? For small quants there are very few values per 4/3 bits (16 or 8), it means there are a lot of equal values. Very simple encoding with bit strings easily reduce model's size twice or even more. It requires some computation to uncompress, but it is done in cache and takes a small time when inference is not compute bound, but memory throughput, so there is an extra time for decompression. Prompt processing will be a bit slower, but token generation increases twice or more. A big leap to ignore it. |
RotorQuant (planar3/iso3) vs TurboQuant (turbo3) — Qwen3.6-27B, RTX 4090Following up with a bench of the RotorQuant fork ( RotorQuant's published claims are on Llama 3.1 8B (head dim 128, RTX 5090). Qwen3.6 has GQA with Perplexity — wikitext2, 2048 ctx:
Finding: planar3/iso3 K cache is larger than q8_0 on this model. turbo3: K=12.5 MiB, V=12.5 MiB — 63% reduction vs baseline. The block-diagonal rotation in RotorQuant appears to hit a layout issue with 256-dim heads. At 128 dims (Llama 3.1 8B), the blocks presumably divide cleanly into the quantization grain. At 256 dims on Qwen3.6, they don't — producing an inflated storage representation and 38–50% throughput loss. turbo3 is the clear winner on this architecture: better PPL, 63% KV reduction, no throughput regression. Full results: https://github.com/sztlink/turboquant-cuda-bench/blob/main/bench/rotorquant/results.md Note: |
|
RotorQuant Llama 3.1 8B update — confirming PPL claim, but K cache and throughput are problematic. Ran
PPL is confirmed — iso3 (6.82) beats turbo3 (6.98) on the target model, consistent with the RotorQuant README claim. But the K cache is 2× q8_0 (128 MiB vs 68 MiB) despite being nominally 3-bit. And throughput is −82% vs q8_0, not the +28% the README claims. Same K cache anomaly appeared on Qwen3.6-27B (head_dim=256): K was 64 MiB vs 34 MiB for q8_0. Hypothesis: the K cache is stored at higher precision for deferred rotation at attention time, quantized on-the-fly during dot product — explaining both memory inflation and throughput loss. The PPL gain is real; the memory/speed benefits require a fused write-time quantization path. Full cross-model data (Llama 8B + Qwen3.6-27B): https://github.com/sztlink/turboquant-cuda-bench/tree/main/bench/rotorquant @johndpope — issues are disabled on your fork; posting here since the community is active. Is the deferred-rotation hypothesis correct? Is a write-time path planned? |
RTX 4090 bench — turbo3 vs q8_0, Llama 3.1-8B Q4_K_M + REFRACT partial (Qwen3.6-27B)Testing TG speed (RTX 4090, Llama 3.1-8B Q4_K_M,
|
| Context | Format | Prefill (t/s) | Gen (t/s) |
|---|---|---|---|
| d0 (512) | q8_0 | 1207 | 122 |
| d0 (512) | turbo3 | 745 | 102 |
| d16384 | q8_0 | 6826 | 82 |
| d16384 | turbo3 | 8674 (+27%) | 50 |
| d32768 | q8_0 | 7302 | 63 |
| d32768 | turbo3 | 7124 (−2%) | 44 |
| any ctx | planar3/iso3 | CRASH | — |
Key observations:
- 16K prefill: turbo3 beats q8_0 by +27% (bandwidth win from smaller KV entries)
- 32K prefill: parity (bandwidth gap closes as KV access patterns shift)
- Generation: turbo3 pays ~17–39% throughput cost vs q8_0 — dequant overhead currently exceeds bandwidth savings at generation workload
- planar3/iso3 crash in sampler → filed as TheTom/llama-cpp-turboquant#123
REFRACT v0.3.2 quality — partial results (Qwen3.6-27B Q4_K_M, RTX 4090)
Running with --axis-a gtm (trajectory axis blocked on patched binary build, compiling now):
| Candidate | Composite | Band | GTM | KLD |
|---|---|---|---|---|
| q8_0/q8_0 | 97.59 | EXCELLENT | 95.65 | 99.61 |
| q8_0/turbo3 | 🔄 running | — | — | — |
| turbo3/turbo3 | ⏳ queued | — | — | — |
Will reply here with full turbo3 scores when the run completes (~2h). Also building patched llama-completion for trajectory axis to cross-validate against the published matrix.
|
turbo3 REFRACT scores — Qwen3.6-27B Q4_K_M, RTX 4090 (CUDA), REFRACT v0.3.2 As promised, full GTM+KLD results across all 3 candidates:
All three land in EXCELLENT band. turbo3/turbo3 drops only 4.1 composite points vs q8_0 baseline — well within the "indistinguishable from reference, safe to deploy" threshold per REFRACT diagnostics. Notes:
Next: R-NIAH axis (long-context retrieval) to validate quality at 16K+ context. |
REFRACT score4 (trajectory v0.1.4) + score3090 — Qwen3-27B & 32B, RTX 4090 & 3090Following up on my earlier score3 results (GTM axis, Qwen3.6-27B). Two new datasets tonight. 1. Axis A: trajectory v0.1.4 vs GTM — Qwen3.6-27B Q4_K_M, RTX 4090 (SM89)The key finding: GTM and trajectory disagree significantly on turbo3.
GTM classifies all three as EXCELLENT. Trajectory v0.1.4 reveals that turbo3 on the V cache degrades generation trajectories by ~33 points — enough to flip the band to DEGRADED. KLD (perplexity on wikitext) stays high regardless, confirming that perplexity alone misses this. Notable: ctk=q8_0 vs ctk=turbo3 makes zero difference to the trajectory score (both 57.93) — the V cache is the critical component. 2. Cross-model: Qwen3-32B Q4_K_M, RTX 3090 (SM86), GTM axisFirst public REFRACT scores for Qwen3-32B dense.
Two observations:
Build: |
|
Follow-up: REFRACT score5 — Trajectory axis on Qwen3-32B (RTX 3090, SM86) Hardware: RTX 3090 (SM86, compute cap 8.6), CUDA 11.8, REFRACT v0.3.2.3
For reference — 27B trajectory (RTX 4090, SM89, from previous comment):
Findings:
Technical note: |
REFRACT attn-fix rerun: 27B + 32B, SM86 + SM89I reran the REFRACT GTM/Trajectory comparison after the attention fix, using a clean build from the turboquant branch ( Hardware
Models
The 27B result is stable cross-GPU: 4090 vs 3090 differs by <~0.5 pts in comparable cases. Axis A scores: GTM vs Trajectory
The important part: ctv=turbo3 preserves high GTM but collapses Trajectory, and the effect gets much stronger at 32B.
KLD remains high for 32B q8/turbo3 (97.54), so distribution-level closeness does not imply path preservation. This supports the sign-inversion hypothesis: scalar closeness can look good while generation trajectory drifts. |
This comment was marked as spam.
This comment was marked as spam.
|
Ampere (RTX 3080 Ti SM 86) — Qwen3.5 9B Hybrid + DeepSeek MoE Update Catching up after a few weeks. Two sets of results on the canonical branch tip ( 1. Qwen3.5 9B Hybrid: turbo beats f16 at long contextQwen3.5 9B is now a hybrid DeltaNet+attention model (
turbo3 prefill is 103% of f16 at 8K and 118% at 32K. Same pattern across turbo2 and turbo4. Decode is 96-98% of f16 for all turbo types. This follows the same dynamic as the MoE 1.76x result from April — when only a fraction of layers use attention, the bandwidth savings from compressed KV cache outweigh dequant overhead. The fewer attention layers a model has, the more turbo helps. Note: 2. DeepSeek MoE: turbo2 advantage invertedRevisiting the "turbo2 1.76x faster than f16" result from April. On the current canonical:
f16 improved 4.28x (56→242) from upstream llama.cpp MoE optimizations. turbo2 improved 9% (100→108). The turbo2 VEC FA path doesn't benefit from the new optimized MMA-based MoE attention. Result: turbo2 is now 0.45x of f16 on MoE decode, inverting the April advantage. Turbo's value on MoE is now purely about memory compression (fitting longer contexts), not decode speed. As upstream improves, turbo types fall behind on models where f16 gets the optimized kernel paths. Hardware: RTX 3080 Ti (SM 8.6, 12GB VRAM), CUDA 12.x |
|
Disclosure: posting on behalf of @X-15. This comment and the underlying experiments were run end-to-end by Claude (Anthropic's LLM) on the user's machine, with the user authorizing the build, downloads, test runs, and this post. The data is real and reproducible; the analysis is mine. TurboQuant + MTP on RTX 4090 — output-level correctness check + 3-way speed matrixI tested the combined It does not reproduce on this fork on this hardware on the prompts I tried. Setup
Note: Three-way speed matrix on Qwen3.6-27B Q4_K_MSame model file, same
MTP draft acceptance from the server log: 60.9 % on tool call, 62.5 % on needle, 15.4 % on long summary. The summary regression is the expected consequence of low draft acceptance on open-ended generation — the draft head's overhead outweighs the savings when most drafts get rejected. Tool-call and short-factual outputs draft very well because their next tokens are highly predictable. TurboQuant alone has only ≈ 1–3 % overhead on this model because Qwen3.5/3.6 is a hybrid attention/SSM with Extended stress battery (10 prompts, all pass)After the basic A/B/C smoke prompts, I ran the qualitative tests that the literature actually uses for KV-compression × spec-decode correctness — RULER variable tracking, NIAH at 5 depths, BFCL-style irrelevance detection, LoopLLM-style repetition stress, LongGenBench-style constrained 50-line generation, and a greedy
Test D is the headline result: at temperature 0, generation with No GGUF quality caveat — "MTP" in the filename ≠ MTP weights presentWorth flagging explicitly because I hit it on the first 27B I tried. There's at least one parallel report on r/LocalLLaMA of a different missing-tensor failure ( Suggested rule of thumb for re-quantizers: validate that loading with What this does NOT claimThis is a smoke + correctness battery on a specific 27B at Q4_K_M. It is not:
What it does say is that on this specific hybrid 27B, the vllm#40831 failure pattern (tool-call text-spam, amber-loop retrieval failures, long-output stutter) does not reproduce on llama.cpp on RTX 4090 with this fork's MTP backport, and that under greedy decoding MTP produces byte-identical output to no-MTP (which is the strongest available correctness signal for the speculative path). Full reports + raw artifactsPublic gist with all three reports — 3-way matrix details, extended battery raw outputs, the prompt-level benchmark research that informed the test choice, and the full GGUF-compatibility writeup including the RDson failure log. |
|
Disclosure: follow-up to my earlier comment — same setup, posted on behalf of @X-15 by Claude (Anthropic's LLM). Data is real; analysis mine. Context-length OOM frontier on a single RTX 4090 (Qwen3.6-27B Q4_K_M)The earlier comment compared decode speed at fixed
So on a 24 GiB card, with this 27B-class hybrid attention/SSM model:
Diagnostic finding worth flagging — misleading error on TQ+MTP OOMEvery TQ+MTP probe past the threshold prints exactly this on stderr: There's no The downstream message — "failed to load MTP head from The reason this matters: I had previously seen the identical error message on
A user has no way to tell from the error which one they're hitting. Suggested upstream fix: catch the allocator failure inside the second-pass model load and emit something like Methodology / what was actually runProbed each config in descending Why not Cleanup matters: a leftover Implications for users on consumer GPUs
Updated gisthttps://gist.github.com/X-15/a597ff3b84f15fb32d7434117a9ef160 — now includes |
|
Independent data point that lines up with what @sztlink has been finding on the trajectory axis, but from a simpler angle. I built a benchmark harness comparing KIVI (4-bit and 2-bit) against a norm-direction quantization approach (8-bit norm + 3/4-bit unit direction) across Qwen2.5-7B, Qwen2.5-1.5B, Llama-3.1-8B, and Mistral-7B-v0.3. The harness reports per-head minimum cosine similarity alongside average cosine. The finding that lines up with sztlink's REFRACT work: average-cosine and PPL can both look healthy while worst-case quality has already collapsed. KIVI 4-bit on Qwen2.5-7B reports avg cos 0.983 — looks fine. Min cos is 0.588, meaning at least one layer/head combination is producing near-random output. Same pattern at Qwen2.5-1.5B (avg 0.983 / min 0.646). On Llama-3.1-8B and Mistral-7B-v0.3, KIVI 4-bit min cos stays at 0.953–0.977. So it's not a universal KIVI failure — it's architecture-dependent, consistent with @scos-lab's K/V norm-ratio data from earlier in the thread. This isn't the same as what trajectory metrics capture (path divergence over many decode steps), but it's a cheap proxy for one class of the problem — the per-token failures that get averaged away. Easy to compute from the FP16 forward pass without running full generation. N+D quantization (8-bit norm + low-bit unit direction) stabilizes the Qwen failure: min cos 0.969–0.991 at ~3.9× compression across all four models. It's mechanistically distinct from rotation-based methods — no Hadamard, no codebook. Decomposition primitive overlaps with MiniCache (NeurIPS 2024); the application differs from those. No llama.cpp port; that was paused once it became clear how much serious TurboQuant work was happening here. Mostly sharing in case the harness is useful: it's pluggable, so dropping in turbo3/turbo4 or any of the rotorquant variants for a direct head-to-head against KIVI and N+D on the same four-model suite is a Repo: https://github.com/gvillines-hub/nd-kv-quant (Apache 2.0) |
|
Hay guys, look it Read README. Hello, community. I'm doing hardcore Vibe skinning on my smartphone in our beloved Termux, mostly in Codex/Claude code. One API is getting more expensive, another is being blocked, and a third has been DDoS all day. I thought, "Let's install a local model." I sat there, poring over the thread for a long time, but even with a 3 billion parameter model and my 12GB RAM, it barely delivered a token per second. And here it is – the solution is out there, mesa source code, all the world's resources, dozens of repositories to explore, and we have a ready-made version of Turboquantum, which, mind you, I implemented as an MCP. It works in Codex/Claude code (I'll be honest, Claude started producing diffs in whole blocks). Overall, Turboquantum's performance doubles when running Claude code/Codex in the cloud, not to mention the performance gains from the Mesa driver modification. This is the era - AI can live locally on a smartphone... According to benchmarks, the increase in KV calculations is x5.7+%, but in reality, the 8B Qwen model has 4 times less memory. Unfortunate for Mali owners: no device means no tests. Panfrost is already generally available, but deep forensics and reverse engineering are needed. |
|
M1 Pro 16 GB datapoint + upstream PRs Catching this thread late. I ran a full TurboQuant evaluation on Apple M1 Pro 16 GB across two rounds (MLX path via mlx-optiq / turboquant_plus, and CPU+Metal via Aaryan-Kapoor/llama.cpp's turboquant-tq3_0). Stock implementations returned 0% on needle-in-haystack at every context length I tried. After fixing the QJL math and adding the missing Metal kernels, the Hybrid K5/V4 config reached 100% retrieval at 16K tokens. Five fixes were required. Three were already known or have since been picked up upstream (Hybrid K5/V4, GGML context sizing for the shared rotation tensors — independently fixed by @wxtry in 70e45b7 on llama-cpp-turboquant). Two are new and now upstream PRs:
Full benchmarks, logs, patches, and a post-mortem on why every stock implementation degenerated are at: https://github.com/devYRPauli/turboquant-m1pro-evaluation Headline numbers on Qwen2.5-3B-Instruct, M1 Pro 16 GB:
Happy to share more detail on any of the fixes if useful. |
|
Sharing a Windows x64 prebuilt that combines TheTom's TurboQuant kernels Targeted at the gap I kept hitting: upstream prebuilts have MTP but no TurboQuant, Benchmarks — RTX 5060 Ti 16GB, Qwen3.6-27B-UD-IQ3_XXS (Unsloth MTP variant)
256K context loads on 16 GB VRAM (~14.7 GB total footprint, ~430 MB free margin). Worth highlighting from the build config
Known limits
Links
Credits: TheTom for the TurboQuant kernel port that made all of this possible, @NJannasch — your |



Uh oh!
There was an error while loading. Please reload this page.
Google Research just posted a blog and paper about a new algorithm that allows quantizing the KV cache down to under 3 bits with close to 0 accuracy loss.
Blog: https://research.google/blog/turboquant-redefining-ai-efficiency-with-extreme-compression/
Paper: https://arxiv.org/pdf/2504.19874
This could be huge if their claims are true and MLX developers are already jumping on this
https://x.com/Prince_Canuma/status/2036611007523512397
Thought I'd share the news here to see if llama.cpp developers would be interested in adding this feature.
All reactions