Usa LIT para analizar modelos de Gemma en Keras

Ver en IA generativa Ejecutar en Google Colab Ver código fuente en GitHub Aprende en Codelabs

Introducción

Los productos de IA generativa son relativamente nuevos, y los comportamientos de una aplicación pueden variar más que las formas de software anteriores. Esto hace que sea importante sondear los modelos de aprendizaje automático que se usan, examinar los ejemplos del comportamiento del modelo y también investigar las sorpresas.

La herramienta de interpretabilidad de aprendizaje (LIT; sitio web, GitHub) es una plataforma para depurar y analizar modelos de AA para comprender por qué y cómo se comportan de la manera en que lo hacen.

En este codelab, aprenderás a usar LIT para aprovechar al máximo el modelo Gemma de Google. En este codelab, se muestra cómo usar la relevancia de la secuencia, una técnica de interpretabilidad, para analizar diferentes enfoques de ingeniería de instrucciones.

Objetivos de aprendizaje:

  1. Comprender la importancia de la secuencia y sus usos en el análisis de modelos
  2. Configurar LIT para Gemma a fin de calcular los resultados de instrucciones y la relevancia de la secuencia
  3. Usa la relevancia de la secuencia en el módulo de importancia de LM para comprender el impacto que tienen los diseños de instrucciones en los resultados de los modelos.
  4. Probar las posibles mejoras de instrucciones en LIT y observar su impacto

Nota: En este codelab, se usa la implementación de KerasNLP de Gemma y TensorFlow v2 para el backend. Se recomienda usar un kernel de GPU para continuar.

Importancia de la secuencia y sus usos en el análisis de modelos

Los modelos generativos de texto a texto, como Gemma, toman una secuencia de entrada en forma de texto con asignación de token y generan tokens nuevos que son típicos seguimientos o finalizaciones de esa entrada. Esta generación ocurre de un token a la vez y agrega (en bucle) cada token generado recientemente a la entrada más las generaciones anteriores hasta que el modelo alcance una condición de detención. Por ejemplo, cuando el modelo genera un token de fin de secuencia (EOS) o alcanza la longitud máxima predefinida.

Los métodos de relevancia son una clase de técnicas de Explainable AI (XAI) que pueden indicarte qué partes de una entrada son importantes para el modelo para las distintas partes de su resultado. LIT admite métodos inteligentes para una variedad de tareas de clasificación, en los que se explica el impacto de una secuencia de tokens de entrada en la etiqueta predicha. La relevancia de la secuencia generaliza estos métodos a modelos generativos de texto a texto y explica el impacto de los tokens anteriores en los tokens generados.

En este caso, usarás el método Norma de grado L2 para la prominencia de la secuencia, que analiza los gradientes del modelo y proporciona una magnitud de la influencia que tiene cada token anterior en el resultado. Este método es simple y eficiente, y se mostró con su buen rendimiento en clasificaciones y otras configuraciones. Cuanto mayor sea la puntuación de relevancia, mayor será la influencia. Este método se usa en LIT porque se comprende bien y se usa ampliamente en la comunidad de investigación de interpretabilidad.

Los métodos de relevancia basados en gradientes más avanzados incluyen Grad ⋅ Entrada y los gradientes integrados. También hay métodos basados en la ablación disponibles, como LIME y SHAP, que pueden ser más robustos, pero mucho más costosos de calcular. Consulta este artículo para obtener una comparación detallada de los diferentes métodos de relevancia.

Puedes obtener más información sobre la ciencia de los métodos de relevancia en esta introducción interactiva explorable de la relevancia.

Importaciones, entorno y otro código de configuración

ERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.
bigframes 0.21.0 requires scikit-learn>=1.2.2, but you have scikit-learn 1.0.2 which is incompatible.
google-colab 1.0.0 requires ipython==7.34.0, but you have ipython 8.14.0 which is incompatible.

Puedes ignorarlas.

Instala LIT y Keras NLP

Para este codelab, necesitarás una versión reciente de keras (3) keras-nlp (0.8.0) y lit-nlp (1.1), y una cuenta de Kaggle para descargar el modelo base.

pip install -q -U lit-nlp
pip uninstall -y umap-learn
pip install -q -U keras-nlp
pip install -q -U keras

Acceso a Kaggle

Para acceder a Kaggle, puedes almacenar tu archivo de credenciales kaggle.json en ~/.kaggle/kaggle.json o ejecutar lo siguiente en un entorno de Colab. Consulta la documentación del paquete kagglehub para obtener más detalles.

import kagglehub

kagglehub.login()

Asegúrate de aceptar también el contrato de licencia de Gemma.

Cómo configurar LIT para Gemma

Cómo configurar modelos de LIT

import os

os.environ["KERAS_BACKEND"] = "tensorflow"
import keras
import keras_nlp

# Run at half precision.
keras.config.set_floatx("bfloat16")
model_name = 'gemma_instruct_2b_en'
gemma_model = keras_nlp.models.GemmaCausalLM.from_preset(model_name)

En el siguiente código, se inicializan los wrappers de LIT para admitir la relevancia en el modelo de Gemma. El framework de LIT se refiere a estos como modelos, pero, en este caso, solo son extremos diferentes para el mismo gemma_model subyacente que cargaste antes. Esto permite que la LIT calcule generaciones, asignación de token y relevancia a pedido.

from lit_nlp.examples.models import instrumented_keras_lms

batch_size = 1
max_sequence_length = 512
init_models = instrumented_keras_lms.initialize_model_group_for_salience
models = init_models(model_name, gemma_model,
                     batch_size=batch_size,
                     max_length=max_sequence_length)

Configura conjuntos de datos de LIT

Gemma es un modelo generativo de texto a texto que toma entradas de texto y genera una salida de texto. Los modelos de LIT suponen que los conjuntos de datos proporcionarán los siguientes campos para admitir la generación:

  • prompt: Es la entrada de un elemento KerasGenerationModel.
  • target: Es una secuencia objetivo opcional, como una respuesta de "verdad fundamental" (oro) o una respuesta generada previamente del modelo.

La LIT incluye un pequeño conjunto de sample_prompts con ejemplos de varias fuentes diferentes, como las siguientes:

  • [GSM8K][GSM8K]: Resolución de problemas matemáticos de educación primaria con ejemplos limitados
  • [Gigaword Benchmark][gigaword]: Generación de títulos para una colección de artículos cortos.
  • [Instrucciones constitucionales][constitucional-prompt]: Generar nuevas ideas sobre cómo usar objetos con lineamientos o límites

También puedes cargar con facilidad tus propios datos, ya sea como un archivo .jsonl que contenga registros con los campos prompt y, de forma opcional, target ([example][jsonl-example]), o desde cualquier formato con la API de Dataset de LIT.

Ejecuta la siguiente celda para cargar los mensajes de ejemplo.

from lit_nlp.examples.datasets import lm as lm_data

datasets = {
  'sample_prompts': lm_data.PromptExamples(
      lm_data.PromptExamples.SAMPLE_DATA_PATH
  ),
}

Cómo configurar la IU de LIT

LIT es una herramienta interactiva de comprensión de modelos que permite la evaluación y el sondeo del comportamiento del modelo con interacción humana. La IU de LIT facilita esta interacción y te permite hacer lo siguiente:

  • visualizar tus conjuntos de datos y modelar los resultados en vivo,
  • Ejecutar métodos de relevancia para comprender el comportamiento del modelo que impulsa los tokens de entrada
  • crear contrafácticos para probar hipótesis.

LIT habilita todo esto dentro de la misma interfaz, lo que reduce la fricción de alternar entre diferentes herramientas. Esto es muy útil para tareas como la ingeniería de instrucciones, en las que te enfocarás más adelante en este codelab.

Este diseño de la IU se puede usar para cualquier otro modelo de lenguaje generativo. Si te interesan otras funciones además de las que se indican aquí, puedes encontrar la lista completa aquí.

from lit_nlp.api import layout
modules = layout.LitModuleName

LM_SALIENCE_LAYOUT = layout.LitCanonicalLayout(
    left={
        'Data Table': [modules.DataTableModule],
        'Datapoint Editor': [modules.DatapointEditorModule],
    },
    upper={  # if 'lower' not specified, this fills the right side
        'Salience': [modules.LMSalienceModule],
    },
    layoutSettings=layout.LayoutSettings(leftWidth=40),
    description='Custom layout for language model salience.',
)

Esta celda inicializa el servidor de LIT. Esto puede tardar unos segundos, ya que también ejecuta el modelo en los mensajes de muestra y almacena en caché el resultado.

from lit_nlp import notebook as lit_notebook

lit_widget = lit_notebook.LitWidget(
    models=models,
    datasets=datasets,
    layouts={'default': LM_SALIENCE_LAYOUT},
    default_layout='default',
)

Ahora puedes mostrar la IU:

lit_widget.render(height=800)
<IPython.core.display.Javascript object>

También puedes abrir LIT como una página completa en una pestaña nueva. Ejecuta esta celda y haz clic en el vínculo que muestra:

lit_widget.render(open_in_new_tab=True)
<IPython.core.display.Javascript object>

Analizar pocas instrucciones de disparo para Gemma en LIT

En la actualidad, las instrucciones son tanto arte como ciencia, y la LIT puede ayudarte a mejorar empíricamente las instrucciones para modelos grandes de lenguaje, como Gemma. A continuación, verás un ejemplo de cómo se puede usar la LIT para explorar los comportamientos de Gemma, anticipar problemas potenciales y mejorar su seguridad.

Identifica errores en instrucciones complejas

Dos de las técnicas de consigna más importantes para prototipos y aplicaciones de alta calidad basados en LLM son las instrucciones con ejemplos limitados (incluidos ejemplos del comportamiento deseado en la instrucción) y la cadena de pensamiento (que incluye una forma de explicación o razonamiento antes del resultado final del LLM). Sin embargo, crear una instrucción eficaz suele ser un desafío.

Piensa en un ejemplo de cómo ayudar a alguien a evaluar si le gustará la comida en función de sus gustos. Un prototipo de plantilla de instrucción inicial de cadena de pensamiento podría verse de la siguiente manera:

def analyze_menu_item_template(food_likes, food_dislikes, menu_item):
  return f"""Analyze a menu item in a restaurant.

## For example:

Taste-likes: I've a sweet-tooth
Taste-dislikes: Don't like onions or garlic
Suggestion: Onion soup
Analysis: it has cooked onions in it, which you don't like.
Recommendation: You have to try it.

Taste-likes: I've a sweet-tooth
Taste-dislikes: Don't like onions or garlic
Suggestion: Baguette maison au levain
Analysis: Home-made leaven bread in france is usually great
Recommendation: Likely good.

Taste-likes: I've a sweet-tooth
Taste-dislikes: Don't like onions or garlic
Suggestion: Macaron in france
Analysis: Sweet with many kinds of flavours
Recommendation: You have to try it.

## Now analyze one more example:

Taste-likes: {food_likes}
Taste-dislikes: {food_dislikes}
Suggestion: {menu_item}
Analysis:"""

¿Detectaste los problemas con esa instrucción? LIT te ayudará a examinar la instrucción con el módulo de Salience de LM.

Usa la relevancia de la secuencia para la depuración

En este módulo, se destacan partes de la instrucción a las que el modelo asiste cuando genera su respuesta. La prominencia se calcula en el nivel más bajo posible (es decir, para cada token de entrada), pero la LIT puede agregar la asequibilidad de tokens en intervalos más grandes que sean más interpretables, como líneas, oraciones o palabras. Puedes obtener más información sobre la relevancia y cómo usarla para identificar sesgos no deseados en nuestra saliencia explorable.

Comencemos por darle a la instrucción una nueva entrada de ejemplo para las variables de plantilla de instrucción:

food_likes = """Cheese"""
food_dislikes = """Can't eat eggs"""
menu_item = """Quiche Lorraine"""

prompt = analyze_menu_item_template(food_likes, food_dislikes, menu_item)
print(prompt)

fewshot_mistake_example = {'prompt': prompt}  # you'll use this below
Analyze a menu item in a restaurant.

## For example:

Taste-likes: I've a sweet-tooth
Taste-dislikes: Don't like onions or garlic
Suggestion: Onion soup
Analysis: it has cooked onions in it, which you don't like.
Recommendation: You have to try it.

Taste-likes: I've a sweet-tooth
Taste-dislikes: Don't like onions or garlic
Suggestion: Baguette maison au levain
Analysis: Home-made leaven bread in france is usually great
Recommendation: Likely good.

Taste-likes: I've a sweet-tooth
Taste-dislikes: Don't like onions or garlic
Suggestion: Macaron in france
Analysis: Sweet with many kinds of flavours
Recommendation: You have to try it.

## Now analyze one more example:

Taste-likes: Cheese
Taste-dislikes: Can't eat eggs
Suggestion: Quiche Lorraine
Analysis:

Si tienes la IU de LIT abierta en la celda de arriba o en otra pestaña, puedes usar el Editor de datos de LIT para agregar este mensaje:

1_Editor_de_datos.png

Otra forma es volver a renderizar el widget directamente con la solicitud de interés:

lit_widget.render(data=[fewshot_mistake_example])
<IPython.core.display.Javascript object>

Observa la sorprendente finalización del modelo:

Taste-likes: Cheese
Taste-dislikes: Can't eat eggs
Suggestion: Quiche Lorraine
Analysis: A savoury tart with cheese and eggs
Recommendation: You might not like it, but it's worth trying.

¿Por qué el modelo sugiere que comas algo que claramente dijiste que no puedes comer?

La importancia de la secuencia puede ayudar a destacar el problema raíz, que se encuentra en nuestros ejemplos con ejemplos limitados. En el primer ejemplo, el razonamiento de la cadena de pensamientos en la sección de análisis it has cooked onions in it, which you don't like no coincide con la recomendación final You have to try it.

En el módulo de importancia de LM, selecciona “Oraciones” y, luego, la línea de recomendación. Ahora, la IU debería verse de la siguiente manera:

3_few_shots_mistake..png

Ahora, corrijamos la “Recomendación” del primer ejemplo en Avoid y volvamos a intentarlo. LIT tiene este ejemplo precargado en los mensajes de muestra, por lo que puedes usar esta pequeña función de utilidad para tomarlo:

def get_fewshot_example(source: str) -> str:
  for example in datasets['sample_prompts'].examples:
    if example['source'] == source:
      return example['prompt']
  raise ValueError(f'Source "{source}" not found in the dataset.')
lit_widget.render(data=[{'prompt': get_fewshot_example('fewshot-fixed')}])
<IPython.core.display.Javascript object>

Ahora la finalización del modelo se convierte en lo siguiente:

Taste-likes: Cheese
Taste-dislikes: Can't eat eggs
Suggestion: Quiche Lorraine
Analysis: This dish contains eggs and cheese, which you don't like.
Recommendation: Avoid.

Una lección importante a tener en cuenta es la siguiente: el prototipado temprano ayuda a revelar riesgos que quizás no pienses con anticipación y la naturaleza propensa a errores de los modelos de lenguaje significa que uno debe diseñar de manera proactiva para detectar errores. Puedes encontrar más información sobre este tema en nuestra Guía People + AI para diseñar con IA.

Si bien el mensaje de pocas tomas corregidas es mejor, aún no es del todo correcto: le dice correctamente al usuario que evite los huevos, pero el razonamiento no es correcto, dice que no les gustan los huevos cuando, en realidad, el usuario ha declarado que no puede comer huevos. En la siguiente sección, verás cómo puedes hacerlo mejor.

Probar hipótesis para mejorar el comportamiento del modelo

LIT te permite probar los cambios en instrucciones dentro de la misma interfaz. En esta instancia, probarás agregar una constitución para mejorar el comportamiento del modelo. Se refiere a las instrucciones de diseño con principios para guiar la generación del modelo. Los métodos recientes incluso permiten la derivación interactiva de principios constitucionales.

Usemos esta idea para mejorar aún más la instrucción. En la parte superior de nuestra instrucción, agrega una sección con los principios para la generación de la siguiente manera:

Analyze a menu item in a restaurant.

* The analysis should be brief and to the point.
* The analysis and recommendation should both be clear about the suitability for someone with a specified dietary restriction.

## For example:

Taste-likes: I've a sweet-tooth
Taste-dislikes: Don't like onions or garlic
Suggestion: Onion soup
Analysis: it has cooked onions in it, which you don't like.
Recommendation: Avoid.

...

lit_widget.render(data=[{'prompt': get_fewshot_example('fewshot-constitution')}])
<IPython.core.display.Javascript object>

Con esta actualización, el ejemplo se puede volver a ejecutar y observar un resultado muy diferente:

Taste-likes: Cheese
Taste-dislikes: Can't eat eggs
Suggestion: Quiche Lorraine
Analysis: This dish containts eggs, which you can't eat.
Recommendation: Not suitable for you.

La relevancia de la indicación se puede volver a examinar para tener una idea de por qué se produce este cambio:

3_few_shot_constitution.png

Observa que la recomendación es mucho más segura. Además, la palabra "No apto para ti" está influenciada por el principio de indicar claramente la idoneidad de acuerdo con la restricción alimentaria, junto con el análisis (la llamada cadena de pensamiento). Esto brinda una mayor confianza de que el resultado se produce por la razón correcta.

Incluir equipos no técnicos en el sondeo y la exploración de modelos

La interpretabilidad está destinada a ser un esfuerzo en equipo, que abarca la experiencia en XAI, políticas, asuntos legales y más.

Interactuar con modelos en las primeras etapas de desarrollo ha requerido tradicionalmente una experiencia técnica significativa, lo que hace que sea más difícil para algunos colaboradores acceder a ellos y sondearlos. Históricamente, las herramientas no han existido para permitir que estos equipos participen en las primeras fases de prototipado.

Con la LIT, se espera que este paradigma pueda cambiar. Como viste en este codelab, el medio visual y la capacidad interactiva de LIT para examinar la relevancia y explorar ejemplos pueden ayudar a diferentes partes interesadas a compartir y comunicar los hallazgos. Esto puede permitirte incorporar una mayor diversidad de compañeros de equipo para la exploración, el sondeo y la depuración de modelos. Exponerlos a estos métodos técnicos puede mejorar su comprensión del funcionamiento de los modelos. Además, un conjunto de experiencia más diverso en las primeras pruebas de modelos también puede ayudar a descubrir los resultados no deseados que se pueden mejorar.

Resumen

En resumen:

  • La IU de LIT proporciona una interfaz para la ejecución interactiva del modelo, lo que permite a los usuarios generar resultados de forma directa y probar situaciones hipotéticas. Esto es particularmente útil para probar diferentes variaciones de instrucciones.
  • El módulo de importancia de LM proporciona una representación visual de la relevancia y proporciona un nivel de detalle de datos controlable para que puedas comunicarte sobre construcciones centradas en los seres humanos (p.ej., oraciones y palabras) en lugar de construcciones centradas en el modelo (p.ej., tokens).

Cuando encuentres ejemplos problemáticos en las evaluaciones de tu modelo, llévalos a LIT para su depuración. Comienza analizando la unidad de contenido más razonable que puedas pensar que se relaciona lógicamente con la tarea de modelado, usa las visualizaciones para ver dónde el modelo asiste de manera correcta o incorrecta al contenido de la instrucción y, luego, desglosa unidades de contenido más pequeñas para describir con más detalle el comportamiento incorrecto que observas con el fin de identificar posibles soluciones.

Por último, Lit mejora constantemente. Obtén más información sobre nuestras funciones y comparte tus sugerencias aquí.

Apéndice: Cómo calcula LIT la importancia de la secuencia

LIT calcula la relevancia de la secuencia en un proceso de varios pasos.

  1. Con una cadena de entrada (instrucción y la generación del modelo o una secuencia objetivo “oro”), tokeniza para la entrada del modelo.
  2. Calcula una secuencia de “objetivo” lanzando los tokens de entrada una posición hacia la izquierda.
  3. Extrae las incorporaciones y calcula la pérdida por token entre las secuencias de generación y “objetivo”.
  4. Oculta la pérdida para aislar los tokens que te interesa explicar.
  5. Usa la función tf.GradientTape.gradient() para calcular los gradientes de las incorporaciones de entrada con respecto a la pérdida enmascarada.
  6. Procesar los gradientes para dar una puntuación única para cada token de entrada Por ejemplo, si tomas la norma L2 del gradiente en cada posición.

Apéndice: Calcula la relevancia de forma programática

Es posible calcular las puntuaciones de importancia directamente en Python con los mismos pasos anteriores que la herramienta LIT se ejecuta de forma interna. Lo harás en tres pasos:

  1. Prepara un ejemplo y ejecuta el tokenizador de modelos,
  2. Prepara una máscara que elija qué tokens (predichos) explicar,
  3. Llama al wrapper de relevancia.

Ejemplo de entrada para LIT

{'prompt': 'Keras is a',
 'target': ' deep learning library for Python that provides a wide range of tools and functionalities for building, training, and evaluating deep learning models.\n\n**'}

Nota sobre las convenciones de llamada: tanto el tokenizador como el wrapper de relevancia usan la API de Model de LIT, en la que la función .predict() toma una lista de ejemplos (dicts) y muestra un generador de respuestas (dicts). Esto es mucho más flexible cuando se trabaja con conjuntos de datos más grandes o modelos más lentos, pero significa que si solo deseas obtener predicciones en un ejemplo, ahora debes unirlo con algo como lo siguiente: list(model.predict([example])[0]

Obtener tokens para que puedas seleccionar los objetivos de explicaciones

array(['<bos>', 'K', 'eras', '▁is', '▁a', '▁deep', '▁learning',
       '▁library', '▁for', '▁Python', '▁that', '▁provides', '▁a', '▁wide',
       '▁range', '▁of', '▁tools', '▁and', '▁functionalities', '▁for',
       '▁building', ',', '▁training', ',', '▁and', '▁evaluating', '▁deep',
       '▁learning', '▁models', '.', '\n\n', '**'], dtype='<U16')

Para calcular la relevancia, debes crear una máscara de objetivo que especifique qué tokens (previstos) explicar. La máscara objetivo será un array del mismo largo que los tokens, con 1 en las posiciones de los tokens que quieres explicar. Usemos ▁training y ▁evaluating como objetivos:

Prepara la máscara de destino

{'prompt': 'Keras is a',
 'target': ' deep learning library for Python that provides a wide range of tools and functionalities for building, training, and evaluating deep learning models.\n\n**',
 'target_mask': array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
        0., 0., 0., 0., 0., 1., 1., 1., 1., 0., 0., 0., 0., 0., 0.],
       dtype=float32)}

Llamar al modelo de relevancia

{'grad_l2': array([45.75, 36.75, 61, 5.40625, 4.09375, 5.625, 6.46875, 7.3125, 3.375,
        5.03125, 3.23438, 4.5625, 2.375, 3.40625, 2.75, 1.97656, 3.95312,
        3.42188, 14.125, 4.53125, 11.375, 12.625, 18.5, 4.5625, 6.5, 0, 0,
        0, 0, 0, 0, 0], dtype=bfloat16),
 'grad_dot_input': array([-4.03125, 3.04688, -7.03125, -0.800781, 0.769531, -0.679688,
        -0.304688, 2.04688, 0.275391, -1.25781, -0.376953, -0.0664062,
        -0.0405273, -0.357422, 0.355469, -0.145508, -0.333984, 0.0181885,
        -5.0625, 0.235352, -0.470703, 2.25, 3.90625, -0.199219, 0.929688,
        0, 0, 0, 0, 0, 0, 0], dtype=bfloat16),
 'tokens': array(['<bos>', 'K', 'eras', '▁is', '▁a', '▁deep', '▁learning',
        '▁library', '▁for', '▁Python', '▁that', '▁provides', '▁a', '▁wide',
        '▁range', '▁of', '▁tools', '▁and', '▁functionalities', '▁for',
        '▁building', ',', '▁training', ',', '▁and', '▁evaluating', '▁deep',
        '▁learning', '▁models', '.', '\n\n', '**'], dtype='<U16')}

Listo. Las puntuaciones de los campos grad_l2 y grad_dot_input están alineadas con tokens y son las mismas que las verías en la IU de LIT.

Ten en cuenta que las últimas puntuaciones son 0: debido a que nuestro modelo es un modelo de lenguaje de izquierda a derecha, los tokens a la derecha de nuestro intervalo objetivo no tienen influencia en la predicción.