¿Estás visitando desde Argentina?
Ingresá a Linware Argentina ⯈
Continuar en Linware Argentina ⯈
×
¿Qué estás buscando?
BUSCAR!
BLOG
Ahorre espacio con vectores de tamaño de byte
Publicada el 23/01/2023

Elasticsearch está introduciendo un nuevo tipo de vector en 8.6. Este vector tiene dimensiones enteras de 8 bits, donde cada dimensión tiene un rango de [-128, 127]. Es 4 veces más pequeño que el vector actual con dimensiones flotantes de 32 bits, lo que puede resultar en un ahorro sustancial de espacio.

Puede comenzar a indexar estos vectores más pequeños de 8 bits ahora mismo agregando el parámetro element_type con el valor de byte a sus asignaciones de vectores, similar al ejemplo a continuación.

 
{n    "mappings": {n        "properties": {n            "my_vector": {n                "type": "dense_vector",n                "element_type": "byte",n                "dims": 3,n                "index": true,n                "similarity": "dot_product"n            }n        }n    }n}Lee mas
 
 

Pero, ¿qué pasa si las dimensiones de sus vectores existentes no encajan en este tipo más pequeño? Entonces podemos usar el proceso de cuantización para hacer que encajen, ¡a menudo con solo una pequeña pérdida de precisión!

Cuantifiquemos

Comencemos definiendo la cuantización. La cuantificación es el proceso de tomar un conjunto más grande de valores y asignarlos a un conjunto más pequeño de valores. Más específicamente, en nuestro caso, esto sería tomar el rango de un flotante de 32 bits y asignarlo al rango de un entero de 8 bits para cada dimensión en un vector. (Esto no debe confundirse con la reducción dimensional, que es un tema diferente. Esto solo reduce el rango de valores para las dimensiones existentes). 

 

Esto lleva a dos preguntas más. ¿Cuál es el rango real de nuestros vectores flotantes de 32 bits? ¿Y qué función debemos usar para hacer el mapeo? Las respuestas varían significativamente según el caso de uso.

 

Como ejemplo, una de las formas más simples de cuantificación es tomar las dimensiones de los vectores de 32 bits normalizados y asignarlos linealmente al rango completo de las dimensiones de los vectores de 8 bits. Usando Python, esto sería algo como lo siguiente:

 
import numpy as npnimport typing as tnndef quantize_embeddings(text_and_embeddings: t.List[t.Mapping[str, t.Any]]) -> t.List[t.Mapping[str, t.Any]]:n    quantized_embeddings = np.array([x['embedding'] for x in nquery_and_embeddings])n    quantized_embeddings = (quantized_embeddings * 128)n    quantized_embeddings = quantized_embeddings.clip(-128, n127).astype(int).tolist()n    return [dict(item, **{'embedding': embedding}) for (item, nembedding) in zip(text_and_embeddings, quantized_embeddings)]Lee mas
 
 

Sin embargo, este es solo un ejemplo. Hay muchas otras funciones de cuantización útiles. Para su caso de uso específico, es importante evaluar qué método de cuantificación le dará los mejores resultados en relación con el equilibrio entre reducción de espacio, relevancia y recuperación.

Algunos números del mundo real

Los vectores de 8 bits y la cuantificación son geniales y todo, pero ¿realmente reducen el espacio en un caso de uso del mundo real? La respuesta es inequívocamente ¡SÍ! Y sustancialmente. Todo esto mientras continúan dando buenos resultados sin dañar la relevancia y el recuerdo. Elasticsearch incluso tiene todas las herramientas que necesita para hacer esa evaluación usted mismo con nuestra API de evaluación de clasificación .

 

Ahora, veamos algunos números generados a partir de un ejemplo del mundo real con la siguiente configuración:

  1. Todos los datos se recopilaron mediante Elasticsearch en la nube con dos nodos gcp.data.highcpu.1 de 64 GB
  2. Los datos se recopilaron del conjunto de datos NQ (Pregunta natural) , creado por Google, utilizado en BEIR
  3. El modelo de incrustaciones fue sentencia-transformadores/todos-MiniLM-L6-v2
  4. La cuantificación para generar vectores enteros de 8 bits se aplicó a los vectores flotantes de 32 bits recopilados de los datos utilizando el fragmento de Python del ejemplo anterior

Luego hacemos que suceda algo de magia y recolectamos resultados basados ​​en esta configuración:

 
 

categoría

Tiempo de respuesta mediano de kNN

Tiempo de respuesta exacto medio

Recuperar@100

NDCG@10

Tamaño total del índice (1p, 1r)

byte

32ms

1072ms

0.79

0.385.8gb

flotar

36ms

1530ms

0.79

0.3816,4 gb
% Reducción11%30%0%0%64%
 
 

Y nuestros resultados se ven fantásticos. Desglosemos cada uno.

  • Tiempo de respuesta mediano de kNN: este tiempo de respuesta se recopila utilizando una búsqueda aproximada de kNN en nuestro conjunto de datos de ejemplo. Este tipo de búsqueda utiliza el gráfico HNSW de Lucene como estructura de datos de respaldo. Vemos un aumento del 11 % en el tiempo de respuesta de byte frente a flotante.
  • Tiempo de respuesta exacto medio: este tiempo de respuesta se recopila mediante la búsqueda exacta de kNN en nuestro conjunto de datos de ejemplo. Este tipo de búsqueda utiliza un script para iterar a través de cada vector en el conjunto de datos y devolverá los mejores resultados posibles. ¡Vemos una gran mejora de reducción del 30% en el tiempo de respuesta!
  • Recall@100: Esto nos muestra si los resultados más relevantes están incluidos en el top 100. Esto es importante para mostrar si nuestra función de cuantificación funcionó bien. Podemos ver que los números son idénticos para byte versus float, lo que significa que nuestra relevancia, incluso después de la cuantificación, es tan buena para byte como para float.
  • @NDCG@10: Esto nos muestra cuán buena es la calidad de nuestros primeros 10 resultados. Esta es otra métrica importante para evaluar si nuestra función de cuantificación funcionó bien. Una vez más, los números son idénticos entre byte y float, por lo que podemos estar seguros de que nuestros resultados siguen siendo igual de buenos incluso después de la cuantificación.
  • Tamaño de índice total (1p, 1r): este es el tamaño de índice total utilizado para el índice de nuestros vectores con una sola partición y una sola réplica. Para esta métrica, deshabilitamos la fuente, que recomendamos para todos los campos vectoriales en los que los datos vectoriales ingeridos no se modifican para que no se almacenen dos veces. ¡Y vemos una reducción masiva del 64% en el tamaño total del índice! Esto no llega a la diferencia de 4x entre un byte y un flotante debido a la sobrecarga adicional para la estructura de datos HNSW, incluidas las conexiones de gráficos, pero sigue siendo una reducción de tamaño bastante sustancial.

Los vectores de bytes están listos para funcionar como parte de 8.6.

Ir al Blog