HNSW_SQ

O HNSW_SQ combina gráficos Hierarchical Navigable Small World (HNSW) com Scalar Quantization (SQ), criando um método avançado de indexação vetorial que oferece um compromisso controlável entre tamanho e precisão. Em comparação com o HNSW padrão, este tipo de índice mantém uma elevada velocidade de processamento de consultas, embora introduza um ligeiro aumento no tempo de construção do índice.

Visão geral

O HNSW_SQ combina duas técnicas de indexação: HNSW para uma navegação rápida baseada em grafos e SQ para uma compressão vetorial eficiente.

HNSW

O HNSW constrói um gráfico de várias camadas em que cada nó corresponde a um vetor no conjunto de dados. Neste gráfico, os nós são ligados com base na sua semelhança, permitindo uma rápida deslocação através do espaço de dados. A estrutura hierárquica permite que o algoritmo de pesquisa reduza os vizinhos candidatos, acelerando significativamente o processo de pesquisa em espaços de elevada dimensão.

Para mais informações, consulte HNSW.

SQ

SQ é um método de compressão de vectores, representando-os com menos bits. Por exemplo:

  • SQ8 usa 8 bits, mapeando valores em 256 níveis. Para mais informações, consulte IVF_SQ8.

  • SQ6 utiliza 6 bits para representar cada valor de vírgula flutuante, resultando em 64 níveis discretos.

Hnsw Sq Hnsw Sq

Esta redução na precisão diminui drasticamente o espaço de memória e acelera o cálculo, mantendo a estrutura essencial dos dados.

SQ4UCompatible with Milvus 2.6.8+

Para cenários que exigem uma velocidade de consulta extrema e uma utilização mínima de memória, Milvus introduz SQ4U, uma Quantização Escalar Uniforme de 4 bits. Esta é uma forma agressiva de quantização escalar que comprime o valor de ponto flutuante de cada dimensão num inteiro sem sinal de 4 bits.

O "U" em SQ4U significa Uniforme. Ao contrário da Quantização escalar não uniforme, que normalmente calcula os valores mínimo e máximo independentemente para cada dimensão (Quantização por dimensão), o SQ4U aplica uma estratégia de Quantização uniforme global:

  1. Estatísticas Globais: O sistema calcula um único valor mínimo vmin e um único intervalo de valores vdiff que se aplica a todas as dimensões do vetor (ou a todo o segmento do vetor).

  2. Mapeamento uniforme: O intervalo de valores globais é dividido em 16 intervalos iguais. Cada valor de vírgula flutuante no vetor, independentemente da dimensão a que pertence, é mapeado para um inteiro de 4 bits (0-15) utilizando estes parâmetros partilhados.

Vantagens de desempenho:

  • Rácio de compressão de 8x: Reduz o tamanho em 8x em comparação com FP32 e 2x em comparação com SQ8, diminuindo significativamente a pressão da largura de banda da memória - frequentemente o gargalo na pesquisa de vetores.

  • Otimização SIMD: A estrutura compacta permite que as CPUs modernas (AVX2/AVX-512) processem mais dimensões por ciclo. Crucialmente, o uso de parâmetros globais elimina a necessidade de carregar valores variáveis de escala/offset durante o cálculo da distância, mantendo o pipeline de instruções totalmente saturado.

  • Eficiência da cache: Tamanhos menores de vetor significam que mais dados cabem no cache da CPU, reduzindo a latência causada pelo acesso à memória.

Devido à partilha global de parâmetros, o SQ4U tem um melhor desempenho em dados normalizados ou conjuntos de dados com distribuições de valores consistentes entre dimensões.

HNSW + SQ

O HNSW_SQ combina os pontos fortes do HNSW e do SQ para permitir uma pesquisa eficiente do vizinho mais próximo aproximado. Veja como o processo funciona:

  1. Compressão de dados: O SQ comprime os vectores utilizando o sq_type (por exemplo, SQ6 ou SQ8), o que reduz a utilização de memória. Esta compressão pode diminuir a precisão, mas permite que o sistema lide com conjuntos de dados maiores.

  2. Construção de gráficos: Os vectores comprimidos são utilizados para construir um gráfico HNSW. Como os dados são comprimidos, o gráfico resultante é mais pequeno e mais rápido de pesquisar.

  3. Recuperação de candidatos: Quando é fornecido um vetor de consulta, o algoritmo utiliza os dados comprimidos para identificar rapidamente um conjunto de vizinhos candidatos a partir do gráfico HNSW.

  4. (Opcional) Refinamento de resultados: Os resultados candidatos iniciais podem ser refinados para uma melhor precisão, com base nos seguintes parâmetros:

    • refine: Controla se esta etapa de refinamento está activada. Quando definido para true, o sistema recalcula as distâncias utilizando representações de maior precisão ou não comprimidas.

    • refine_type: Especifica o nível de precisão dos dados utilizados durante o refinamento (por exemplo, SQ6, SQ8, BF16). Uma escolha de maior precisão, como FP32, pode produzir resultados mais exactos, mas requer mais memória. Isto deve exceder a precisão do conjunto de dados comprimido original em sq_type.

    • refine_k: Actua como um fator de ampliação. Por exemplo, se o seu top k for 100 e refine_k for 2, o sistema volta a classificar os 200 principais candidatos e devolve os 100 melhores, aumentando a precisão geral.

Para obter uma lista completa de parâmetros e valores válidos, consulte Parâmetros do índice.

Criar índice

Para construir um índice HNSW_SQ num campo vetorial em Milvus, utilize o método add_index(), especificando os parâmetros index_type, metric_type, e parâmetros adicionais para o índice.

from pymilvus import MilvusClient

# Prepare index building params
index_params = MilvusClient.prepare_index_params()

index_params.add_index(
    field_name="your_vector_field_name", # Name of the vector field to be indexed
    index_type="HNSW_SQ", # Type of the index to create
    index_name="vector_index", # Name of the index to create
    metric_type="L2", # Metric type used to measure similarity
    params={
        "M": 64, # Maximum number of neighbors each node can connect to in the graph
        "efConstruction": 100, # Number of candidate neighbors considered for connection during index construction
        "sq_type": "SQ6", # Scalar quantizer type
        "refine": true, # Whether to enable the refinement step
        "refine_type": "SQ8" # Precision level of data used for refinement
    } # Index building params
)

Nesta configuração:

  • index_type: O tipo de índice a construir. Neste exemplo, defina o valor para HNSW_SQ.

  • metric_type: O método utilizado para calcular a distância entre vectores. Os valores suportados incluem COSINE, L2, e IP. Para obter detalhes, consulte Tipos de métricas.

  • params: Opções de configuração adicionais para criar o índice. Para obter detalhes, consulte Parâmetros de construção de índice.

Assim que os parâmetros do índice estiverem configurados, pode criar o índice utilizando diretamente o método create_index() ou passando os parâmetros do índice no método create_collection. Para obter detalhes, consulte Criar coleção.

Pesquisar no índice

Depois de o índice ser criado e as entidades serem inseridas, pode efetuar pesquisas de semelhança no índice.

search_params = {
    "params": {
        "ef": 10, # Parameter controlling query time/accuracy trade-off
        "refine_k": 1 # The magnification factor
    }
}

res = MilvusClient.search(
    collection_name="your_collection_name", # Collection name
    anns_field="vector_field",  # Vector field name
    data=[[0.1, 0.2, 0.3, 0.4, 0.5]],  # Query vector
    limit=3,  # TopK results to return
    search_params=search_params
)

Nesta configuração:

Parâmetros de índice

Esta secção fornece uma visão geral dos parâmetros utilizados para criar um índice e executar pesquisas no índice.

Parâmetros de construção de índice

A tabela seguinte lista os parâmetros que podem ser configurados em params ao construir um índice.

Parâmetro

Descrição

Intervalo de valores

Sugestão de ajuste

HNSW

M

Número máximo de ligações (ou arestas) que cada nó pode ter no gráfico, incluindo as arestas de saída e de entrada.

Este parâmetro afecta diretamente a construção e a pesquisa de índices.

Tipo: Inteiro

Range: [2, 2048]

Valor por defeito: 30 (até 30 arestas de saída e 30 arestas de entrada por nó)

Um M maior geralmente leva a uma maior precisão, mas aumenta a sobrecarga de memória e torna mais lenta a construção do índice e a pesquisa.

Considere o aumento de M para conjuntos de dados com elevada dimensionalidade ou quando é crucial uma elevada recuperação.

Considere diminuir M quando a utilização da memória e a velocidade de pesquisa forem as principais preocupações.

Na maioria dos casos, recomendamos que defina um valor dentro deste intervalo: [5, 100].

efConstruction

Número de vizinhos candidatos considerados para conexão durante a construção do índice.

Um conjunto maior de candidatos é avaliado para cada novo elemento, mas o número máximo de conexões realmente estabelecidas ainda é limitado por M.

Tipo: Integer

Range: [1, int_max]

Valor predefinido: 360

Um efConstruction mais elevado resulta normalmente num índice mais preciso, uma vez que são exploradas mais ligações potenciais. No entanto, isto também leva a um tempo de indexação mais longo e a uma maior utilização de memória durante a construção.

Considere aumentar efConstruction para melhorar a precisão, especialmente em cenários em que o tempo de indexação é menos crítico.

Considere diminuir efConstruction para acelerar a construção do índice quando as restrições de recursos são uma preocupação.

Na maioria dos casos, recomendamos que defina um valor dentro deste intervalo: [50, 500].

SQ

sq_type

Especifica o método de quantização escalar para comprimir vectores. Cada opção oferece um equilíbrio diferente entre compressão e precisão:

  • SQ4U: Codifica vectores utilizando quantização uniforme de 4 bits. Este modo oferece a maior velocidade e compressão.

  • SQ6: Codifica vectores utilizando números inteiros de 6 bits.

  • SQ8: Codifica vectores utilizando números inteiros de 8 bits.

  • BF16: Usa o formato Bfloat16.

  • FP16: Utiliza o formato padrão de ponto flutuante de 16 bits.

Tipo: String

Range: [ SQ4U, SQ6, SQ8, BF16, FP16 ]

Valor por defeito: SQ8

A escolha de sq_type depende das necessidades específicas da aplicação. SQ4U é escolhido para máxima velocidade e eficiência de memória. SQ6 ou SQ8 podem ser adequados para um desempenho equilibrado. Por outro lado, se a precisão for primordial, BF16 ou FP16 podem ser preferidos.

refine

Um sinalizador booleano que controla se uma etapa de refinamento é aplicada durante a pesquisa. O refinamento envolve uma nova classificação dos resultados iniciais através do cálculo de distâncias exactas entre o vetor de consulta e os candidatos.

Tipo: Booleano

Range: [true, false]

Valor predefinido: false

Defina para true se for essencial uma elevada precisão e puder tolerar tempos de pesquisa ligeiramente mais lentos. Utilize false se a velocidade for uma prioridade e for aceitável um pequeno compromisso na precisão.

refine_type

Determina a precisão dos dados utilizados para o refinamento.

Esta precisão tem de ser superior à dos vectores comprimidos (conforme definido por sq_type), o que afecta a exatidão dos vectores reordenados e o seu espaço de memória.

Tipo: String

Intervalo:[ SQ6, SQ8, BF16, FP16, FP32 ]

Valor por defeito: Nenhum

Utilize FP32 para obter a máxima precisão com um custo de memória mais elevado, ou SQ6/SQ8 para uma melhor compressão. BF16 e FP16 oferecem uma alternativa equilibrada.

Parâmetros de pesquisa específicos do índice

A tabela seguinte lista os parâmetros que podem ser configurados em search_params.params ao pesquisar no índice.

Parâmetro

Descrição

Intervalo de valores

Sugestão de ajuste

HNSW

ef

Controla a amplitude da pesquisa durante a recuperação do vizinho mais próximo. Ele determina quantos nós são visitados e avaliados como possíveis vizinhos mais próximos.

Este parâmetro afecta apenas o processo de pesquisa e aplica-se exclusivamente à camada inferior do gráfico.

Tipo: Inteiro

Intervalo: [1, int_max]

Valor por defeito: limite (TopK vizinhos mais próximos a devolver)

Um ef maior conduz geralmente a uma maior precisão de pesquisa, uma vez que são considerados mais vizinhos potenciais. No entanto, isto também aumenta o tempo de pesquisa.

Considere aumentar ef quando a obtenção de uma elevada recuperação é crítica e a velocidade de pesquisa é menos preocupante.

Considere diminuir ef para dar prioridade a pesquisas mais rápidas, especialmente em cenários em que uma ligeira redução na precisão é aceitável.

Na maioria dos casos, recomendamos que defina um valor dentro deste intervalo: [K, 10K].

SQ

refine_k

O fator de ampliação que controla quantos candidatos extra são examinados durante a fase de refinamento, relativamente aos K resultados principais solicitados.

Tipo: Flutuante

Intervalo: [1, float_max)

Valor predefinido: 1

Valores mais altos de refine_k podem melhorar a recuperação e a precisão, mas também aumentarão o tempo de pesquisa e a utilização de recursos. Um valor de 1 significa que o processo de refinamento considera apenas os K resultados principais iniciais.