Addestrare GPT-2 nella propria lingua
Una guida passo passo per addestrare da zero il proprio modello GPT-2 per la generazione di testo in una lingua a scelta
Sappiamo tutti che la moderna elaborazione del linguaggio naturale (NLP) ha fatto passi da gigante negli ultimi due anni grazie allo sviluppo delle reti di attenzione e dei trasformatori. Ciò ha aperto la strada a una pletora di nuovi algoritmi che hanno raggiunto lo stato dell’arte (SOTA) per i diversi compiti dell’NLP.
OpenAI è stato uno dei leader nel fornire il proprio modello linguistico (ora rilasciato GPT-3), addestrato su un enorme corpus di dati internet. Dato che il GPT-3 è un fenomeno recente, al momento in lingua inglese, ed è accessibile solo tramite le API fornite da OpenAI, ci concentreremo sulla versione precedente, cioè il GPT-2. Per conoscere i dettagli interni di GPT-2, vi suggerisco di consultare questo link. Per approfondire il tema dell’attenzione e dei trasformatori, ecco alcuni link eccellenti:
– Il trasformatore illustrato di Jay Alammar
– Il Trasformatore commentato di Harvard NLP
Il GPT-2 è stato rilasciato anche per l’inglese, il che rende difficile per chi cerca di generare testo in una lingua diversa.
Allora perché non addestrare il proprio modello GPT-2 sulla propria lingua preferita per la generazione di testi? Questo è esattamente ciò che faremo. Quindi, senza ulteriori indugi, iniziamo.
Per la dimostrazione, ho preso in considerazione una scrittura con alfabeto non latino (il bengalese), perché no! Per il modello ho utilizzato l’implementazione di Huggingface.
Se non sapete di cosa sto parlando, vi consigliamo il nostro corso livello 1 di NLP 😉
1. Raccolta dei dati
La raccolta di dati di buona qualità è una delle fasi più importanti, come concordano tutti i Data Scientist. Pertanto, si presuppone che si disponga già di una cartella contenente file .txt con tutti i dati puliti e memorizzati. Per semplicità, si possono usare i dati degli articoli di Wikipedia, che sono disponibili e possono essere scaricati con il seguente codice.
In questo modo verrà creata una cartella contenente tutti i file di Wikipedia dall’aspetto simile:
Nota: a causa della scarsità di risorse e poiché è a scopo dimostrativo, ho addestrato il modello su un piccolo sottoinsieme di libri di Satyajit Ray, in particolare la serie del detective Feluda.
python wikipedia_download.py --lang bn
2. Tokenizzazione
Il secondo passo è la tokenizzazione dei dati. A tale scopo, utilizziamo la seguente classe.
Alcune note sulla tokenizzazione:
– Utilizziamo la codifica BPE (Byte Pair Encoding), che è una codifica di sottoparole, che in genere si preoccupa di non trattare forme diverse di parole come diverse. (Ad esempio, greatest sarà trattato come due token: ‘great’ ed ‘est’, il che è vantaggioso perché mantiene la somiglianza tra great e greatest, mentre ‘greatest’ ha un altro token aggiunto ‘est’ che lo rende diverso). Inoltre, non è un livello così basso come la codifica a livello di carattere, che non conserva alcun valore di una particolare parola.
– Un altro punto piccolo ma sottile è NFKC (Normalization Form Compatibility Composition) nella riga 13 del codice. Si tratta di una delle forme di compatibilità standard di Unicode. Non avrebbe molta importanza se la lingua fosse l’inglese, ma dato che stiamo usando il bengalese, che contiene una forma diversa di carattere, usiamo questa specifica. Per saperne di più, consultare questo link
Quindi, quello che facciamo è tokenizzare i nostri dati e salvarli in una cartella. Verranno creati due file (merges.txt e vocab.json) in una directory specificata. Per eseguire il file, utilizzare il seguente codice:
from tokenise import BPE_token
from pathlib import Path
import os# the folder 'text' contains all the files
paths = [str(x) for x in Path("./text/").glob("**/*.txt")]tokenizer = BPE_token()# train the tokenizer model
tokenizer.bpe_train(paths)# saving the tokenized data in our specified folder
save_path = 'tokenized_data'
tokenizer.save_tokenizer(save_path)
3. Inizializzazione del modello
Prima di iniziare la vera magia, dobbiamo assicurarci che le artiglierie siano pronte. Cominciamo con alcune inizializzazioni.
Inoltre, creiamo una singola stringa da tutti i nostri documenti e la tokenizziamo.
Dopo aver codificato l’intera stringa, passiamo a creare un set di dati TensorFlow, suddividendo i dati in intervalli uguali, in modo che il nostro modello possa imparare. In questo caso utilizziamo una dimensione di blocco di 100 (lunghezza del token in ciascun esempio) e una dimensione di batch di 16. Questa dimensione è stata mantenuta bassa per poterla eseguire con facilità su una GPU RTX 2060.
import tensorflow as tf
from transformers import GPT2Config, TFGPT2LMHeadModel, GPT2Tokenizer# loading tokenizer from the saved model path
tokenizer = GPT2Tokenizer.from_pretrained(save_path)tokenizer.add_special_tokens({
"eos_token": "",
"bos_token": "",
"unk_token": "",
"pad_token": "",
"mask_token": ""
})# creating the configurations from which the model can be made
config = GPT2Config(
vocab_size=tokenizer.vocab_size,
bos_token_id=tokenizer.bos_token_id,
eos_token_id=tokenizer.eos_token_id
)# creating the model
model = TFGPT2LMHeadModel(config)
single_string = ''
for filename in paths:
with open(filename, "r", encoding='utf-8') as f:
x = f.read() single_string += x + tokenizer.eos_tokenstring_tokenized = tokenizer.encode(single_string)
examples = []
block_size = 100
BATCH_SIZE = 12
BUFFER_SIZE = 1000for i in range(0, len(string_tokenized) - block_size + 1, block_size):
examples.append(string_tokenized[i:i + block_size])
inputs, labels = [], []for ex in examples:
inputs.append(ex[:-1])
labels.append(ex[1:])dataset = tf.data.Dataset.from_tensor_slices((inputs, labels))
dataset = dataset.shuffle(BUFFER_SIZE).batch(BATCH_SIZE, drop_remainder=True)
4. Formazione del modello
Ora arriva la parte che stavamo aspettando: la creazione del modello e l’addestramento. Definiamo quindi il nostro ottimizzatore, le funzioni di perdita e le metriche e iniziamo l’addestramento.
Ora, addestriamo il modello
# defining our optimizer
optimizer = tf.keras.optimizers.Adam(learning_rate=3e-5, epsilon=1e-08, clipnorm=1.0)# definining our loss function
loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)# defining our metric which we want to observe
metric = tf.keras.metrics.SparseCategoricalAccuracy('accuracy')# compiling the model
model.compile(optimizer=optimizer, loss=[loss, *[None] * model.config.n_layer], metrics=[metric])
num_epoch = 10
history = model.fit(dataset, epochs=num_epoch)
5. Predizione
Per predire, è sufficiente codificare il testo in ingresso e passarlo al modello
Ora, se siete bengalesi, potete far notare che l’output, sebbene la frase sia sintatticamente corretta, non sembra coeso. È vero, ma per questa dimostrazione l’ho ridotta al minimo.
text = "লালমোহনবাবু "# encoding the input text
input_ids = tokenizer.encode(text, return_tensors='tf')# getting out output
beam_output = model.generate(
input_ids,
max_length = 50,
num_beams = 5,
temperature = 0.7,
no_repeat_ngram_size=2,
num_return_sequences=5
)
6. Salvare il modello
Dopo un lungo periodo di addestramento, a cosa servirebbe se chiudessimo la sessione e tutto il modello addestrato andasse perso e dovessimo addestrarlo di nuovo da zero. Quindi, salviamo il modello e il tokenizer in modo da poter riallenare da dove abbiamo lasciato
from transformers import WEIGHTS_NAME, CONFIG_NAME
import osoutput_dir = './model_bn_custom/'# creating directory if it is not present
if not os.path.exists(output_dir):
os.mkdir(output_dir)model_to_save = model.module if hasattr(model, 'module') else model
output_model_file = os.path.join(output_dir, WEIGHTS_NAME)
output_config_file = os.path.join(output_dir, CONFIG_NAME)# save model and model configs
model.save_pretrained(output_dir)
model_to_save.config.to_json_file(output_config_file)# save tokenizer
tokenizer.save_pretrained(output_dir)
Bonus
Abbiamo già fatto tutto il lavoro duro, quindi per caricare il modello salvato e il tokenizer, dobbiamo eseguire solo due righe di codice e siamo a posto.
Voila! Ora potete addestrare il vostro modello nella vostra lingua. E creare contenuti in grado di competere con alcune delle migliori opere letterarie in qualsiasi lingua.
Articolo originale di Arshabhi Kayal
Train GPT-2 in your own language. A step-by-step guide to train your own… | by Arshabhi Kayal | Towards Data Science
tokenizer = GPT2Tokenizer.from_pretrained(output_dir)
model = TFGPT2LMHeadModel.from_pretrained(output_dir)