~Non~ Ripeterti

'Non ripeterti'

🤗 Filosofia di design di Transformers

“Non ripetere te stesso”, o DRY, è un principio ben noto dello sviluppo del software. Il principio viene dal libro “The pragmatic programmer”, uno dei libri più letti sul design del codice. Il messaggio semplice del principio ha un senso ovvio: non riscrivere una logica che esiste già altrove. Ciò garantisce che il codice rimanga sincronizzato, rendendolo più facile da mantenere e più robusto. Ogni modifica a questo schema logico influenzerà uniformemente tutte le sue dipendenze.

A prima vista, il design della libreria Transformers di Hugging Face sembra essere in totale contrasto con il principio DRY. Il codice del meccanismo di attenzione viene più o meno copiato oltre 50 volte in diversi file di modelli. A volte il codice dell’intero modello BERT viene copiato in altri file di modelli. Spesso costringiamo nuovi contributi di modelli identici ai modelli esistenti – a parte una piccola modifica logica – a copiare tutto il codice esistente. Perché facciamo questo? Siamo solo troppo pigri o sopraffatti per centralizzare tutte le parti logiche in un unico posto?

No, non siamo pigri: è una decisione molto consapevole quella di non applicare il principio di design DRY alla libreria Transformers. Invece, abbiamo deciso di adottare un diverso principio di design che chiamiamo la politica del singolo file di modello. La politica del singolo file di modello stabilisce che tutto il codice necessario per il passaggio in avanti di un modello sia in un unico file chiamato il file di modello. Se un lettore vuole capire come funziona BERT per l’elaborazione, dovrebbe guardare solo il file modeling_bert.py di BERT. Di solito rifiutiamo ogni tentativo di astrarre i sottocomponenti identici di modelli diversi in un nuovo posto centralizzato. Non vogliamo avere un attention_layer.py che includa tutti i possibili meccanismi di attenzione. Di nuovo, perché facciamo questo?

In breve, le ragioni sono queste:

  • 1. Transformers è costruito dalla comunità open-source.
  • 2. I nostri prodotti sono modelli e i nostri clienti sono utenti che leggono o modificano il codice del modello.
  • 3. Il campo dell’apprendimento automatico evolve estremamente velocemente.
  • 4. I modelli di apprendimento automatico sono statici.

1. Costruito dalla comunità open-source

Transformers è costruito per incentivare attivamente i contributi esterni. Un contributo è spesso una correzione di bug o un nuovo contributo di modello. Se viene trovato un bug in uno dei file di modelli, vogliamo rendere il più facile possibile per chi lo ha trovato correggerlo. C’è poco di più demotivante che correggere un bug solo per vedere che ha causato 100 errori in altri modelli.

Perché il codice del modello è indipendente da tutti gli altri modelli, è abbastanza facile per chiunque comprenda solo il modello con cui sta lavorando correggerlo. Allo stesso modo, è più facile aggiungere nuovo codice di modellazione e revisionare la corrispondente richiesta di pull (PR) se viene aggiunto solo un nuovo file di modello. Il contributore non deve capire come aggiungere nuove funzionalità a un meccanismo di attenzione centralizzato senza rompere i modelli esistenti. Il revisore può facilmente verificare che nessuno dei modelli esistenti sia rotto.

2. Il codice di modellazione è il nostro prodotto

Assumiamo che una quantità significativa di utenti della libreria Transformers non solo legga la documentazione, ma guardi anche il codice di modellazione effettivo e potenzialmente lo modifichi. Questa ipotesi è supportata dal fatto che la libreria Transformers è stata clonata oltre 10.000 volte e il paper Transformers è stato citato oltre mille volte. Pertanto, è di estrema importanza che qualcuno che legge il codice di modellazione di Transformers per la prima volta possa comprenderlo facilmente e potenzialmente adattarlo. Fornire tutti i componenti logici necessari in ordine in un singolo file di modellazione aiuta molto a migliorare la leggibilità e l’adattabilità. Inoltre, ci preoccupiamo molto della denominazione sensata delle variabili/metodi e preferiamo il codice espressivo/leggibile al codice efficiente in termini di caratteri.

3. L’apprendimento automatico sta evolvendo a una velocità vertiginosa

La ricerca nel campo dell’apprendimento automatico, e in particolare delle reti neurali, evolve estremamente velocemente. Un modello che era all’avanguardia un anno fa potrebbe essere superato oggi. Non sappiamo quale meccanismo di attenzione, incorporazione di posizione o architettura sarà il migliore tra un anno. Pertanto, non possiamo definire schemi logici standard che si applicano a tutti i modelli.

Come esempio, due anni fa si potrebbe avere definito il livello di auto attenzione di BERT come il livello di attenzione standard utilizzato da tutti i modelli Transformers. Logicamente, una funzione di attenzione “standard” potrebbe essere stata spostata in un file centrale attention.py. Ma poi sono arrivati livelli di attenzione che hanno aggiunto incorporamenti posizionali relativi in ogni livello di attenzione (T5), diverse forme di attenzione suddivisa (Reformer, Longformer, BigBird) e meccanismi di attenzione separati per l’incorporazione di posizione e parole (DeBERTa), ecc… Ogni volta avremmo dovuto chiederci se la funzione di attenzione “standard” avrebbe dovuto essere adattata o se sarebbe stato meglio aggiungere una nuova funzione di attenzione a attention.py. Ma come la chiamiamo? attention_with_positional_embd, reformer_attention, deberta_attention?

È pericoloso dare nomi generali ai componenti logici dei modelli di apprendimento automatico perché la percezione di ciò che questo componente rappresenta potrebbe cambiare o diventare obsoleta molto rapidamente. Ad esempio, il chunked attention corrisponde all’attention di GPTNeo, Reformer o BigBird? Il layer di attention è uno strato di auto-attention, uno strato di cross-attention o include entrambi? Tuttavia, se nominiamo i layer di attention con il nome del modello, dovremmo inserire direttamente la funzione di attention nel file di modellazione corrispondente.

4. I modelli di apprendimento automatico sono statici

La libreria Transformers è una collezione unificata e raffinata di modelli di apprendimento automatico creati da diversi team di ricerca. Di solito ogni modello di apprendimento automatico è accompagnato da un articolo e dal suo repository ufficiale su GitHub. Una volta che un modello di apprendimento automatico viene pubblicato, viene raramente adattato o modificato successivamente.

Invece, i team di ricerca tendono a pubblicare un nuovo modello basato su modelli precedenti, ma raramente apportano modifiche significative al codice già pubblicato. Questa è una realizzazione importante nella scelta dei principi di progettazione della libreria Transformers. Significa che una volta che un’architettura del modello è stata aggiunta a Transformers, i componenti fondamentali del modello non cambiano più. Spesso vengono trovati e corretti bug, i metodi e le variabili potrebbero essere rinominati e il formato di input o output del modello potrebbe essere leggermente modificato, ma i componenti principali del modello non cambiano più. Di conseguenza, la necessità di apportare modifiche globali a tutti i modelli in Transformers è significativamente ridotta, rendendo meno importante che ogni schema logico esista solo una volta poiché raramente viene modificato.

Una seconda realizzazione è che i modelli non dipendono l’uno dall’altro in modo bidirezionale. Modelli pubblicati più di recente potrebbero dipendere da modelli esistenti, ma è abbastanza ovvio che un modello esistente non può dipendere logicamente dal suo successore. Ad esempio, T5 è in parte basato su BERT e quindi il codice di modellazione di T5 potrebbe dipendere logicamente dal codice di modellazione di BERT, ma BERT non può dipendere logicamente in nessun modo da T5. Pertanto, non sarebbe logicamente corretto modificare la funzione di attention di BERT in modo che funzioni anche con la funzione di attention di T5: chiunque legga il layer di attention di BERT non dovrebbe dover sapere nulla su T5. Anche in questo caso, ciò si oppone alla centralizzazione dei componenti come il layer di attention in moduli a cui tutti i modelli possono accedere.

D’altra parte, il codice di modellazione dei modelli successivi può dipendere logicamente dal modello predecessore. Ad esempio, il codice di modellazione di DeBERTa-v2 dipende logicamente in qualche misura dal codice di modellazione di DeBERTa. La manutenibilità viene significativamente migliorata garantendo che il codice di modellazione di DeBERTa-v2 rimanga sincronizzato con quello di DeBERTa. Correggere un bug in DeBERTa dovrebbe idealmente correggere lo stesso bug in DeBERTa-v2. Come possiamo mantenere la politica del singolo file modello mentre assicuriamo che i modelli successivi rimangano sincronizzati con il modello predecessore?

Ora, spieghiamo perché mettiamo l’asterisco * {}^{\textbf{*}} * dopo “Ripetizione del codice”. Non copiamo e incolliamo ciecamente tutto il codice di modellazione esistente, anche se sembra così. Uno dei principali manutentori di Transformers, Sylvain Gugger, ha trovato un ottimo meccanismo che rispetta sia la politica del singolo file che mantiene i costi di manutenzione entro limiti ragionevoli. Questo meccanismo, chiamato in modo informale “il meccanismo di copia”, ci consente di contrassegnare i componenti logici, come una funzione di attention layer, con una dichiarazione # Copiato da <modello_predecessore>.<funzione>, che impone che il codice contrassegnato sia identico alla <funzione> del <modello_predecessore>. Ad esempio, questa riga in classe di DeBERTa-v2 impone che l’intera classe sia identica alla classe di DeBERTa, ad eccezione del prefisso DeBERTav2. In questo modo, il meccanismo di copia rende il codice di modellazione molto facile da capire, riducendo significativamente la manutenzione. Se viene modificato del codice in una funzione di un modello predecessore a cui fa riferimento una funzione del modello successore, sono disponibili strumenti che correggono automaticamente la funzione del modello successore.

Svantaggi

Chiaramente, ci sono anche svantaggi nella politica del singolo file, due dei quali vogliamo menzionare rapidamente qui.

Uno dei principali obiettivi di Transformers è fornire un’API unificata sia per l’inferenza che per l’addestramento di tutti i modelli in modo che un utente possa passare rapidamente tra modelli diversi nella propria configurazione. Tuttavia, assicurare un’API unificata tra i modelli è molto più difficile se i file di modellazione non possono utilizzare schemi logici astratti. Risolviamo questo problema eseguendo molte prove (circa 20.000 prove vengono eseguite quotidianamente al momento della scrittura di questo post sul blog) per garantire che i modelli seguano un’API coerente. In questo caso, la politica del singolo file richiede da parte nostra una rigorosa revisione delle aggiunte di modelli e test.

Secondo, esiste molta ricerca su un singolo componente di un modello di apprendimento automatico. Ad esempio, i team di ricerca investigano nuove forme di meccanismo di attenzione che potrebbero essere applicate a tutti i modelli pre-addestrati esistenti, come è stato fatto in “Ripensare l’attenzione con Performers”. Come dovremmo incorporare tale ricerca nella libreria Transformers? È effettivamente problematico. Dovremmo cambiare tutti i modelli esistenti? Questo andrebbe contro i punti 3 e 4 come sopra citati. Dovremmo aggiungere oltre 100 nuovi file di modellazione, ciascuno con il prefisso Performer...? Questo sembra assurdo. In un caso del genere, purtroppo non c’è una buona soluzione e optiamo per non integrare l’articolo in Transformers in questo caso. Se l’articolo avesse ottenuto molto più successo e inclusi checkpoint pre-addestrati robusti, avremmo probabilmente aggiunto nuovi file di modellazione dei modelli più importanti come modeling_performer_bert.py disponibili.

Conclusioni

Tutto sommato, presso 🤗 Hugging Face siamo convinti che la politica del singolo file sia la giusta filosofia di codifica per Transformers.

Cosa ne pensi? Se hai letto fino a qui, saremmo molto interessati a sentire la tua opinione! Se desideri lasciare un commento, visita il post sul forum corrispondente qui .