Vector quantization: acelerando buscas e reduzindo custos
Como diminuir latência e consumo de RAM em buscas HNSW
Os sistemas de IA, como motores de busca semânticos, sistemas de recomendação e modelos de geração de texto, dependem cada vez mais de embeddings de alta dimensão, por exemplo vetores de 1.024, 1.536 ou 4.096 dimensões. Armazenar e consultar milhões ou bilhões desses embeddings em formato float32 demanda enormes recursos de memória, alto poder de processamento e intenso acesso a I/O, especialmente quando se utiliza o índice HNSW (Hierarchical Navigable Small World). A técnica de Vector Quantization (VQ) oferece uma solução interessante, comprimindo esses vetores em estruturas compactas que reduzem drasticamente o uso de memória e aceleram as buscas, com perda de precisão muitas vezes praticamente imperceptível.
Fundamentos
Representação de dados em ponto flutuante
Um vetor típico de dimensão D em float32 ocupa 4 D bytes de memória. Cada valor float32 é codificado em 32 bits: 1 bit para o sinal, 8 bits para o expoente e 23 bits para a parte fracionária, oferecendo ampla faixa dinâmica e precisão, mas a um custo elevado de armazenamento e processamento.
Como o vector quantization armazena vetores
Em vez de guardar cada vetor completo, o VQ cria um pequeno “dicionário” de vetores de referência que capturam bem as características dos dados. Para cada vetor original, ele identifica qual vetor de referência é o mais semelhante e passa a armazenar apenas o índice desse vetor de referência. Assim, a maior parte da informação é preservada, mas o espaço de armazenamento e o custo de busca caem drasticamente.
Por que Quantizar?
Índices como HNSW exigem que os vetores residam em memória rápida (RAM/SSD) para leituras aleatórias de baixa latência. À medida que o volume de dados cresce, os custos e a latência sobem linearmente. A quantização comprime vetores, permitindo que mais dados caibam na mesma memória e reduzindo a carga de I/O durante buscas.
Técnicas de quantização
1. Escalar
Nesta técnica, cada componente do vetor é transformado de float32 (32 bits) para int8 (8 bits), reduzindo de 4 bytes para 1 byte por dimensão. Supondo que os valores relevantes de uma dimensão estejam entre Xmin e Xmax, o valor quantizado q(x) é:
Isso corresponde a uma economia de até 75 % de memória (de 4 bytes para 1 byte).
Prós
Implementação simples;
Operações de distância com int8 são mais rápidas que com float32;
Bom trade‑off para casos gerais;
Contras
Perda de precisão nos valores extremos.
Pode ser necessário “rescoring” para recuperar precisão em buscas críticas
2. Produto
Divide o vetor de dimensão D em M sub‑vetores de dimensão D/M. Em cada subespaço, aplica‑se K‑means para gerar K centróides, e o vetor original é representado por uma sequência de índices, onde cada elemento aponta ao centróide mais próximo dentro do subespaço.
Compressão típica:
Se D=1024 e M=256, cada sub‑vetor tem 4 dimensões. Com K=256 centróides (8 bits por índice), o vetor quantizado ocupa:\(\begin{aligned} M \times 1\ \text{byte} &= 256\ \text{bytes}\\ \text {contra}\\ D \times 4\ \text{bytes} &= 4096\ \text{bytes} \end{aligned}\)Prós:
Preserva melhor a estrutura local dos vetores.
Taxa de compressão ajustável (via M e K).
Contras:
Treinamento offline de K‑means em cada subespaço é custoso;
A precisão declina conforme aumentamos M (mais compressão);
3. Binária
A forma mais extrema de compressão: converte cada componente do vetor em 1 bit, mapeando valores positivos para 1
e não-positivos para 0
. Um vetor de 1 536 dimensões, que ocupa 6 144 bytes em float32, passa a ocupar apenas 192 bytes, ou seja, 32x de redução:
Prós:
Distâncias podem ser calculadas com instruções de CPU como
XOR
ePOPCNT
, muito rápidas.Indicado para embeddings de alta dimensão (≥1024).
Contras:
Maior perda de detalhe do que em quantização escalar ou PQ;
Nem todos os modelos trabalham bem essa binarização, é necessário testar;
Frequentemente requer rescoring para manter qualidade;
Conclusão
Encontrar o ponto de equilíbrio entre a redução do tamanho dos embeddings e a manutenção da qualidade das buscas é essencial para qualquer aplicação que trabalhe com grandes volumes de vetores. Processos como o cálculo de quantis para Scalar Quantization e o treinamento de K‑means para Product Quantization exigem um investimento inicial de tempo e recursos, mas garantem retornos substanciais em throughput e latência na fase de consulta. É necessário ajustar continuamente parâmetros como o número de subvetores e o tamanho do codebook, além de definir critérios de quantil ou de binarização que façam sentido para o seu caso de uso. Testes comparativos entre buscas com vetores originais e com versões quantizadas permitem mensurar com precisão o impacto de cada técnica em métricas como precisão nos top K resultados, recall e latência, bem como o custo de infraestrutura.
PS: em produção eu usei com sucesso Scalar Quantization, um dia posso entrar em mais detalhes:
As opções de compressão oferecem diferentes níveis de economia e perda de detalhe: a Scalar Quantization proporciona uma redução moderada de até 75 % de uso de memória com implementação simples; a Product Quantization viabiliza taxas maiores de compressão (por exemplo, 16×) preservando boa parte da estrutura local dos vetores; e a Binary Quantization atinge a compactação mais extrema (até 32×), indicada para embeddings de dimensionalidade muito alta, mas exige cuidado para não degradar demais a informação. Quando essas técnicas são adotadas em conjunto com índices eficientes como o HNSW e complementadas por uma etapa de rescoring, é possível escalar sistemas de busca vetorial de forma econômica, mantendo a agilidade e a precisão necessárias para atender às demandas de aplicações de IA.