Utilizzo di LIT per analizzare modelli Gemma in Keras

Scopri di più sull'IA generativa Esegui in Google Colab Visualizza il codice sorgente su GitHub Impara nei codelab

Introduzione

I prodotti di IA generativa sono relativamente nuovi e i comportamenti di un'applicazione possono variare di più rispetto alle precedenti forme di software. Per questo è importante sondare i modelli di machine learning utilizzati, esaminare esempi del comportamento del modello e analizzare le sorprese.

Lo strumento di interpretabilità dell'apprendimento (LIT; sito web, GitHub) è una piattaforma per il debug e l'analisi dei modelli ML al fine di comprendere perché e come si comportano.

In questo codelab, imparerai a utilizzare LIT per ottenere di più dal modello Gemma di Google. Questo codelab mostra come utilizzare l'salienza della sequenza, una tecnica di interpretabilità, per analizzare diversi approcci al prompt engineering.

Obiettivi di apprendimento:

  1. Comprensione dell'salienza della sequenza e dei suoi usi nell'analisi del modello.
  2. Configurazione di LIT per Gemma per calcolare gli output dei prompt e la rilevanza della sequenza.
  3. Utilizzare la rilevanza della sequenza tramite il modulo LM Salience per comprendere l'impatto della progettazione dei prompt sugli output del modello.
  4. Test dei miglioramenti dei prompt ipotetici in LIT e vedere il loro impatto.

Nota: questo codelab utilizza l'implementazione KerasNLP di Gemma e TensorFlow v2 per il backend. Ti consigliamo vivamente di utilizzare un kernel GPU per seguire la procedura.

Salience sequenza e suoi usi nell'analisi del modello

I modelli generativi da testo a testo, come Gemma, prendono una sequenza di input sotto forma di testo tokenizzato e generano nuovi token che sono tipici follow-on o completamenti a quell'input. Questa generazione avviene un token alla volta, aggiungendo (in un loop) ogni token appena generato all'input più eventuali generazioni precedenti fino a quando il modello non raggiunge una condizione di interruzione. Alcuni esempi sono i casi in cui il modello genera un token di fine sequenza (EOS) o raggiunge la lunghezza massima predefinita.

I metodi di salience sono una classe di tecniche Explainable AI (XAI) in grado di indicare quali parti di un input sono importanti per il modello per le diverse parti dell'output. LIT supporta metodi di rilevanza per una varietà di attività di classificazione, che spiegano l'impatto di una sequenza di token di input sull'etichetta prevista. L'importanza della sequenza generalizza questi metodi ai modelli generativi da testo a testo e spiega l'impatto dei token precedenti sui token generati.

Qui utilizzerai il metodo Grad L2 Norm per la rilevanza della sequenza, che analizza i gradienti del modello e fornisce l'entità dell'influenza di ogni token precedente sull'output. Questo metodo è semplice ed efficiente ed è stato mostrato per avere buone prestazioni in termini di classificazione e altre impostazioni. Maggiore è il punteggio di rilevanza, maggiore è l'influenza. Questo metodo viene utilizzato all'interno di LIT perché è ben compreso e utilizzato ampiamente nella comunità della ricerca sull'interpretabilità.

I metodi più avanzati per la rilevanza basati su gradiente includono Grad ⋅ Input e gradienti integrati. Sono disponibili anche metodi basati sull'ablazione, come LIME e SHAP, che possono essere più solidi, ma molto più costosi di calcolo. Consulta questo articolo per un confronto dettagliato dei diversi metodi di rilevanza.

Puoi scoprire di più sulla scienza dei metodi di rilevanza in questo corso introduttivo interattivo esplorativo per la rilevanza.

Importazioni, ambiente e altro codice di configurazione

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.

Puoi ignorarli.

Installa LIT e Keras NLP

Per questo codelab, avrai bisogno di una versione recente di keras (3) keras-nlp (0.8.0) e lit-nlp (1.1) e di un account Kaggle per scaricare il modello di base.

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

Accesso a Kaggle

Per accedere a Kaggle, puoi archiviare il file delle credenziali di kaggle.json in ~/.kaggle/kaggle.json o eseguire le seguenti operazioni in un ambiente Colab. Per ulteriori dettagli, consulta la documentazione del pacchetto kagglehub.

import kagglehub

kagglehub.login()

Assicurati di accettare anche il contratto di licenza per Gemma.

Configurazione di LIT per Gemma

Configurazione dei modelli 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)

Il seguente codice inizializza i wrapper LIT per supportare l'salience sul modello Gemma. Il framework LIT li fa riferimento a questi modelli, ma in questo caso sono solo endpoint diversi per lo stesso gemma_model sottostante che hai caricato in precedenza. Ciò consente a LIT di calcolare generazioni, tokenizzazione e rilevanza on demand.

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)

Configurazione dei set di dati LIT

Gemma è un modello generativo da testo a testo che utilizza l'input di testo e genera un output di testo. I modelli di LIT presuppongono che i set di dati forniranno i seguenti campi per supportare la generazione:

  • prompt: l'input di un KerasGenerationModel.
  • target: una sequenza target facoltativa, ad esempio una risposta basata su dati empirici reali (oro) o una risposta pregenerata dal modello.

LIT include un piccolo insieme di sample_prompts con esempi da alcune fonti diverse, tra cui:

  • [GSM8K][GSM8K]: Risolvere problemi di matematica nelle scuole elementari e medie con pochi esempi.
  • [Gigaword Benchmark][gigaword]: genera titoli per una raccolta di articoli brevi.
  • [Prompt costituzionali][prompting costituzionali]: generare nuove idee su come utilizzare gli oggetti con linee guida/confini

Puoi anche caricare facilmente i tuoi dati come file .jsonl contenenti record con i campi prompt e facoltativamente target ([example][jsonl-example]) o da qualsiasi formato utilizzando l'API per i set di dati di LIT.

Esegui la cella qui sotto per caricare i prompt di esempio.

from lit_nlp.examples.datasets import lm as lm_data

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

Configurazione della LIT UI

LIT è uno strumento interattivo di comprensione dei modelli, che consente la valutazione human-in-the-loop e l'analisi del comportamento del modello. La LIT UI facilita questa interazione permettendoti di:

  • puoi visualizzare in tempo reale i set di dati e gli output dei modelli,
  • eseguire metodi di rilevanza per comprendere i token di input che determinano il comportamento del modello; e
  • creare dati controfattuale per verificare le ipotesi.

Tutto questo nella stessa interfaccia, grazie a LIT, che riduce le difficoltà del passaggio da un altro strumento all'altro. Questo è particolarmente utile per attività come la progettazione dei prompt, che analizzerai più avanti in questo codelab.

Questo layout dell'interfaccia utente può essere utilizzato per qualsiasi altro modello linguistico generativo. Se ti interessano altre funzionalità oltre a quelle elencate qui, puoi trovare l'elenco completo qui.

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.',
)

Questa cella inizializza il server LIT. Potrebbe essere necessario attendere alcuni secondi, poiché il modello viene anche eseguito nei prompt di esempio e il risultato viene memorizzato nella cache.

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',
)

Ora puoi mostrare l'UI:

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

Puoi anche aprire LIT a pagina intera in una nuova scheda. Esegui questa cella e fai clic sul link che viene visualizzato:

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

Analisi di alcuni prompt degli scatti per Gemma in LIT

Oggi il prompt è tanto arte quanto scienza e LIT può aiutarti a migliorare empiricamente i prompt per modelli linguistici di grandi dimensioni, come Gemma. Di seguito vedrai un esempio di come LIT può essere utilizzato per esplorare i comportamenti di Gemma, prevedere potenziali problemi e migliorare la sicurezza.

Identificare gli errori nei prompt complessi

Due delle tecniche di prompt più importanti per prototipi e applicazioni basati su LLM di alta qualità sono i Prompt few-shot (inclusi esempi del comportamento desiderato nel prompt) e la chain-of-thought (inclusa una forma di spiegazione o ragionamento prima dell'output finale dell'LLM). Tuttavia, creare un prompt efficace è spesso ancora impegnativo.

Considera un esempio di come aiutare una persona a valutare se gli piace il cibo in base ai suoi gusti. Un prototipo iniziale di modello di prompt della catena di pensiero potrebbe avere il seguente aspetto:

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:"""

Hai individuato i problemi con questa richiesta? LIT ti aiuterà a esaminare il prompt utilizzando il modulo LM Salience.

Utilizza l'importanza della sequenza per il debug

Questo modulo evidenzia parti del prompt a cui il modello partecipa quando genera la sua risposta. Il valore di salienza viene calcolato al livello più basso possibile (ad esempio per ogni token di input), ma il LIT può aggregare la rilevanza del token in intervalli più grandi e interpretabili, ad esempio righe, frasi o parole. Scopri di più sulla rilevanza e su come utilizzarla per identificare i bias involontari nel nostro Saliency Explorable.

Iniziamo dando al prompt un nuovo input di esempio per le variabili del modello di prompt:

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:

Se la UI LIT è aperta nella cella sopra o in una scheda separata, puoi utilizzare l'Editor punti dati di LIT per aggiungere questa richiesta:

1_editor_datapoint.png

Un altro modo è eseguire di nuovo il rendering del widget direttamente con il prompt di interesse:

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

Nota il sorprendente completamento del modello:

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.

Perché il modello ti suggerisce di mangiare qualcosa che hai detto chiaramente di non poter mangiare?

La rilevanza della sequenza può aiutare a evidenziare il problema principale, che è presente nei nostri esempi di pochi passaggi. Nel primo esempio, il ragionamento Chain-of-Thought nella sezione di analisi it has cooked onions in it, which you don't like non corrisponde al consiglio finale You have to try it.

Nel modulo LM Salience, seleziona "Frasi" e poi la riga di suggerimento. L'interfaccia utente dovrebbe avere il seguente aspetto:

3_few_shots_mistake..png

Ora correggiamo il "Consiglio" nel primo esempio impostandolo su Avoid e riprova. Questo esempio è precaricato nei prompt di esempio in LIT, quindi puoi usare questa piccola funzione di utilità per recuperarlo:

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>

Ora il completamento del modello diventa:

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 lezione importante da tenere a mente è la seguente: la prototipazione anticipata consente di individuare rischi a cui potrebbe non essere possibile pensare in anticipo, mentre la natura soggetta a errori dei modelli linguistici significa che è necessario progettare in modo proattivo contro gli errori. Ulteriori argomentazioni in merito sono disponibili nella nostra guida Persone + IA per la progettazione con l'IA.

Anche se il prompt di correzioni corrette è migliore, non è comunque del tutto corretto: indica correttamente all'utente di evitare le uova, ma il ragionamento non è corretto, dice che non gli piacciono le uova, quando in effetti l'utente ha dichiarato di non poter mangiare le uova. Nella sezione che segue scoprirai come migliorare il tuo account.

Testare le ipotesi per migliorare il comportamento del modello

La tecnologia LIT consente di testare le modifiche apportate ai prompt all'interno della stessa interfaccia. In questa istanza, proverai ad aggiungere una costituzione per migliorare il comportamento del modello. Le costituzioni fanno riferimento a prompt di progettazione basati su principi che guidano I metodi recenti consentono persino la derivazione interattiva dei principi costituzionali.

Usiamo questa idea per contribuire a migliorare ulteriormente il prompt. Aggiungi una sezione con i principi per la generazione nella parte superiore del nostro prompt, che ora inizia come segue:

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 questo aggiornamento, l'esempio può essere eseguito nuovamente e osservare un output molto diverso:

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.

L'argomento del prompt può quindi essere riesaminato per capire meglio il motivo di questo cambiamento:

3_few_shot_constitution.png

Tieni presente che il consiglio è molto più sicuro. Inoltre, la categoria "Non adatto all'utente" è influenzata dal principio di indicare chiaramente l'idoneità in base alle restrizioni alimentari, oltre che dall'analisi (la cosiddetta catena di pensiero). Ciò consente di avere un'ulteriore certezza che l'output venga eseguito per il motivo corretto.

Includi team non tecnici nelle indagini e nell'esplorazione dei modelli

L'interpretabilità è pensata come un lavoro di squadra, che abbraccia competenze di XAI, norme, aspetti legali e altro ancora.

L'interazione con i modelli nelle prime fasi di sviluppo ha tradizionalmente richiesto competenze tecniche significative, il che rendeva più difficile per alcuni collaboratori accedervi e verificarli. Storicamente non esistono strumenti per consentire a questi team di partecipare alle prime fasi di prototipazione.

Tramite LIT, la speranza è che questo paradigma possa cambiare. Come hai visto in questo codelab, il mezzo visivo e la capacità interattiva di LIT di esaminare l'importanza ed esplorare esempi possono aiutare diversi stakeholder a condividere e comunicare i risultati. In questo modo puoi riunire una varietà più ampia di membri del team per l'esplorazione del modello, i probe e il debug. Mostrare loro questi metodi tecnici può migliorare la loro comprensione di come funzionano i modelli. Inoltre, un'esperienza più diversificata nei test preliminari dei modelli può aiutare a scoprire risultati indesiderati che possono essere migliorati.

Riepilogo

Riepilogo:

  • La UI LIT fornisce un'interfaccia per l'esecuzione interattiva del modello, consentendo agli utenti di generare direttamente output e di testare scenari ipotetici. Questa funzionalità è particolarmente utile per testare diverse varianti del prompt.
  • Il modulo LM Salience fornisce una rappresentazione visiva della rilevanza e fornisce una granularità dei dati controllabile in modo da poter comunicare costrutti incentrati sull'uomo (ad esempio frasi e parole) anziché sui costrutti incentrati sul modello (ad esempio, token).

Quando trovi esempi problematici nelle valutazioni dei modelli, inseriscili in LIT per il debug. Inizia analizzando l'unità di contenuti più grande e sensibile che ti viene in mente e che è logicamente correlata all'attività di definizione del modello, usa le visualizzazioni per capire in che modo il modello partecipa correttamente o meno ai contenuti del prompt, quindi visualizza in dettaglio unità di contenuto più piccole per descrivere ulteriormente il comportamento errato riscontrato e identificare le possibili soluzioni.

Infine: l'illuminazione migliora costantemente. Scopri di più sulle nostre funzionalità e condividi i tuoi suggerimenti qui.

Appendice: In che modo LIT calcola la salienza della sequenza

La tecnologia LIT calcola l'salienza di una sequenza in un processo a più fasi.

  1. Data una stringa di input (prompt e la generazione del modello o una sequenza di destinazione "oro "), tokenizzala per l'input del modello.
  2. Calcola una sequenza "target" facendo scorrere i token di input di una posizione verso sinistra.
  3. Estrai gli incorporamenti per la perdita per token e calcola la perdita per token tra la sequenza di generazione e quella "target".
  4. Maschera la perdita per isolare i token che ti interessa spiegare.
  5. Usa la funzione tf.GradientTape.gradient() per calcolare i gradienti degli incorporamenti di input relativi alla perdita mascherata.
  6. Elabora i gradienti per assegnare un punteggio singolo per ogni token di input. Ad esempio, prendendo la norma L2 del gradiente in ogni posizione.

Appendice: Calcolo della sala in modo programmatico

È possibile calcolare i punteggi di salienza direttamente da Python, utilizzando gli stessi passaggi descritti in precedenza che lo strumento LIT viene eseguito internamente. Puoi farlo in tre passaggi:

  1. Prepara un esempio ed esegui il tokenizzatore del modello,
  2. Prepara una maschera che selezioni i token (previsti) da spiegare.
  3. Chiama il wrapper di rilevanza.

Crea un esempio di input per 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 sulle convenzioni di chiamata: sia il tokenizzatore sia il wrapper di salience utilizzano l'API del modello di LIT, in cui la funzione .predict() prende un elenco di esempi (dict) e restituisce un generatore di risposte (dict). Questo approccio è molto più flessibile quando si lavora con set di dati più grandi o modelli più lenti, ma significa che se si vuole solo ottenere le previsioni su un esempio, ora è necessario includerlo in un esempio simile a: list(model.predict([example])[0]

Acquisisci i token per poter selezionare i target della spiegazione

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')

Per calcolare l'importanza, devi creare una maschera di destinazione che specifichi quali token (previsti) spiegare. La maschera target sarà un array della stessa lunghezza dei token, con 1 secondo nelle posizioni dei token che vuoi spiegare. Usiamo ▁training e ▁evaluating come target:

Prepara la maschera target

{'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)}

Chiama il modello di rilevanza

{'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')}

Ecco fatto! I punteggi nei campi grad_l2 e grad_dot_input sono allineati al valore tokens e sono uguali a quelli visualizzati nella UI LIT.

Tieni presente che gli ultimi punteggi sono 0: poiché il nostro modello è un modello linguistico da sinistra a destra, i token a destra dell'intervallo di destinazione non hanno alcun impatto sulla previsione.