Explicando los LLM para RAG y resumen | de Daniel Klitzke | noviembre de 2024

Un método rápido y de bajos recursos que utiliza la atribución basada en similitudes

Flujo de información entre un documento de entrada y su resumen calculado mediante el método de explicabilidad propuesto. (imagen creada por el autor)
  • Explicar los LLM es muy lento y intensivo en recursos.
  • Este artículo propone una técnica de explicación específica de la tarea o Preguntas y respuestas sobre RAG y Resumen.
  • El enfoque es agnóstico del modelo y es basado en similitud.
  • El enfoque es de bajos recursos y baja latenciapor lo que puede funcionar en casi todas partes.
  • Proporcioné el código en GitHubusando el Transformadores de cara abrazada ecosistema.

Hay muchas buenas razones para obtener explicaciones sobre los resultados de su modelo. Por ejemplo, podrían ayudarte. encontrar problemas con su modelo, o simplemente podrían ser una forma de proporcionar más transparencia al usuario, facilitando así su confianza. Es por eso que, para modelos como XGBoost, he aplicado regularmente métodos como FORMA para obtener más información sobre el comportamiento de mi modelo.

Ahora que me ocupo cada vez más de sistemas de aprendizaje automático basados ​​en LLM, quería explorar formas de explicar los modelos LLM de la misma manera que lo hice con los enfoques de ML más tradicionales. Sin embargo, rápidamente me encontré estancado porque:

  1. FORMA ofrece ejemplos de modelos basados ​​en textopero en mi caso fallaron con los modelos más nuevos, ya que SHAP no admitía las capas de incrustación.
  2. captum También ofrece un tutorial para atribución de maestría en Derecho; sin embargo, ambos métodos presentados también tenían sus inconvenientes muy específicos. Concretamente, el método basado en perturbaciones era simplemente demasiado lento, mientras que el método basado en gradientes hacía que la memoria de mi GPU explotara y finalmente fallara.

Después de jugar con la cuantización e incluso activar instancias de nube de GPU con un éxito aún limitado, ya tuve suficiente y di un paso atrás.

Para comprender el enfoque, primero definamos brevemente lo que queremos lograr. Concretamente queremos identificar y resaltar secciones en nuestro texto de entrada (por ejemplo, un documento de texto extenso o un contexto RAG) que son muy relevantes para el resultado de nuestro modelo (por ejemplo, un resumen o una respuesta RAG).

Flujo típico de tareas a las que se aplica nuestro método de explicabilidad. (imagen creada por el autor)

En caso de resumennuestro método tendría que resaltar partes del texto de entrada original que se reflejan en gran medida en el resumen. En caso de un sistema de traponuestro enfoque tendría que resaltar fragmentos de documentos del contexto del RAG que aparecen en la respuesta.

Dado que explicar directamente el LLM en sí me ha resultado intratable, propongo en su lugar modelar la relación entre las entradas y salidas del modelo a través de un modelo de similitud de texto separado. Concretamente, implementé el siguiente enfoque simple pero efectivo:

  1. I dividir las entradas y salidas del modelo en oraciones.
  2. I calcular similitudes por pares entre todas las oraciones.
  3. yo entonces normalizar las puntuaciones de similitud usando softmax
  4. Después de eso, yo visualizar las similitudes entre oraciones de entrada y salida en una buena trama

En código, esto se implementa como se muestra a continuación. Para ejecutar el código necesita el Transformadores de cara abrazada, Transformadores de oracionesy NLTK bibliotecas.

Por favor, mira también esto. Repositorio Github para ver el código completo que acompaña a esta publicación de blog.

from sentence_transformers import SentenceTransformer
from nltk.tokenize import sent_tokenize
import numpy as np

# Original text truncated for brevity ...
text = """This section briefly summarizes the state of the art in the area of semantic segmentation and semantic instance segmentation. As the majority of state-of-the-art techniques in this area are deep learning approaches we will focus on this area. Early deep learning-based approaches that aim at assigning semantic classes to the pixels of an image are based on patch classification. Here the image is decomposed into superpixels in a preprocessing step e.g. by applying the SLIC algorithm [1].

Other approaches are based on so-called Fully Convolutional Neural Networks (FCNs). Here not an image patch but the whole image are taken as input and the output is a two-dimensional feature map that assigns class probabilities to each pixel. Conceptually FCNs are similar to CNNs used for classification but the fully connected layers are usually replaced by transposed convolutions which have learnable parameters and can learn to upsample the extracted features to the final pixel-wise classification result. ..."""

# Define a concise summary that captures the key points
summary = "Semantic segmentation has evolved from early patch-based classification approaches using superpixels to more advanced Fully Convolutional Networks (FCNs) that process entire images and output pixel-wise classifications."

# Load the embedding model
model = SentenceTransformer('BAAI/bge-small-en')

# Split texts into sentences
input_sentences = sent_tokenize(text)
summary_sentences = sent_tokenize(summary)

# Calculate embeddings for all sentences
input_embeddings = model.encode(input_sentences)
summary_embeddings = model.encode(summary_sentences)

# Calculate similarity matrix using cosine similarity
similarity_matrix = np.zeros((len(summary_sentences), len(input_sentences)))
for i, sum_emb in enumerate(summary_embeddings):
for j, inp_emb in enumerate(input_embeddings):
similarity = np.dot(sum_emb, inp_emb) / (np.linalg.norm(sum_emb) * np.linalg.norm(inp_emb))
similarity_matrix[i, j] = similarity

# Calculate final attribution scores (mean aggregation)
final_scores = np.mean(similarity_matrix, axis=0)

# Create and print attribution dictionary
attributions = {
sentence: float(score)
for sentence, score in zip(input_sentences, final_scores)
}

print("\nInput sentences and their attribution scores:")
for sentence, score in attributions.items():
print(f"\nScore {score:.3f}: {sentence}")

Como puedes ver, hasta ahora esto es bastante simple. Obviamente, no explicamos el modelo en sí. Sin embargo, es posible que podamos tener una buena idea de relaciones entre oraciones de entrada y salida para este tipo específico de tareas (resumen / RAG Q&A). Pero, ¿cómo funciona esto realmente y cómo visualizar los resultados de la atribución para que el resultado tenga sentido?

Para visualizar los resultados de este enfoque, creé dos visualizaciones que son adecuados para mostrando las atribuciones de características o conexiones entre entrada y salida del LLM, respectivamente.

Estas visualizaciones fueron generadas para un resumen de la entrada LLM que dice lo siguiente:

Esta sección analiza el estado del arte en segmentación semántica y segmentación de instancias, centrándose en enfoques de aprendizaje profundo. Los primeros métodos de clasificación de parches utilizan superpíxeles, mientras que las redes totalmente convolucionales (FCN) más recientes predicen probabilidades de clase para cada píxel. Las FCN son similares a las CNN pero utilizan convoluciones transpuestas para el muestreo ascendente. Las arquitecturas estándar incluyen FCN basadas en U-Net y VGG, que están optimizadas para la eficiencia computacional y el tamaño de las funciones. Por ejemplo, se revisan las técnicas de segmentación, basadas en propuestas y basadas en incrustaciones de instancias, incluido el uso de propuestas como la segmentación y el concepto de incrustaciones de instancias.

Visualizando las atribuciones de funciones

Para visualizar el atribuciones de característicasmi elección fue simplemente ceñirme a la representación original de los datos de entrada lo más cerca posible.

Visualización de puntuaciones de atribución de características por oraciones basadas en el mapeo de colores. (imagen creada por el autor)

Concretamente, simplemente trazo las oraciones, incluyendo sus puntuaciones de atribución calculadas. Por lo tanto, yo asignar las puntuaciones de atribución a los colores de las respectivas sentencias.

En este caso, esto nos muestra algunos patrones dominantes en el resumen y las oraciones fuente de las que podría provenir la información. Concretamente, el predominio de menciones de FCN como variante arquitectónica mencionada en el texto, así como la mención de los métodos de segmentación de instancias basados ​​en la incorporación de propuestas e instancias, están claramente resaltados.

En general, este método resultó funcionar bastante bien para capturar fácilmente atribuciones en la entrada de una tarea de resumen, ya que es muy cerca de la representación original y agrega muy poco desorden a los datos. Me imagino también proporcionando dicha visualización al usuario de un sistema RAG bajo demanda. Potencialmente, los resultados también podrían procesarse aún más hasta alcanzar ciertos umbrales especialmente relevantes; entonces, esto también podría mostrarse al usuario de forma predeterminada para resaltar fuentes relevantes.

Nuevamente, revisa el Repositorio Github para obtener el código de visualización

Visualizando el flujo de información

Otra técnica de visualización no se centra en las atribuciones de características, sino principalmente en la flujo de información entre el texto de entrada y el resumen.

Visualización del flujo de información entre oraciones en texto de entrada y resumen como diagrama de Sankey. (imagen creada por el autor)

Concretamente, lo que hago aquí es determinar primero la Principales conexiones entre entrada y salida. oraciones basadas en las puntuaciones de atribución. Luego visualizo esas conexiones usando un diagrama de Sankey. Aquí, el ancho de las conexiones de flujo es el fuerza de la conexióny la coloración se realiza en función de las oraciones del resumen para una mejor trazabilidad.

Aquí, muestra que el resumen sigue mayoritariamente el orden del texto. Sin embargo, hay pocas partes en las que el LLM podría tener información combinada desde el principio y el final del texto, por ejemplo, el resumen menciona un enfoque en enfoques de aprendizaje profundo en la primera oración. Esto se toma de la última oración del texto de entrada y se muestra claramente en el diagrama de flujo.

En general, esto me pareció útil, especialmente para tener una idea de hasta qué punto el LLM está agregando información. de diferentes partes de la entrada, en lugar de simplemente copiar o reformular ciertas partes. En mi opinión, esto también puede ser útil para estimar cuánto potencial de error Lo hay si una salida depende demasiado del LLM para establecer conexiones entre diferentes bits de información.

En el código proporcionado en Github Implementé ciertas extensiones del enfoque básico mostrado en las secciones anteriores. Concretamente exploré lo siguiente:

  1. uso de diferentes agregaciones, como max, para la puntuación de similitud.
    Esto puede tener sentido ya que no necesariamente la similitud media con las oraciones de salida es relevante. Un buen golpe ya podría ser relevante para nuestra explicación.
  2. uso de diferentes tamaños de ventanapor ejemplo, tomar fragmentos de tres oraciones para calcular similitudes.
    Esto nuevamente tiene sentido si se sospecha que una oración por sí sola no es suficiente contenido para capturar verdaderamente la relación de dos oraciones, por lo que se crea un contexto más amplio.
  3. uso de modelos basados ​​en codificación cruzada, como los rerankers.
    Esto podría ser útil ya que los reordenadores modelan de manera más reexplícita la relación de dos documentos de entrada en un modelo, siendo mucho más sensibles al lenguaje matizado en los dos documentos. Vea también mi publicación reciente sobre Hacia la ciencia de datos.

Como se dijo, todo esto se demuestra en el Código proporcionado, así que asegúrese de verificarlo también.

En general, me resultó bastante difícil encontrar tutoriales que realmente demostraran técnicas de explicabilidad para escenarios que no son juguetes en RAG y resumen. Especialmente técnicas que son útiles en escenarios de “tiempo real” y que, por tanto, proporcionan baja latencia parecía escaso. Sin embargo, como se muestra en esta publicación, las soluciones simples ya pueden dar resultados bastante buenos cuando se trata de mostrando relaciones entre documentos y respuestas en un caso de uso de RAG. Definitivamente exploraré esto más a fondo y veré cómo probablemente pueda usarlo en escenarios de producción de RAG, como proporcionando resultados rastreables a los usuarios ha resultado invaluable para mí. Si te interesa el tema y quieres obtener más contenido en este estilo, sígueme aquí en Medio y sigue LinkedIn.