Il Transformer, aperto col cacciavite
Il pezzo sull’attenzione ha lasciato il meccanismo sul tavolo, smontato: domanda, chiave e valore, la softmax che pesa, la maschera causale, le teste multiple. Manca il montaggio - come questi pezzi si combinano in una macchina che genera testo. Questo pezzo lo fa seguendo le trecento righe di nanoGPT, il GPT minimo di Andrej Karpathy che la serie usa come cacciavite: un modello completo, licenza MIT, pensato per essere letto. Ogni componente che incontreremo ha un nome, un posto e poche righe di codice.
La promessa della serie si chiude qui per metà: il montaggio. Sappiamo che cosa entra (token e posizione), sappiamo come i token si mettono in relazione (l’attenzione). Resta da vedere come si alternano i pezzi, che cosa tiene in piedi una pila di dodici blocchi, e come dalla cima della pila esca la probabilità del prossimo token.
L’inventario: i numeri del config e il percorso
I numeri di nanoGPT stanno in cima al file: dodici blocchi, dodici teste, 768 dimensioni, un vocabolario di 50.304 voci; e il percorso sta in poche righe.
Il config di nanoGPT
dichiara la taglia del modello prima di costruirlo: una finestra di
contesto (nel codice block_size) di 1024 token, un vocabolario di 50.304 voci - la taglia
di GPT-2 (50.257) arrotondata a un multiplo di 64 per efficienza -,
dodici blocchi in pila, dodici teste di attenzione, e una
dimensione interna di 768 numeri per vettore. Sono i numeri del GPT-2
di base, che nanoGPT riproduce: il modello da 124 milioni di parametri
che il pezzo sull’embedding ha già incontrato parlando del trapianto
del vocabolario.
Il percorso del testo dentro il modello sta in poche righe della
funzione forward: la somma dei due embedding - quello del token e
quello della posizione, già visti nel pezzo sull’embedding - passa per
i dodici blocchi uno dopo l’altro, poi per un’ultima normalizzazione e
infine per la testa d’uscita, che produce i punteggi che la softmax
trasforma in probabilità. Ogni passo del percorso corrisponde a un
pezzo che la serie ha già aperto: la somma sta nel pezzo
sull’embedding, l’attenzione nel proprio, la softmax nel pezzo sulle
reti multistrato. Mancava l’ordine in cui si montano, ed è l’ordine
del codice.
Un blocco: attenzione e MLP, con la scorciatoia
Il blocco alterna due operazioni: l’attenzione mette in relazione le posizioni, l’MLP elabora ogni posizione da sola; intorno a ognuna una connessione residua, la somma dell’ingresso con l’uscita che lascia scorrere il segnale.
La classe Block di nanoGPT è la scatola che si ripete dodici volte,
ed è il blocco del Transformer; il suo
corpo è di quattro righe,
di cui queste sono le due che contano:
x = x + attn(ln_1(x))
x = x + mlp(ln_2(x))
Il blocco fa due operazioni, in ordine, e le circonda con due gesti. La prima operazione è l’attenzione multi-testa del pezzo precedente: mette in relazione le posizioni fra loro - è il punto dove la frase si lega. La seconda è l’MLP del Transformer, di cui parleremo fra un momento: elabora ogni posizione da sola. L’alternanza è il ritmo del Transformer: prima le relazioni, poi il pensiero locale, poi di nuovo le relazioni.
I due gesti sono la normalizzazione e la scorciatoia. La
normalizzazione di livello (ln_1, ln_2) riporta i vettori a una scala
comune prima di ogni operazione: i prodotti scalari dell’attenzione
tendono a crescere con la dimensione (è il motivo della divisione per
la radice quadrata visto nel pezzo sull’attenzione), e senza una messa in scala i
numeri finirebbero per esplodere lungo la pila. La connessione
residua è il x + che somma l’ingresso del sotto-blocco alla sua
uscita. La somma ha due effetti. Il primo è pratico: il blocco non
deve ricostruire la rappresentazione da zero, le basta correggerla - e
un’aggiunta è più facile da imparare di una riscrittura. Il secondo è
decisivo per l’addestramento: quando la retropropagazione risale la
pila, la derivata della somma fa passare il segnale d’errore per
intero, senza attraversare il sotto-blocco. Il gradiente ha una
scorciatoia, ed è questo che regge una pila profonda.
L’MLP: ogni posizione da sola
L’MLP allarga il vettore di quattro volte, lo passa per una curva e lo riporta alla dimensione di partenza: elabora ogni posizione indipendentemente, senza guardare le altre.
La classe MLP
fa tre cose, e si capiscono dal codice: una proiezione allarga il
vettore da 768 a 3.072 numeri - quattro volte la dimensione interna -,
una curva morbida li trasforma, e una seconda proiezione li riporta a
768. La curva è la GELU, una variante della ReLU del pezzo sulle
reti multistrato: zero
per i valori molto negativi, quasi lineare sopra, e una transizione
dolce in mezzo che tiene viva la pendenza.
Il punto è quello che l’MLP non fa: non guarda le altre posizioni. Ogni vettore della sequenza attraversa l’MLP da solo, con gli stessi pesi. Le relazioni fra posizioni le fa soltanto l’attenzione; l’MLP è il momento in cui ogni posizione “pensa” per conto proprio ciò che ha raccolto. L’alternanza dei due è il meccanismo completo: la frase si lega, ogni parola elabora quello che ha imparato, e il legame si rinnova.
La testa d’uscita: dall’ultimo vettore alla probabilità
L’ultimo strato riporta il vettore alla taglia del vocabolario, e la softmax ne fa una distribuzione di probabilità su ogni possibile prossimo token.
Quando la sequenza ha attraversato i dodici blocchi, l’ultimo vettore (quello dell’ultima posizione) deve diventare la scelta del prossimo token. Lo fa la testa d’uscita, una proiezione da 768 a 50.304 numeri: uno per ogni voce del vocabolario. Quei numeri sono i logits, le somme grezze che la softmax delle reti multistrato trasforma in probabilità - 50.304 valori positivi che sommano a 1. Il prossimo token non è ancora scelto: è pesato.
Il codice di nanoGPT ripete qui un dettaglio che la serie ha già incontrato. La testa d’uscita condivide la matrice con l’embedding dei token
- il weight tying del pezzo sull’embedding: entrare nel modello e uscirne passa dalla stessa tabella, letta al contrario. È la stessa economia che rende possibile il trapianto del vocabolario: cambiare le righe della matrice cambia insieme ingresso e uscita.
La generazione: un token alla volta
Il modello non scrive una risposta: a ogni passo pesa tutte le voci del vocabolario e ne sceglie una, poi ripete con la sequenza allungata - finché non ha prodotto i token richiesti.
La funzione generate di nanoGPT è il ciclo completo. A ogni passo il
modello riceve la sequenza finora prodotta, calcola le probabilità
dell’ultima posizione, e ne sceglie una. Il codice mostra tre
dettagli che contano. Il primo: se la sequenza è più lunga del blocco
di contesto, si tiene solo la coda - la finestra si taglia, e il costo
è quello quadratico del pezzo sull’attenzione. Il secondo: prima della
softmax i logits si dividono per la temperatura, il cursore che il
piccolo GPT di questa serie mostra dal vivo: una temperatura bassa
schiaccia le probabilità verso il candidato più alto e il testo diventa
prevedibile; alta le appiattisce e il testo diventa creativo, fino
all’insensato. Il terzo dettaglio è il più facile da trascurare: la
scelta non prende il candidato più probabile: è un campionamento,
cioè una scelta fatta secondo le probabilità - una moneta truccata,
non una risposta secca. Per questo
lo stesso modello, con lo stesso ingresso, può produrre testi diversi:
la probabilità decide quanto spesso ogni candidato vince, non quale
deve vincere.
Il token scelto si aggiunge alla sequenza, e il ciclo ricomincia: il modello legge ciò che ha appena scritto, pesa e sceglie di nuovo. È esattamente ciò che il pezzo sul tokenizzatore aveva descritto a parole - una rete che legge una sequenza di token e la allunga di un token - ora con il meccanismo per intero.
Potete smontarlo: il widget qui sotto usa il piccolo GPT della serie, gli stessi pesi e un seme fisso, e vi lascia togliere pezzi - la connessione residua, l’attenzione, l’MLP, i blocchi. A parità di seme e di pesi, se il testo cambia è colpa di quello che avete smontato.
Le tre difese del montaggio
Le connessioni residue, la normalizzazione e l’inizializzazione calibrata fanno sì che dodici blocchi in fila non si rompano: il segnale scorre, il gradiente risale, e i numeri restano in scala.
Dodici blocchi in pila non crollano sotto il loro stesso peso perché
il montaggio ha tre difese, e tutte e tre stanno nel codice. La prima
è la connessione residua: il gradiente risale per la scorciatoia
senza attraversare i sotto-blocchi, e il lavoro di ogni blocco resta
una correzione. La seconda è la normalizzazione: le scale restano sotto
controllo a ogni passaggio, e i numeri non esplodono né si spengono.
La terza è l’inizializzazione calibrata: l’ultima proiezione di
ogni blocco - la c_proj che riporta alla dimensione di partenza -
parte con una deviazione standard tanto più piccola
quanto più la pila è profonda:
0,02 diviso per la radice del doppio del numero di blocchi, circa
0,004 con dodici blocchi. Così, all’inizio, ogni blocco aggiunge un
ritocco minuscolo, e l’addestramento può decidere quanto farli
crescere.
Il GPT-2 di base ne ha dodici; il GPT-2 XL arriva a quarantotto blocchi e 1.558 milioni di parametri. La profondità non è gratis: ogni blocco aggiunge calcolo e memoria, e il costo sale con la finestra di contesto. Il pezzo sulle evoluzioni racconta come i modelli riducono quel costo senza rinunciare al montaggio.
Perché un modello piccolo
La serie apre un modello minimo perché è completo: ha gli stessi componenti dei grandi, in poche righe leggibili. E mentre GPT e Claude non dichiarano come sono fatti dentro, il modello piccolo si può aprire per intero.
Il cacciavite funziona perché il modello che apre è piccolo ma completo: nanoGPT contiene l’intero percorso - la somma dei due embedding, i blocchi di attenzione e MLP, la testa d’uscita, il campionamento - e ogni componente sta in poche righe. Un modello grande non è una macchina diversa: è la stessa, con più blocchi, più parametri e qualche trucco in più. I trucchi sono la materia dei prossimi due pezzi: la miscela di esperti e la cache di chiavi e valori, che riducono il costo che questo pezzo ha appena misurato. Una ragione in più chiude il cerchio: di DeepSeek e Qwen i rapporti tecnici dicono come sono fatti dentro, di GPT e Claude no. Il modello piccolo è l’unico di cui questa serie può dire per intero com’è fatto.
I concetti che questo articolo introduce
Sei voci coprono il montaggio: il blocco, i due gesti che lo sorreggono, il pensiero locale, la testa e la scelta del prossimo token.
| Concetto | Ambito | Che cos’è | Si lega a |
|---|---|---|---|
| Blocco del Transformer | machine-learning | L’unità che si ripete lungo la pila: una normalizzazione, l’attenzione multi-testa, una connessione residua, poi una seconda normalizzazione, l’MLP e una seconda connessione residua | compone il meccanismo di attenzione e l’MLP del Transformer; la sua pila è il corpo del modello di linguaggio |
| Connessione residua | machine-learning | La somma dell’ingresso di un sotto-blocco con la sua uscita: il segnale e il gradiente hanno una scorciatoia, e ogni blocco corregge invece di riscrivere | è nel blocco del Transformer; rende addestrabile la profondità (la profondità della rete) |
| Normalizzazione di livello | machine-learning | La messa in scala che riporta i vettori a una scala comune prima di ogni operazione, tenendo i numeri sotto controllo lungo la pila | precede il meccanismo di attenzione e l’MLP del Transformer nel blocco; stabilizza l’addestramento |
| MLP del Transformer | machine-learning | Lo strato che allarga ogni vettore di quattro volte, lo passa per una curva morbida e lo riporta alla dimensione di partenza, elaborando ogni posizione da sola | è nel blocco del Transformer; usa la GELU, variante della ReLU delle reti multistrato; non guarda le altre posizioni |
| Testa d’uscita | machine-learning | L’ultimo strato che riporta il vettore alla taglia del vocabolario, da cui la softmax produce le probabilità del prossimo token | condivide la matrice con l’embedding del token (weight tying); è seguita dalla softmax e dal campionamento |
| Campionamento | machine-learning | La scelta del prossimo token secondo le probabilità - con la temperatura che le schiaccia o le appiattisce - invece di prendere il candidato più probabile | segue la softmax; alimenta la generazione un token alla volta |
Fonti
Le affermazioni portanti vengono dal codice nanoGPT fissato al commit esaminato, letto per intero per questo pezzo.
- Improve and Manage,
serie-machine-learning,
GitHub, 2026 - il repository dei widget della serie: qui sta «Smonta il
modello» di questo pezzo (cartella
transformer/), insieme ai widget di tutti gli altri pezzi della serie. - Andrej Karpathy,
nanoGPT al commit
3adf61e154c3, licenza MIT, codice letto - ilmodel.pyche questo pezzo segue riga per riga: il config (block_size 1024, 12 blocchi, 12 teste, 768 dimensioni, vocabolario 50.304), la classeBlockcoi due sotto-blocchi e le connessioni residue, la classeMLP, la testa d’uscita col weight tying, l’inizializzazione calibrata dellec_proj, e la funzionegeneratecol campionamento e la temperatura. - Ashish Vaswani e colleghi, Attention Is All You Need, NeurIPS 2017, primaria aperta e letta (già in Fonti del pezzo sull’attenzione) - l’architettura: i blocchi che alternano multi-head attention e MLP, le connessioni residue intorno a ogni sotto-blocco e la normalizzazione di livello; qui richiamata per il montaggio, senza ripetere il meccanismo.
- Alec Radford e colleghi, Language Models are Unsupervised Multitask Learners, OpenAI, 2019, rapporto tecnico aperto e letto (già in Fonti del pezzo sul tokenizzatore) - i numeri del GPT-2 di base che nanoGPT riproduce: 12 blocchi, 124 milioni di parametri.