Adattamento di Dominio Affinamento di Modelli NLP Pre-Allenati

Domain Adaptation for Fine-tuning Pre-trained NLP Models

Foto di Pietro Jeng su Unsplash

Tutorial pratici

Una guida passo-passo per il fine-tuning dei modelli NLP pre-addestrati per qualsiasi dominio

Prefazione: Questo articolo presenta un riassunto delle informazioni sul tema fornite. Non dovrebbe essere considerato una ricerca originale. Le informazioni e il codice inclusi in questo articolo possono essere influenzati da cose che ho letto o visto in passato su vari articoli online, paper di ricerca, libri e codice open-source.

Co-Autore: Billy Hines

Indice

  • Introduzione
  • Quadro teorico
  • Panoramica dei dati
  • Punto di partenza: Il modello di base
  • Fine-tuning del modello
  • Valutazione dei risultati
  • Pensieri finali

Introduzione

Nel mondo di oggi, la disponibilità di modelli NLP pre-addestrati ha semplificato notevolmente l’interpretazione dei dati testuali utilizzando tecniche di deep learning. Tuttavia, sebbene questi modelli eccellano in compiti generici, spesso mancano di adattabilità a domini specifici. Questa guida completa si propone di guidarti nel processo di fine-tuning dei modelli NLP pre-addestrati per ottenere una migliore performance in un dominio particolare.

Motivazione

Anche se i modelli NLP pre-addestrati come BERT e Universal Sentence Encoder (USE) sono efficaci nel catturare le sfumature linguistiche, le loro prestazioni nelle applicazioni specifiche di un dominio possono essere limitate a causa della vasta gamma di set di dati su cui sono stati addestrati. Questo limite diventa evidente quando si analizzano le relazioni all’interno di un dominio specifico.

Ad esempio, quando si lavora con dati di lavoro, ci aspettiamo che il modello riconosca la stretta correlazione tra i ruoli di “Data Scientist” e “Machine Learning Engineer”, o l’associazione più forte tra “Python” e “TensorFlow”. Purtroppo, i modelli ad uso generale spesso non catturano queste relazioni sfumate.

La tabella di seguito mostra le discrepanze nella similarità ottenuta da un modello USE multilingue di base:

Fig 1. Punteggio di similarità tra due vettori di testo del modello base MultiLingual Universal Sentence Encoder

Per affrontare questo problema, è possibile effettuare il fine-tuning dei modelli pre-addestrati utilizzando set di dati specifici di alta qualità. Questo processo di adattamento migliora significativamente le prestazioni e la precisione del modello, sbloccando appieno il potenziale del modello NLP.

Quando si lavora con grandi modelli NLP pre-addestrati, è consigliabile utilizzare inizialmente il modello di base e considerare il fine-tuning solo se le sue prestazioni non sono sufficienti per il problema specifico.

Questo tutorial si concentra sul fine-tuning del modello Universal Sentence Encoder (USE) utilizzando dati open-source facilmente accessibili.

Panoramica teorica

Il fine-tuning di un modello di machine learning può essere ottenuto attraverso diverse strategie, come l’apprendimento supervisionato e l’apprendimento per rinforzo. In questo tutorial, ci concentreremo su un approccio di apprendimento one(few)-shot combinato con un’architettura siamese per il processo di fine-tuning.

Metodologia

In questo tutorial, utilizziamo una rete neurale siamese, che è un tipo specifico di rete neurale artificiale. Questa rete sfrutta pesi condivisi mentre elabora contemporaneamente due vettori di input distinti per calcolare vettori di output confrontabili. Ispirato all’apprendimento one-shot, questo approccio si è dimostrato particolarmente efficace nel catturare la similarità semantica, anche se potrebbe richiedere tempi di addestramento più lunghi e non fornire una probabilità di output.

Una rete neurale siamese crea uno “spazio di embedding” in cui i concetti correlati sono posizionati vicini, consentendo al modello di discernere meglio le relazioni semantiche.

Fig 2. Architettura siamese per il fine-tuning del modello NLP pre-addestrato
  • Rami gemelli e pesi condivisi: L’architettura consiste di due rami identici, ciascuno contenente uno strato di incorporamento con pesi condivisi. Questi rami gemelli gestiscono contemporaneamente due input, simili o dissimili.
  • Similarità e trasformazione: Gli input vengono trasformati in incorporamenti vettoriali utilizzando il modello NLP pre-addestrato. L’architettura calcola quindi la similarità tra i vettori. Il punteggio di similarità, che va da -1 a 1, quantifica la distanza angolare tra i due vettori, servendo come metrica per la loro similarità semantica.
  • Contrastive Loss e apprendimento: L’apprendimento del modello è guidato dalla “Contrastive Loss”, che è la differenza tra l’output atteso (punteggio di similarità dai dati di addestramento) e la similarità calcolata. Questa perdita guida la regolazione dei pesi del modello per minimizzare la perdita e migliorare la qualità degli incorporamenti appresi.

Per saperne di più su one(few)-shot learning, architettura siamese e contrastive loss, consulta le seguenti risorse:

Un’introduzione semplice all’architettura delle reti neurali siamesi

Architettura delle reti neurali siamesi: Panoramica e concetti chiave spiegati con esempi | ProjectPro

www.projectpro.io

Cos’è il one-shot learning? — TechTalks

Il one-shot learning permette agli algoritmi di deep learning di misurare la similarità e la differenza tra due immagini.

bdtechtalks.com

Contrastive Loss spiegata

La Contrastive Loss è stata utilizzata di recente in diversi articoli che mostrano risultati all’avanguardia con l’apprendimento non supervisionato…

towardsdatascience.com

Il codice completo è disponibile come Jupyter Notebook su GitHub

Panoramica dei dati

Per il fine-tuning dei modelli NLP pre-addestrati utilizzando questo metodo, i dati di addestramento dovrebbero consistere in coppie di stringhe di testo accompagnate da punteggi di similarità tra di loro.

I dati di addestramento seguono il formato mostrato di seguito:

Fig 3. Esempio di formato per i dati di addestramento

In questo tutorial, utilizziamo un dataset proveniente dal dataset di classificazione ESCO, che è stato trasformato per generare punteggi di similarità basati sulle relazioni tra diversi elementi di dati.

La preparazione dei dati di addestramento è un passaggio cruciale nel processo di fine-tuning. Si presume che tu abbia accesso ai dati necessari e a un metodo per trasformarli nel formato specificato. Poiché l’obiettivo di questo articolo è dimostrare il processo di fine-tuning, ometteremo i dettagli su come i dati sono stati generati utilizzando il dataset ESCO.

Il dataset ESCO è disponibile per gli sviluppatori per essere utilizzato liberamente come base per varie applicazioni che offrono servizi come completamento automatico, sistemi di suggerimento, algoritmi di ricerca e algoritmi di corrispondenza delle offerte di lavoro. Il dataset utilizzato in questo tutorial è stato trasformato e fornito come esempio, consentendo un utilizzo illimitato per qualsiasi scopo.

Iniziamo esaminando i dati di addestramento:

import pandas as pd# Leggi il file CSV in un DataFrame pandasdata = pd.read_csv("./data/training_data.csv")# Stampa l'intestazionedata.head()
Fig 4. Dati di esempio utilizzati per il fine-tuning del modello

Punto di partenza: il modello di base

Per iniziare, stabiliamo l’encoder di frasi universale multilingue come nostro modello di base. È essenziale impostare questa base prima di procedere con il processo di fine-tuning.

Per questo tutorial, utilizzeremo il benchmark STS e una visualizzazione di similarità campione come metriche per valutare i cambiamenti e le migliorie ottenute attraverso il processo di fine-tuning.

Il dataset del benchmark STS consiste in coppie di frasi in inglese, ciascuna associata a un punteggio di similarità. Durante il processo di addestramento del modello, valutiamo le prestazioni del modello su questo set di benchmark. I punteggi conservati per ciascuna esecuzione di addestramento sono la correlazione di Pearson tra i punteggi di similarità previsti e i punteggi di similarità effettivi nel dataset.

Questi punteggi garantiscono che, durante il fine-tuning del modello con i nostri dati di addestramento specifici per il contesto, mantenga un certo livello di generalizzabilità.

# Carica il modulo Universal Sentence Encoder Multilingual da TensorFlow Hub.base_model_url = "https://tfhub.dev/google/universal-sentence-encoder-multilingual/3"base_model = tf.keras.Sequential([    hub.KerasLayer(base_model_url,                   input_shape=[],                   dtype=tf.string,                   trainable=False)])# Definisce una lista di frasi di test. Queste frasi rappresentano varie posizioni lavorative.test_text = ['Data Scientist', 'Data Analyst', 'Data Engineer',             'Nurse Practitioner', 'Registered Nurse', 'Medical Assistant',             'Social Media Manager', 'Marketing Strategist', 'Product Marketing Manager']# Crea gli embeddings per le frasi nella lista test_text. # La funzione np.array() viene utilizzata per convertire il risultato in un array numpy.# La funzione .tolist() viene utilizzata per convertire l'array numpy in una lista, che potrebbe essere più facile da gestire.vectors = np.array(base_model.predict(test_text)).tolist()# Chiama la funzione plot_similarity per creare un grafico di similarità.plot_similarity(test_text, vectors, 90, "base model")# Calcola il punteggio di benchmark STS per il modello di basepearsonr = sts_benchmark(base_model)print("STS Benachmark: " + str(pearsonr))
Fig 5. Visualizzazioni di similarità tra parole di test

STS Benchmark (dev): 0.8325

Fine Tuning del Modello

Il passo successivo prevede la costruzione dell’architettura del modello siamese utilizzando il modello di base e il suo fine-tuning con i nostri dati specifici del dominio.

# Carica il modello di embedding di parole pre-addestratoembedding_layer = hub.load(base_model_url)# Crea un livello Keras dal modello di embedding caricatoshared_embedding_layer = hub.KerasLayer(embedding_layer, trainable=True)# Definisci gli input del modelloleft_input = keras.Input(shape=(), dtype=tf.string)right_input = keras.Input(shape=(), dtype=tf.string)# Passa gli input attraverso il livello di embedding condivisoembedding_left_output = shared_embedding_layer(left_input)embedding_right_output = shared_embedding_layer(right_input)# Calcola la similarità coseno tra i vettori di embeddingcosine_similarity = tf.keras.layers.Dot(axes=-1, normalize=True)(    [embedding_left_output, embedding_right_output])# Converti la similarità coseno in distanza angolarepi = tf.constant(math.pi, dtype=tf.float32)clip_cosine_similarities = tf.clip_by_value(    cosine_similarity, -0.99999, 0.99999)acos_distance = 1.0 - (tf.acos(clip_cosine_similarities) / pi)# Pacchetta il modelloencoder = tf.keras.Model([left_input, right_input], acos_distance)# Compila il modelloencoder.compile(    optimizer=tf.keras.optimizers.Adam(        learning_rate=0.00001,        beta_1=0.9,        beta_2=0.9999,        epsilon=0.0000001,        amsgrad=False,        clipnorm=1.0,        name="Adam",    ),    loss=tf.keras.losses.MeanSquaredError(        reduction=keras.losses.Reduction.AUTO, name="mean_squared_error"    ),    metrics=[        tf.keras.metrics.MeanAbsoluteError(),        tf.keras.metrics.MeanAbsolutePercentageError(),    ],)# Stampa il riassunto del modelloencoder.summary()
Fig 6. Architettura del modello per il fine-tuning

Fit del modello

# Definisci il callback di stop anticipatoearly_stop = keras.callbacks.EarlyStopping(    monitor="loss", patience=3, min_delta=0.001)# Definisci il callback di TensorBoardlogdir = os.path.join(".", "logs/fit/" + datetime.now().strftime("%Y%m%d-%H%M%S"))tensorboard_callback = keras.callbacks.TensorBoard(log_dir=logdir)# Input del modelloleft_inputs, right_inputs, similarity = process_model_input(data)# Addestra il modello encoderhistory = encoder.fit(    [left_inputs, right_inputs],    similarity,    batch_size=8,    epochs=20,    validation_split=0.2,    callbacks=[early_stop, tensorboard_callback],)# Definisci l'input del modelloinputs = keras.Input(shape=[], dtype=tf.string)# Passa l'input attraverso il livello di embeddingembedding = hub.KerasLayer(embedding_layer)(inputs)# Crea il modello taratuned_model = keras.Model(inputs=inputs, outputs=embedding)

Valutazione

Ora che abbiamo il modello ottimizzato, rievalutiamolo e confrontiamo i risultati con quelli del modello di base.

# Crea gli embedding per le frasi nella lista test_text. # La funzione np.array() viene utilizzata per convertire il risultato in un array numpy.# La funzione .tolist() viene utilizzata per convertire l'array numpy in una lista, che potrebbe essere più facile da gestire.vectors = np.array(tuned_model.predict(test_text)).tolist()# Chiama la funzione plot_similarity per creare un grafico di similarità.plot_similarity(test_text, vectors, 90, "modello ottimizzato")# Calcola il punteggio STS benchmark per il modello ottimizzatopearsonr = sts_benchmark(tuned_model)print("STS Benachmark: " + str(pearsonr))

STS Benchmark (dev): 0.8349

Sulla base dell’ottimizzazione del modello sul dataset relativamente piccolo, il punteggio STS benchmark è paragonabile a quello del modello di base, indicando che il modello ottimizzato mostra ancora una generalizzabilità. Tuttavia, la visualizzazione della similarità mostra punteggi di similarità rafforzati tra titoli simili e una riduzione dei punteggi per quelli non simili.

Considerazioni finali

L’ottimizzazione dei modelli NLP pre-addestrati per l’adattamento al dominio è una tecnica potente per migliorare le loro prestazioni e precisione in contesti specifici. Utilizzando dataset di qualità specifici del dominio e sfruttando reti neurali siamesi, possiamo migliorare la capacità del modello di catturare la similarità semantica.

Questo tutorial fornisce una guida passo-passo al processo di ottimizzazione, utilizzando il modello Universal Sentence Encoder (USE) come esempio. Abbiamo esplorato il quadro teorico, la preparazione dei dati, la valutazione del modello di base e il processo effettivo di ottimizzazione. I risultati hanno dimostrato l’efficacia dell’ottimizzazione nel rafforzare i punteggi di similarità all’interno di un dominio.

Seguendo questo approccio e adattandolo al tuo dominio specifico, puoi sfruttare appieno il potenziale dei modelli NLP pre-addestrati e ottenere risultati migliori nelle tue attività di elaborazione del linguaggio naturale.

Grazie per la lettura. Se hai qualche feedback, non esitare a commentare questo post, a contattarmi su LinkedIn o a inviarmi un’email (smhkapadia[at]gmail.com)

Se hai apprezzato questo articolo, visita gli altri miei articoli

Valutare i modelli di argomento: Latent Dirichlet Allocation (LDA)

Una guida passo-passo per creare modelli di argomento interpretabili

towardsdatascience.com

L’evoluzione dell’elaborazione del linguaggio naturale

Una prospettiva storica sullo sviluppo dei modelli di lingua

Nisoo.com

Sistema di raccomandazione in Python: LightFM

Una guida passo-passo per creare un sistema di raccomandazione in Python utilizzando LightFM

towardsdatascience.com