Las aplicaciones de IA suelen comenzar con costos de computación, datos y monetarios reducidos. A medida que las aplicaciones de producción escalan debido a la mayor participación del usuario, factores clave como el costo asociado con el almacenamiento y la recuperación de grandes volúmenes de datos se convierten en oportunidades de optimización cruciales. Estos desafíos pueden abordarse centrándose en:
Algoritmos eficientes de búsqueda vectorial
Procesos de cuantificación automatizados
Estrategias de incrustación optimizadas
Tanto la Generación Aumentada por Recuperación (RAG) como los sistemas basados en agentes se basan en datos vectoriales (representaciones numéricas de objetos de datos como imágenes, vídeos y texto) para realizar búsquedas de similitud semántica. Los sistemas que utilizan RAG o flujos de trabajo basados en agentes deben gestionar eficientemente conjuntos de datos masivos y de alta dimensión para mantener tiempos de respuesta rápidos, minimizar la latencia de recuperación y controlar los costes de infraestructura.
Acerca del Tutorial
Este tutorial le proporciona las técnicas necesarias para diseñar, implementar y administrar cargas de trabajo de IA avanzadas a escala, garantizando un rendimiento óptimo y una rentabilidad óptima.
En concreto, en este tutorial aprenderás a:
Generar incrustaciones utilizando Voyage AI
voyage-3-large, un modelo de incrustación multilingüe de propósito general que también tiene en cuenta la cuantificación y los incorpora a una base de datos MongoDB.Cuantifique automáticamente las incrustaciones para reducir los tipos de datos de precisión, optimizando tanto el uso de memoria como la latencia de consulta.
Ejecute una consulta que compare incrustaciones float32, int8 y binarias, sopesando la precisión del tipo de datos frente a la eficiencia y la precisión de recuperación.
Mida la recuperación (también denominada retención) de las incrustaciones cuantificadas, que evalúa la eficacia con la que se cuantifican La búsquedaANN recupera los mismos documentos que una búsqueda ENN de precisión completa.
Nota
La cuantificación binaria es óptima para escenarios que exigen un menor consumo de recursos, aunque puede requerir una nueva pasada de puntuación para abordar cualquier pérdida de precisión.
La cuantificación escalar ofrece un punto medio práctico, adecuado para la mayoría de los casos de uso que necesitan equilibrar el rendimiento y la precisión.
Float32 asegura la máxima fidelidad, pero conlleva la mayor sobrecarga de rendimiento y memoria, lo que lo hace menos ideal para sistemas de gran escala o sensibles a la latencia.
Requisitos previos
Para completar este tutorial, debes tener lo siguiente:
Procedimiento
Importe las bibliotecas necesarias y configure las variables de entorno.
Cree un cuaderno de Python interactivo guardando un archivo con la extensión
.ipynb.Instalar las bibliotecas.
Para este tutorial, debes importar las siguientes bibliotecas:
PyMongo
Controlador Python de MongoDB para conectarse a su clúster, crear índices y ejecutar consultas.
voyageai
Cliente Python de Voyage AI para generar las incrustaciones para los datos.
pandas
Herramienta de manipulación y análisis de datos para cargar los datos y prepararlos para la búsqueda vectorial.
conjuntos de datos
Biblioteca Hugging Face que proporciona acceso a conjuntos de datos listos para usar.
matplotlib
Biblioteca de gráficosy visualización para visualizar los datos.
Para instalar las bibliotecas, ejecute lo siguiente:
pip install --quiet -U pymongo voyageai pandas datasets matplotlib Obtenga y configure variables de entorno de forma segura.
La siguiente
set_env_securelyfunción auxiliar obtiene y establece variables de entorno de forma segura. Copie, pegue y ejecute el siguiente código y, cuando se le solicite, establezca valores secretos como su clave de API de Voyage AI y la cadena de conexión del clúster.1 import getpass 2 import os 3 import voyageai 4 5 # Function to securely get and set environment variables 6 def set_env_securely(var_name, prompt): 7 value = getpass.getpass(prompt) 8 os.environ[var_name] = value 9 10 # Environment Variables 11 set_env_securely("VOYAGE_API_KEY", "Enter your Voyage API Key: ") 12 set_env_securely("MONGO_URI", "Enter your MongoDB URI: ") 13 MONGO_URI = os.environ.get("MONGO_URI") 14 if not MONGO_URI: 15 raise ValueError("MONGO_URI not set in environment variables.") 16 17 # Voyage Client 18 voyage_client = voyageai.Client()
Ingiera los datos en su clúster.
En este paso, cargará hasta 250000 documentos de los siguientes conjuntos de datos:
El conjunto de datos wikipedia-22-12-en-voyage-embed contiene fragmentos de artículos de Wikipedia con incrustaciones de 1024coma flotante de dimensiones pregeneradas32 a partir del voyage-3-large modelo de Voyage AI. Esta es la principal colección de documentos con metadatos. Este conjunto de datos sirve como un corpus vectorial diverso para probar los efectos de la cuantificación vectorial en la búsqueda semántica. Cada documento de este conjunto de datos contiene los siguientes campos:
| El ObjectId ( |
| El identificador único del documento. |
| El título del documento. |
| El texto del documento. |
| La URL del documento. |
| El ID de Wikipedia del documento. |
| El número de vistas del documento. |
| El ID del párrafo en el documento. |
| El número de idiomas en el documento. |
| Las incrustaciones vectoriales de dimensión 1024 para el documento. |
El conjunto de datos wikipedia-22-12-en-annotation contiene los datos de referencia anotados para la función de medición de recuperación. Estos datos se utilizan como referencia para la validación de la precisión y para evaluar el impacto de la cuantificación en la calidad de la recuperación. Cada documento de este conjunto de datos contiene los siguientes campos, que constituyen la base para evaluar el rendimiento de la búsqueda vectorial:
| El ObjectId ( |
| El identificador único del documento. |
| El ID de Wikipedia del documento. |
| Las consultas que contienen las frases clave, preguntas, información parcial y oraciones del documento. |
| El arreglo de frases clave utilizadas para evaluar el rendimiento de la búsqueda vectorial para el documento. |
| La matriz de información parcial que se utiliza para evaluar el rendimiento de la búsqueda vectorial del documento. |
| El conjunto de preguntas que se utilizan para evaluar el rendimiento de la búsqueda vectorial del documento. |
| El conjunto de oraciones que se utilizan para evaluar el rendimiento de la búsqueda vectorial del documento. |
Define las funciones para cargar los datos en tu clúster.
Copia, pega y ejecuta el siguiente código en tu notebook. El código de ejemplo define las siguientes funciones:
generate_bson_vectorpara convertir las incrustaciones en el conjunto de datos en vectores binarios BSON para un almacenamiento y procesamiento eficiente de sus vectores.get_mongo_clientpara obtener la cadena de conexión de su clúster.insert_dataframe_into_collectionpara ingerir datos en el clúster.
1 import pandas as pd 2 from datasets import load_dataset 3 from bson.binary import Binary, BinaryVectorDtype 4 import pymongo 5 6 # Connect to Cluster 7 def get_mongo_client(uri): 8 """Connect to MongoDB and confirm the connection.""" 9 client = pymongo.MongoClient(uri) 10 if client.admin.command("ping").get("ok") == 1.0: 11 print("Connected to MongoDB successfully.") 12 return client 13 print("Failed to connect to MongoDB.") 14 return None 15 16 # Generate BSON Vector 17 def generate_bson_vector(array, data_type): 18 """Convert an array to BSON vector format.""" 19 array = [float(val) for val in eval(array)] 20 return Binary.from_vector(array, BinaryVectorDtype(data_type)) 21 22 # Load Datasets 23 def load_and_prepare_data(dataset_name, amount): 24 """Load and prepare streaming datasets for DataFrame.""" 25 data = load_dataset(dataset_name, streaming=True, split="train").take(amount) 26 return pd.DataFrame(data) 27 28 # Insert datasets into MongoDB Collection 29 def insert_dataframe_into_collection(df, collection): 30 """Insert Dataset records into MongoDB collection.""" 31 collection.insert_many(df.to_dict("records")) 32 print(f"Inserted {len(df)} records into '{collection.name}' collection.") Cargue los datos en su clúster.
Copie, pegue y ejecute el siguiente código en su notebook para cargar el conjunto de datos en su clúster. Este código realiza las siguientes acciones:
Recupera los conjuntos de datos.
Convierte las incrustaciones al formato BSON.
Crea colecciones en su clúster e inserta los datos.
1 import pandas as pd 2 from bson.binary import Binary, BinaryVectorDtype 3 from pymongo.errors import CollectionInvalid 4 5 wikipedia_data_df = load_and_prepare_data("MongoDB/wikipedia-22-12-en-voyage-embed", amount=250000) 6 wikipedia_annotation_data_df = load_and_prepare_data("MongoDB/wikipedia-22-12-en-annotation", amount=250000) 7 wikipedia_annotation_data_df.drop(columns=["_id"], inplace=True) 8 9 # Convert embeddings to BSON format 10 wikipedia_data_df["embedding"] = wikipedia_data_df["embedding"].apply( 11 lambda x: generate_bson_vector(x, BinaryVectorDtype.FLOAT32) 12 ) 13 14 # MongoDB Setup 15 mongo_client = get_mongo_client(MONGO_URI) 16 DB_NAME = "testing_datasets" 17 db = mongo_client[DB_NAME] 18 19 collections = { 20 "wikipedia-22-12-en": wikipedia_data_df, 21 "wikipedia-22-12-en-annotation": wikipedia_annotation_data_df, 22 } 23 24 # Create Collections and Insert Data 25 for collection_name, df in collections.items(): 26 if collection_name not in db.list_collection_names(): 27 try: 28 db.create_collection(collection_name) 29 print(f"Collection '{collection_name}' created successfully.") 30 except CollectionInvalid: 31 print(f"Error creating collection '{collection_name}'.") 32 else: 33 print(f"Collection '{collection_name}' already exists.") 34 35 # Clear collection and insert fresh data 36 collection = db[collection_name] 37 collection.delete_many({}) 38 insert_dataframe_into_collection(df, collection) Connected to MongoDB successfully. Collection 'wikipedia-22-12-en' created successfully. Inserted 250000 records into 'wikipedia-22-12-en' collection. Collection 'wikipedia-22-12-en-annotation' created successfully. Inserted 87200 records into 'wikipedia-22-12-en-annotation' collection. IMPORTANTE: Puede llevar algún tiempo convertir las incrustaciones en vectores BSON e ingerir los conjuntos de datos en su clúster.
Verifique que los conjuntos de datos se hayan cargado correctamente iniciando sesión en su clúster e inspeccionando visualmente las colecciones en Explorador de datos.
Cree índices de búsqueda vectorial MongoDB en la colección.
En este paso, creará los siguientes tres índices en el campo embedding:
Índice cuantificado escalar | Utilizar el método de cuantificación escalar para cuantificar las incrustaciones. |
Índice cuantificado binario | Utilizar el método de cuantificación binaria para cuantificar las incrustaciones. |
Float32 ANN Index | Utilizar el método32 ANN float para cuantificar las incrustaciones. |
Define la función para crear el índice de búsqueda vectorial de MongoDB.
Copie, pegue y ejecute lo siguiente en su cuaderno:
1 import time 2 from pymongo.operations import SearchIndexModel 3 4 def setup_vector_search_index(collection, index_definition, index_name="vector_index"): 5 new_vector_search_index_model = SearchIndexModel( 6 definition=index_definition, name=index_name, type="vectorSearch" 7 ) 8 9 # Create the new index 10 try: 11 result = collection.create_search_index(model=new_vector_search_index_model) 12 print(f"Creating index '{index_name}'...") 13 14 # Wait for initial sync to complete 15 print("Polling to check if the index is ready. This may take a couple of minutes.") 16 predicate=None 17 if predicate is None: 18 predicate = lambda index: index.get("queryable") is True 19 while True: 20 indices = list(collection.list_search_indexes(result)) 21 if len(indices) and predicate(indices[0]): 22 break 23 time.sleep(5) 24 print(f"Index '{index_name}' is ready for querying.") 25 return result 26 27 except Exception as e: 28 print(f"Error creating new vector search index '{index_name}': {e!s}") 29 return None Definir los índices.
Las siguientes configuraciones de índices implementan una estrategia diferente de cuantificación:
vector_index_definition_scalar_quantizedEsta configuración utiliza cuantificación escalar (int8), que:
Reduce cada dimensión vectorial de un valor flotante de 32bits a un valor entero de 8bits
Mantiene un buen equilibrio entre precisión y eficiencia de memoria.
Es adecuado para la mayoría de los casos de uso de producción donde se necesita optimización de memoria.
vector_index_definition_binary_quantizedEsta configuración utiliza cuantificación binaria (int1), que:
Reduce cada dimensión vectorial a un solo bit
Proporciona la máxima eficiencia de memoria
Es ideal para implementaciones a gran escala donde las limitaciones de memoria son críticas.
La cuantización automática se realiza de manera transparente cuando se crean estos índices, y la Búsqueda Vectorial de MongoDB gestiona la conversión de float32 al formato cuantizado especificado durante la creación de índices y las operaciones de búsqueda.
La configuración del índice
vector_index_definition_float32_annindexa vectores de fidelidad completa de1024dimensiones mediante la función de similitudcosine.1 # Scalar Quantization 2 vector_index_definition_scalar_quantized = { 3 "fields": [ 4 { 5 "type": "vector", 6 "path": "embedding", 7 "quantization": "scalar", 8 "numDimensions": 1024, 9 "similarity": "cosine", 10 } 11 ] 12 } 13 # Binary Quantization 14 vector_index_definition_binary_quantized = { 15 "fields": [ 16 { 17 "type": "vector", 18 "path": "embedding", 19 "quantization": "binary", 20 "numDimensions": 1024, 21 "similarity": "cosine", 22 } 23 ] 24 } 25 # Float32 Embeddings 26 vector_index_definition_float32_ann = { 27 "fields": [ 28 { 29 "type": "vector", 30 "path": "embedding", 31 "numDimensions": 1024, 32 "similarity": "cosine", 33 } 34 ] 35 } Cree los índices escalares, binarios y flotantes32 utilizando la función
setup_vector_search_index.Establezca los nombres de colección e índice para los índices.
wiki_data_collection = db["wikipedia-22-12-en"] wiki_annotation_data_collection = db["wikipedia-22-12-en-annotation"] vector_search_scalar_quantized_index_name = "vector_index_scalar_quantized" vector_search_binary_quantized_index_name = "vector_index_binary_quantized" vector_search_float32_ann_index_name = "vector_index_float32_ann" Cree los índices de búsqueda vectorial de MongoDB.
1 setup_vector_search_index( 2 wiki_data_collection, 3 vector_index_definition_scalar_quantized, 4 vector_search_scalar_quantized_index_name, 5 ) 6 setup_vector_search_index( 7 wiki_data_collection, 8 vector_index_definition_binary_quantized, 9 vector_search_binary_quantized_index_name, 10 ) 11 setup_vector_search_index( 12 wiki_data_collection, 13 vector_index_definition_float32_ann, 14 vector_search_float32_ann_index_name, 15 ) Creating index 'vector_index_scalar_quantized'... Polling to check if the index is ready. This may take a couple of minutes. Index 'vector_index_scalar_quantized' is ready for querying. Creating index 'vector_index_binary_quantized'... Polling to check if the index is ready. This may take a couple of minutes. Index 'vector_index_binary_quantized' is ready for querying. Creating index 'vector_index_float32_ann'... Polling to check if the index is ready. This may take a couple of minutes. Index 'vector_index_float32_ann' is ready for querying. vector_index_float32_ann' IMPORTANTE: La operación puede tardar unos minutos en completarse. Los índices deben estar en Ready estado para poder usarlos en las consultas.
Verifique que la creación del índice se haya realizado correctamente iniciando sesión en su clúster e inspeccionando visualmente los índices en Atlas Search.
Define las funciones para generar incrustaciones y consultar una colección utilizando los índices de búsqueda vectorial de MongoDB.
Este código define las siguientes funciones:
La función
get_embedding()genera incrustaciones de dimensión 1024 para el texto dado utilizando el modelo de incrustaciónvoyage-3-largede Voyage AI.La función
custom_vector_searchtoma los siguientes parámetros de entrada y devuelve los resultados de la operación de búsqueda vectorial.user_querystring de texto de query para la que se desea generar incrustaciones.
collectionColección MongoDB para buscar.
embedding_pathCampo de la colección que contiene las incrustaciones.
vector_search_index_nameNombre del índice a utilizar en la consulta.
top_kNúmero de documentos principales en los resultados a devolver.
num_candidatesNúmero de candidatos a considerar.
use_full_precisionBandera para realizar
FalseTruebúsqueda ANN, si, o ENN, si.El
use_full_precisionvalor se establece enFalsede forma predeterminada para una búsqueda ANN. Establezca eluse_full_precisionvalor enTruepara realizar una búsqueda ENN.En concreto, esta función realiza las siguientes acciones:
Genera las incrustaciones para el texto de la consulta.
Construye la
$vectorSearchetapaConfigura el tipo de búsqueda
Especifica los campos de la colección que se devolverán
Ejecuta la canalización después de recopilar estadísticas de rendimiento
Devuelve los resultados
1 def get_embedding(text, task_prefix="document"): 2 """Fetch embedding for a given text using Voyage AI.""" 3 if not text.strip(): 4 print("Empty text provided for embedding.") 5 return [] 6 result = voyage_client.embed([text], model="voyage-3-large", input_type=task_prefix) 7 return result.embeddings[0] 8 9 def custom_vector_search( 10 user_query, 11 collection, 12 embedding_path, 13 vector_search_index_name="vector_index", 14 top_k=5, 15 num_candidates=25, 16 use_full_precision=False, 17 ): 18 19 # Generate embedding for the user query 20 query_embedding = get_embedding(user_query, task_prefix="query") 21 22 if query_embedding is None: 23 return "Invalid query or embedding generation failed." 24 25 # Define the vector search stage 26 vector_search_stage = { 27 "$vectorSearch": { 28 "index": vector_search_index_name, 29 "queryVector": query_embedding, 30 "path": embedding_path, 31 "limit": top_k, 32 } 33 } 34 35 # Add numCandidates only for approximate search 36 if not use_full_precision: 37 vector_search_stage["$vectorSearch"]["numCandidates"] = num_candidates 38 else: 39 # Set exact to true for exact search using full precision float32 vectors and running exact search 40 vector_search_stage["$vectorSearch"]["exact"] = True 41 42 project_stage = { 43 "$project": { 44 "_id": 0, 45 "title": 1, 46 "text": 1, 47 "wiki_id": 1, 48 "url": 1, 49 "score": { 50 "$meta": "vectorSearchScore" 51 }, 52 } 53 } 54 55 # Define the aggregate pipeline with the vector search stage and additional stages 56 pipeline = [vector_search_stage, project_stage] 57 58 # Execute the explain command 59 explain_result = collection.database.command( 60 "explain", 61 {"aggregate": collection.name, "pipeline": pipeline, "cursor": {}}, 62 verbosity="executionStats", 63 ) 64 65 # Extract the execution time 66 vector_search_explain = explain_result["stages"][0]["$vectorSearch"] 67 execution_time_ms = vector_search_explain["explain"]["query"]["stats"]["context"][ 68 "millisElapsed" 69 ] 70 71 # Execute the actual query 72 results = list(collection.aggregate(pipeline)) 73 74 return {"results": results, "execution_time_ms": execution_time_ms}
Ejecute una consulta de búsqueda vectorial MongoDB para evaluar el rendimiento de la búsqueda.
La siguiente consulta realiza búsquedas vectoriales con diferentes estrategias de cuantificación, midiendo métricas de rendimiento para vectores de cuantificación escalar, cuantificación binaria y precisión completa (float32), a la vez que captura mediciones de latencia en cada nivel de precisión y estandariza el formato de los resultados para su comparación analítica. Utiliza incrustaciones generadas con Voyage AI para la cadena de consulta "¿Cómo puedo aumentar mi productividad para obtener el máximo rendimiento?".
La consulta almacena indicadores de rendimiento esenciales clave en la variable results, incluido el nivel de precisión (escalar, binario, flotante32), el tamaño del conjunto de resultados (top_k), la latencia de la consulta en milisegundos y el contenido del documento recuperado, lo que proporciona métricas integrales para evaluar el rendimiento de la búsqueda en diferentes estrategias de cuantificación.
1 vector_search_indices = [ 2 vector_search_float32_ann_index_name, 3 vector_search_scalar_quantized_index_name, 4 vector_search_binary_quantized_index_name, 5 ] 6 7 # Random query 8 user_query = "How do I increase my productivity for maximum output" 9 test_top_k = 5 10 test_num_candidates = 25 11 12 # Result is a list of dictionaries with the following headings: precision, top_k, latency_ms, results 13 results = [] 14 15 for vector_search_index in vector_search_indices: 16 # Conduct a vector search operation using scalar quantized 17 vector_search_results = custom_vector_search( 18 user_query, 19 wiki_data_collection, 20 embedding_path="embedding", 21 vector_search_index_name=vector_search_index, 22 top_k=test_top_k, 23 num_candidates=test_num_candidates, 24 use_full_precision=False, 25 ) 26 # Include the precision in the results 27 precision = vector_search_index.split("vector_index")[1] 28 precision = precision.replace("quantized", "").capitalize() 29 30 results.append( 31 { 32 "precision": precision, 33 "top_k": test_top_k, 34 "num_candidates": test_num_candidates, 35 "latency_ms": vector_search_results["execution_time_ms"], 36 "results": vector_search_results["results"][0], # Just taking the first result, modify this to include more results if needed 37 } 38 ) 39 40 # Conduct a vector search operation using full precision 41 precision = "Float32_ENN" 42 vector_search_results = custom_vector_search( 43 user_query, 44 wiki_data_collection, 45 embedding_path="embedding", 46 vector_search_index_name="vector_index_scalar_quantized", 47 top_k=test_top_k, 48 num_candidates=test_num_candidates, 49 use_full_precision=True, 50 ) 51 52 results.append( 53 { 54 "precision": precision, 55 "top_k": test_top_k, 56 "num_candidates": test_num_candidates, 57 "latency_ms": vector_search_results["execution_time_ms"], 58 "results": vector_search_results["results"][0], # Just taking the first result, modify this to include more results if needed 59 } 60 ) 61 62 # Convert the results to a pandas DataFrame with the headings: precision, top_k, latency_ms 63 results_df = pd.DataFrame(results) 64 results_df.columns = ["precision", "top_k", "num_candidates", "latency_ms", "results"] 65 66 # To display the results: 67 results_df.head()
precision top_k num_candidates latency_ms results 0 _float32_ann 5 25 1659.498601 {'title': 'Henry Ford', 'text': 'Ford had deci... 1 _scalar_ 5 25 951.537687 {'title': 'Gross domestic product', 'text': 'F... 2 _binary_ 5 25 344.585193 {'title': 'Great Depression', 'text': 'The fir... 3 Float32_ENN 5 25 0.231693 {'title': 'Great Depression', 'text': 'The fir...
Las métricas de rendimiento de los resultados muestran diferencias de latencia entre los distintos niveles de precisión. Esto demuestra que, si bien la cuantificación proporciona mejoras sustanciales en el rendimiento, existe una clara compensación entre la precisión y la velocidad de recuperación, ya que las operaciones float32 de precisión completa requieren un tiempo de cálculo considerablemente mayor que sus contrapartes cuantificadas.
Mida la latencia con top-k num_candidates valores variables y.
La siguiente consulta introduce un marco sistemático de medición de latencia que evalúa el rendimiento de la búsqueda vectorial con diferentes niveles de precisión y escalas de recuperación. El parámetro top-k no solo determina el número de resultados a devolver, sino que también establece el numCandidates parámetro en la búsqueda de grafos HNSW de MongoDB.
El numCandidates valor influye en la cantidad de nodos que MongoDB Vector Search explora en el grafo HNSW durante la búsqueda de ANN. En este caso, un valor más alto aumenta la probabilidad de encontrar los vecinos más cercanos, pero requiere más tiempo de cálculo.
Define la función para formatear
latency_msen un formato legible para humanos.1 from datetime import timedelta 2 3 def format_time(ms): 4 """Convert milliseconds to a human-readable format""" 5 delta = timedelta(milliseconds=ms) 6 7 # Extract minutes, seconds, and milliseconds with more precision 8 minutes = delta.seconds // 60 9 seconds = delta.seconds % 60 10 milliseconds = round(ms % 1000, 3) # Keep 3 decimal places for milliseconds 11 12 # Format based on duration 13 if minutes > 0: 14 return f"{minutes}m {seconds}.{milliseconds:03.0f}s" 15 elif seconds > 0: 16 return f"{seconds}.{milliseconds:03.0f}s" 17 else: 18 return f"{milliseconds:.3f}ms" Define la función para medir la latencia de la consulta de búsqueda vectorial.
La siguiente función toma como entrada los valores
user_query,collection,vector_search_index_name,use_full_precision,top_k_valuesynum_candidates_valuesy devuelve los resultados de la búsqueda vectorial. Anote lo siguiente:La latencia aumenta a medida que aumentan los valores
top_kynum_candidatesporque la operación de búsqueda vectorial utiliza una mayor cantidad de documentos y hace que la búsqueda tarde más.La latencia es mayor para la búsqueda de fidelidad total (
use_full_precision=True) que para la búsqueda aproximada (use_full_precision=False) porque la búsqueda de fidelidad total toma más tiempo que la búsqueda aproximada ya que busca en todo el conjunto de datos, utilizando vectores float32 de precisión total.La latencia de la búsqueda cuantificada es menor que la búsqueda de fidelidad completa porque la búsqueda cuantificada utiliza la búsqueda aproximada y los vectores cuantificados.
1 def measure_latency_with_varying_topk( 2 user_query, 3 collection, 4 vector_search_index_name="vector_index_scalar_quantized", 5 use_full_precision=False, 6 top_k_values=[5, 10, 100], 7 num_candidates_values=[25, 50, 100, 200, 500, 1000, 2000, 5000, 10000], 8 ): 9 results_data = [] 10 11 # Conduct vector search operation for each (top_k, num_candidates) combination 12 for top_k in top_k_values: 13 for num_candidates in num_candidates_values: 14 # Skip scenarios where num_candidates < top_k 15 if num_candidates < top_k: 16 continue 17 18 # Construct the precision name 19 precision_name = vector_search_index_name.split("vector_index")[1] 20 precision_name = precision_name.replace("quantized", "").capitalize() 21 22 # If use_full_precision is true, then the precision name is "_float32_" 23 if use_full_precision: 24 precision_name = "_float32_ENN" 25 26 # Perform the vector search 27 vector_search_results = custom_vector_search( 28 user_query=user_query, 29 collection=collection, 30 embedding_path="embedding", 31 vector_search_index_name=vector_search_index_name, 32 top_k=top_k, 33 num_candidates=num_candidates, 34 use_full_precision=use_full_precision, 35 ) 36 37 # Extract the execution time (latency) 38 latency_ms = vector_search_results["execution_time_ms"] 39 40 # Store results 41 results_data.append( 42 { 43 "precision": precision_name, 44 "top_k": top_k, 45 "num_candidates": num_candidates, 46 "latency_ms": latency_ms, 47 } 48 ) 49 50 return results_data Ejecuta la consulta de búsqueda vectorial de MongoDB para medir la latencia.
La operación de evaluación de latencia realiza un análisis integral del rendimiento ejecutando búsquedas a través de todas las estrategias de cuantización, probando múltiples tamaños de conjuntos de resultados, capturando métricas de rendimiento estandarizadas y agregando los resultados para un análisis comparativo, lo que permite una evaluación detallada del comportamiento de búsqueda vectorial bajo diferentes configuraciones y cargas de recuperación.
1 # Run the measurements 2 user_query = "How do I increase my productivity for maximum output" 3 top_k_values = [5, 10, 50, 100] 4 num_candidates_values = [25, 50, 100, 200, 500, 1000, 2000, 5000, 10000] 5 6 latency_results = [] 7 8 for vector_search_index in vector_search_indices: 9 latency_results.append( 10 measure_latency_with_varying_topk( 11 user_query, 12 wiki_data_collection, 13 vector_search_index_name=vector_search_index, 14 use_full_precision=False, 15 top_k_values=top_k_values, 16 num_candidates_values=num_candidates_values, 17 ) 18 ) 19 20 # Conduct vector search operation using full precision 21 latency_results.append( 22 measure_latency_with_varying_topk( 23 user_query, 24 wiki_data_collection, 25 vector_search_index_name="vector_index_scalar_quantized", 26 use_full_precision=True, 27 top_k_values=top_k_values, 28 num_candidates_values=num_candidates_values, 29 ) 30 ) 31 32 # Combine all results into a single DataFrame 33 all_latency_results = pd.concat([pd.DataFrame(latency_results)]) Top-K: 5, NumCandidates: 25, Latency: 1672.855906 ms, Precision: _float32_ann ... Top-K: 100, NumCandidates: 10000, Latency: 184.905389 ms, Precision: _float32_ann Top-K: 5, NumCandidates: 25, Latency: 828.45855 ms, Precision: _scalar_ ... Top-K: 100, NumCandidates: 10000, Latency: 214.199836 ms, Precision: _scalar_ Top-K: 5, NumCandidates: 25, Latency: 400.160243 ms, Precision: _binary_ ... Top-K: 100, NumCandidates: 10000, Latency: 360.908558 ms, Precision: _binary_ Top-K: 5, NumCandidates: 25, Latency: 0.239107 ms, Precision: _float32_ENN ... Top-K: 100, NumCandidates: 10000, Latency: 0.179203 ms, Precision: _float32_ENN Las mediciones de latencia revelan una clara jerarquía de rendimiento entre los tipos de precisión, donde la cuantificación binaria presenta los tiempos de recuperación más rápidos, seguida de la cuantificación escalar. Las operaciones de32 ANN float de precisión completa muestran latencias significativamente mayores. La diferencia de rendimiento entre las búsquedas cuantificadas y las de precisión completa se acentúa a medida que aumentan los valores Top-K. Las32 operaciones de ENN float son las más lentas, pero ofrecen los resultados de mayor precisión.
Grafique la latencia de búsqueda en función de varios valores top-k.
1 import matplotlib.pyplot as plt 2 3 # Map your precision field to the labels and colors you want in the legend 4 precision_label_map = { 5 "_scalar_": "scalar", 6 "_binary_": "binary", 7 "_float32_ann": "float32_ann", 8 "_float32_ENN": "float32_ENN", 9 } 10 11 precision_color_map = { 12 "_scalar_": "orange", 13 "_binary_": "red", 14 "_float32_ann": "blue", 15 "_float32_ENN": "purple", 16 } 17 18 # Flatten all measurements and find the unique top_k values 19 all_measurements = [m for precision_list in latency_results for m in precision_list] 20 unique_topk = sorted(set(m["top_k"] for m in all_measurements)) 21 22 # For each top_k, create a separate plot 23 for k in unique_topk: 24 plt.figure(figsize=(10, 6)) 25 26 # For each precision type, filter out measurements for the current top_k value 27 for measurements in latency_results: 28 # Filter measurements with top_k equal to the current k 29 filtered = [m for m in measurements if m["top_k"] == k] 30 if not filtered: 31 continue 32 33 # Extract x (num_candidates) and y (latency) values 34 x = [m["num_candidates"] for m in filtered] 35 y = [m["latency_ms"] for m in filtered] 36 37 # Determine the precision, label, and color from the first measurement in this filtered list 38 precision = filtered[0]["precision"] 39 label = precision_label_map.get(precision, precision) 40 color = precision_color_map.get(precision, "blue") 41 42 # Plot the line for this precision type 43 plt.plot(x, y, marker="o", color=color, label=label) 44 45 # Label axes and add title including the top_k value 46 plt.xlabel("Number of Candidates") 47 plt.ylabel("Latency (ms)") 48 plt.title(f"Search Latency vs Num Candidates for Top-K = {k}") 49 50 # Add a legend and grid, then show the plot 51 plt.legend() 52 plt.grid(True) 53 plt.show() El código devuelve los siguientes gráficos de latencia, que ilustran cómo funciona la recuperación de documentos de búsqueda vectorial con diferentes tipos de precisión de incrustación, binario, escalar y flotante32, a medida que aumenta
top-k(la cantidad de resultados recuperados):
haga clic para ampliar
haga clic para ampliar
haga clic para ampliar
Medir la capacidad de representación y retención.
La siguiente consulta mide la eficacia con la que MongoDB Vector Search recupera documentos relevantes del conjunto de datos de datos de campo. Se calcula como la proporción de documentos relevantes encontrados correctamente respecto al número total de documentos relevantes en el conjunto de datos de campo (Encontrados/Total). Por ejemplo, si una consulta tiene 5 documentos relevantes en el conjunto de datos de campo y MongoDB Vector Search encuentra 4, la recuperación sería de 0.8 o 80%.
Defina una función para medir la capacidad de representación y la retención de la operación de búsqueda vectorial. Esta función realiza lo siguiente:
Crea la búsqueda de línea base utilizando32 vectores float de precisión completa y búsqueda ENN.
Crea la búsqueda cuantificada utilizando los vectores cuantificados y la búsqueda ANN.
Calcula la retención de la búsqueda cuantificada en comparación con la búsqueda de referencia.
La retención debe mantenerse dentro de un rango razonable para la búsqueda cuantificada. Si la capacidad de representación es baja, significa que la búsqueda vectorial no puede capturar el significado semántico de la consulta y que los resultados podrían no ser precisos. Esto indica que la cuantificación no es efectiva y que el modelo de incrustación inicial utilizado no es eficaz para el proceso de cuantificación. Recomendamos utilizar modelos de incrustación que tengan en cuenta la cuantificación, es decir, que durante el proceso de entrenamiento, el modelo se optimice específicamente para producir incrustaciones que mantengan sus propiedades semánticas incluso después de la cuantificación.
1 def measure_representational_capacity_retention_against_float_enn( 2 ground_truth_collection, 3 collection, 4 quantized_index_name, # This is used for both the quantized search and (with use_full_precision=True) for the baseline. 5 top_k_values, # List/array of top-k values to test. 6 num_candidates_values, # List/array of num_candidates values to test. 7 num_queries_to_test=1, 8 ): 9 retention_results = {"per_query_retention": {}} 10 overall_retention = {} # overall_retention[top_k][num_candidates] = [list of retention values] 11 12 # Initialize overall retention structure 13 for top_k in top_k_values: 14 overall_retention[top_k] = {} 15 for num_candidates in num_candidates_values: 16 if num_candidates < top_k: 17 continue 18 overall_retention[top_k][num_candidates] = [] 19 20 # Extract and store the precision name from the quantized index name. 21 precision_name = quantized_index_name.split("vector_index")[1] 22 precision_name = precision_name.replace("quantized", "").capitalize() 23 retention_results["precision_name"] = precision_name 24 retention_results["top_k_values"] = top_k_values 25 retention_results["num_candidates_values"] = num_candidates_values 26 27 # Load ground truth annotations 28 ground_truth_annotations = list( 29 ground_truth_collection.find().limit(num_queries_to_test) 30 ) 31 print(f"Loaded {len(ground_truth_annotations)} ground truth annotations") 32 33 # Process each ground truth annotation 34 for annotation in ground_truth_annotations: 35 # Use the ground truth wiki_id from the annotation. 36 ground_truth_wiki_id = annotation["wiki_id"] 37 38 # Process only queries that are questions. 39 for query_type, queries in annotation["queries"].items(): 40 if query_type.lower() not in ["question", "questions"]: 41 continue 42 43 for query in queries: 44 # Prepare nested dict for this query 45 if query not in retention_results["per_query_retention"]: 46 retention_results["per_query_retention"][query] = {} 47 48 # For each valid combination of top_k and num_candidates 49 for top_k in top_k_values: 50 if top_k not in retention_results["per_query_retention"][query]: 51 retention_results["per_query_retention"][query][top_k] = {} 52 for num_candidates in num_candidates_values: 53 if num_candidates < top_k: 54 continue 55 56 # Baseline search: full precision using ENN (Float32) 57 baseline_result = custom_vector_search( 58 user_query=query, 59 collection=collection, 60 embedding_path="embedding", 61 vector_search_index_name=quantized_index_name, 62 top_k=top_k, 63 num_candidates=num_candidates, 64 use_full_precision=True, 65 ) 66 baseline_ids = { 67 res["wiki_id"] for res in baseline_result["results"] 68 } 69 70 # Quantized search: 71 quantized_result = custom_vector_search( 72 user_query=query, 73 collection=collection, 74 embedding_path="embedding", 75 vector_search_index_name=quantized_index_name, 76 top_k=top_k, 77 num_candidates=num_candidates, 78 use_full_precision=False, 79 ) 80 quantized_ids = { 81 res["wiki_id"] for res in quantized_result["results"] 82 } 83 84 # Compute retention for this combination 85 if baseline_ids: 86 retention = len( 87 baseline_ids.intersection(quantized_ids) 88 ) / len(baseline_ids) 89 else: 90 retention = 0 91 92 # Store the results per query 93 retention_results["per_query_retention"][query].setdefault( 94 top_k, {} 95 )[num_candidates] = { 96 "ground_truth_wiki_id": ground_truth_wiki_id, 97 "baseline_ids": sorted(baseline_ids), 98 "quantized_ids": sorted(quantized_ids), 99 "retention": retention, 100 } 101 overall_retention[top_k][num_candidates].append(retention) 102 103 print( 104 f"Query: '{query}' | top_k: {top_k}, num_candidates: {num_candidates}" 105 ) 106 print(f" Ground Truth wiki_id: {ground_truth_wiki_id}") 107 print(f" Baseline IDs (Float32): {sorted(baseline_ids)}") 108 print( 109 f" Quantized IDs: {precision_name}: {sorted(quantized_ids)}" 110 ) 111 print(f" Retention: {retention:.4f}\n") 112 113 # Compute overall average retention per combination 114 avg_overall_retention = {} 115 for top_k, cand_dict in overall_retention.items(): 116 avg_overall_retention[top_k] = {} 117 for num_candidates, retentions in cand_dict.items(): 118 if retentions: 119 avg = sum(retentions) / len(retentions) 120 else: 121 avg = 0 122 avg_overall_retention[top_k][num_candidates] = avg 123 print( 124 f"Overall Average Retention for top_k {top_k}, num_candidates {num_candidates}: {avg:.4f}" 125 ) 126 127 retention_results["average_retention"] = avg_overall_retention 128 return retention_results Evalúe y compare el rendimiento de sus índices de búsqueda vectorial de MongoDB.
1 overall_recall_results = [] 2 top_k_values = [5, 10, 50, 100] 3 num_candidates_values = [25, 50, 100, 200, 500, 1000, 5000] 4 num_queries_to_test = 1 5 6 for vector_search_index in vector_search_indices: 7 overall_recall_results.append( 8 measure_representational_capacity_retention_against_float_enn( 9 ground_truth_collection=wiki_annotation_data_collection, 10 collection=wiki_data_collection, 11 quantized_index_name=vector_search_index, 12 top_k_values=top_k_values, 13 num_candidates_values=num_candidates_values, 14 num_queries_to_test=num_queries_to_test, 15 ) 16 ) Loaded 1 ground truth annotations Query: 'What happened in 2022?' | top_k: 5, num_candidates: 25 Ground Truth wiki_id: 69407798 Baseline IDs (Float32): [52251217, 60254944, 64483771, 69094871] Quantized IDs: _float32_ann: [60254944, 64483771, 69094871] Retention: 0.7500 ... Query: 'What happened in 2022?' | top_k: 5, num_candidates: 5000 Ground Truth wiki_id: 69407798 Baseline IDs (Float32): [52251217, 60254944, 64483771, 69094871] Quantized IDs: _float32_ann: [52251217, 60254944, 64483771, 69094871] Retention: 1.0000 Query: 'What happened in 2022?' | top_k: 10, num_candidates: 25 Ground Truth wiki_id: 69407798 Baseline IDs (Float32): [52251217, 60254944, 64483771, 69094871, 69265870] Quantized IDs: _float32_ann: [60254944, 64483771, 65225795, 69094871, 70149799] Retention: 1.0000 ... Query: 'What happened in 2022?' | top_k: 10, num_candidates: 5000 Ground Truth wiki_id: 69407798 Baseline IDs (Float32): [52251217, 60254944, 64483771, 69094871, 69265870] Quantized IDs: _float32_ann: [52251217, 60254944, 64483771, 69094871, 69265870] Retention: 1.0000 Query: 'What happened in 2022?' | top_k: 50, num_candidates: 50 Ground Truth wiki_id: 69407798 Baseline IDs (Float32): [25391, 832774, 8351234, 18426568, 29868391, 52241897, 52251217, 60254944, 63422045, 64483771, 65225795, 69094871, 69265859, 69265870, 70149799, 70157964] Quantized IDs: _float32_ann: [25391, 8351234, 29868391, 40365067, 52241897, 52251217, 60254944, 64483771, 65225795, 69094871, 69265859, 69265870, 70149799, 70157964] Retention: 0.8125 ... Query: 'What happened in 2022?' | top_k: 50, num_candidates: 5000 Ground Truth wiki_id: 69407798 Baseline IDs (Float32): [25391, 832774, 8351234, 18426568, 29868391, 52241897, 52251217, 60254944, 63422045, 64483771, 65225795, 69094871, 69265859, 69265870, 70149799, 70157964] Quantized IDs: _float32_ann: [25391, 832774, 8351234, 18426568, 29868391, 52241897, 52251217, 60254944, 63422045, 64483771, 65225795, 69094871, 69265859, 69265870, 70149799, 70157964] Retention: 1.0000 Query: 'What happened in 2022?' | top_k: 100, num_candidates: 100 Ground Truth wiki_id: 69407798 Baseline IDs (Float32): [16642, 22576, 25391, 547384, 737930, 751099, 832774, 8351234, 17742072, 18426568, 29868391, 40365067, 52241897, 52251217, 52851695, 53992315, 57798792, 60163783, 60254944, 62750956, 63422045, 64483771, 65225795, 65593860, 69094871, 69265859, 69265870, 70149799, 70157964] Quantized IDs: _float32_ann: [22576, 25391, 243401, 547384, 751099, 8351234, 17742072, 18426568, 29868391, 40365067, 47747350, 52241897, 52251217, 52851695, 53992315, 57798792, 60254944, 64483771, 65225795, 69094871, 69265859, 69265870, 70149799, 70157964] Retention: 0.7586 ... Query: 'What happened in 2022?' | top_k: 100, num_candidates: 5000 Ground Truth wiki_id: 69407798 Baseline IDs (Float32): [16642, 22576, 25391, 547384, 737930, 751099, 832774, 8351234, 17742072, 18426568, 29868391, 40365067, 52241897, 52251217, 52851695, 53992315, 57798792, 60163783, 60254944, 62750956, 63422045, 64483771, 65225795, 65593860, 69094871, 69265859, 69265870, 70149799, 70157964] Quantized IDs: _float32_ann: [16642, 22576, 25391, 547384, 737930, 751099, 832774, 8351234, 17742072, 18426568, 29868391, 40365067, 52241897, 52251217, 52851695, 53992315, 57798792, 60163783, 60254944, 62750956, 63422045, 64483771, 65225795, 65593860, 69094871, 69265859, 69265870, 70149799, 70157964] Retention: 1.0000 Overall Average Retention for top_k 5, num_candidates 25: 0.7500 ... La salida muestra los resultados de retención para cada consulta en el conjunto de datos de datos de campo. La retención se expresa como un decimal entre 0 y 1, donde 1.0 significa que se conservan los ID de datos de campo y 0.25 que solo se conserva el 25% de los mismos.
Grafique la capacidad de retención de los diferentes tipos de precisión.
1 import matplotlib.pyplot as plt 2 3 # Define colors and labels for each precision type 4 precision_colors = {"_scalar_": "orange", "_binary_": "red", "_float32_": "green"} 5 6 if overall_recall_results: 7 # Determine unique top_k values from the first result's average_retention keys 8 unique_topk = sorted(list(overall_recall_results[0]["average_retention"].keys())) 9 10 for k in unique_topk: 11 plt.figure(figsize=(10, 6)) 12 # For each precision type, plot retention vs. number of candidates at this top_k 13 for result in overall_recall_results: 14 precision_name = result.get("precision_name", "unknown") 15 color = precision_colors.get(precision_name, "blue") 16 # Get candidate values from the average_retention dictionary for top_k k 17 candidate_values = sorted(result["average_retention"][k].keys()) 18 retention_values = [ 19 result["average_retention"][k][nc] for nc in candidate_values 20 ] 21 22 plt.plot( 23 candidate_values, 24 retention_values, 25 marker="o", 26 label=precision_name.strip("_"), 27 color=color, 28 ) 29 30 plt.xlabel("Number of Candidates") 31 plt.ylabel("Retention Score") 32 plt.title(f"Retention vs Number of Candidates for Top-K = {k}") 33 plt.legend() 34 plt.grid(True) 35 plt.show() 36 37 # Print detailed average retention results 38 print("\nDetailed Average Retention Results:") 39 for result in overall_recall_results: 40 precision_name = result.get("precision_name", "unknown") 41 print(f"\n{precision_name} Embedding:") 42 for k in sorted(result["average_retention"].keys()): 43 print(f"\nTop-K: {k}") 44 for nc in sorted(result["average_retention"][k].keys()): 45 ret = result["average_retention"][k][nc] 46 print(f" NumCandidates: {nc}, Retention: {ret:.4f}") El código devuelve los gráficos de retención para lo siguiente:
haga clic para ampliar
haga clic para ampliar
haga clic para ampliar
haga clic para ampliarPara las incrustaciones
float32_ann,scalarybinary, el código también devuelve resultados de retención promedio detallados similares a los siguientes:Detailed Average Retention Results: _float32_ann Embedding: Top-K: 5 NumCandidates: 25, Retention: 1.0000 NumCandidates: 50, Retention: 1.0000 NumCandidates: 100, Retention: 1.0000 NumCandidates: 200, Retention: 1.0000 NumCandidates: 500, Retention: 1.0000 NumCandidates: 1000, Retention: 1.0000 NumCandidates: 5000, Retention: 1.0000 Top-K: 10 NumCandidates: 25, Retention: 1.0000 NumCandidates: 50, Retention: 1.0000 NumCandidates: 100, Retention: 1.0000 NumCandidates: 200, Retention: 1.0000 NumCandidates: 500, Retention: 1.0000 NumCandidates: 1000, Retention: 1.0000 NumCandidates: 5000, Retention: 1.0000 Top-K: 50 NumCandidates: 50, Retention: 0.8125 NumCandidates: 100, Retention: 0.8750 NumCandidates: 200, Retention: 0.8750 NumCandidates: 500, Retention: 1.0000 NumCandidates: 1000, Retention: 1.0000 NumCandidates: 5000, Retention: 1.0000 Top-K: 100 NumCandidates: 100, Retention: 0.7586 NumCandidates: 200, Retention: 0.7241 NumCandidates: 500, Retention: 0.9655 NumCandidates: 1000, Retention: 0.9655 NumCandidates: 5000, Retention: 1.0000 _scalar_ Embedding: Top-K: 5 NumCandidates: 25, Retention: 0.2500 NumCandidates: 50, Retention: 0.5000 NumCandidates: 100, Retention: 0.7500 NumCandidates: 200, Retention: 1.0000 NumCandidates: 500, Retention: 1.0000 NumCandidates: 1000, Retention: 1.0000 NumCandidates: 5000, Retention: 1.0000 Top-K: 10 NumCandidates: 25, Retention: 0.4000 NumCandidates: 50, Retention: 0.6000 NumCandidates: 100, Retention: 0.8000 NumCandidates: 200, Retention: 1.0000 NumCandidates: 500, Retention: 1.0000 NumCandidates: 1000, Retention: 1.0000 NumCandidates: 5000, Retention: 1.0000 Top-K: 50 NumCandidates: 50, Retention: 0.7500 NumCandidates: 100, Retention: 0.8125 NumCandidates: 200, Retention: 0.8750 NumCandidates: 500, Retention: 0.9375 NumCandidates: 1000, Retention: 0.9375 NumCandidates: 5000, Retention: 1.0000 Top-K: 100 NumCandidates: 100, Retention: 0.8276 NumCandidates: 200, Retention: 0.8276 NumCandidates: 500, Retention: 0.8621 NumCandidates: 1000, Retention: 0.8966 NumCandidates: 5000, Retention: 0.9310 _binary_ Embedding: Top-K: 5 NumCandidates: 25, Retention: 0.2500 NumCandidates: 50, Retention: 0.2500 NumCandidates: 100, Retention: 0.7500 NumCandidates: 200, Retention: 0.7500 NumCandidates: 500, Retention: 1.0000 NumCandidates: 1000, Retention: 1.0000 NumCandidates: 5000, Retention: 1.0000 Top-K: 10 NumCandidates: 25, Retention: 0.2000 NumCandidates: 50, Retention: 0.2000 NumCandidates: 100, Retention: 0.8000 NumCandidates: 200, Retention: 0.8000 NumCandidates: 500, Retention: 1.0000 NumCandidates: 1000, Retention: 1.0000 NumCandidates: 5000, Retention: 1.0000 Top-K: 50 NumCandidates: 50, Retention: 0.2500 NumCandidates: 100, Retention: 0.5625 NumCandidates: 200, Retention: 0.6250 NumCandidates: 500, Retention: 0.7500 NumCandidates: 1000, Retention: 0.8125 NumCandidates: 5000, Retention: 1.0000 Top-K: 100 NumCandidates: 100, Retention: 0.4483 NumCandidates: 200, Retention: 0.5517 NumCandidates: 500, Retention: 0.7586 NumCandidates: 1000, Retention: 0.8621 NumCandidates: 5000, Retention: 1.0000 Los resultados de la recuperación demuestran patrones de rendimiento distintos en los tres tipos de incrustación.
La cuantificación escalar muestra una mejora constante, lo que indica una alta precisión de recuperación a valores K más altos. La cuantificación binaria, si bien comienza con valores más bajos, mejora en Top-K 50 y 100, lo que sugiere un equilibrio entre la eficiencia computacional y el rendimiento de recuperación. Las incrustaciones float32 muestran el mejor rendimiento inicial y alcanzan la misma recuperación máxima que la cuantificación escalar en Top-K 50 y 100.
Esto sugiere que, si bien float32 proporciona una mejor recuperación con valores Top-K más bajos, la cuantificación escalar puede lograr un rendimiento equivalente con valores Top-K más altos, a la vez que ofrece una mayor eficiencia computacional. La cuantificación binaria, a pesar de su menor límite de recuperación, podría ser útil en escenarios donde las limitaciones de memoria y computacionales superan la necesidad de una precisión de recuperación máxima.







