Dal loro introduzione nel 2017I trasformatori sono emersi come una forza di spicco nel campo del Machine Learning, rivoluzionandone le capacità traduzione principale E completamento automatico Servizi.
Recentemente, la popolarità dei trasformatori è aumentata ancora di più con l’avvento di modelli linguistici di grandi dimensioni come quello di OpenAI ChatGPT, GPT-4e quello di Meta Lama. Questi modelli, che hanno raccolto enorme attenzione ed entusiasmo, sono tutti costruiti sulla base dell’architettura del trasformatore. Sfruttando la potenza dei trasformatori, questi modelli hanno raggiunto notevoli progressi nella comprensione e nella generazione del linguaggio naturale; esponendoli al grande pubblico.
Nonostante molti buone risorse che analizzano il funzionamento dei trasformatori, mi sono trovato in una posizione in cui ho capito come funzionava matematicamente la meccanica, ma ho trovato difficile spiegare come funziona un trasformatore in modo intuitivo. Dopo aver condotto numerose interviste, parlato con i miei colleghi e tenuto un discorso lampo sull’argomento, sembra che molte persone condividano questo problema!
In questo post del blog, mirerò a fornire una spiegazione di alto livello di come funzionano i trasformatori senza fare affidamento su codice o matematica. Il mio obiettivo è evitare confusione nel gergo tecnico e nei confronti con le architetture precedenti. Anche se cercherò di mantenere le cose il più semplici possibile, non sarà facile dato che i trasformatori sono piuttosto complessi, ma spero che fornisca un’intuizione migliore di cosa fanno e come lo fanno.
Un trasformatore è un tipo di architettura di rete neurale che ben si adatta ad attività che implicano l’elaborazione di sequenze come input. Forse l’esempio più comune di sequenza in questo contesto è una frase, che possiamo considerare come un insieme ordinato di parole.
Lo scopo di questi modelli è creare una rappresentazione numerica per ciascun elemento all’interno di una sequenza; incapsulare informazioni essenziali sull’elemento e sul contesto circostante. Le rappresentazioni numeriche risultanti possono quindi essere trasmesse alle reti a valle, che possono sfruttare queste informazioni per eseguire vari compiti, tra cui la generazione e la classificazione.
Creando rappresentazioni così ricche, questi modelli consentono alle reti a valle di comprendere meglio i modelli e le relazioni sottostanti all’interno della sequenza di input, il che migliora la loro capacità di generare output coerenti e contestualmente rilevanti.
Il vantaggio principale dei trasformatori risiede nella loro capacità di gestire dipendenze a lungo raggio all’interno di sequenze, oltre ad essere altamente efficienti; in grado di elaborare sequenze in parallelo. Ciò è particolarmente utile per attività come la traduzione automatica, l’analisi del sentiment e la generazione di testo.
Per alimentare un input in un trasformatore, dobbiamo prima convertirlo in una sequenza di token; un insieme di numeri interi che rappresentano il nostro input.
Poiché i trasformatori sono stati applicati per la prima volta nel dominio della PNL, consideriamo prima questo scenario. Il modo più semplice per convertire una frase in una serie di token è definire a vocabolario che funge da tabella di ricerca, mappando le parole in numeri interi; possiamo riservare un numero specifico per rappresentare qualsiasi parola non contenuta in questo vocabolario, in modo da poter sempre assegnare un valore intero.
In pratica, questo è un modo ingenuo di codificare il testo, come parole come gatto E gatti sono trattati come simboli completamente diversi, nonostante siano descrizioni singolari e plurali dello stesso animale! Per superare questo problema, diverse strategie di tokenizzazione, come codifica della coppia di byte – sono stati ideati che spezzano le parole in pezzi più piccoli prima di indicizzarle. Inoltre, è spesso utile aggiungere token speciali per rappresentare caratteristiche come l’inizio e la fine di una frase, per fornire ulteriore contesto al modello.
Consideriamo l’esempio seguente, per comprendere meglio il processo di tokenizzazione.
“Ciao a tutti, non è bello il tempo oggi a Drosval?”
Drosval è un nome generato da GPT-4 utilizzando il seguente prompt: “Puoi creare un nome di luogo immaginario a cui sembra che possa appartenere L’universo Drenai di David Gemmell?“; scelto deliberatamente in quanto non dovrebbe apparire nel vocabolario di nessun modello addestrato.
Usando il bert-base-uncased
tokenizzatore dal libreria di trasformatoriquesto viene convertito nella seguente sequenza di token:
I numeri interi che rappresentano ciascuna parola cambieranno in base alla specifica strategia di training e tokenizzazione del modello. Decodificandolo, possiamo vedere la parola che ciascun token rappresenta:
È interessante notare che possiamo vedere che questo non è lo stesso del nostro input. Sono stati aggiunti token speciali, la nostra abbreviazione è stata divisa in più token e il nome del nostro luogo immaginario è rappresentato da diversi “pezzi”. Poiché abbiamo utilizzato il modello “uncased”, abbiamo perso anche tutto il contesto delle maiuscole.
Tuttavia, anche se abbiamo utilizzato una frase per il nostro esempio, i trasformatori non si limitano agli input di testo; anche questa architettura ha ha dimostrato buoni risultati nei compiti di visione. Per convertire un’immagine in una sequenza, gli autori di ViT hanno suddiviso l’immagine in patch di 16×16 pixel non sovrapposte e le hanno concatenate in un lungo vettore prima di passarlo al modello. Se stessimo utilizzando un trasformatore in un sistema Recommender, un approccio potrebbe essere quello di utilizzare gli ID oggetto dell’ultimo N elementi esplorati da un utente come input per la nostra rete. Se riusciamo a creare una rappresentazione significativa dei token di input per il nostro dominio, possiamo inserirla in una rete di trasformazione.
Incorporando i nostri token
Una volta che abbiamo una sequenza di numeri interi che rappresenta il nostro input, possiamo convertirli in incastri. Gli incorporamenti sono un modo di rappresentare informazioni che possono essere facilmente elaborate da algoritmi di apprendimento automatico; mirano a catturare il significato del token codificato in un formato compresso, rappresentando l’informazione come una sequenza di numeri. Inizialmente, gli incorporamenti vengono inizializzati come sequenze di numeri casuali e durante l’addestramento vengono apprese rappresentazioni significative. Tuttavia, questi incorporamenti hanno un limite intrinseco: non tengono conto del contesto in cui appare il token. Ci sono due aspetti di questo.
A seconda dell’attività, quando incorporiamo i nostri token, potremmo anche voler preservare l’ordine dei nostri token; questo è particolarmente importante in domini come la PNL, altrimenti essenzialmente ci ritroveremo con a sacco di parole approccio. Per superare questo, applichiamo codifica posizionale ai nostri incorporamenti. Mentre ci sono molteplici modi per creare incorporamenti posizionalil’idea principale è che abbiamo un altro insieme di incorporamenti che rappresentano la posizione di ciascun token nella sequenza di input, che sono combinati con i nostri incorporamenti di token.
L’altro problema è che i token possono avere significati diversi a seconda dei token che li circondano. Considera le seguenti frasi:
È buio, chi ha spento la luce?
Wow, questo pacco è davvero leggero!
Ecco, la parola leggero viene utilizzato in due contesti diversi, dove ha significati completamente diversi! Tuttavia, è probabile che, a seconda della strategia di tokenizzazione, l’incorporamento sarà lo stesso. In un trasformatore, questo è gestito da its Attenzione meccanismo.
Forse il meccanismo più importante utilizzato dall’architettura del trasformatore è noto come Attenzioneche consente alla rete di comprendere quali parti della sequenza di input sono le più rilevanti per un determinato compito. Per ogni token nella sequenza, il meccanismo di attenzione identifica quali altri token sono importanti per comprendere il token corrente nel contesto dato. Prima di esplorare come questo viene implementato all’interno di un trasformatore, iniziamo in modo semplice e proviamo a capire cosa il meccanismo dell’attenzione sta cercando di ottenere concettualmente, per costruire la nostra intuizione.
Un modo per comprendere l’attenzione è pensarla come un metodo che sostituisce ogni incorporamento di token con un incorporamento che include informazioni sui token vicini; invece di utilizzare lo stesso incorporamento per ogni token indipendentemente dal suo contesto. Se sapessimo quali token sono rilevanti per il token corrente, un modo per catturare questo contesto sarebbe creare una media ponderata – o, più in generale, una combinazione lineare – di questi incorporamenti.
Consideriamo un semplice esempio di come potrebbe apparire una delle frasi che abbiamo visto prima. Prima che venga applicata l’attenzione, gli incorporamenti nella sequenza non hanno il contesto dei loro vicini. Pertanto, possiamo visualizzare l’incorporamento della parola leggero come la seguente combinazione lineare.
Qui possiamo vedere che i nostri pesi sono solo la matrice identità. Dopo aver applicato il nostro meccanismo di attenzione, vorremmo apprendere una matrice di peso tale da poter esprimere la nostra leggero incorporamento in un modo simile al seguente.
Questa volta, viene dato un peso maggiore agli incorporamenti che corrispondono alle parti più rilevanti della sequenza per il token scelto; che dovrebbe garantire che il contesto più importante venga catturato nel nuovo vettore di incorporamento.
Gli incorporamenti che contengono informazioni sul loro contesto attuale sono talvolta noti come incorporamenti contestualizzati, e questo è in definitiva ciò che stiamo cercando di creare.
Ora che abbiamo una comprensione di alto livello di ciò che l’attenzione sta cercando di ottenere, esploriamo come questo viene effettivamente implementato nella sezione seguente.
Esistono molteplici tipi di attenzione e le differenze principali risiedono nel modo in cui vengono calcolati i pesi utilizzati per eseguire la combinazione lineare. Qui considereremo attenzione al prodotto scalarecome introdotto nel carta originalepoiché questo è l’approccio più comune. In questa sezione, supponiamo che tutti i nostri incorporamenti siano stati codificati posizionalmente.
Ricordando che il nostro obiettivo è creare incorporamenti contestualizzati utilizzando combinazioni lineari dei nostri incorporamenti originali, iniziamo in modo semplice e assumiamo di poter codificare tutte le informazioni necessarie necessarie nei nostri vettori di incorporamento appresi, e tutto ciò che dobbiamo calcolare sono i pesi.
Per calcolare i pesi, dobbiamo prima determinare quali token sono rilevanti tra loro. Per raggiungere questo obiettivo, dobbiamo stabilire una nozione di somiglianza tra due incorporamenti. Un modo per rappresentare questa somiglianza è utilizzare il prodotto scalare, dove vorremmo imparare gli incorporamenti in modo tale che punteggi più alti indichino che due parole sono più simili.
Poiché, per ogni token, dobbiamo calcolare la sua rilevanza con ogni altro token nella sequenza, possiamo generalizzare questo a una moltiplicazione di matrici, che ci fornisce la nostra matrice dei pesi; che vengono spesso definiti come punteggi di attenzione. Per garantire che la somma dei nostri pesi sia pari a uno, applichiamo anche il Funzione SoftMax. Tuttavia, poiché le moltiplicazioni di matrici possono produrre numeri arbitrariamente grandi, ciò potrebbe far sì che la funzione SoftMax restituisca gradienti molto piccoli per punteggi di attenzione elevati; che può portare al problema del gradiente evanescente durante l’allenamento. Per contrastare questo problema, i punteggi di attenzione vengono moltiplicati per un fattore di scala, prima di applicare SoftMax.
Ora, per ottenere la nostra matrice di incorporamento contestualizzata, possiamo moltiplicare i nostri punteggi di attenzione per la nostra matrice di incorporamento originale; che equivale a prendere combinazioni lineari dei nostri incorporamenti.
Fonte: towardsdatascience.com