Guida pratica per creare da zero un modello linguistico per attività MLM utilizzando la libreria Python e Transformers
Negli ultimi anni, i modelli linguistici di grandi dimensioni (LLM) hanno attirato tutta l’attenzione della comunità del machine learning. Prima dell’arrivo dei LLM, abbiamo avuto una fase di ricerca cruciale su varie tecniche di modellazione del linguaggio, tra cui la modellazione del linguaggio mascherato, la modellazione del linguaggio causale e la modellazione del linguaggio da sequenza a sequenza.
Dall’elenco precedente, i modelli di linguaggio mascherato come BERT sono diventati più utilizzabili nelle attività di PNL a valle come la classificazione e il clustering. Grazie a librerie come Hugging Face Transformers, l’adattamento di questi modelli per le attività successive è diventato più accessibile e gestibile. Inoltre, grazie alla comunità open source, disponiamo di numerosi modelli linguistici tra cui scegliere che coprono lingue e domini ampiamente utilizzati.
Quando adattiamo i modelli linguistici esistenti ai vostri casi d’uso specifici, a volte possiamo utilizzare i modelli esistenti senza ulteriore messa a punto (il cosiddetto fine tuning). Ad esempio, se desideri un modello di rilevamento di sentimenti/intenti in inglese, puoi andare su HuggingFace.co e trovare un modello adatto al tuo caso d’uso.
Tuttavia, puoi aspettartelo solo per alcune delle attività incontrate nel mondo reale. È qui che abbiamo bisogno di una tecnica aggiuntiva chiamata messa a punto. Innanzitutto, devi scegliere un modello base che verrà messo a punto. Qui devi fare attenzione al modello selezionato e alla somiglianza lessicale della tua lingua di destinazione.
Tuttavia, se non riesci a trovare un modello adatto riqualificato nella lingua desiderata, valuta la possibilità di crearne uno da zero. In questo tutorial implementeremo il modello BERT per il modello del linguaggio mascherato.
Anche se la descrizione dell’architettura BERT esula dallo scopo di questo tutorial, per motivi di chiarezza, esamineremo la questione in modo molto restrittivo. BERT, o Bidirezionale Ecodificatore Rpresentazioni da Ttrasformatori, appartiene alla famiglia dei trasformatori solo encoder. È stato introdotto nel 2018 dai ricercatori di Google.
Estratto cartaceo:
Noi introdurre un nuovo modello di rappresentazione del linguaggio chiamato BERT, che sta per Bidirection Encoder Representations from Transformers. A differenza dei recenti modelli di rappresentazione linguistica, BERT è progettato per pre-addestrare rappresentazioni bidirezionali profonde da testo senza etichetta condizionando congiuntamente sia il contesto sinistro che quello destro in tutti i livelli. Di conseguenza, il modello BERT pre-addestrato può essere perfezionato con un solo livello di output aggiuntivo per creare modelli all’avanguardia per un’ampia gamma di attività, come la risposta alle domande e l’inferenza linguistica, senza compiti sostanziali. modifiche specifiche dell’architettura.
BERT è concettualmente semplice ed empiricamente potente. Ottiene nuovi risultati all’avanguardia su undici attività di elaborazione del linguaggio naturale, tra cui l’incremento del punteggio GLUE all’80,5% (miglioramento assoluto del 7,7%), accuratezza MultiNLI all’86,7% (miglioramento assoluto del 4,6%), SQuAD v1.1 Test di risposta alle domande F1 a 93,2 (miglioramento assoluto di 1,5 punti) e Test SQuAD v2.0 F1 a 83,1 (miglioramento assoluto di 5,1 punti).
Carta: https://arxiv.org/abs/1810.04805
Sopra, possiamo vedere una parola chiave interessante, Bidirezionale. La natura bidirezionale conferisce a BERT un potere simile a quello umano. Supponiamo che tu debba riempire uno spazio vuoto come quello sottostante,
“La guerra a volte può essere un male necessario. Ma non importa quanto sia necessario, è sempre un _____, mai un bene.
Per indovinare che la parola si trova in una posizione vuota, dovresti essere consapevole di alcune cose: le parole prima dello spazio vuoto, le parole dopo lo spazio vuoto e il contesto generale della frase. Adattando questa natura umana, BERT funziona allo stesso modo. Durante l’allenamento, nascondiamo alcune parole e chiediamo a BERT di provare a prevederle. Una volta terminato l’addestramento, BERT può prevedere i token mascherati in base alle parole prima e dopo. Per fare ciò, il modello dovrebbe prestare diversa attenzione alle parole presentate nella sequenza di input, il che potrebbe avere un impatto significativo sulla previsione dei token mascherati.
Come puoi vedere qui, il modello vede una parola adatta per la posizione nascosta come cattivo e quella della prima frase cattivo quanto necessario per fare questa previsione. Questo è un punto evidente e implica che il modello comprenda il contesto della sequenza di input. Questa consapevolezza del contesto consente a BERT di generare incorporamenti di frasi significativi per determinati compiti. Inoltre, questi incorporamenti possono essere utilizzati in attività a valle come il clustering e la classificazione. Basta con BERT; costruiamone uno da zero.
Generalmente abbiamo BERT(base) e BERT(grande). Entrambi hanno 64 dimensioni pro capite. IL grande la variante contiene 24 livelli di codifica, mentre il base la variante ne ha solo 12. Tuttavia, non ci limitiamo a queste configurazioni. Sorprendentemente, abbiamo il controllo completo sulla definizione del modello utilizzando la libreria Hugging Face Transformers. Tutto quello che dobbiamo fare è definire le configurazioni del modello desiderate utilizzando il file BertConfig classe.
Ho scelto 6 teste e 384 dimensioni totali del modello per rispettare l’implementazione originale. In questo modo ogni testa ha 64 dimensioni simili all’implementazione originale. Inizializziamo il nostro modello BERT.
from transformers import BertConfig, BertForMaskedLMconfig = BertConfig(
hidden_size = 384,
vocab_size= tokenizer.vocab_size,
num_hidden_layers = 6,
num_attention_heads = 6,
intermediate_size = 1024,
max_position_embeddings = 256
)
model = BertForMaskedLM(config=config)
print(model.num_parameters()) #10457864
Qui non descriverò come funziona la tokenizzazione dietro le quinte. Invece, addestriamone uno da zero utilizzando la libreria di tokenizzatori Hugging Face. Tieni presente che il tokenizzatore utilizzato nell’implementazione BERT originale è il tokenizer WordPiece, un altro metodo di tokenizzazione basato su sottoparole. Puoi saperne di più su questa tokenizzazione utilizzando la risorsa HuggingFace di seguito.
Il set di dati utilizzato qui è il set di dati Sinhala-400M (sotto Apache-2.0). Puoi seguire lo stesso con qualsiasi set di dati che hai.
Come potresti notare, alcune parole singalesi sono state digitate anche in inglese. Formiamo un tokenizzatore per questi corpora.
Importiamo prima i moduli necessari. L’aspetto positivo dell’addestramento dei tokenizzatori utilizzando la libreria Hugging Face Tokenizers è che possiamo utilizzare i tokenizzatori esistenti e sostituire solo il vocabolario (e unirlo ove applicabile) in base al nostro corpus di formazione. Ciò significa che i passaggi di tokenizzazione come la pre-tokenizzazione e la post-tokenizzazione verranno preservati. Per questo, possiamo usare un metodo, train_new_from_iterator Classe BertTokenizer.
from tokenizers.implementations import ByteLevelBPETokenizer
from tokenizers.processors import BertProcessing
from transformers import AutoTokenizer
from datasets import Dataset
import pandas as pd#load base tokenizer to train on dataset
tokenizer_base = AutoTokenizer.from_pretrained("bert-base-cased")
# convert pandas dataset to HF dataset
dataset = Dataset.from_pandas(df.rename(columns={"comment":'text'}))
# define iterator
training_corpus = (
dataset(i : i + 1000)("text")
for i in range(0, len(dataset), 1000)
)
#train the new tokenizer for dataset
tokenizer = tokenizer_base.train_new_from_iterator(training_corpus, 5000)
#test trained tokenizer for sample text
text = dataset('text')(123)
print(text)
# let's check tokenization process
input_ids = tokenizer(text).input_ids
subword_view = (tokenizer.convert_ids_to_tokens(id) for id in input_ids)
np.array(subword_view)
Puoi vedere parole come ‘giocatore di cricket’ scomposte in cricket E ##È, indicando che il tokenizzatore è stato adeguatamente formato. Tuttavia, prova diverse dimensioni di vocabolario; il mio è 5000, che è relativamente piccolo ma adatto a questo esempio di giocattolo.
Infine, possiamo salvare il tokenizzatore addestrato nella nostra directory.
tokenizer.save_pretrained("tokenizer/sinhala-wordpiece-yt-comments")
Definiamo un raccoglitore per le attività MLM. Qui maschereremo il 15% dei token. Possiamo comunque impostare diverse probabilità di mascheramento.
from transformers import DataCollatorForLanguageModelingdata_collator = DataCollatorForLanguageModeling(
tokenizer=tokenizer, mlm=True, mlm_probability=0.15
)
Tokenizziamo il set di dati utilizzando un tokenizzatore creato in precedenza. Sto sostituendo l’originale LineByLineTextDataset usando la mia classe personalizzata utilizzando Hugging Face accelera.
import torch
from torch.utils.data import Dataset
from accelerate import Accelerator, DistributedTypeclass LineByLineTextDataset(Dataset):
def __init__(self, tokenizer, raw_datasets, max_length: int):
self.padding = "max_length"
self.text_column_name = 'text'
self.max_length = max_length
self.accelerator = Accelerator(gradient_accumulation_steps=1)
self.tokenizer = tokenizer
with self.accelerator.main_process_first():
self.tokenized_datasets = raw_datasets.map(
self.tokenize_function,
batched=True,
num_proc=4,
remove_columns=(self.text_column_name),
desc="Running tokenizer on dataset line_by_line",
)
self.tokenized_datasets.set_format('torch',columns=('input_ids'),dtype=torch.long)
def tokenize_function(self,examples):
examples(self.text_column_name) = (
line for line in examples(self.text_column_name) if len(line(0)) > 0 and not line(0).isspace()
)
return self.tokenizer(
examples(self.text_column_name),
padding=self.padding,
truncation=True,
max_length=self.max_length,
return_special_tokens_mask=True,
)
def __len__(self):
return len(self.tokenized_datasets)
def __getitem__(self, i):
return self.tokenized_datasets(i)
Tokenizziamo il set di dati.
tokenized_dataset_train = LineByLineTextDataset(
tokenizer= tokenizer,
raw_datasets = dataset,
max_length=256,
)
Va bene, codifichiamo il nostro ciclo di addestramento.
from transformers import Trainer, TrainingArgumentstraining_args = TrainingArguments(
output_dir="./model",
overwrite_output_dir=True,
push_to_hub=True,
hub_model_id="Ransaka/sinhala-bert-yt-comments",
num_train_epochs=2,
per_device_train_batch_size=32,
save_steps=5_000,
logging_steps = 1000,
save_total_limit=2,
use_mps_device = True, # disable this if you're running non-mac env
hub_private_repo = False, # please set true if you want to save model privetly
save_safetensors= True,
learning_rate = 1e-4,
report_to='wandb'
)
trainer = Trainer(
model=model,
args=training_args,
data_collator=data_collator,
train_dataset=tokenized_dataset_train
)trainer.train()
Possiamo invocare il trainer utilizzando its treno() metodo.
trainer.train()
Dopo una formazione sufficiente, il nostro modello può essere utilizzato per attività a valle come la classificazione zero-shot e il clustering. Puoi trovare l’esempio utilizzando questo spazio Hugging Face per maggiori dettagli.
Con risorse limitate, i modelli preaddestrati possono riconoscere solo modelli linguistici specifici, ma possono comunque essere utili per casi d’uso particolari. Si consiglia vivamente di perfezionare quando possibile.
In questo articolo tutte le immagini, se non diversamente specificato, sono dell’autore.
- Un BERT esplorabile — https://huggingface.co/spaces/exbert-project/exbert
- Carta BERT — https://arxiv.org/abs/1810.04805
- Set di dati — https://huggingface.co/datasets/Ransaka/Sinhala-400M
Fonte: towardsdatascience.com