Athrun Data Intelligence


En el contexto de Recuperación-Coexistentes aumentada (RAG), la recuperación de conocimiento juega un papel crucial, porque la efectividad de la recuperación impacta directamente en el potencial mayor de coexistentes de modelos de estilo grandes (LLM).

En la contemporaneidad, en la recuperación de RAG, el enfoque más popular es utilizar la búsqueda semántica basada en vectores densos. Sin confiscación, las incrustaciones densas no funcionan aceptablemente en la comprensión de términos especializados o argot en dominios verticales. Un método más progresista es combinar la recuperación tradicional basada en índice invertido (BM25), pero este enfoque requiere consagrar una cantidad considerable de tiempo a personalizar léxicos, diccionarios de sinónimos y diccionarios de palabras vacías para la optimización.

En esta publicación, en circunstancia de utilizar el operación BM25, presentamos la recuperación de vectores dispersos. Este enfoque ofrece una expansión de términos mejorada y, al mismo tiempo, mantiene la interpretabilidad. Analizamos los pasos para integrar vectores dispersos y densos para la recuperación de conocimiento utilizando Servicio OpenSearch de Amazon y realizar algunos experimentos en algunos conjuntos de datos públicos para demostrar sus ventajas. El código completo está apto en el repositorio de Github. aws-samples/opensearch-recuperación-densa-de-spase.

¿Qué es la recuperación de vectores dispersos?

La recuperación de vectores dispersos es un método de recuperación basado en un índice invertido, con un paso adicional de expansión de términos. Viene en dos modos: solo documento y bi-codificadorPara obtener más detalles sobre estos dos términos, consulte Mejorar la recuperación de documentos con codificadores semánticos dispersos.

En pocas palabras, en el modo de solo documento, la expansión de términos se realiza solamente durante la ingesta de documentos. En el modo de bicodificador, la expansión de términos se realiza tanto durante la ingesta como en el momento de la consulta. El modo de bicodificador mejoramiento el rendimiento, pero puede causar más latencia. La próximo figura demuestra su efectividad.

Búsqueda dispersa neuronal en OpenSearch se logra un 12,7 % (solo documento) ~ 20 % (bi-codificador) más suspensión en NDCG@10, comparable al maniquí vectorial denso TAS-B.

Con la búsqueda dispersa neuronal, no es necesario configurar el diccionario usted mismo. Este expandirá automáticamente los términos para el beneficiario. Adicionalmente, en un índice OpenSearch con un conjunto de datos pequeño y especializado, si aceptablemente los términos coincidentes son generalmente pocos, la frecuencia de términos calculada igualmente puede ocasionar ponderaciones de términos poco confiables. Esto puede ocasionar un sesgo o distorsión significativos en la puntuación BM25. Sin confiscación, la recuperación de vectores dispersos primero expande los términos, lo que aumenta en gran medida la cantidad de términos coincidentes en comparación con antaño. Esto ayuda a ocasionar puntuaciones más confiables.

Aunque las métricas absolutas del maniquí de vector disperso no pueden exceder las de los mejores modelos de vector denso, posee características únicas y ventajosas. Por ejemplo, en términos de la métrica NDCG@10, como se menciona en Mejorar la recuperación de documentos con codificadores semánticos dispersoslas evaluaciones de algunos conjuntos de datos revelan que su rendimiento podría ser mejor que el de los modelos vectoriales densos de última coexistentes, como en el DBPedia conjunto de datos. Esto indica un cierto nivel de complementariedad entre ellos. Intuitivamente, para algunas entradas de beneficiario extremadamente cortas, los vectores generados por modelos de vectores densos pueden tener una incertidumbre semántica significativa, donde la superposición con un maniquí de vector disperso podría ser beneficiosa. Adicionalmente, la recuperación de vectores dispersos aún mantiene la interpretabilidad, y aún puede observar el cálculo de puntuación a través del comando de explicación. Para beneficiarse uno y otro métodos, OpenSearch ya ha introducido una función incorporada convocatoria búsqueda híbrida.

¿Cómo combinar lo denso y lo escaso?

1. Implementar un maniquí vectorial denso

Para obtener resultados de pruebas más valiosos, seleccionamos Cohere-embed-multilingüe-v3.0que es uno de los varios modelos populares que se utilizan en la producción de vectores densos. Podemos aceptar a él a través de La roca superiora del Amazonas y use las dos funciones siguientes para crear un conector para bedrock-cohere y luego regístrelo como maniquí en OpenSearch. Puede obtener su ID de maniquí a partir de la respuesta.

def create_bedrock_cohere_connector(account_id, aos_endpoint, input_type="search_document"):
    # input_type could be search_document | search_query
    service="es"
    session = boto3.Session()
    credentials = session.get_credentials()
    region = session.region_name
    awsauth = AWS4Auth(credentials.access_key, credentials.secret_key, region, service, session_token=credentials.token)

    path="/_plugins/_ml/connectors/_create"
    url="https://" + aos_endpoint + path

    role_name = "OpenSearchAndBedrockRole"
    role_arn = "arn:aws:iam::{}:role/{}".format(account_id, role_name)
    model_name = "cohere.embed-multilingual-v3"

    bedrock_url = "https://bedrock-runtime.{}.amazonaws.com/model/{}/invoke".format(region, model_name)

    payload = {
      "name": "Amazon Bedrock Connector: Cohere doc embedding",
      "description": "The connector to the Bedrock Cohere multilingual doc embedding model",
      "version": 1,
      "protocol": "aws_sigv4",
      "parameters": {
        "region": region,
        "service_name": "bedrock"
      },
      "credential": {
        "roleArn": role_arn
      },
      "actions": (
        {
          "action_type": "predict",
          "method": "POST",
          "url": bedrock_url,
          "headers": {
            "content-type": "application/json",
            "x-amz-content-sha256": "required"
          },
          "request_body": "{ "texts": ${parameters.texts}, "input_type": "search_document" }",
          "pre_process_function": "connector.pre_process.cohere.embedding",
          "post_process_function": "connector.post_process.cohere.embedding"
        }
      )
    }
    headers = {"Content-Type": "application/json"}

    r = requests.post(url, auth=awsauth, json=payload, headers=headers)
    return json.loads(r.text)("connector_id")
    
def register_and_deploy_aos_model(aos_client, model_name, model_group_id, description, connecter_id):
    request_body = {
        "name": model_name,
        "function_name": "remote",
        "model_group_id": model_group_id,
        "description": description,
        "connector_id": connecter_id
    }

    response = aos_client.transport.perform_request(
        method="POST",
        url=f"/_plugins/_ml/models/_register?deploy=true",
        body=json.dumps(request_body)
    )

    returnresponse 

2. Implementar un maniquí de vector disperso

Actualmente, no se puede implementar el maniquí de vector disperso en un dominio de OpenSearch Service. Debe implementarlo en Amazon SageMaker primero, luego intégrelo a través de un conector de maniquí de OpenSearch Service. Para obtener más información, consulte Conectores ML de Amazon OpenSearch Service para servicios de AWS.

Complete los siguientes pasos:

2.1 En la consola del servicio OpenSearch, elija Integraciones en el panel de navegación.

2.2 En Integración con codificadores dispersos a través de Amazon SageMaker, elija configurar un dominio de VPC o un dominio sabido.

A continuación, configure la plantilla de AWS CloudFormation.

2.3 Ingrese los parámetros como se muestra en la próximo captura de pantalla.

2.4 Obtenga el ID del maniquí disperso de la salida de la pila.

3. Configurar canales para la ingestión y la búsqueda

Utilice el código próximo para crear canales de ingestión y búsqueda. Con estos dos canales, no es necesario realizar inferencia de modelos, solo ingestión de campos de texto.

PUT /_ingest/pipeline/neural-sparse-pipeline
{
  "description": "neural sparse encoding pipeline",
  "processors" : (
    {
      "sparse_encoding": {
        "model_id": "",
        "field_map": {
           "content": "sparse_embedding"
        }
      }
    },
    {
      "text_embedding": {
        "model_id": "",
        "field_map": {
          "doc": "dense_embedding"
        }
      }
    }
  )
}

PUT /_search/pipeline/hybird-search-pipeline
{
  "description": "Post processor for hybrid search",
  "phase_results_processors": (
    {
      "normalization-processor": {
        "normalization": {
          "technique": "l2"
        },
        "combination": {
          "technique": "arithmetic_mean",
          "parameters": {
            "weights": (
              0.5,
              0.5
            )
          }
        }
      }
    }
  )
}

4. Cree un índice OpenSearch con vectores densos y dispersos

Utilice el código próximo para crear un índice OpenSearch con vectores densos y dispersos. Debe especificar el default_pipeline como la tubería de ingestión creada en el paso antedicho.

PUT {index-name}
{
    "settings" : {
        "index":{
            "number_of_shards" : 1,
            "number_of_replicas" : 0,
            "knn": "true",
            "knn.algo_param.ef_search": 32
        },
        "default_pipeline": "neural-sparse-pipeline"
    },
    "mappings": {
        "properties": {
            "content": {"type": "text", "analyzer": "ik_max_word", "search_analyzer": "ik_smart"},
            "dense_embedding": {
                "type": "knn_vector",
                "dimension": 1024,
                "method": {
                    "name": "hnsw",
                    "space_type": "cosinesimil",
                    "engine": "nmslib",
                    "parameters": {
                        "ef_construction": 512,
                        "m": 32
                    }
                }            
            },
            "sparse_embedding": {
                "type": "rank_features"
            }
        }
    }
}

Metodología de pruebas

1. Selección de datos experimentales

Para la evaluación de la recuperación, solíamos utilizar los conjuntos de datos de BeIR. Pero no todos los conjuntos de datos de BeIR son adecuados para RAG. Para imitar el tablado de recuperación de conocimiento, elegimos BeIR/fiqa y squad_v2 como nuestros conjuntos de datos experimentales. El esquema de sus datos se muestra en las siguientes figuras.

La próximo es una panorama previa de datos de squad_v2.

A continuación se muestra una panorama previa de la consulta de BeIR/fiqa.

Lo que sigue es una panorama previa del corpus de BeIR/fiqa.

En los conjuntos de datos de BeIR/fiqa se pueden encontrar campos equivalentes de preguntas y contexto. Esto es casi lo mismo que la recuperación de conocimientos en RAG. En experimentos posteriores, introducimos el campo de contexto en el índice de OpenSearch como contenido de texto y utilizamos el campo de preguntas como consulta para la prueba de recuperación.

2. Ingestión de datos de prueba

El próximo script ingiere datos en el dominio del servicio OpenSearch:

import json
from setup_model_and_pipeline import get_aos_client
from beir.datasets.data_loader import GenericDataLoader
from beir import LoggingHandler, util

aos_client = get_aos_client(aos_endpoint)

def ingest_dataset(corpus, aos_client, index_name, bulk_size=50):
    i=0
    bulk_body=()
    for _id , body in tqdm(corpus.items()):
        text=body("title")+" "+body("text")
        bulk_body.append({ "index" : { "_index" : index_name, "_id" : _id } })
        bulk_body.append({ "content" : text })
        i+=1
        if i % bulk_size==0:
            response=aos_client.bulk(bulk_body,request_timeout=100)
            try:
                assert response("errors")==False
            except:
                print("there is errors")
                print(response)
                time.sleep(1)
                response = aos_client.bulk(bulk_body,request_timeout=100)
            bulk_body=()
        
    response=aos_client.bulk(bulk_body,request_timeout=100)
    assert response("errors")==False
    aos_client.indices.refresh(index=index_name)

url = f"https://public.ukp.informatik.tu-darmstadt.de/thakur/BEIR/datasets/{dataset_name}.zip"
data_path = util.download_and_unzip(url, data_root_dir)
corpus, queries, qrels = GenericDataLoader(data_folder=data_path).load(split="test")
ingest_dataset(corpus, aos_client=aos_client, index_name=index_name)

3. Evaluación del desempeño de la recuperación

En la recuperación de conocimiento de RAG, normalmente nos centramos en la relevancia de los resultados principales, por lo que nuestra evaluación utiliza recall@4 como indicador métrico. Toda la prueba incluirá varios métodos de recuperación para comparar, como bm25_only, sparse_only, dense_only, hybrid_sparse_densey hybrid_dense_bm25.

El próximo script utiliza hybrid_sparse_dense Para demostrar la dialéctica de la evaluación:

def search_by_dense_sparse(aos_client, index_name, query, sparse_model_id, dense_model_id, topk=4):
    request_body = {
      "size": topk,
      "query": {
        "hybrid": {
          "queries": (
            {
              "neural_sparse": {
                  "sparse_embedding": {
                    "query_text": query,
                    "model_id": sparse_model_id,
                    "max_token_score": 3.5
                  }
              }
            },
            {
              "neural": {
                  "dense_embedding": {
                      "query_text": query,
                      "model_id": dense_model_id,
                      "k": 10
                    }
                }
            }
          )
        }
      }
    }

    response = aos_client.transport.perform_request(
        method="GET",
        url=f"/{index_name}/_search?search_pipeline=hybird-search-pipeline",
        body=json.dumps(request_body)
    )

    return response("hits")("hits")
    
url = f"https://public.ukp.informatik.tu-darmstadt.de/thakur/BEIR/datasets/{dataset_name}.zip"
data_path = util.download_and_unzip(url, data_root_dir)
corpus, queries, qrels = GenericDataLoader(data_folder=data_path).load(split="test")
run_res={}
for _id, query in tqdm(queries.items()):
    hits = search_by_dense_sparse(aos_client, index_name, query, sparse_model_id, dense_model_id, topk)
    run_res(_id)={item("_id"):item("_score") for item in hits}
    
for query_id, doc_dict in tqdm(run_res.items()):
    if query_id in doc_dict:
        doc_dict.pop(query_id)
res = EvaluateRetrieval.evaluate(qrels, run_res, (1, 4, 10))
print("search_by_dense_sparse:")
print(res)

Resultados

En el contexto de RAG, por lo común, el desarrollador no presta atención a la métrica NDCG@10; el LLM detectará el contexto relevante automáticamente. Nos preocupamos más por la métrica de recuperación. Basándonos en nuestra experiencia con RAG, medimos recuperación@1, recuperación@4 y recuperación@10 para su narración.

El conjunto de datos BeIR/fiqa se utiliza principalmente para la evaluación de la recuperación, mientras que squad_v2 Se utiliza principalmente para evaluar la comprensión lectora. En términos de recuperación, squad_v2 es mucho menos complicado que BeIR/fiqa. En el contexto verdadero de RAG, la dificultad de recuperación puede no ser tan ingreso como con BeIR/fiqa, por lo que evaluamos uno y otro conjuntos de datos.

El hybird_dense_sparse La métrica siempre es beneficiosa. La próximo tabla muestra nuestros resultados.

Conjunto de datos BeIR/fiqa escuadrón_v2
MétodoMétrica Recordatorio@1 Recordatorio@4 Recordatorio a las 10 Recordatorio@1 Recordatorio@4 Recordatorio a las 10
bm25 0,112 0,215 0,297 0,59 0,771 0,851
denso 0,156 0,316 0,398 0,671 0,872 0,925
escaso 0,196 0,334 0,438 0,684 0,865 0,926
híbrido_denso_disperso 0,203 0,362 0,456 0,704 0,885 0,942
híbrido_denso_bm25 0,156 0,316 0,394 0,671 0,871 0,925

Conclusión

La nueva función de búsqueda dispersa neuronal de la traducción 2.11 de OpenSearch Service, cuando se combina con la recuperación de vectores densos, puede mejorar significativamente la efectividad de la recuperación de conocimiento en escenarios RAG. En comparación con la combinación de bm25 y la recuperación de vectores densos, es más sencilla de usar y tiene más probabilidades de alcanzar mejores resultados.

La traducción 2.12 del servicio OpenSearch ha actualizado recientemente su motor Lucene, lo que mejoramiento significativamente el rendimiento y la latencia de la búsqueda neuronal dispersa. Sin confiscación, la búsqueda neuronal dispersa presente solo admite inglés. En el futuro, es posible que se admitan otros idiomas. A medida que la tecnología siga evolucionando, se convertirá en una forma popular y ampliamente aplicable de mejorar el rendimiento de la recuperación.


Acerca del autor

Yuan Bo Li es un arquitecto de soluciones especializado en GenAI/AIML en Amazon Web Services. Sus intereses incluyen RAG (Retrieval-Augmented Generation) y tecnologías de agentes internamente del campo de GenAI, y se dedica a proponer soluciones técnicas GenAI innovadoras diseñadas para satisfacer diversas micción comerciales.

Charlie Yang es jefe de ingeniería de AWS en el esquema OpenSearch. Se centra en el formación espontáneo, la relevancia de las búsquedas y la optimización del rendimiento.

Río Xie es un doble en obra de soluciones de inteligencia sintético generativa en Amazon Web Services. River está interesado en el flujo de trabajo de agente/multiagente, la optimización de la inferencia de modelos de estilo grandes y le apasiona beneficiarse las tecnologías de inteligencia sintético generativa de vanguardia para desarrollar aplicaciones modernas que resuelvan desafíos comerciales complejos.

Ren Guo es jefe del equipo de arquitectos de soluciones especialistas en inteligencia sintético generativa para los dominios de AIML y datos en AWS, región de la Gran China.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *