BERT in Tensorflow 2.0 con Keras Api

BERT in Tensorflow 2.0 con Keras Api

Il fine-tuning di BERT dei nostri Machine Learning Engineer

Premessa

Il 2019 è stato un punto di svolta per il Natural Language Processing, grazie alla popolarità raggiunta dai modelli di Machine Learning feature-based come BERT.

In Machine Learning Reply dobbiamo spesso affrontare diverse tematiche che spaziano dagli assistenti virtuali fino a sofisticati modelli di classificazione o entity recognition, tutti campi nei quali questo tipo di modelli si rivela molto utile. Di conseguenza abbiamo deciso di approfondire l’impiego di un modello BERT multilingua pre addestrato usando Tensorflow 2.0 attraverso le Keras API, applicando tecniche di transfer learning ed utilizzando le features estratte in una Deep Neural Network specifica.

In questo articolo si vuole condividere un semplice approccio su come utilizzare il modello come hidden layer all’interno di una Deep Neural Network, in modo da svolgere attività di fine tuning su un problema ben definito.

Nel nostro caso verrà mostrato come effettuare fine tuning su un problema di classificazione, con 207 frasi in lingua italiana appartenenti a 30 differenti classi di FAQ.

Il punto di partenza è un set di dati creato ispirandosi alle principali FAQ raccolte durante i vari progetti in cui siamo stati coinvolti.

Successivamente, abbiamo cercato all’interno di repositories GitHub informazioni su come usare un modello pre addestrato di BERT come hidden layer in Tensorflow 2.0 tramite l’utilizzo delle API Keras e del modulo bert-for-tf2.

Infine abbiamo utilizzato il modello di BERT pre addestrato multilingua impiegando tecniche di Transfer Learning per applicarlo a differenti classi di problemi.

Prerequisiti

Per una efficace fruizione di questo articolo è necessario essere in possesso dei seguenti prerequisiti:

  • Buona conoscenza di Python
  • Conoscenza di Tensorflow 2.0 Keras
  • Conoscenza di text tokenization e dei concetti base di NLP
  • Buona conoscenza di Deep Neural Networks
  • Buona conoscenza di Recurrent Neural Networks
  • Conoscenza del modello BERT

Google BERT

Prima di proseguire, una breve panoramica sul modello di Machine Learning presentato da Google: BERT.

Con BERT (Bidirectional Encoder Representations from Transformers) si fa riferimento ad un articolo pubblicato nella primavera 2019 da un gruppo di ricercatori di Google AI Language. I risultati presentati hanno fatto scalpore nella comunità del Machine Learning, in particolar modo possiamo citare come di particolare impatto il task relativo alla risposta automatizzata alle domande (SQuAD v1.1).

La particolarità del modello consiste nell’applicazione della tecnica bidirezionale dei Transformer, il cui modello è abbastanza noto nell’ambito applicativo della compressione.

Alla base dei Transformer, schematizzati nell'immagine seguente, vi è il meccanismo di apprendimento delle relazioni contestuali tra parole (anche tra parole definite secondarie, ovvero non propriamente rilevanti nel contesto di una frase).

Tecnica di apprendimento bidirezionale Tecnica di apprendimento bidirezionale

Nella pratica, un Transformer effettua una codifica del testo ricevuto in input e genera una decodifica della previsione fatta in base all’attività per cui è trainato il modello nel quale è stato applicato. La differenza, rispetto agli approcci bidirezionali, i quali leggono il testo in sequenza, consiste nel leggere tale sequenza di parole in contemporanea.

Tale approccio, illustrato nell'immagine seguente, risulta in contro tendenza rispetto a quelli presenti in letteratura fino a quel momento, i quali si basavano sull’analisi delle sequenze di testo da sinistra a destra e viceversa.

Google BERT Transformer Google BERT Transformer

Se fino a quel momento, un Transformer veniva considerato bidirezionale, nella realtà dei fatti, con l’introduzione del modello Google BERT, si è passati ad un approccio non direzionale. Questa sua caratteristica permette al modello di apprendere il contesto di una parola in base a tutto ciò che la circonda, non solo basandosi sulla parola precedente e su quella successiva.

Durante le fasi di training, il modello BERT riceve in input una coppia di frasi, sotto forma di sequenze di token, ed impara a prevedere se la seconda sequenza di token risulta essere la frase successiva della prima sequenza nel documento originale (corpora).

Per maggiori approfondimenti si consiglia la lettura del paper.

Dati

Il file csv di partenza contiene 207 frasi appartenenti a 30 classi differenti. Per ogni classe abbiamo almeno 5 esempi differenti. Un esempio è riportato di seguito:

Esempi di frasi di training Esempi di frasi di training

Il nostro approccio prevede di utilizzare almeno un paio di esempi, presi da ogni classe, per poter definire un set di frasi di validazione da utilizzare durante le fasi successive di training del modello. Di seguito è rappresentata la distribuzione delle frasi.

Distribuzione delle frasi Distribuzione delle frasi

Preprocessing

Come descritto nella documentazione all’interno della pagina PyPi, il layer di BERT richiede come input un array di sequenze, con la definizione della lunghezza massima da applicare ad ogni sequenza.

Il primo passo da seguire è la definizione del tokenizer BERT FullTokenizer, il quale richiede come input il vocabolario, o corpora, utilizzato per addestrare il modello BERT. Dopo aver scaricato dal repository GitHub il modello pre addestrato di BERT nella sua versione multilingua, lo abbiamo inserito all’interno della cartella di riferimento. Il modello scaricato contiene una serie di file tra cui vi è appunto il vocab.txt file, richiesto in input dalla classe FullTokenizer.

Abbiamo utilizzato il tokenizer appena definito per poter effettuare del pre processamento sui nostri dati, seguendo questi step:

  • Split dei dati in set di training, classi di training, set di test e classi di test
  • I dati sono stati riordinati, in modo da non avere sequenze consecutive di dati appartenenti alla stessa classe
  • Tokenizzazione di tutte le frasi utilizzando il tokenizer precedentemente descritto
  • Inserite le keyword “[CLS]” e “[SEP]” all’inizio e alla fine di ogni sequenza. Questa attività è consigliata nell’utilizzo del modello BERT; il token “[CLS]” indica la classe di appartenenza della sequenza, e deve essere posto all’inizio della sequenza stessa. Il token “[SEP]” indica la fine di una sequenza e l’eventuale inizio della sequenza successiva.
  • Applicata la tecnica one hot encoder ad ogni classe appartenente ad entrambi i set di classi

BERT Layer

E’ arrivato il momento della definizione del layer BERT da utilizzare all’interno della nostra Deep Neural Network. Come descritto nella pagina del repository PyPi, abbiamo utilizzato il wrapper BertModelLayer in modo da poter creare il layer Keras da inserire all’interno della nostra DNN.

All’interno della cartella contenente il modello pre addestrato di BERT, è presente il file bert_config.json il quale contiene tutti i parametri richiesti per la configurazione del layer. Poichè il nostro obiettivo è quello di utilizzare tale modello così come è stato addestrato, abbiamo deciso di bloccare tutti i layer originali all’interno del wrapper BertModelLayer. Questa scelta è dovuta al fatto che, per questo esperimento, il numero di dati non è tale da poter giustificare un training completo del modello.

Modello

In questa sezione finale mostreremo la definizione del modello DNN, utilizzato per poter effettuare fine tuning sui dati di training.

La definizione dei primi due layer è descritta in modo chiaro e completo all’interno del repository PyPi del modulo bert-for-tf2.

Il parametro max_seq_length è stato definito durante la fase di analisi. Dato che la lunghezza media di ogni sequenza appartenente al training set è pari a 48.2, abbiamo deciso di definire tale parametro uguale a tale valore. Tale attività è stata fatta all’interno della fase di tokenizzazione descritta precedentemente.

Successivamente, abbiamo inserito due layer Dense dopo il layer BERT costruito, ciascuno con 256 neuroni. Per la parte di regolarizzazione, abbiamo inserito due layer di Dropout con parametro di regolarizzazione pari a 0.5. Come funzione di ottimizzazione, abbiamo utilizzato la funzione Adam con un parametro di learning rate pari a 0.00001.

Risultati

Salvando, durante ogni epoca, i checkpoint ottenuti durante ogni fase di training, abbiamo deciso di impostare il training completo con un parametro uguale a 200 epoche.

I risultati ottenuti sono:

  • loss: 0.232
  • accuracy: 0.957
  • val_loss: 0.496
  • val_accuracy: 0.897