HNSW_SQ

HNSW_SQ combina los gráficos Hierarchical Navigable Small World (HNSW) con la cuantificación escalar (SQ), creando un método avanzado de indexación vectorial que ofrece un equilibrio controlable entre tamaño y precisión. Comparado con el HNSW estándar, este tipo de índice mantiene una alta velocidad de procesamiento de consultas, aunque introduce un ligero incremento en el tiempo de construcción del índice.

Resumen

HNSW_SQ combina dos técnicas de indexación: HNSW para una navegación rápida basada en grafos y SQ para una compresión vectorial eficaz.

HNSW

HNSW construye un grafo multicapa en el que cada nodo corresponde a un vector del conjunto de datos. En este grafo, los nodos se conectan en función de su similitud, lo que permite recorrer rápidamente el espacio de datos. La estructura jerárquica permite al algoritmo de búsqueda reducir el número de vecinos candidatos, lo que acelera considerablemente el proceso de búsqueda en espacios de gran dimensión.

Para más información, consulte HNSW.

SQ

SQ es un método para comprimir vectores representándolos con menos bits. Por ejemplo:

  • SQ8 utiliza 8 bits, mapeando los valores en 256 niveles. Para más información, consulte IVF_SQ8.

  • SQ6 utiliza 6 bits para representar cada valor de coma flotante, dando como resultado 64 niveles discretos.

Hnsw Sq Hnsw Sq

Esta reducción en la precisión disminuye drásticamente la huella de memoria y acelera el cálculo al tiempo que conserva la estructura esencial de los datos.

SQ4UCompatible with Milvus 2.6.8+

Para escenarios que exigen una velocidad de consulta extrema y un uso mínimo de memoria, Milvus introduce SQ4U, una cuantificación escalar uniforme de 4 bits. Se trata de una forma agresiva de cuantificación escalar que comprime el valor de punto flotante de cada dimensión en un entero sin signo de 4 bits.

La "U" de SQ4U significa Uniforme. A diferencia de la cuantización escalar no uniforme, que suele calcular los valores mínimo y máximo de forma independiente para cada dimensión (cuantización por dimensión), SQ4U aplica una estrategia de cuantización uniforme global:

  1. Estadística Global: El sistema calcula un único valor mínimo vmin y un único rango de valores vdiff que se aplica a todas las dimensiones del vector (o a todo el segmento del vector).

  2. Mapeado uniforme: El rango de valores global se divide en 16 intervalos iguales. Cada valor de coma flotante del vector, independientemente de la dimensión a la que pertenezca, se asigna a un entero de 4 bits (0-15) utilizando estos parámetros compartidos.

Ventajas de rendimiento:

  • Tasa de compresión 8x: Reduce el tamaño 8 veces en comparación con FP32 y 2 veces en comparación con SQ8, lo que disminuye significativamente la presión sobre el ancho de banda de la memoria, que suele ser el cuello de botella en la búsqueda vectorial.

  • Optimización SIMD: La estructura compacta permite a las CPU modernas (AVX2/AVX-512) procesar más dimensiones por ciclo. Además, el uso de parámetros globales elimina la necesidad de cargar valores de escala/desplazamiento variables durante el cálculo de la distancia, lo que mantiene el canal de instrucciones totalmente saturado.

  • Eficiencia de la caché: Los vectores de menor tamaño hacen que quepan más datos en la caché de la CPU, lo que reduce la latencia causada por el acceso a la memoria.

Debido a la compartición global de parámetros, SQ4U funciona mejor con datos normalizados o conjuntos de datos con distribuciones de valores coherentes en todas las dimensiones.

HNSW + SQ

HNSW_SQ combina los puntos fuertes de HNSW y SQ para permitir una búsqueda aproximada eficiente del vecino más próximo. El proceso funciona de la siguiente manera

  1. Compresión de datos: SQ comprime los vectores utilizando sq_type (por ejemplo, SQ6 o SQ8), lo que reduce el uso de memoria. Esta compresión puede disminuir la precisión, pero permite al sistema manejar conjuntos de datos más grandes.

  2. Construcción de gráficos: Los vectores comprimidos se utilizan para construir un gráfico HNSW. Como los datos están comprimidos, el gráfico resultante es más pequeño y más rápido de buscar.

  3. Búsqueda de candidatos: Cuando se proporciona un vector de consulta, el algoritmo utiliza los datos comprimidos para identificar rápidamente un grupo de vecinos candidatos a partir del grafo HNSW.

  4. (Opcional) Perfeccionamiento de resultados: Los resultados candidatos iniciales pueden ser refinados para una mayor precisión, basándose en los siguientes parámetros:

    • refine: Controla si se activa este paso de refinamiento. Cuando se establece en true, el sistema recalcula las distancias utilizando representaciones de mayor precisión o sin comprimir.

    • refine_type: Especifica el nivel de precisión de los datos utilizados durante el refinamiento (por ejemplo, SQ6, SQ8, BF16). Una elección de mayor precisión, como FP32, puede producir resultados más precisos, pero requiere más memoria. Debe superar la precisión del conjunto de datos comprimido original en sq_type.

    • refine_k: Actúa como factor de ampliación. Por ejemplo, si su k superior es 100 y refine_k es 2, el sistema vuelve a clasificar los 200 candidatos superiores y devuelve los 100 mejores, mejorando la precisión general.

Para obtener una lista completa de parámetros y valores válidos, consulte Parámetros del índice.

Crear un índice

Para construir un índice HNSW_SQ sobre un campo vectorial en Milvus, utilice el método add_index(), especificando los parámetros index_type, metric_type, y parámetros adicionales para el í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
)

En esta configuración:

  • index_type: El tipo de índice a construir. En este ejemplo, establezca el valor HNSW_SQ.

  • metric_type: El método utilizado para calcular la distancia entre vectores. Los valores soportados incluyen COSINE, L2, y IP. Para más detalles, consulte Tipos de métricas.

  • params: Opciones de configuración adicionales para construir el índice. Para más información, consulte Parámetros de creación de índices.

Una vez configurados los parámetros del índice, puede crear el índice utilizando el método create_index() directamente o pasando los parámetros del índice en el método create_collection. Para más detalles, consulte Crear colección.

Búsqueda en el índice

Una vez creado el índice e insertadas las entidades, puede realizar búsquedas de similitud en el í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
)

En esta configuración:

Parámetros del índice

Esta sección proporciona una visión general de los parámetros utilizados para construir un índice y realizar búsquedas en el índice.

Parámetros de creación de índices

La siguiente tabla enumera los parámetros que pueden configurarse en params al crear un índice.

Parámetro

Descripción

Rango de valores

Sugerencia de ajuste

HNSW

M

Número máximo de conexiones (o aristas) que puede tener cada nodo en el grafo, incluyendo tanto las aristas salientes como las entrantes.

Este parámetro afecta directamente tanto a la construcción como a la búsqueda de índices.

Tipo: Entero

Rango: [2, 2048]

Valor por defecto: 30 (hasta 30 aristas salientes y 30 entrantes por nodo)

Un valor mayor de M conduce generalmente a una mayor precisión, pero aumenta la sobrecarga de memoria y ralentiza tanto la construcción del índice como la búsqueda.

Considere la posibilidad de aumentar M para conjuntos de datos de alta dimensionalidad o cuando sea crucial una alta recuperación.

Considere la posibilidad de reducir M cuando el uso de memoria y la velocidad de búsqueda sean las principales preocupaciones.

En la mayoría de los casos, se recomienda establecer un valor dentro de este intervalo: [5, 100].

efConstruction

Número de vecinos candidatos considerados para la conexión durante la construcción del índice.

Para cada nuevo elemento se evalúa un conjunto mayor de candidatos, pero el número máximo de conexiones realmente establecidas sigue estando limitado por M.

Tipo: Entero

Rango: [1, int_max]

Valor por defecto: 360

Un valor más alto de efConstruction suele dar como resultado un índice más preciso, ya que se exploran más conexiones potenciales. Sin embargo, esto también conlleva un mayor tiempo de indexación y un mayor uso de memoria durante la construcción.

Considere aumentar efConstruction para mejorar la precisión, especialmente en escenarios donde el tiempo de indexación es menos crítico.

Considere la posibilidad de reducir efConstruction para acelerar la construcción del índice cuando las limitaciones de recursos sean un problema.

En la mayoría de los casos, se recomienda establecer un valor dentro de este intervalo: [50, 500].

SQ

sq_type

Especifica el método de cuantificación escalar para comprimir vectores. Cada opción ofrece un equilibrio diferente entre compresión y precisión:

  • SQ4U: Codifica los vectores utilizando una cuantización uniforme de 4 bits. Este modo ofrece la mayor velocidad y compresión.

  • SQ6: Codifica vectores utilizando enteros de 6 bits.

  • SQ8: Codifica vectores utilizando enteros de 8 bits.

  • BF16: Utiliza el formato Bfloat16.

  • FP16: Utiliza el formato estándar de coma flotante de 16 bits.

Tipo Cadena

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

Valor por defecto: SQ8

La elección de sq_type depende de las necesidades específicas de la aplicación. SQ4U se elige para obtener la máxima velocidad y eficiencia de memoria. SQ6 o SQ8 podrían ser adecuados para un rendimiento equilibrado. Por otra parte, si la precisión es primordial, podría preferirse BF16 o FP16.

refine

Un indicador booleano que controla si se aplica un paso de refinamiento durante la búsqueda. El refinamiento consiste en volver a clasificar los resultados iniciales calculando las distancias exactas entre el vector de consulta y los candidatos.

Tipo: Booleano

Rango: [true, false]

Valor por defecto: false

Establezca true si la alta precisión es esencial y puede tolerar tiempos de búsqueda ligeramente más lentos. Utilice false si la velocidad es una prioridad y es aceptable un compromiso menor en la precisión.

refine_type

Determina la precisión de los datos utilizados para el refinamiento.

Esta precisión debe ser mayor que la de los vectores comprimidos (como se establece en sq_type), lo que afecta tanto a la precisión de los vectores reordenados como a su consumo de memoria.

Tipo: Cadena

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

Valor por defecto: Ninguno

Utilice FP32 para obtener la máxima precisión con un mayor coste de memoria, o SQ6/SQ8 para una mejor compresión. BF16 y FP16 ofrecen una alternativa equilibrada.

Parámetros de búsqueda específicos del índice

La siguiente tabla enumera los parámetros que pueden configurarse en search_params.params cuando se realizan búsquedas en el índice.

Parámetro

Descripción

Rango de valores

Sugerencia de ajuste

HNSW

ef

Controla la amplitud de la búsqueda durante la recuperación del vecino más cercano. Determina cuántos nodos son visitados y evaluados como vecinos más cercanos potenciales.

Este parámetro sólo afecta al proceso de búsqueda y se aplica exclusivamente a la capa inferior del gráfico.

Tipo: Entero

Rango: [1, int_max]

Valor por defecto: limit (TopK vecinos más cercanos a devolver)

Un valor mayor de ef suele aumentar la precisión de la búsqueda, ya que se tienen en cuenta más vecinos potenciales. Sin embargo, esto también aumenta el tiempo de búsqueda.

Considere la posibilidad de aumentar ef cuando sea fundamental lograr una alta recuperación y la velocidad de búsqueda sea menos importante.

Considere la posibilidad de reducir ef para dar prioridad a las búsquedas más rápidas, especialmente en situaciones en las que sea aceptable una ligera reducción de la precisión.

En la mayoría de los casos, se recomienda establecer un valor dentro de este rango: [K, 10K].

SQ

refine_k

El factor de ampliación que controla cuántos candidatos adicionales se examinan durante la etapa de refinamiento, en relación con los K resultados principales solicitados.

Tipo: Float

Rango: [1, float_max)

Valor por defecto: 1

Los valores más altos de refine_k pueden mejorar la recuperación y la precisión, pero también aumentarán el tiempo de búsqueda y el uso de recursos. Un valor de 1 significa que el proceso de refinamiento sólo tiene en cuenta los K primeros resultados iniciales.