‘Deep Learning su Internet Allenamento collaborativo dei modelli di linguaggio’

Collaborative training of language models for Deep Learning on the Internet

Con l’aiuto aggiuntivo di Quentin Lhoest e Sylvain Lesage.

I moderni modelli di linguaggio richiedono spesso una quantità significativa di calcolo per il pretraining, rendendo impossibile ottenerli senza accesso a decine o centinaia di GPU o TPU. Sebbene in teoria potrebbe essere possibile combinare le risorse di più individui, nella pratica, tali metodi di addestramento distribuito hanno avuto successo limitato in quanto le velocità di connessione su Internet sono molto più lente rispetto ai supercomputer GPU ad alte prestazioni.

In questo post del blog, descriviamo DeDLOC – un nuovo metodo per l’addestramento distribuito collaborativo che può adattarsi alle restrizioni di rete e hardware dei partecipanti. Mostreremo che può essere applicato con successo in scenari del mondo reale preaddestrando sahajBERT, un modello per la lingua bengalese, con l’aiuto di 40 volontari. Nei compiti successivi in bengalese, questo modello raggiunge una qualità quasi all’avanguardia con risultati comparabili a modelli molto più grandi che utilizzano centinaia di acceleratori di fascia alta.

Deep Learning Distribuito in Collaborazioni Aperte

Perché dovremmo farlo?

Oggi molti dei migliori sistemi NLP sono basati su grandi Transformer preaddestrati. In generale, la loro qualità migliora con la dimensione: è possibile ottenere risultati senza pari nella comprensione e generazione del linguaggio naturale aumentando il numero di parametri e sfruttando l’abbondanza di testi non etichettati.

Purtroppo, utilizziamo questi modelli preaddestrati non solo perché è conveniente. Le risorse hardware necessarie per addestrare i Transformer su grandi set di dati spesso superano le possibilità economiche di un singolo individuo e persino della maggior parte delle organizzazioni commerciali o di ricerca. Prendiamo ad esempio BERT: si stima che il suo addestramento costi circa 7.000 dollari, e per i modelli più grandi come GPT-3, questo numero può arrivare fino a 12 milioni di dollari! Questa limitazione delle risorse potrebbe sembrare ovvia ed inevitabile, ma esiste davvero un’alternativa all’uso di modelli preaddestrati per la comunità più ampia di Machine Learning?

Tuttavia, potrebbe esserci una soluzione a questa situazione: per trovare una soluzione, dobbiamo solo guardare intorno a noi. Potrebbe essere il caso che le risorse di calcolo che stiamo cercando siano già disponibili; ad esempio, molti di noi hanno potenti computer con GPU per giochi o workstation a casa. Probabilmente avrete già intuito che stiamo per unire la loro potenza in modo simile a Folding@home, Rosetta@home, Leela Chess Zero o diversi progetti BOINC che sfruttano il calcolo distribuito volontario, ma l’approccio è ancora più generale. Ad esempio, diversi laboratori possono unire le loro piccole infrastrutture per utilizzare tutte le risorse disponibili, e altri potrebbero voler partecipare all’esperimento utilizzando istanze cloud economiche.

Per una mente scettica, potrebbe sembrare che ci manchi un fattore chiave qui: il trasferimento dei dati nel deep learning distribuito è spesso un collo di bottiglia, poiché è necessario aggregare i gradienti da più lavoratori. Infatti, qualsiasi approccio ingenuo all’addestramento distribuito su Internet è destinato a fallire, poiché la maggior parte dei partecipanti non dispone di connessioni gigabit e potrebbe disconnettersi dalla rete in qualsiasi momento. Quindi come è possibile addestrare qualsiasi cosa con un piano dati domestico? 🙂

Come soluzione a questo problema, proponiamo un nuovo algoritmo di addestramento chiamato Deep Learning Distribuito in Collaborazioni Aperte (o DeDLOC), che viene descritto in dettaglio nel nostro preprint recentemente rilasciato. Ora, scopriamo quali sono le idee principali dietro questo algoritmo!

Addestramento con volontari

Nella sua versione più comune, l’addestramento distribuito con più GPU è piuttosto semplice. Ricordiamo che durante il deep learning, si calcolano i gradienti della funzione di perdita mediati su molti esempi in un batch di dati di addestramento. Nel caso del deep learning distribuito con parallelismo dei dati, si suddivide semplicemente il dato tra più lavoratori, si calcolano i gradienti separatamente e quindi si fanno la media una volta che i batch locali sono stati processati. Una volta calcolato il gradiente medio su tutti i lavoratori, si aggiustano i pesi del modello con l’ottimizzatore e si continua ad addestrare il modello. Qui di seguito puoi vedere un’illustrazione delle diverse attività eseguite.

Spesso, per ridurre la quantità di sincronizzazione e stabilizzare il processo di apprendimento, possiamo accumulare i gradienti per N batch prima di fare la media, il che equivale ad aumentare la dimensione effettiva del batch N volte. Questo approccio, combinato con l’osservazione che la maggior parte dei modelli di linguaggio all’avanguardia utilizza batch grandi, ci ha portato a un’idea semplice: accumuliamo un batch molto grande su tutti i dispositivi dei volontari prima di ogni passo dell’ottimizzatore! Oltre a essere completamente equivalente all’addestramento distribuito regolare e facilmente scalabile, questo metodo ha anche il vantaggio di una tolleranza ai guasti integrata, che illustreremo di seguito.

Consideriamo alcuni casi di potenziali guasti che potremmo incontrare durante un esperimento collaborativo. Finora, lo scenario più frequente è che uno o più partecipanti si disconnettano dalla procedura di addestramento: potrebbero avere una connessione instabile o semplicemente voler utilizzare le loro GPU per altre attività. In questo caso, subiamo solo un lieve ritardo nell’addestramento: il contributo di questi partecipanti viene sottratto alla dimensione del batch attualmente accumulato, ma gli altri partecipanti compenseranno ciò con i loro gradienti. Inoltre, se si uniscono più partecipanti, la dimensione del batch obiettivo verrà raggiunta più velocemente e la nostra procedura di addestramento si accelererà naturalmente. Puoi vedere una dimostrazione di questo nel video:

Media mobile adattiva

Ora che abbiamo discusso della procedura di allenamento complessiva, rimane ancora una domanda: come aggregare effettivamente i gradienti dei partecipanti? La maggior parte dei computer domestici non può facilmente accettare connessioni in ingresso e la velocità di download potrebbe rappresentare un limite.

Dato che ci affidiamo all’hardware volontario per gli esperimenti, un server centrale non è davvero una soluzione praticabile, poiché si troverebbe rapidamente in sovraccarico quando si scala a decine di client e centinaia di milioni di parametri. La maggior parte delle esecuzioni di addestramento parallelo dei dati oggi non utilizza comunque questa strategia; invece, si basano su All-Reduce – una primitiva di comunicazione efficiente di tipo tutti-tutti. Grazie a ottimizzazioni algoritmiche intelligenti, ogni nodo può calcolare la media globale senza inviare l’intero gradiente locale a ogni peer.

Poiché All-Reduce è decentralizzato, sembra una buona scelta; tuttavia, dobbiamo comunque tenere conto della diversità dell’hardware e delle configurazioni di rete. Ad esempio, alcuni volontari potrebbero unirsi da computer con una connessione lenta ma potenti GPU, altri potrebbero avere una migliore connettività solo con un sottoinsieme di altri peer e alcuni potrebbero essere bloccati da connessioni in ingresso.

Si scopre che possiamo effettivamente ideare una strategia ottimale di trasferimento dati al volo sfruttando queste informazioni sulle prestazioni! A un livello alto, suddividiamo l’intero vettore del gradiente in parti in base alla velocità di Internet di ogni peer: quelli con la connessione più veloce aggregano le parti più grandi. Inoltre, se alcuni nodi non accettano connessioni in ingresso, semplicemente inviano i loro dati per l’aggregazione ma non calcolano la media stessi. A seconda delle condizioni, questo algoritmo adattivo può recuperare noti algoritmi di apprendimento profondo distribuito e migliorarli con una strategia ibrida, come dimostrato di seguito.

sahajBERT

Come sempre, avere un framework algoritmico ben progettato non significa che funzionerà come previsto in pratica, perché alcune ipotesi potrebbero non essere vere nelle esecuzioni di addestramento effettive. Per verificare le prestazioni competitive di questa tecnologia e mostrare il suo potenziale, abbiamo organizzato un evento collaborativo speciale per preaddestrare un modello di linguaggio mascherato per la lingua bengalese. Anche se è la quinta lingua madre più parlata al mondo, ci sono pochissimi modelli di linguaggio mascherati disponibili pubblicamente, il che sottolinea l’importanza degli strumenti che possono dare potere alla comunità, aprendo una moltitudine di opportunità nel campo.

Abbiamo condotto questo esperimento con veri volontari della comunità di Neuropark e abbiamo utilizzato set di dati disponibili pubblicamente (OSCAR e Wikipedia), perché volevamo avere un esempio completamente riproducibile che potesse servire da ispirazione per altri gruppi. Di seguito, descriviamo la configurazione dettagliata della nostra esecuzione di addestramento e ne dimostriamo i risultati.

Architettura

Per il nostro esperimento, abbiamo scelto ALBERT (A Lite BERT) – un modello per rappresentazioni linguistiche che viene preaddestrato con Masked Language Modeling (MLM) e Sentence Order Prediction (SOP) come obiettivi. Utilizziamo questa architettura perché la condivisione dei pesi la rende molto efficiente in termini di parametri: ad esempio, ALBERT-large ha ~18M di parametri addestrabili e si comporta in modo comparabile a BERT-base con ~108M di pesi nel benchmark GLUE. Significa che c’è meno dati da scambiare tra i peer, il che è cruciale nella nostra configurazione, poiché accelera significativamente ogni iterazione di addestramento.

Tokenizer

Il primo componente del nostro modello è chiamato tokenizer e si occupa di trasformare il testo grezzo in indici di vocabolario. Poiché stiamo addestrando un modello per il bengalese, che non è molto simile all’inglese, dobbiamo implementare il preprocessing specifico della lingua come parte del nostro tokenizer. Possiamo considerarlo come una sequenza di operazioni:

  1. Normalizzazione: include tutte le operazioni di preprocessing sui dati testuali grezzi. Questo è stato il passaggio in cui abbiamo apportato più modifiche, perché la rimozione di determinati dettagli può cambiare il significato del testo o lasciarlo uguale, a seconda della lingua. Ad esempio, il normalizzatore standard di ALBERT rimuove gli accenti, mentre per la lingua bengalese dobbiamo mantenerli, perché contengono informazioni sulle vocali. Di conseguenza, utilizziamo le seguenti operazioni: normalizzazione NMT, normalizzazione NFKC, rimozione di spazi multipli, omogeneizzazione di caratteri ricorrenti Unicode nella lingua bengalese e conversione in minuscolo.
  2. Pretokenizzazione descrive le regole per suddividere l’input (ad esempio, tramite spazi bianchi) per imporre limiti specifici ai token. Come nel lavoro originale, abbiamo scelto di mantenere gli spazi bianchi fuori dai token. Pertanto, per distinguere le parole l’una dall’altra e non avere token singoli con spazio singolo, ogni token corrispondente all’inizio di una parola inizia con un carattere speciale “_” (U+2581). Inoltre, abbiamo isolato tutta la punteggiatura e i numeri da altri caratteri per condensare il nostro vocabolario.
  3. Modellizzazione del tokenizer: È a questo livello che il testo viene mappato in una sequenza di elementi di un vocabolario. Ci sono diversi algoritmi per questo, come Byte-Pair Encoding (BPE) o Unigram, e la maggior parte di essi ha bisogno di costruire il vocabolario da un corpus di testo. Seguendo la configurazione di ALBERT, abbiamo utilizzato l’approccio del Modello di Lingua Unigram, addestrando un vocabolario di 32k token sulla parte bengalese deduplicata del set di dati OSCAR.
  4. Post-elaborazione: Dopo la tokenizzazione, potremmo voler aggiungere diversi token speciali richiesti dall’architettura, come l’inizio della sequenza con un token speciale [CLS] o la separazione di due segmenti con un token speciale [SEP]. Poiché la nostra architettura principale è la stessa dell’ALBERT originale, manteniamo la stessa post-elaborazione: in particolare, aggiungiamo un token [CLS] all’inizio di ogni esempio e un token [SEP] sia tra due segmenti che alla fine.

Puoi riutilizzare il nostro tokenizer eseguendo il seguente codice:

from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("neuropark/sahajBERT")

Dataset

L’ultima cosa che dobbiamo coprire è l’insieme di dati di addestramento. Come probabilmente sai, la grande forza dei modelli preaddestrati come BERT o ALBERT è che non hai bisogno di un insieme di dati annotato, ma solo di molti testi. Per addestrare sahajBERT, abbiamo utilizzato il dump di Wikipedia in bengalese del 03/20/2021 e il sottoinsieme in bengalese di OSCAR (600 MB + 6 GB di testo). Questi due insiemi di dati possono essere facilmente scaricati da HF Hub.

Tuttavia, caricare un intero insieme di dati richiede tempo e spazio di archiviazione, due cose che i nostri colleghi non hanno necessariamente. Per sfruttare al meglio le risorse fornite dai partecipanti, abbiamo implementato il dataset streaming, che consente loro di addestrare il modello quasi immediatamente dopo essersi uniti alla rete. In particolare, gli esempi nell’insieme di dati vengono scaricati e trasformati in parallelo all’addestramento. Possiamo anche mescolare l’insieme di dati in modo che i nostri colleghi abbiano poche possibilità di elaborare gli stessi esempi contemporaneamente. Poiché l’insieme di dati non viene scaricato e preelaborato in anticipo, le trasformazioni necessarie per passare dal testo normale a un esempio di addestramento (mostrato nella figura sottostante) vengono eseguite al volo.

La modalità di streaming dell’insieme di dati è disponibile dalla versione v1.9 della libreria 🤗 datasets, quindi puoi utilizzarla subito come segue:

from datasets import load_dataset

oscar_dataset = load_dataset("oscar", name="unshuffled_deduplicated_bn", streaming=True)

Evento collaborativo

L’evento di addestramento collaborativo di sahajBERT si è svolto dal 12 maggio al 21 maggio. L’evento ha riunito 40 partecipanti, di cui 30 volontari di lingua bengalese e 10 volontari di una delle organizzazioni degli autori. Questi 40 volontari si sono uniti al canale Discord di Neuropark per ricevere tutte le informazioni riguardanti l’evento e partecipare alle discussioni. Per partecipare all’esperimento, ai volontari è stato chiesto di:

  1. Inviare il proprio nome utente ai moderatori per essere inseriti nella lista di accesso;
  2. Aprire il notebook fornito localmente, su Google Colaboratory o su Kaggle;
  3. Eseguire una cella di codice e compilare le proprie credenziali di Hugging Face quando richiesto;
  4. Osservare la diminuzione della perdita di addestramento sui pannelli condivisi!

Per motivi di sicurezza, abbiamo creato un sistema di autorizzazione in modo che solo i membri della comunità di Neuropark potessero addestrare il modello. Risparmiandoti i dettagli tecnici, il nostro protocollo di autorizzazione ci consente di garantire che ogni partecipante sia nella lista di accesso e di riconoscere il contributo individuale di ogni collega.

Nella figura seguente, puoi vedere l’attività di ogni volontario. Durante l’esperimento, i volontari hanno effettuato l’accesso a 600 sessioni diverse. I partecipanti hanno regolarmente avviato più esecuzioni in parallelo e molti di loro hanno distribuito le esecuzioni avviate nel tempo. Le esecuzioni dei singoli partecipanti hanno avuto una durata media di 4 ore e la durata massima è stata di 21 ore. Puoi leggere ulteriori informazioni sulle statistiche di partecipazione nell’articolo.

Oltre alle risorse fornite dai partecipanti, abbiamo utilizzato anche 16 istanze cloud preemptible (economiche ma interrotte frequentemente) con singola GPU T4 per garantire la stabilità dell’esecuzione. Il tempo di esecuzione cumulativo per l’esperimento è stato di 234 giorni e nella figura sottostante puoi vedere le parti della curva di perdita a cui ogni collega ha contribuito!

Il modello finale è stato caricato su Model Hub, quindi puoi scaricarlo e giocarci se vuoi: https://hf.co/neuropark/sahajBERT

Valutazione

Per valutare le prestazioni di sahajBERT, lo abbiamo sottoposto a un affinamento su due compiti secondari in bengalese:

  • Named entity recognition (NER) sul subset in bengalese di WikiANN. L’obiettivo di questo compito è classificare ogni token nel testo di input in una delle seguenti categorie: persona, organizzazione, luogo o nessuna di queste.
  • News Category Classification (NCC) sull’insieme di dati degli articoli di Soham da IndicGLUE. L’obiettivo di questo compito è prevedere la categoria a cui appartiene il testo di input.

L’abbiamo valutato durante l’addestramento sul compito NER per verificare che tutto procedesse bene; come puoi vedere nel grafico seguente, questo è stato effettivamente il caso!

Alla fine dell’addestramento, abbiamo confrontato sahajBERT con altri tre modelli di linguaggio preaddestrati: XLM-R Large, IndicBert e bnRoBERTa. Nella tabella sottostante, puoi vedere che il nostro modello ha risultati paragonabili ai migliori modelli di linguaggio in bengalese disponibili su HF Hub, anche se il nostro modello ha solo ~18M di parametri addestrati, mentre, ad esempio, XLM-R (una robusta base multilingue), ha ~559M di parametri ed è stato addestrato su diverse centinaia di GPU V100.

Questi modelli sono disponibili anche su Hub. Puoi testarli direttamente giocando con il widget Hosted Inference API nelle loro Model Cards o caricandoli direttamente nel tuo codice Python.

sahajBERT-NER

Model Card: https://hf.co/neuropark/sahajBERT-NER

from transformers import (
    AlbertForTokenClassification,
    TokenClassificationPipeline,
    PreTrainedTokenizerFast,
)

# Inizializza il tokenizer
tokenizer = PreTrainedTokenizerFast.from_pretrained("neuropark/sahajBERT-NER")

# Inizializza il modello
model = AlbertForTokenClassification.from_pretrained("neuropark/sahajBERT-NER")

# Inizializza la pipeline
pipeline = TokenClassificationPipeline(tokenizer=tokenizer, model=model)

raw_text = "এই ইউনিয়নে ৩ টি মৌজা ও ১০ টি গ্রাম আছে ।" # Cambiami
output = pipeline(raw_text)

sahajBERT-NCC

Model Card: https://hf.co/neuropark/sahajBERT-NER

from transformers import (
    AlbertForSequenceClassification,
    TextClassificationPipeline,
    PreTrainedTokenizerFast,
)

# Inizializza il tokenizer
tokenizer = PreTrainedTokenizerFast.from_pretrained("neuropark/sahajBERT-NCC")

# Inizializza il modello
model = AlbertForSequenceClassification.from_pretrained("neuropark/sahajBERT-NCC")

# Inizializza la pipeline
pipeline = TextClassificationPipeline(tokenizer=tokenizer, model=model)

raw_text = "এই ইউনিয়নে ৩ টি মৌজা ও ১০ টি গ্রাম আছে ।" # Cambiami
output = pipeline(raw_text)

Conclusioni

In questo post del blog, abbiamo discusso del metodo che consente il preallenamento collaborativo delle reti neurali con sahajBERT come primo esempio di successo nell’applicazione a un problema del mondo reale.

Cosa significa tutto ciò per la comunità ML più ampia? In primo luogo, ora è possibile eseguire il preallenamento distribuito su larga scala con i tuoi amici, e speriamo di vedere molti nuovi modelli interessanti che in precedenza erano meno fattibili da ottenere. Inoltre, il nostro risultato potrebbe essere importante per l’NLP multilingue, poiché ora la comunità di qualsiasi lingua può addestrare i propri modelli senza la necessità di risorse computazionali significative concentrate in un unico luogo.

Riconoscimenti

Il paper DeDLOC e l’esperimento di addestramento di sahajBERT sono stati creati da Michael Diskin, Alexey Bukhtiyarov, Max Ryabinin, Lucile Saulnier, Quentin Lhoest, Anton Sinitsin, Dmitry Popov, Dmitry Pyrkin, Maxim Kashirin, Alexander Borzunov, Albert Villanova del Moral, Denis Mazur, Ilia Kobelev, Yacine Jernite, Thomas Wolf e Gennady Pekhimenko. Questo progetto è il risultato di una collaborazione tra Hugging Face, Yandex Research, HSE University, MIPT, University of Toronto e Vector Institute.

Inoltre, vorremmo ringraziare Stas Bekman, Dmitry Abulkhanov, Roman Zhytar, Alexander Ploshkin, Vsevolod Plokhotnyuk e Roman Kail per il loro prezioso aiuto nella costruzione dell’infrastruttura di addestramento. Ringraziamo anche Abhishek Thakur per l’aiuto nella valutazione successiva e Tanmoy Sarkar con Omar Sanseviero, che ci hanno aiutato a organizzare l’esperimento collaborativo e hanno fornito regolari aggiornamenti di stato ai partecipanti durante il corso dell’esecuzione dell’addestramento.

Sotto, puoi vedere tutti i partecipanti dell’esperimento collaborativo:

Riferimenti

“Distributed Deep Learning in Open Collaborations”, ArXiv

Codice per gli esperimenti sahajBERT nel repository DeDLOC.