Turboquant Pytorch
PyTorch implementation of TurboQuant for LLM KV cache compression using two-stage vector quantization (random rotation + Lloyd-Max + QJL residual correction).
- Skill ID
- reason-machines/trending-skills/turboquant-pytorch
- Publisher
- reason-machines
- Repository
- trending-skills
- Installs
- 0
- Files
- 1
- Synced
- Sep 23, 2026
Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.
reason-machines/trending-skills/turboquant-pytorchInstalls these files- SKILL.md
What this skill tells the agent
TurboQuant PyTorch
Skill by ara.so — Daily 2026 Skills collection.
From-scratch PyTorch implementation of Google's TurboQuant (ICLR 2026) for compressing LLM KV caches. Achieves 5x compression at 3-bit with 99.5% attention fidelity via two-stage vector quantization.
What It Does
TurboQuant compresses LLM key-value caches to 2–4 bits per coordinate:
- Stage 1: Random orthogonal rotation + Lloyd-Max scalar quantization (MSE-optimal)
- Stage 2: QJL residual correction — 1-bit sign projection that makes inner product estimates unbiased
Result: attention scores remain accurate even when individual vectors look quite different from originals. The algorithm preserves inner products, not vector fidelity.
Compression ratios at 8K context on Qwen2.5-3B (289 MB FP16 baseline):
- 4-bit → 76 MB (3.8x)
- 3-bit → 58 MB (5.0x) ← practical sweet spot
- 2-bit → 40 MB (7.3x)
Installation
git clone https://github.com/tonbistudio/turboquant-pytorch
cd turboquant-pytorch
pip install -r requirements.txt
# For CUDA PyTorch:
pip install torch --index-url https://download.pytorch.org/whl/cu128requirements.txt includes:
torch>=2.0scipy(Lloyd-Max codebook computation)transformers,accelerate,bitsandbytes(only for real model validation)
Project Structure
turboquant/
__init__.py # Package exports
lloyd_max.py # Lloyd-Max optimal scalar quantizer
turboquant.py # Core: TurboQuantMSE, TurboQuantProd, TurboQuantKVCache
compressors.py # Production compressors for real model tensors
test_turboquant.py # Synthetic validation tests
validate.py # Real model (Qwen2.5-3B) validationKey Commands
# Run synthetic algorithm validation (no GPU required, but GPU enables speed benchmark)
python -m turboquant.test_turboquant
# Run real model validation on Qwen2.5-3B-Instruct
# Requires CUDA GPU with ≥6GB VRAM; downloads ~2GB model on first run
python -m turboquant.validateCore API
Lloyd-Max Codebook
from turboquant.lloyd_max import build_lloyd_max_codebook
# Build optimal scalar quantizer codebook for d-dimensional rotated unit vectors
# Returns (boundaries, centroids) for the given bit-width
boundaries, centroids = build_lloyd_max_codebook(dim=128, bits=3)Stage 1: MSE Quantization (TurboQuantMSE)
from turboquant.turboquant import TurboQuantMSE
# Initialize for head_dim=128, 3-bit quantization
tq_mse = TurboQuantMSE(dim=128, bits=3)
# Compress a batch of vectors: shape (batch, dim)
keys = torch.randn(512, 128) # 512 key vectors
codes = tq_mse.quantize(keys) # integer codes, (512, 128)
reconstructed = tq_mse.dequantize(codes) # approximate keys, (512, 128)Stage 2: Unbiased Inner Product Estimation (TurboQuantProd)
from turboquant.turboquant import TurboQuantProd
# Initialize with QJL correction
tq_prod = TurboQuantProd(dim=128, bits=3, proj_dim=64)
# Compress key vectors (stores codes + QJL residual signs)
compressed = tq_prod.compress(keys) # dict with 'codes', 'signs', 'residual_norms'
# Estimate inner products <query, key> for all keys — unbiased estimator
query = torch.randn(128)
scores = tq_prod.inner_product(query, compressed) # shape (512,)KV Cache Wrapper (TurboQuantKVCache)
from turboquant.turboquant import TurboQuantKVCache
# Wrap a KV cache for a single attention head
cache = TurboQuantKVCache(dim=128, bits=3, proj_dim=64)
# Add key/value vectors as tokens are generated
cache.append_key(new_key) # shape (dim,)
cache.append_value(new_val) # shape (dim,)
# Compute attention scores for a query against all cached keys
query = torch.randn(128)
scores = cache.attention_scores(query) # shape (seq_len,), unbiased
# Get values (MSE-reconstructed, used for weighted sum)
values = cache.get_values() # shape (seq_len, dim)Production Compressors (for real model tensors)
from turboquant.compressors import TurboQuantCompressorV2, TurboQuantCompressorMSE
# Key compressor — supports asymmetric attention score computation
key_compressor = TurboQuantCompressorV2(dim=128, bits=3, proj_dim=64)
# Compress all keys in a layer: shape (num_heads, seq_len, head_dim)
compressed_keys = key_compressor.compress(layer_keys)
# Compute attention scores directly from compressed keys (no decompress needed)
# query shape: (num_heads, head_dim)
scores = key_compressor.asymmetric_attention_scores(query, compressed_keys)
# scores shape: (num_heads, seq_len)
# Value compressor — MSE reconstruction (Stage 1 only, acceptable for values)
val_compressor = TurboQuantCompressorMSE(dim=128, bits=3)
compressed_vals = val_compressor.compress(layer_values)
reconstructed_vals = val_compressor.decompress(compressed_vals)Common Patterns
Pattern 1: Compress a Full Model's KV Cache
import torch
from turboquant.compressors import TurboQuantCompressorV2, TurboQuantCompressorMSE
def compress_kv_cache(kv_cache, head_dim=128, bits=3, proj_dim=64):
"""
kv_cache: list of (keys, values) per layer
keys/values shape: (num_heads, seq_len, head_dim)
Returns list of compressed (keys, values) per layer.
"""
key_comp = TurboQuantCompressorV2(dim=head_dim, bits=bits, proj_dim=proj_dim)
val_comp = TurboQuantCompressorMSE(dim=head_dim, bits=bits)
compressed = []
for layer_keys, layer_vals in kv_cache:
c_keys = key_comp.compress(layer_keys)
c_vals = val_comp.compress(layer_vals)
compressed.append((c_keys, c_vals))
return compressed, key_comp, val_comp
def run_attention_with_compressed_cache(query, compressed_keys, compressed_vals,
key_comp, val_comp):
"""
query: (num_heads, head_dim)
Returns: attention output (num_heads, head_dim)
"""
# Unbiased attention scores from compressed keys
scores = key_comp.asymmetric_attention_scores(query, compressed_keys)
# scores: (num_heads, seq_len)
attn_weights = torch.softmax(scores, dim=-1) # (num_heads, seq_len)
# Decompress values and compute weighted sum
values = val_comp.decompress(compressed_vals) # (num_heads, seq_len, head_dim)
output = torch.einsum('hs,hsd->hd', attn_weights, values)
return outputPattern 2: Validate Compression Quality
import torch
import torch.nn.functional as F
from turboquant.turboquant import TurboQuantProd
def measure_attention_fidelity(keys, queries, bits=3, proj_dim=64):
"""
Measure how well TurboQuant preserves attention distributions.
keys: (seq_len, head_dim)
queries: (num_queries, head_dim)
"""
dim = keys.shape[-1]
tq = TurboQuantProd(dim=dim, bits=bits, proj_dim=proj_dim)
compressed = tq.compress(keys)
cosine_sims = []
top1_matches = []
for q in queries:
# True attention scores
true_scores = (keys @ q) # (seq_len,)
true_attn = torch.softmax(true_scores, dim=0)
# TurboQuant estimated scores
est_scores = tq.inner_product(q, compressed) # (seq_len,)
est_attn = torch.softmax(est_scores, dim=0)
# Cosine similarity of attention distributions
cos_sim = F.cosine_similarity(true_attn.unsqueeze(0),
est_attn.unsqueeze(0)).item()
cosine_sims.append(cos_sim)
# Top-1 match
top1_matches.append(true_attn.argmax() == est_attn.argmax())
return {
'mean_cosine_sim': sum(cosine_sims) / len(cosine_sims),
'top1_accuracy': sum(top1_matches) / len(top1_matches),
}
# Example usage
keys = torch.randn(2048, 128)
keys = F.normalize(keys, dim=-1)
queries = torch.randn(100, 128)
queries = F.normalize(queries, dim=-1)
results = measure_attention_fidelity(keys, queries, bits=3)
print(f"Cosine similarity: {results['mean_cosine_sim']:.4f}")More from reason-machines
Use this skill in a project
Open any RiverX project, search the Skills panel for reason-machines/trending-skills/turboquant-pytorch, and install it in one click.
