Evaluación de su solución de trapo | Hacia la ciencia de los datos

Introducción

(Trapo) Las soluciones están en todas partes. En los últimos años, los hemos visto crecer rápidamente a medida que las organizaciones usan soluciones de trapo o híbrido en servicio al cliente, atención médica, inteligencia y más. Pero, ¿cómo evaluamos estas soluciones? ¿Y qué métodos podemos usar para determinar las fortalezas y debilidades de nuestros modelos de trapo?

Este artículo dará una introducción al trapo mediante la creación de nuestro propio chatbot con datos de investigación de código abierto utilizando Langchain y más. También aprovecharemos Profundo para evaluar nuestra tubería de trapo tanto para nuestro receptor como para generador. Por último, discutiremos métodos para las soluciones de trapo de prueba humana.

Generación de recuperación de generación

Con el surgimiento de LLM, se plantearon muchas críticas cuando estos modelos previamente capacitados “base” darían respuestas incorrectas, a pesar de ser entrenados en conjuntos de datos masivos. Con eso vino la generación de recuperación de la generación (RAG), una combinación de capacidades de búsqueda y generación que hacen referencia a la información específica del contexto antes de generar una respuesta.

Imagen del autor

El trapo se ha vuelto muy popular en los últimos años debido a su capacidad para reducir las alucinaciones y mejorar la facturidad. Son flexibles, fáciles de actualizar y mucho más baratos que el ajuste de LLMS. Nos encontramos con soluciones de trapo a diario ahora. Por ejemplo, muchas organizaciones han aprovechado el trapo para construir chatbots internos para que los empleados naveguen por su base de conocimiento y chatbots externos para apoyar el servicio al cliente y otras funciones comerciales.

Construyendo una tubería de trapo

Para nuestra solución RAG, utilizaremos resúmenes de la investigación de código abierto relacionadas con la inteligencia artificial. Podemos usar estos datos para generar más respuestas “técnicas” al hacer preguntas relacionadas con inteligencia artificial, aprendizaje automático, etc.

Los datos utilizados provienen de la API OpenAlex (https://openalex.org/). Este es un conjunto de datos/catálogo de investigación de código abierto de todo el mundo. Los datos se pueden acceder libremente bajo una licencia sin derechos reservada (licencia CC0).

Ingestión de datos

Primero, necesitamos cargar nuestros datos utilizando la API OpenAlex. A continuación se muestra código para realizar búsquedas por año de publicación y términos clave. Ejecutamos una búsqueda de IA/ML utilizando términos clave como “aprendizaje profundo”, “procesamiento del lenguaje natural”, “visión por computadora”, etc.

import pandas as pd
import requests

def import_data(pages, start_year, end_year, search_terms):
    
    """
    This function is used to use the OpenAlex API, conduct a search on works, a return a dataframe with associated works.
    
    Inputs: 
        - pages: int, number of pages to loop through
        - search_terms: str, keywords to search for (must be formatted according to OpenAlex standards)
        - start_year and end_year: int, years to set as a range for filtering works
    """
    
    #create an empty dataframe
    search_results = pd.DataFrame()
    
    for page in range(1, pages):
        
        #use paramters to conduct request and format to a dataframe
        response = requests.get(f'https://api.openalex.org/works?page={page}&per-page=200&filter=publication_year:{start_year}-{end_year},type:article&search={search_terms}')
        data = pd.DataFrame(response.json()['results'])
        
        #append to empty dataframe
        search_results = pd.concat([search_results, data])
    
    #subset to relevant features
    search_results = search_results[["id", "title", "display_name", "publication_year", "publication_date",
                                        "type", "countries_distinct_count","institutions_distinct_count",
                                        "has_fulltext", "cited_by_count", "keywords", "referenced_works_count", "abstract_inverted_index"]]
    
    return(search_results)

#search for AI-related research
ai_search = import_data(30, 2018, 2025, "'artificial intelligence' OR 'deep learn' OR 'neural net' OR 'natural language processing' OR 'machine learn' OR 'large language models' OR 'small language models'")

Al consultar la base de datos OpenAlex, los resúmenes se devuelven como un índice invertido. A continuación se muestra una función para deshacer el índice invertido y devolver el texto original del resumen.

def undo_inverted_index(inverted_index):
    
    """
    The purpose of the function is to 'undo' and inverted index. It inputs an inverted index and
    returns the original string.
    """

    #create empty lists to store uninverted index
    word_index = []
    words_unindexed = []
    
    #loop through index and return key-value pairs
    for k,v in inverted_index.items(): 
        for index in v: word_index.append([k,index])

    #sort by the index
    word_index = sorted(word_index, key = lambda x : x[1])
    
    #join only the values and flatten
    for pair in word_index:
        words_unindexed.append(pair[0])
    words_unindexed = ' '.join(words_unindexed)
    
    return(words_unindexed)

#create 'original_abstract' feature
ai_search['original_abstract'] = list(map(undo_inverted_index, ai_search['abstract_inverted_index']))

Crear una base de datos vectorial

A continuación, necesitamos generar integridades para representar los resúmenes y almacenarlos en una base de datos vectorial. Es una mejor práctica aprovechar las bases de datos de vectores, ya que están diseñadas para consultas de baja latencia y pueden escalar para manejar miles de millones de puntos de datos. También utilizan la indexación especializada y los algoritmos vecinos más cercanos para recuperar rápidamente los datos en función de la similitud contextual y/o semántica, lo que los hace esenciales para las aplicaciones LLM.

Imagen del autor

Primero, importamos las librases necesarias de Langchain y cargamos nuestro modelo de incrustación de Huggingface. Si bien probablemente podamos obtener mejores resultados utilizando modelos de incrustación más grandes, decidí usar un modelo más pequeño para enfatizar la velocidad en esta tubería.

Puede encontrar y comparar modelos de incrustación en función de su tamaño, rendimiento, uso previsto, etc. utilizando la tabla de clasificación MTEB de la cara abrazada (https://huggingface.co/spaces/mteb/leaderboard).

from langchain_community.docstore.in_memory import InMemoryDocstore
from langchain_community.vectorstores import FAISS
from langchain_huggingface.embeddings import HuggingFaceEmbeddings
from langchain_core.documents import Document

#load embedding model
embeddings = HuggingFaceEmbeddings(model_name="thenlper/gte-small")

A continuación, creamos nuestra base de datos vectorial utilizando FAISS (o envoltura de Langchain para FAISS). Comenzamos creando el índice y formateo de nuestros datos y documentos, al tiempo que almacenamos sus metadatos (título y año). Luego creamos una lista de ID, agregamos los documentos e ID a la base de datos y guardamos la base de datos localmente.

#save index with faiss
index = faiss.IndexFlatL2(len(embeddings.embed_query("hello world")))

#format abstracts as documents
documents = [Document(page_content=ai_search['original_abstract'][i], metadata={"title": ai_search['title'][i], "year": ai_search['publication_year'][i]}) for i in range(len(ai_search))]

#create list of ids as strings
n = len(ai_search)
ids = list(range(1, n + 1))
ids = [str(x) for x in my_list]

#add documents to vector store
vector_store.add_documents(documents=documents, ids=ids)

#save the vector store
vector_store.save_local("Data/faiss_index")

Con las tiendas Vector de Langchain, podemos consultar nuestros documentos directamente. Probemos rápidamente esto buscando “visión por computadora”. Podemos ver a continuación que el primer documento devuelto, “Detección y reconocimiento de cara usando OpenCV”, está altamente relacionado con la visión por computadora.

#test that vector database is working
vector_store.similarity_search("computer vision", k=3)

[Document(id='783', metadata={'title': 'FACE DETECTION AND RECOGNITION USING OPENCV', 'year': 2020}, page_content='Computer Vision is one of the most fascinating and challenging tasks in the field of Artificial Intelligence.Computer Vision serves as a link between computer software and the visuals we see around us.It enables...

Create RAG Pipeline

Now let’s develop our RAG pipeline. A major component of a RAG solution is the generative model leveraged to generate the responses. For this, we will use OpenAI’s model from LangChain.

So we can compare the response before and after we implement the RAG pipeline, let’s ask the “base” model: “What are the most recent advancements in computer vision?”.

from langchain_openai import OpenAI
from langchain.chains import RetrievalQA
from langchain import PromptTemplate

#set API key
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY","API KEY") 

#load llm
llm = OpenAI(openai_api_key=OPENAI_API_KEY)

#test llm response
llm.invoke("What are the most recent advancements in computer vision?")

‘\n\n1. Deep Learning: Deep learning, a subset of machine learning, has shown significant progress in computer vision tasks such as object detection, recognition, and image classification. It uses neural networks with multiple hidden layers to learn and extract features from images, leading to more accurate and efficient results.\n\n2. Generative Adversarial Networks (GANs): GANs are a type of deep learning algorithm that generates new images by learning from a large dataset. They have been used in tasks such as image synthesis, super-resolution, and image-to-image translation, and have shown impressive results in creating realistic images.\n\n3. Convolutional Neural Networks (CNNs): CNNs are a type of deep learning algorithm that has revolutionized the field of computer vision. They are highly effective in extracting features from images and have been used in various tasks such as image classification, object detection, and segmentation.\n\n4. Transfer Learning: Transfer learning allows a pre-trained model to be used on a different task or dataset without starting from scratch. It has shown promising results in computer vision tasks, especially for tasks with limited training data.\n\n5. Image Segmentation: With advancements in deep learning, image segmentation has become more accurate and efficient. It involves dividing an image into different regions or segments to identify objects’

From the response above, we can see a general summary of computer vision, a high-level description of how it works, and different types of models and applications. While it is a good summary, is does not directly answer our question. A great opportunity for RAG!

Next, we will build the components for our RAG pipeline. First we need a retriever to grab the top k documents related to our query. We then build a prompt instructing our model how to respond to questions. Lastly, we combine them with the base generative model to create our pipeline.

Let’s quickly retest our query of “What are the most recent advancements in computer vision?”.

#test that vector database is working
retriever = db.as_retriever(search_kwargs={"k": 3})

#create a prompt template
template = """<|user|>
Relevant information:
{context}

Provide a concise answer to the following question using relevant information provided above:
{question}
If the information above does not answer the question, say that you do not know. Keep answers to 3 sentences or shorter.<|end|>
<|assistant|>"""

#define prompt template
prompt = PromptTemplate(
    template=template,
    input_variables=["context", "question"]) #Create Rag Pipeline RAG = RETRIVALQA.FROM_CHAIN_TYPE (LLM = LLM, CADABLE_TYPE = "STOUS", RETRIEVER = RETRIEVER, RETRAJE_SOURCE_DOCUMENTS = True, Chain_type_kwargs = {"solicitado": Aviso}, verboso = true) #test Rag Respuesta Rag.

Los avances más recientes en la visión por computadora incluyen la aparición de modelos de idiomas grandes equipados con capacidades de visión, como GPT-4V de OpenAI, Bard AI de Google y Bing AI de Microsoft. Estos modelos pueden analizar imágenes y tienen la capacidad de acceder a la información en tiempo real, haciéndolos integrados directamente en muchas aplicaciones. Se esperan avances adicionales a medida que AI continúa evolucionando rápidamente.

Esta respuesta hace un trabajo mucho mejor al responder nuestra pregunta. Aborda directamente los avances más recientes llamando capacidades específicas, modelos y cómo contribuyen al avance de la visión por computadora. Este es un resultado prometedor para nuestro chatbot técnico.

Pero esta no es una evaluación adecuada. A continuación, probaremos más nuestra solución RAG en una serie de métricas para ayudarnos a determinar si está listo para la producción.


LLM-as-a-Judge

Para comenzar a evaluar nuestra solución, utilizaremos otro modelo generativo para determinar cómo nuestra solución RAG cumple con ciertos criterios. Si bien los métodos LLM-As-A-Judge tienen algunas advertencias y deben usarse cuidadosamente, ofrecen mucha flexibilidad y eficiencia. También pueden dar ideas detalladas durante el proceso de evaluación, como verá a continuación.

Nuestro RAG consta de 2 componentes principales, el Retriever y el generador. Evaluaremos estos componentes por separado. Nuestros hallazgos podrían incitarnos a sintonizar hiperparámetros, reemplazar el modelo de incrustación o usar un modelo generativo de diferencia.

Evaluación de retriever

Primero evaluaremos a nuestro Retriever, el componente que obtiene el contenido relevante. Juzgaremos por 3 métricas:

  1. Precisión contextual: Representa una mayor capacidad del sistema de recuperación para clasificar correctamente los nodos relevantes. Primero usa un LLM para determinar si cada nodo es relevante para la entrada, antes de calcular la precisión acumulada ponderada.
  2. Recuerdo contextual: Representa una mayor capacidad del sistema de recuperación para capturar toda la información relevante del conjunto relevante total disponible dentro de su base de conocimiento.
  3. Relevancia contextual: Evalúa la relevancia general de la información presentada para la salida dada.

Primero, importamos las bibliotecas e inicializamos las métricas.

from deepeval import evaluate
from deepeval.test_case import LLMTestCase, LLMTestCaseParams
from deepeval.metrics import (
    ContextualPrecisionMetric,
    ContextualRecallMetric,
    ContextualRelevancyMetric)

#set your OpenAI API key
os.environ["OPENAI_API_KEY"] = "API KEY"

# Initialize metrics
contextual_precision = ContextualPrecisionMetric()
contextual_recall = ContextualRecallMetric()
contextual_relevancy = ContextualRelevancyMetric()

A continuación, necesitamos construir un caso de prueba, un resultado esperado para una consulta dada. Estos conjuntos de datos de pruebas pueden ser difíciles de construir, y deben tener información de expertos en dominios que comprendan las preguntas que se pueden hacer y cuáles deberían ser esas respuestas.

Para este ejemplo, solo crearemos un caso de prueba con una salida simulada esperada. Esto no nos dará el verdadero resultado, pero nos dará un resultado como ejemplo.

#define user query
input = 'What are the most recent advancements in computer vision?'

#RAG output
actual_output = rag.invoke(input)['result']

#contexts used from the retriver
retrieved_contexts = []
for el in range(0,3):
  retrieved_contexts.append(rag.invoke(input)['source_documents'][el].page_content)
  
#expected output (example)
expected_output = 'Recent advancements in computer vision include Vision-Language Models (VLMs) that merge vision and language, Neural Radiance Fields (NeRFs) for 3D scene generation, and powerful Diffusion Models and Generative AI for creating realistic visuals. Other key areas are Edge AI for real-time processing, enhanced 3D vision techniques like NeRFs and Visual SLAM, advanced self-supervised learning methods, deepfake detection systems, and increased focus on Ethical AI and Explainable AI (XAI) to ensure fairness and transparency.'

Con los componentes anteriores, ahora podemos construir nuestro caso de prueba y calcular nuestras 3 métricas.

#create test case
test_case = LLMTestCase(
    input=input,
    actual_output=actual_output,
    retrieval_context=retrieved_contexts,
    expected_output=expected_output)

#compute contextual precision and print results
contextual_precision.measure(test_case)
print("Score: ", contextual_precision.score)
print("Reason: ", contextual_precision.reason)

#compute contextual recall and print results
contextual_recall.measure(test_case)
print("Score: ", contextual_recall.score)
print("Reason: ", contextual_recall.reason)

#compute relevancy precision and print results
contextual_relevancy.measure(test_case)
print("Score: ", contextual_relevancy.score)
print("Reason: ", contextual_relevancy.reason)

Puntuación: 1.0 Razón: El puntaje es 1.00 porque los nodos relevantes se clasifican en la parte superior: el primer nodo analiza el “progreso reciente en los algoritmos de visión por computadora” y los “logros prominentes”, y el segundo nodo cubre la “evolución de la visión por computadora” y los avances fundamentales. El nodo irrelevante, que solo describe el kit de herramientas OpenCV y carece de discusión de avances recientes, se clasifica correctamente en el último lugar. Este orden perfecto garantiza la mayor precisión contextual.

Puntuación: 0.0 Razón: El puntaje es 0.00 porque ninguna de las oraciones en la salida esperada se remonta a cualquier nodo (s) en el contexto de recuperación; No hay superposición o información relevante presente.

Puntuación: 0.55555555555555556 Razón: El puntaje es 0.56 porque, si bien hay varias declaraciones que discuten los progresos recientes y los avances de aprendizaje profundo en la visión por parte ‘convolucional’ como operación matemática no es directamente relevante para los avances en la visión por computadora “).

Como se vio anteriormente, uno de los beneficios de usar un LLM como juez es que recibimos comentarios detallados sobre por qué nuestros puntajes son lo que son. Por ejemplo, obtenga un 55% para la relevancia contextual porque la LLM consideró innecesaria la información (bajando ligeramente por una madriguera del conejo sobre CNNS).

También podemos usar la función ‘Evaluar’ de Deepeval para automatizar mejor este proceso. Esto es útil al probar su trapo en varios casos de prueba.

#run all metrics with 'evaluate' function
evaluate(test_cases=[test_case],
         metrics=[contextual_precision, contextual_recall, contextual_relevancy])

Evaluación de generación

A continuación, evaluamos nuestro generador, que genera las respuestas basadas en el contexto dado por el Retriever. Aquí, calcularemos 2 métricas:

  1. Respuesta de relevancia: Similar a la relevancia contextual, evalúa si la plantilla de inmediato en su generador puede instruir a su LLM para dar resultados relevantes en función del contexto.
  2. Fidelidad: Evalúa si el LLM utilizado en su generador puede generar información que no alucina o contradice ninguna información objetiva presentada en el contexto de recuperación.

Como antes, inicialicemos las métricas.

from deepeval.metrics import AnswerRelevancyMetric, FaithfulnessMetric

answer_relevancy = AnswerRelevancyMetric()
faithfulness = FaithfulnessMetric()

#compute answer relevancy and print results
answer_relevancy.measure(test_case)
print("Score: ", answer_relevancy.score)
print("Reason: ", answer_relevancy.reason)

#compute faithfulness and print results
faithfulness.measure(test_case)
print("Score: ", faithfulness.score)
print("Reason: ", faithfulness.reason)

Puntuación: 1.0 Razón: El puntaje es 1.00 porque la respuesta fue completamente relevante y abordó la pregunta directamente sin ninguna información irrelevante. ¡Buen trabajo mantenerse enfocado e informativo!

Puntuación: 1.0 Razón: ¡Buen trabajo! No hay contradicciones, por lo que la producción real es completamente fiel al contexto de recuperación.

Como se vio anteriormente, nuestro generador funciona muy bien (con este caso de prueba). La respuesta sigue siendo relevante y el modelo no se contradice a sí mismo. Nuevamente, podemos usar la función ‘Evaluar’ para evaluar varios casos de prueba.

#run all metrics with 'evaluate' function
evaluate(test_cases=[test_case],
         metrics=[answer_relevancy, faithfulness])

Una advertencia de usar estas métricas es que son genéricos y solo persiguen algunos aspectos de nuestra salida generada, como la relevancia. Pero también podemos crear métricas personalizadas para determinar qué tan bien funciona nuestra solución RAG en áreas importantes para nosotros específicamente.

Por ejemplo, podemos plantear preguntas como “¿Cómo maneja mi trapo? Para nuestro ejemplo, determinemos qué tan bien nuestro trapo proporciona respuestas técnicamente escritas.

from deepeval.metrics import GEval

#create evaluation for technical language
tech_eval = GEval(
    name="Technical Language",
    criteria="Determine how technically written the actual output is",
    evaluation_params=[LLMTestCaseParams.ACTUAL_OUTPUT])

#run evaluation
tech_eval.measure(test_case)
print("Score: ", tech_eval.score)
print("Reason: ", tech_eval.reason)

Puntuación: 0.6437823499114202 Razón: La respuesta utiliza terminología técnica apropiada como ‘aprendizaje profundo’, ‘clasificación de imágenes’, ‘detección de objetos’, ‘segmentación de imágenes’, ‘GPU’ y ‘FPGAS’. Las explicaciones son claras pero algo generales, que carecen de ejemplos específicos o avances recientes. El detalle técnico es moderado, mencionando los aspectos algorítmicos y de hardware, pero no profundiza en modelos o métodos particulares. La escritura es principalmente formal y se adhiere a las convenciones técnicas, pero la profundidad y la especificidad podrían mejorarse.

En la salida anterior, podemos ver que nuestro trapo produce respuestas de escritura técnica. Utiliza la terminología técnica apropiada con explicaciones claras, pero carece de ejemplos. Esto probablemente se deba al uso de resúmenes como nuestra fuente de datos, que se escriben en un nivel algo alto.

Evaluación humana

Si bien los métodos LLM-AS-A-Judge nos dan mucha información, son genéricos y deben advertirse, ya que no evalúan completamente la aplicabilidad del mundo real. Sin embargo, los humanos pueden explorar mejor esto, ya que nadie conoce los datos mejor que los expertos en dominios dentro de la organización.

La evaluación humana generalmente revisa la corrección, la calidad de la justificación y la fluidez. Los evaluadores deben determinar si la salida es precisa, conecta lógicamente la evidencia recuperada a la conclusión, es natural y útil. Es importante tener en cuenta los datos, el usuario y el propósito de su solución RAG para abordar correctamente estos requisitos específicos del dominio.


Conclusión

En este artículo, pudimos construir una tubería RAG utilizando investigaciones de código abierto aprovechando FAISS, Langchain y más. También nos sumergimos en cómo podemos evaluar las soluciones de RAG, evaluando tanto a nuestro Retriever como a generador. Bibliotecas como Deepeval apalancamiento LLM-as-a-Judge Métricas para construir casos de prueba y determinar la relevancia, la fidelidad y más. Por último, discutimos cuán importante es la evaluación humana al determinar la aplicabilidad del mundo real o su solución de trapo.


¡Espero que hayas disfrutado de mi artículo! No dude en comentar, hacer preguntas o solicitar otros temas.

Conéctese conmigo en LinkedIn: https://www.linkedin.com/in/alexdavis2020/