TurboQuant - Eu descobri que 50 linhas de código fazem mais diferença do que 300 iterações de otimização.
Passei os últimos dias implementando do zero os 4 métodos de compressão de embeddings do paper TurboQuant (Google Research, 2025) e medindo o impacto real em um pipeline RAG.
Resultado:
7,9× menos memória. Mesma qualidade de busca.
🚨 O problema real
1M docs × embeddings float32 (dim=384) = 1,5 GB só de vetores
10M docs = 15 GB — não cabe em GPU
Solução óbvia: quantizar.
Problema: quantização errada destrói o sistema em silêncio, sem erro.
🛠️ Os 4 métodos implementados
- Uniform — bins iguais. Simples, rápido e catastrófico a 2-bit
- Lloyd-Max — codebook ótimo para geometria da esfera. Melhor no papel, mas com problema oculto
- TurboQuantMSE — rotação ortogonal antes de quantizar. Esse detalhe muda tudo
- TurboQuantProd — MSE + estimador QJL no resíduo, eliminando viés no produto interno
💥 A descoberta surpreendente
Lloyd-Max e TurboQuantMSE usam o MESMO codebook.
Diferença: uma rotação aleatória antes de quantizar — 50 linhas de NumPy.
Sem rotação → ~11× mais erro
Com rotação → qualidade idêntica
Por quê? Embeddings têm energia não-uniforme entre dimensões. A rotação redistribui perfeitamente.
📊 Números reais
Corpus: 591 docs | Modelo: BAAI/bge-small-en-v1.5
| Variante | Compressão | Recall@10 | vs float32 |
|---|---|---|---|
| float32 | 1× | 0.935 | — |
| turbo_mse 4-bit | 7,9× | 0.925 | −1,0 pp ✅ |
| turbo_mse 2-bit | 15,7× | 0.925 | −1,0 pp 🔥 |
| uniform 2-bit | 15,7× | 0.425 | −51,0 pp ❌ |
Mesma compressão 15,7×. Uma cai 1pp. A outra, 51pp.
🧪 Teste prático
Query: "how does Redis handle memory when it runs out?"
✅ float32 → 5 docs certos (LRU/LFU)
✅ turbo_mse 4-bit → idêntico, 7,9× menos RAM
❌ uniform 2-bit → doc do NestJS, LLM: "não encontrei info"
Degradação silenciosa. Sem erro. Só responde errado.
🎯 Projeto completo
- Benchmark de distorção + retrieval
- 8 gráficos detalhados
- Dashboard interativo
- Demo RAG end-to-end (Ollama/OpenAI)
📄 Paper: TurboQuant
🔗 Repo: github.com/...