Pure Rust implementation of Google's TurboQuant (ICLR 2026) — KV cache compression for LLMs
Rust
37
396 commits
updated Apr 19, 2026
Pure Rust TurboQuant KV cache compression. CUDA. AVX2 SIMD. C FFI. crates.io.
Implementation of Google's TurboQuant (ICLR 2026) with the 3-Fix framework that enables aggressive key compression (4-bit, 7.5x) on GGUF quantized models -- where symmetric K compression produces catastrophic output.
Now with Pre-RoPE key quantization (34-59% less PPL gap), KV Compaction (up to 25x token reduction), TriAttention eviction for constant-memory KV cache, per-token mean removal (+40% attention quality at 2-bit), and multi-arch CUDA (Turing → Hopper).
RTX 3080 10 GB, Qwen2.5-7B-Instruct Q4_K_M, own CUDA kernels, no external inference dependency. Three-run mean at 2026-04-19, warmup discarded, TTFT separated.
| Mode | tok/s | TTFT | PPL (/tmp/ppl_bench.txt) | KV memory |
|---|---|---|---|---|
| Standard | 63.6 | 0.19 s | 11.508 | grows linearly |
| TQ 4-bit | 39.3 | 0.11 s | 12.473 (+8.4%) | 3.8× smaller |
| TQ 4-bit + TriAttention | 37.6 | 0.11 s | 12.473 (+8.4%) | constant |
scripts/bench-long-context.sh for the forcing measurement.Full matrix (Llama 3.1 8B, Mistral 7B, multi-context, reproducible CLIs): BENCHMARKS.md.
Everything below is gated and unscoped; priorities in order:
TQ_MEGAKERNEL=1 through model.rs::forward. Architect projection +~10 %; will be measured, not claimed, at merge.flash_decode (single-token). Prefill attention's N×N score tensor is the real long-context OOM cliff; a flash-prefill port unlocks ≥ 4 K contexts on 10 GB cards.Full plan: see the status:planned nodes in the project knowledge graph.
GGUF quantized models (Q4_K_M) already have weight quantization noise. Compressing KV cache on top introduces compound error through softmax. tq-kv solves this with a multi-stage pipeline:
| Config | Qwen 7B Q4_K_M PPL | Status |
|---|---|---|
| No compression | 4.136 | Baseline |
| tq-kv 4-bit | 4.457 (+8%) | Production |
| tq-kv 4-bit + TriAttention | 4.574 (+11%) | Constant memory |
| tq-kv 4-bit (no calibration) | ~15+ | Needs auto-calibrate |
Key innovations for GGUF compound error:
All PPL measured with automated
tq perplexity/tq ablate.
Qwen 2.5 7B Q4_K_M, modern English, skip=4, sink=4
| Config | PPL | vs Baseline | Compression |
|---|---|---|---|
| Baseline (no TQ) | 1.823 | -- | 1x |
| Pre-RoPE 4-bit | 1.890 | +3.7% | ~7.5x |
| Standard 4-bit | 1.925 | +5.6% | ~7.5x |
| TQ + Compact (500t/30%) | 2.227 | +22.2% | ~25x |
| Pre-RoPE + Compact (500t/30%) | 2.281 | +25.1% | ~25x |
| Full stack (Pre-RoPE+V4+Compact) | 2.84 | +55.8% | ~100x |
| Tokens | Baseline | Standard TQ (delta) | Pre-RoPE (delta) | Gap Reduction |
|---|---|---|---|---|
| 475 | 5.117 | 5.820 (+13.7%) | 5.403 (+5.6%) | 59% |
| 793 | 4.901 | 5.250 (+7.1%) | 5.125 (+4.6%) | 35% |
| 2106 | 1.823 | 1.925 (+5.6%) | 1.890 (+3.7%) | 34% |
| Value Config | Extra PPL vs K-only | Value Savings |
|---|---|---|
| V-fp16 (default) | -- | 1.0x |
V-8bit (TQ_VBITS=8) | +0.2% | 2.0x |
V-4bit (TQ_VBITS=4) | +1.3% | 3.2x |
Qwen 2.5 0.5B FP16 safetensors, wikitext-2
| Bits | PPL | vs Baseline | Compression |
|---|---|---|---|
| Baseline | 10.740 | -- | 1.0x |
| 4-bit | 11.967 | +11.4% | 7.5x |
| 2-bit | 27.696 | +157.9% | 14.2x |
| Model | Bits | Ratio | SNR (dB) | Cosine Sim |
|---|---|---|---|---|
| Llama-3 8B | 2 | 14.2x | 9.2 | 0.943 |
| Llama-3 8B | 4 | 7.5x | 20.4 | 0.996 |
| Gemma 3 4B | 2 | 15.1x | 9.2 | 0.943 |
| Bit Width | 10% | 25% | 50% | 75% | 90% |
|---|---|---|---|---|---|
| 4-bit | PASS | PASS | PASS | PASS | PASS |
| 2-bit | PASS | PASS | PASS | PASS | PASS |
[dependencies]
tq-kv = "0.6"
# Pull a model
tq pull qwen2:7b
# Chat with TurboQuant compression
tq chat qwen2:7b --turbo-quant
# Chat with Pre-RoPE (best quality)
TQ_PRE_ROPE=1 tq chat qwen2:7b --turbo-quant
# Start OpenAI-compatible API server
tq serve --model qwen2:7b --turbo-quant --port 11435
# Evaluate perplexity
tq perplexity --model qwen2:7b eval.txt --turbo-quant
# Calibrate (optimal codebook + rotation from real activations)
tq calibrate qwen2:7b --text calibration_data.txt
# Run ablation study
tq ablate qwen2:7b --file eval.txt --quick --output results.csv
use tq_kv::*;
let config = TurboQuantConfig::balanced(); // 4-bit, 7.5x compression
let dim = 128;
// Batch compress
let compressed = compress_keys(&kv_data, dim, &config);
println!("Ratio: {:.1}x", compressed.compression_ratio());
// Fused attention -- no decompression, AVX2+FMA SIMD
let signs = hadamard::generate_signs(dim, config.rotation_seed);
let centroids = codebook::get_centroids(config.bits);
let rotated_q = pre_rotate_query_with_signs(&query, &signs);
let scores = fused_attention_scores(&rotated_q, &compressed, centroids, scale);
// KV Compaction -- reduce token count
let compacted = compaction::compact_head(&keys, &values, &queries,
seq_len, n_queries, dim, target_size);
// compacted.keys, compacted.beta, compacted.values
Input KV vector (from GGUF Q4_K_M model)
|
[0] Pre-RoPE capture (optional) O(1)
| Compress BEFORE RoPE for position-independent stats
|
[1] Channel bias subtraction (calibrated) O(d)
| Remove weight-quantization artifacts
|
[2] Per-token mean removal O(d)
| Softmax shift-invariant: attention ignores mean
| Frees codebook precision (+40% cosine sim @ 2-bit)
|
[3] Randomized Hadamard Transform O(d log d)
| Decorrelates outliers -> coordinates ~ Gaussian
|
[4] Per-channel adaptive sigma (KIVI-style) O(d)
| Per-dimension variance from calibration
| Lloyd-Max codebook + norm correction
|
[5] SRHT QJL Error Correction (optional) O(d log d)
| Structured Hadamard projection (+4.5 dB SNR)
|
Output: packed indices + corrected norm + mean
7.5x compression at 4-bit (keys only)
Fix 1: Sink tokens (first 4) stay FP16 -> -81% attention error
Fix 2: Current token = lossless (POQ) -> highest-impact position protected
Fix 3: Cache reset per conversation -> prevents cross-contamination
[sink FP16] [cold decayed] [compacted + beta] [hot compressed] [current FP16]
| | | | |
Always Temporal Attention- Per-head POQ
lossless decay matching adaptive lossless
(Fix 1) reduction bitwidth (Fix 2)
^
TriAttention eviction scores all segments,
keeps top-B tokens, maintains fixed budget
Based on TriAttention (Mao et al., 2026). Pre-RoPE Q/K vectors concentrate around fixed centers, enabling cheap trigonometric importance scoring without full attention computation.
Orthogonal to TurboQuant: TriAttention decides which tokens to keep (eviction), TurboQuant decides how to compress them (quantization). Combined: fixed-size KV cache at any context length.
# TQ+TriAttention is ON by default with --turbo-quant (requires calibration)
tq chat qwen2:7b --turbo-quant
# Disable TriAttention (TQ-only mode)
TQ_TRIATTN=0 tq chat qwen2:7b --turbo-quant
# Custom budget
TQ_TRIATTN_BUDGET=256 tq chat qwen2:7b --turbo-quant
| Context Length | FP16 KV | TQ 4-bit | TQ + TriAttn | Total Compression |
|---|---|---|---|---|
| 4K tokens | 235 MB | 154 MB | 4.8 MB | 49x |
| 32K tokens | 1,879 MB | 1,233 MB | 4.8 MB | 390x |
| 128K tokens | 7,516 MB | 4,933 MB | 4.8 MB | 1,560x |
| Budget | tok/s | vs TQ only | Fixed KV Memory |
|---|---|---|---|
| 512 | 15.3 | -6% | 19.3 MB |
| 256 | 15.3 | -6% | 9.6 MB |
| 128 | 13.8 | -15% | 4.8 MB |
| 64 | 7.9 | -46% | 2.4 MB |
| (none) | 16.2 | -- | grows linearly |
| Method | Max Context Length |
|---|---|
| FP16 KV | ~87,000 tokens |
| TQ 4-bit | ~133,000 tokens |
| TQ + TriAttention | unlimited |
| Use Case | Key Config | PPL Impact | Compression |
|---|---|---|---|
| Best quality | TQ_PRE_ROPE=1 | +3.7% | ~7.5x |
| Balanced | --turbo-quant (default) | +5.6% | ~7.5x |
| Maximum savings | TQ_PRE_ROPE=1 TQ_VBITS=4 | +5.0% | ~24x |
| Long context | TQ_PRE_ROPE=1 TQ_COMPACT=1000 TQ_COMPACT_RATIO=30 | +30% | ~50x |
| Extreme | Pre-RoPE + V4 + Compact | +56% | ~100x |
| Unlimited context | TQ_TRIATTN=1 TQ_TRIATTN_BUDGET=256 | TBD | constant 10 MB |
| Variable | Default | Description |
|---|---|---|
TQ_SKIP | 4 | Initial layers kept uncompressed (fp16 KV) |
TQ_PROTECT_LAST | 0 | Final layers kept uncompressed (boundary protection) |
TQ_SINK | 4 | Initial tokens preserved at fp16 (attention sinks) |
TQ_PRE_ROPE | 0 | Pre-RoPE key quantization (1=enabled, best quality) |
TQ_COMPACT | 0 | Compaction threshold (0=off, e.g. 500=compact when >500 hot tokens) |
TQ_COMPACT_RATIO | 5 | Compaction target (% of original tokens to keep) |
TQ_VBITS | 0 | Value compression bits (0=fp16, 4=4-bit, 8=8-bit) |
TQ_SPARSE_V | 1e-6 | Skip V rows where softmax weight < threshold |
TQ_FUSED | 0 | Fused attention from compressed indices (CPU only) |
TQ_DECAY | off | Temporal decay (format: "age:bits" e.g. "512:2") |
TQ_LAYER_BITS | -- | Per-layer bit width (format: "start-end:bits") |
TQ_HEAD_BITS | -- | Per-head bit width (format: "0-3:4,4-7:2") |
TQ_GROUP | 32 | Group size for per-group sigma |
TQ_BIAS_CORRECT | 0 | Softmax bias correction (experimental) |
TQ_NO_CAL | 0 | Disable calibration auto-loading |
TQ_TRIATTN | on | TriAttention eviction (on by default with --turbo-quant, 0=disable) |
TQ_TRIATTN_BUDGET | 2048 | Max KV tokens to retain (lower = more aggressive eviction, e.g. 128/256/512) |
TQ_TRIATTN_INTERVAL | 128 | Eviction check interval in tokens |
TQ_CENTER_KEYS | 1 | Per-token mean removal (softmax shift-invariant, +40% @ 2-bit) |
TQ_MAX_SEQ | 2048 | Maximum KV cache sequence length |
TQ_NO_PER_CHANNEL | 0 | Disable per-channel sigma (KIVI-style, for A/B testing) |
TQ_CUDA_ARCHES | all | CUDA target arches (e.g. "86" for dev, "75,80,86,89,90" for release) |
| Model | Context | FP16 KV | TQ 4-bit | TQ 2-bit | Savings |
|---|---|---|---|---|---|
| Qwen 2.5 7B | 4K | 256 MB | 34 MB | 18 MB | 7.5-14.2x |
| Qwen 2.5 72B | 4K | 640 MB | 85 MB | 45 MB | 7.5-14.2x |
| Llama 3.1 70B | 32K | 20 GB | 2.7 GB | 1.4 GB | 7.5-14.2x |
With KV Compaction: effective compression reaches 100-400x. With TriAttention: constant-memory KV cache -- up to 1,560x at 128K context.
| Metric | Dense QJL (paper) | SRHT QJL (ours) | No QJL |
|---|---|---|---|
| Compress overhead | 29x | 1.45x | 1.0x |
| SNR improvement | +1.2 dB | +4.5 dB | -- |
| Attention KL div. | -- | 2.9x lower | -- |
tq-kv powers tq-engine -- "Rust's Ollama" with TurboQuant compression:
tq pull qwen2:7b # download from HuggingFace
tq serve --turbo-quant # OpenAI-compatible API (SSE streaming)
tq chat qwen2:7b # terminal chat
Web UI at localhost:11435. Works with ChatBox and Open WebUI.
4 validated models: Qwen2.5 7B/0.5B, Llama 3.1 8B, Mistral 7B. Auto-detected from GGUF metadata.
tq bench qwen2:7b # Standard vs TQ vs TQ+TriAttention
tq perplexity -m qwen2:7b --compare eval.txt # 3-way PPL comparison
scripts/ppl-check.sh # Regression CI (9 checks, tight thresholds)
RTX 3080 10GB, Qwen 2.5 7B Q4_K_M, own CUDA kernels (no candle dependency). Full reproducible matrix in BENCHMARKS.md.
| Mode | tok/s | TTFT | PPL | KV Memory |
|---|---|---|---|---|
| Standard | 28.0 | 0.19s | 4.136 | grows linearly |
| TQ 4-bit | 19.7 | 0.10s | 4.457 (+7.8%) | 3.8x smaller |
| TQ+TriAttention | 19.4 | 0.11s | 4.574 (+10.6%) | constant |
4 validated models: Qwen2.5 7B/0.5B, Llama 3.1 8B, Mistral 7B. Auto-calibration on first use.
__shfl_xor_sync broadcast to all threads (no broadcast hacks)__ldg read-only cache, dequant + dot in single kernel| Phase | tok/s | Key Change |
|---|---|---|
| Baseline (candle) | 1.3 | candle framework |
| Custom CUDA kernels | 1.9 | Own matvec, RoPE, attention |
| DecodeScratch + fused | 10.1 | Zero-alloc decode, fused kernels |
| GPU prefill + CUDA Graph | 17.8 | Graph replay, Q6K lm_head |
| v2 kernels + multi-arch | 18.5 | __ldg, warp-reduce, cp.async, butterfly reduce |
| cp.async weight pipeline | 23.3 | MLP gateup + MLP down + qmatmul cp.async W-prefetch |
| mrow ladder (v0.6, shipped 2026-04-14) | 28.0 | cooperative-per-superblock gateup/down, RoPE Q+K fuse, bias-fused LM head |
cargo run --release -p tq-kv --bin tq-kv-bench
Full results: BENCHMARK.md
Our work:
Original:
MIT OR Apache-2.0
396 commits
Rust
75.6%
Cuda
18.3%
HTML
2.8%
Shell
1.4%
C
1.0%
Pure Rust implementation of Google's TurboQuant (ICLR 2026) — KV cache compression for LLMs
Rust
37
396 commits
updated Apr 19, 2026
Pure Rust TurboQuant KV cache compression. CUDA. AVX2 SIMD. C FFI. crates.io.
Implementation of Google's TurboQuant (ICLR 2026) with the 3-Fix framework that enables aggressive key compression (4-bit, 7.5x) on GGUF quantized models -- where symmetric K compression produces catastrophic output.
Now with Pre-RoPE key quantization (34-59% less PPL gap), KV Compaction (up to 25x token reduction), TriAttention eviction for constant-memory KV cache, per-token mean removal (+40% attention quality at 2-bit), and multi-arch CUDA (Turing → Hopper).
RTX 3080 10 GB, Qwen2.5-7B-Instruct Q4_K_M, own CUDA kernels, no external inference dependency. Three-run mean at 2026-04-19, warmup discarded, TTFT separated.
| Mode | tok/s | TTFT | PPL (/tmp/ppl_bench.txt) | KV memory |
|---|---|---|---|---|
| Standard | 63.6 | 0.19 s | 11.508 | grows linearly |
| TQ 4-bit | 39.3 | 0.11 s | 12.473 (+8.4%) | 3.8× smaller |
| TQ 4-bit + TriAttention | 37.6 | 0.11 s | 12.473 (+8.4%) | constant |
scripts/bench-long-context.sh for the forcing measurement.Full matrix (Llama 3.1 8B, Mistral 7B, multi-context, reproducible CLIs): BENCHMARKS.md.
Everything below is gated and unscoped; priorities in order:
TQ_MEGAKERNEL=1 through model.rs::forward. Architect projection +~10 %; will be measured, not claimed, at merge.flash_decode (single-token). Prefill attention's N×N score tensor is the real long-context OOM cliff; a flash-prefill port unlocks ≥ 4 K contexts on 10 GB cards.Full plan: see the status:planned nodes in the project knowledge graph.
GGUF quantized models (Q4_K_M) already have weight quantization noise. Compressing KV cache on top introduces compound error through softmax. tq-kv solves this with a multi-stage pipeline:
| Config | Qwen 7B Q4_K_M PPL | Status |
|---|---|---|
| No compression | 4.136 | Baseline |
| tq-kv 4-bit | 4.457 (+8%) | Production |
| tq-kv 4-bit + TriAttention | 4.574 (+11%) | Constant memory |
| tq-kv 4-bit (no calibration) | ~15+ | Needs auto-calibrate |
Key innovations for GGUF compound error:
All PPL measured with automated
tq perplexity/tq ablate.
Qwen 2.5 7B Q4_K_M, modern English, skip=4, sink=4
| Config | PPL | vs Baseline | Compression |
|---|---|---|---|
| Baseline (no TQ) | 1.823 | -- | 1x |
| Pre-RoPE 4-bit | 1.890 | +3.7% | ~7.5x |
| Standard 4-bit | 1.925 | +5.6% | ~7.5x |
| TQ + Compact (500t/30%) | 2.227 | +22.2% | ~25x |
| Pre-RoPE + Compact (500t/30%) | 2.281 | +25.1% | ~25x |
| Full stack (Pre-RoPE+V4+Compact) | 2.84 | +55.8% | ~100x |
| Tokens | Baseline | Standard TQ (delta) | Pre-RoPE (delta) | Gap Reduction |
|---|---|---|---|---|
| 475 | 5.117 | 5.820 (+13.7%) | 5.403 (+5.6%) | 59% |
| 793 | 4.901 | 5.250 (+7.1%) | 5.125 (+4.6%) | 35% |
| 2106 | 1.823 | 1.925 (+5.6%) | 1.890 (+3.7%) | 34% |
| Value Config | Extra PPL vs K-only | Value Savings |
|---|---|---|
| V-fp16 (default) | -- | 1.0x |
V-8bit (TQ_VBITS=8) | +0.2% | 2.0x |
V-4bit (TQ_VBITS=4) | +1.3% | 3.2x |
Qwen 2.5 0.5B FP16 safetensors, wikitext-2
| Bits | PPL | vs Baseline | Compression |
|---|---|---|---|
| Baseline | 10.740 | -- | 1.0x |
| 4-bit | 11.967 | +11.4% | 7.5x |
| 2-bit | 27.696 | +157.9% | 14.2x |
| Model | Bits | Ratio | SNR (dB) | Cosine Sim |
|---|---|---|---|---|
| Llama-3 8B | 2 | 14.2x | 9.2 | 0.943 |
| Llama-3 8B | 4 | 7.5x | 20.4 | 0.996 |
| Gemma 3 4B | 2 | 15.1x | 9.2 | 0.943 |
| Bit Width | 10% | 25% | 50% | 75% | 90% |
|---|---|---|---|---|---|
| 4-bit | PASS | PASS | PASS | PASS | PASS |
| 2-bit | PASS | PASS | PASS | PASS | PASS |
[dependencies]
tq-kv = "0.6"
# Pull a model
tq pull qwen2:7b
# Chat with TurboQuant compression
tq chat qwen2:7b --turbo-quant
# Chat with Pre-RoPE (best quality)
TQ_PRE_ROPE=1 tq chat qwen2:7b --turbo-quant
# Start OpenAI-compatible API server
tq serve --model qwen2:7b --turbo-quant --port 11435
# Evaluate perplexity
tq perplexity --model qwen2:7b eval.txt --turbo-quant
# Calibrate (optimal codebook + rotation from real activations)
tq calibrate qwen2:7b --text calibration_data.txt
# Run ablation study
tq ablate qwen2:7b --file eval.txt --quick --output results.csv
use tq_kv::*;
let config = TurboQuantConfig::balanced(); // 4-bit, 7.5x compression
let dim = 128;
// Batch compress
let compressed = compress_keys(&kv_data, dim, &config);
println!("Ratio: {:.1}x", compressed.compression_ratio());
// Fused attention -- no decompression, AVX2+FMA SIMD
let signs = hadamard::generate_signs(dim, config.rotation_seed);
let centroids = codebook::get_centroids(config.bits);
let rotated_q = pre_rotate_query_with_signs(&query, &signs);
let scores = fused_attention_scores(&rotated_q, &compressed, centroids, scale);
// KV Compaction -- reduce token count
let compacted = compaction::compact_head(&keys, &values, &queries,
seq_len, n_queries, dim, target_size);
// compacted.keys, compacted.beta, compacted.values
Input KV vector (from GGUF Q4_K_M model)
|
[0] Pre-RoPE capture (optional) O(1)
| Compress BEFORE RoPE for position-independent stats
|
[1] Channel bias subtraction (calibrated) O(d)
| Remove weight-quantization artifacts
|
[2] Per-token mean removal O(d)
| Softmax shift-invariant: attention ignores mean
| Frees codebook precision (+40% cosine sim @ 2-bit)
|
[3] Randomized Hadamard Transform O(d log d)
| Decorrelates outliers -> coordinates ~ Gaussian
|
[4] Per-channel adaptive sigma (KIVI-style) O(d)
| Per-dimension variance from calibration
| Lloyd-Max codebook + norm correction
|
[5] SRHT QJL Error Correction (optional) O(d log d)
| Structured Hadamard projection (+4.5 dB SNR)
|
Output: packed indices + corrected norm + mean
7.5x compression at 4-bit (keys only)
Fix 1: Sink tokens (first 4) stay FP16 -> -81% attention error
Fix 2: Current token = lossless (POQ) -> highest-impact position protected
Fix 3: Cache reset per conversation -> prevents cross-contamination
[sink FP16] [cold decayed] [compacted + beta] [hot compressed] [current FP16]
| | | | |
Always Temporal Attention- Per-head POQ
lossless decay matching adaptive lossless
(Fix 1) reduction bitwidth (Fix 2)
^
TriAttention eviction scores all segments,
keeps top-B tokens, maintains fixed budget
Based on TriAttention (Mao et al., 2026). Pre-RoPE Q/K vectors concentrate around fixed centers, enabling cheap trigonometric importance scoring without full attention computation.
Orthogonal to TurboQuant: TriAttention decides which tokens to keep (eviction), TurboQuant decides how to compress them (quantization). Combined: fixed-size KV cache at any context length.
# TQ+TriAttention is ON by default with --turbo-quant (requires calibration)
tq chat qwen2:7b --turbo-quant
# Disable TriAttention (TQ-only mode)
TQ_TRIATTN=0 tq chat qwen2:7b --turbo-quant
# Custom budget
TQ_TRIATTN_BUDGET=256 tq chat qwen2:7b --turbo-quant
| Context Length | FP16 KV | TQ 4-bit | TQ + TriAttn | Total Compression |
|---|---|---|---|---|
| 4K tokens | 235 MB | 154 MB | 4.8 MB | 49x |
| 32K tokens | 1,879 MB | 1,233 MB | 4.8 MB | 390x |
| 128K tokens | 7,516 MB | 4,933 MB | 4.8 MB | 1,560x |
| Budget | tok/s | vs TQ only | Fixed KV Memory |
|---|---|---|---|
| 512 | 15.3 | -6% | 19.3 MB |
| 256 | 15.3 | -6% | 9.6 MB |
| 128 | 13.8 | -15% | 4.8 MB |
| 64 | 7.9 | -46% | 2.4 MB |
| (none) | 16.2 | -- | grows linearly |
| Method | Max Context Length |
|---|---|
| FP16 KV | ~87,000 tokens |
| TQ 4-bit | ~133,000 tokens |
| TQ + TriAttention | unlimited |
| Use Case | Key Config | PPL Impact | Compression |
|---|---|---|---|
| Best quality | TQ_PRE_ROPE=1 | +3.7% | ~7.5x |
| Balanced | --turbo-quant (default) | +5.6% | ~7.5x |
| Maximum savings | TQ_PRE_ROPE=1 TQ_VBITS=4 | +5.0% | ~24x |
| Long context | TQ_PRE_ROPE=1 TQ_COMPACT=1000 TQ_COMPACT_RATIO=30 | +30% | ~50x |
| Extreme | Pre-RoPE + V4 + Compact | +56% | ~100x |
| Unlimited context | TQ_TRIATTN=1 TQ_TRIATTN_BUDGET=256 | TBD | constant 10 MB |
| Variable | Default | Description |
|---|---|---|
TQ_SKIP | 4 | Initial layers kept uncompressed (fp16 KV) |
TQ_PROTECT_LAST | 0 | Final layers kept uncompressed (boundary protection) |
TQ_SINK | 4 | Initial tokens preserved at fp16 (attention sinks) |
TQ_PRE_ROPE | 0 | Pre-RoPE key quantization (1=enabled, best quality) |
TQ_COMPACT | 0 | Compaction threshold (0=off, e.g. 500=compact when >500 hot tokens) |
TQ_COMPACT_RATIO | 5 | Compaction target (% of original tokens to keep) |
TQ_VBITS | 0 | Value compression bits (0=fp16, 4=4-bit, 8=8-bit) |
TQ_SPARSE_V | 1e-6 | Skip V rows where softmax weight < threshold |
TQ_FUSED | 0 | Fused attention from compressed indices (CPU only) |
TQ_DECAY | off | Temporal decay (format: "age:bits" e.g. "512:2") |
TQ_LAYER_BITS | -- | Per-layer bit width (format: "start-end:bits") |
TQ_HEAD_BITS | -- | Per-head bit width (format: "0-3:4,4-7:2") |
TQ_GROUP | 32 | Group size for per-group sigma |
TQ_BIAS_CORRECT | 0 | Softmax bias correction (experimental) |
TQ_NO_CAL | 0 | Disable calibration auto-loading |
TQ_TRIATTN | on | TriAttention eviction (on by default with --turbo-quant, 0=disable) |
TQ_TRIATTN_BUDGET | 2048 | Max KV tokens to retain (lower = more aggressive eviction, e.g. 128/256/512) |
TQ_TRIATTN_INTERVAL | 128 | Eviction check interval in tokens |
TQ_CENTER_KEYS | 1 | Per-token mean removal (softmax shift-invariant, +40% @ 2-bit) |
TQ_MAX_SEQ | 2048 | Maximum KV cache sequence length |
TQ_NO_PER_CHANNEL | 0 | Disable per-channel sigma (KIVI-style, for A/B testing) |
TQ_CUDA_ARCHES | all | CUDA target arches (e.g. "86" for dev, "75,80,86,89,90" for release) |
| Model | Context | FP16 KV | TQ 4-bit | TQ 2-bit | Savings |
|---|---|---|---|---|---|
| Qwen 2.5 7B | 4K | 256 MB | 34 MB | 18 MB | 7.5-14.2x |
| Qwen 2.5 72B | 4K | 640 MB | 85 MB | 45 MB | 7.5-14.2x |
| Llama 3.1 70B | 32K | 20 GB | 2.7 GB | 1.4 GB | 7.5-14.2x |
With KV Compaction: effective compression reaches 100-400x. With TriAttention: constant-memory KV cache -- up to 1,560x at 128K context.
| Metric | Dense QJL (paper) | SRHT QJL (ours) | No QJL |
|---|---|---|---|
| Compress overhead | 29x | 1.45x | 1.0x |
| SNR improvement | +1.2 dB | +4.5 dB | -- |
| Attention KL div. | -- | 2.9x lower | -- |
tq-kv powers tq-engine -- "Rust's Ollama" with TurboQuant compression:
tq pull qwen2:7b # download from HuggingFace
tq serve --turbo-quant # OpenAI-compatible API (SSE streaming)
tq chat qwen2:7b # terminal chat
Web UI at localhost:11435. Works with ChatBox and Open WebUI.
4 validated models: Qwen2.5 7B/0.5B, Llama 3.1 8B, Mistral 7B. Auto-detected from GGUF metadata.
tq bench qwen2:7b # Standard vs TQ vs TQ+TriAttention
tq perplexity -m qwen2:7b --compare eval.txt # 3-way PPL comparison
scripts/ppl-check.sh # Regression CI (9 checks, tight thresholds)
RTX 3080 10GB, Qwen 2.5 7B Q4_K_M, own CUDA kernels (no candle dependency). Full reproducible matrix in BENCHMARKS.md.
| Mode | tok/s | TTFT | PPL | KV Memory |
|---|---|---|---|---|
| Standard | 28.0 | 0.19s | 4.136 | grows linearly |
| TQ 4-bit | 19.7 | 0.10s | 4.457 (+7.8%) | 3.8x smaller |
| TQ+TriAttention | 19.4 | 0.11s | 4.574 (+10.6%) | constant |
4 validated models: Qwen2.5 7B/0.5B, Llama 3.1 8B, Mistral 7B. Auto-calibration on first use.
__shfl_xor_sync broadcast to all threads (no broadcast hacks)__ldg read-only cache, dequant + dot in single kernel| Phase | tok/s | Key Change |
|---|---|---|
| Baseline (candle) | 1.3 | candle framework |
| Custom CUDA kernels | 1.9 | Own matvec, RoPE, attention |
| DecodeScratch + fused | 10.1 | Zero-alloc decode, fused kernels |
| GPU prefill + CUDA Graph | 17.8 | Graph replay, Q6K lm_head |
| v2 kernels + multi-arch | 18.5 | __ldg, warp-reduce, cp.async, butterfly reduce |
| cp.async weight pipeline | 23.3 | MLP gateup + MLP down + qmatmul cp.async W-prefetch |
| mrow ladder (v0.6, shipped 2026-04-14) | 28.0 | cooperative-per-superblock gateup/down, RoPE Q+K fuse, bias-fused LM head |
cargo run --release -p tq-kv --bin tq-kv-bench
Full results: BENCHMARK.md
Our work:
Original:
MIT OR Apache-2.0
396 commits
Rust
75.6%
Cuda
18.3%
HTML
2.8%
Shell
1.4%
C
1.0%