Come si costruisce un LLM (Large Language Model, modello linguistico di grandi dimensioni)

Dal testo grezzo al modello che ragiona

Un LLM è una funzione che riceve del testo e restituisce una probabilità per ogni possibile token successivo. Tutto il resto — il «sapere», la capacità di rispondere, il ragionamento — è il risultato di come quella funzione viene aggiustata, numero per numero, su quantità enormi di esempi. La guida risponde a quattro domande, nell'ordine in cui conviene farsele: come una frase entra nel modello e ne esce il token successivo, con un modello in miniatura da seguire numero per numero; come un errore su un singolo token diventa una modifica a miliardi di pesi; come sono fatti i dati; perché servono più fasi di addestramento e che problema risolve ciascuna. I dettagli tecnici (tokenizer, attention, RoPE, i conti dei 7 miliardi) stanno in una parte di approfondimento alla fine, da leggere quando il quadro è chiaro.

Pre-training
Post-training
«sa tutto, non sa comportarsi»«si comporta, ragiona, costa poco»

Parte I

Il meccanismo: una funzione che prevede il token successivo, e come la si corregge

Capitolo 1 · La frase

Come una frase entra nel modello e ne esce il token successivo

Scrivo «il gatto nero dorme sul» e il modello completa con «divano». Per farlo deve aver usato tutta la frase: «dorme» gli dice che si parla di un posto in cui si dorme, «sul» che manca un nome di luogo. In che modo, concretamente, cinque parole diventano quella previsione?

Per rispondere non basta descrivere il transformer: bisogna arrivarci. Questo capitolo parte dal modo più ingenuo di prevedere una parola (contare), mostra dove si rompe, e introduce un'idea alla volta — i vettori, la rete neurale, la memoria, l'attention — ciascuna come rimedio al limite della precedente. Alla fine il transformer non sarà un oggetto misterioso ma l'ultimo passo di una sequenza di rimedi, e un modello in miniatura lo eseguirà numero per numero sulla nostra frase.

Prima di tutto: dal testo ai numeri

Qualunque modello di linguaggio comincia allo stesso modo, perché una funzione matematica non può lavorare su lettere. Primo passo: la frase viene spezzata in token, pezzi di testo presi da un vocabolario fisso, e ogni token è sostituito dal suo numero d'ordine nel vocabolario, l'ID. In un modello vero i token sono frammenti di parola (il vocabolario ha 30.000–250.000 voci); nei nostri esempi, per leggibilità, un token è una parola intera. «il gatto nero dorme sul» diventa [1, 2, 4, 5, 7].

Secondo passo: ogni ID viene sostituito da un vettore, cioè una lista di d numeri, letta da una tabella che ha una riga per ogni token del vocabolario: la matrice di embedding E. L'ID 2 diventa la riga 2 di E. Perché non lavorare direttamente con gli ID? Perché un ID è un'etichetta: che «gatto» sia 2 e «cane» sia 3 non dice che si somigliano. Un vettore invece può dirlo: se «gatto» e «cane» hanno vettori simili, tutto ciò che il modello impara sull'uno vale anche per l'altro. Vedremo tra poco che è proprio questo il motivo per cui i vettori servono.

Un esempio con due soli numeri rende l'idea concreta. Immagina vettori da due soli numeri, ognuno con un significato preciso: il primo dice quanto è regale, il secondo quanto è femminile, tutti e due da 0 a 1.

ParolaQuanto è regaleQuanto è femminileVettore
uomo0,10,1[0,1 ; 0,1]
donna0,10,9[0,1 ; 0,9]
re0,90,1[0,9 ; 0,1]
regina0,90,9[0,9 ; 0,9]

Ora il famoso conto re − uomo + donna, un passo alla volta.

Calcolo · re − uomo + donna

re − uomo=[0,9 − 0,1 ; 0,1 − 0,1] = [0,8 ; 0]
Hai tolto «l'essere un uomo qualunque»: resta solo la regalità.
+ donna=[0,8 + 0,1 ; 0 + 0,9] = [0,9 ; 0,9]
Hai aggiunto «l'essere donna»: è proprio il vettore di regina.

Sommare e togliere numeri, qui, vuol dire aggiungere e togliere caratteristiche. Nel laboratorio puoi rifare il conto sul disegno e provarlo con altre coppie.

Laboratorio: re − uomo + donna sul piano

valori illustrativi

Premi i pulsanti da 1 a 4 nell'ordine e guarda dove si sposta il punto; poi scegli un'altra coppia e ripeti.

Coppia

I numeri sono inventati, scelti perché il conto torni esatto. In un modello vero il vettore ha migliaia di numeri senza nome, e il conto arriva solo vicino alla parola giusta.

E nei modelli veri? Il vettore di ogni token non ha 2 numeri ma migliaia. Quanti, lo decide chi progetta il modello prima di allenarlo, ed è un compromesso: più numeri lasciano spazio a più sfumature ma costano più calcoli e più memoria. GPT-2 piccolo ne usa 768, i modelli da 7 miliardi di pesi come Llama 2 e Mistral 4.096 (il valore che ritroverai negli esempi di questa guida, che usa come modello di riferimento Llama 2 7B: è aperto, di una taglia che si può eseguire sul proprio computer e ben documentato), GPT-3 12.288. Si scelgono numeri «tondi» per il computer, come 4.096 = 212, perché le schede grafiche fanno i conti a blocchi di 64 o 128 numeri e così non sprecano spazio.

Nessuno dà a questi numeri un nome come «regale» o «femminile»: all'inizio sono numeri a caso, e il modello li sistema da solo durante l'allenamento, leggendo moltissimo testo, con il ciclo del capitolo 2. Alla fine le parole usate in modo simile hanno vettori simili, e alcune direzioni prendono un significato, ma solo in modo approssimato: per questo re − uomo + donna arriva vicino a regina, non esattamente sopra.

Fin qui nessuna previsione: abbiamo solo una lista di punti in uno spazio a d dimensioni, uno per token, ciascuno ignaro degli altri. Il problema da risolvere è: data questa lista, produrre una probabilità per ogni token del vocabolario come prossimo token. Tutto ciò che segue sono modi diversi di costruire questa funzione.

Il modello più semplice: contare

Se dovessi prevedere la parola successiva senza nessuna teoria, che cosa farei?

Conterei. Prenderei un testo molto lungo e, per ogni parola, annoterei quante volte è seguita da ciascun'altra: dopo «il» viene «gatto» 40 volte, «cane» 35, «pesce» 10… Per prevedere, guardo l'ultima parola e leggo la riga corrispondente della tabella, trasformata in percentuali. È un modello a bigrammi (coppie di parole), ed è esattamente il modello del capitolo 3: una tabella 15 × 15, riga = parola attuale, colonna = parola successiva, e la «previsione» è leggere una riga. Funziona, e in un certo senso contiene già i passi 1 e 5 del transformer: dal testo agli ID, e da una riga di numeri a una distribuzione di probabilità.

Ma dopo «sul» questo modello propone «divano», «letto», «tavolo» e «tetto» con le stesse proporzioni che ha visto nel testo, qualunque cosa ci fosse prima. Non sa che la frase parlava di dormire. Per saperlo dovrebbe guardare più indietro: contare le terne (dopo «dorme sul» viene…), le quaterne, e così via. E qui si rompe.

Perché contare non basta

Due motivi, e il transformer nasce per rispondere a entrambi.

1 · La tabella esplode. Con un vocabolario di V token e un contesto di n token, le combinazioni possibili sono Vn. Già con 32.000 token e un contesto di appena 3, sono 32.000³ ≈ 3 × 10¹³ righe: più di quante parole esistano in tutti i testi mai scritti. Quasi tutte le combinazioni non compaiono mai nel corpus, quindi il modello non ha nulla da contare e resta muto davanti a frasi perfettamente normali. Un contesto di migliaia di token, come quello degli LLM attuali, è impensabile per una tabella.

Da dove viene Vn. Ogni riga della tabella è un contesto possibile, cioè una sequenza di n token. Per riempire la prima posizione puoi scegliere uno qualsiasi dei V token; per ognuna di queste scelte, la seconda posizione ne ammette di nuovo V; e così via fino alla n-esima. Le scelte si moltiplicano: V × V × … × V, con n fattori, cioè Vn. Con V = 3 token e n = 2 sono 3 × 3 = 9 contesti; con n = 3 sono 3 × 3 × 3 = 27. Ogni nuova parola di contesto moltiplica le righe per V, non le aumenta di V: è per questo che la crescita è esponenziale. A ogni riga poi si associano V colonne (la parola successiva), quindi le celle da riempire sono Vn+1.

Calcolo · quante righe ha la tabella

contesti possibili=V × V × … × V = Vn
una scelta tra V token per ognuna delle n posizioni
V = 3, n = 2=3 × 3 = 9
V = 3, n = 3=3 × 3 × 3 = 27
V = 32.000, n = 3=32.0003 ≈ 3 × 1013 righe
più di quante parole esistano in tutti i testi mai scritti

Le celle da riempire sono una per colonna: Vn+1.

Laboratorio: la tabella disegnata

vocabolario giocattolo

Ogni riga è un contesto, ogni colonna la parola successiva. Le celle colorate sono quelle che un testo di sole 12 parole è riuscito a riempire: le altre restano a zero, e il modello non può dire nulla su quelle righe. Aumenta il contesto n e guarda la tabella allungarsi mentre le celle piene restano le stesse.

Vocabolario V
Contesto n

Le celle piene sono scelte a caso, solo per illustrare. Il punto è la proporzione: un testo finito riempie un numero finito di celle, mentre la tabella cresce a ogni parola di contesto in più.

Calcolatore: quanto sarebbe grande la tabella dei conteggi

aritmetica

2 · Non generalizza. Anche se la tabella ci stesse, «il gatto dorme sul» e «il cane dorme sul» sarebbero due righe separate, contate separatamente. Aver visto mille volte che dopo «il gatto dorme sul» viene «divano» non dice nulla su «il cane dorme sul». Un essere umano, invece, trasferisce: gatto e cane sono entrambi animali che dormono. Serve un modo per cui ciò che si impara su una parola valga anche per le parole simili, e un modo per cui la previsione dipenda dal contenuto del contesto, non dalla sua forma esatta.

I vettori del secondo passo risolvono il secondo problema: se «gatto» e «cane» hanno vettori vicini, una funzione che lavora sui vettori darà risultati vicini per i due. Resta da costruire quella funzione, che prenda in ingresso i vettori del contesto e restituisca i punteggi del token successivo. Lo strumento è la rete neurale.

La rete neurale, e il primo modello a finestra fissa

Che cos'è, in concreto, una rete neurale? Ne basta una definizione da tre righe.

Un neurone è una funzione che riceve dei numeri, li moltiplica ciascuno per un proprio peso, somma tutto e applica una soglia: se la somma è negativa restituisce 0, altrimenti la somma stessa (la funzione ReLU, Rectified Linear Unit). Con i pesi giusti un neurone diventa un rilevatore: «c'è la caratteristica dormire ma non la caratteristica luogo?» è un neurone con peso +1 su «dormire», −1 su «luogo», e la ReLU che spegne tutto il resto. Uno strato è un gruppo di neuroni che leggono gli stessi ingressi, ciascuno con i propri pesi; una rete è una sequenza di strati in cui l'uscita di uno è l'ingresso del successivo. I pesi non li scrive nessuno: si parte da numeri casuali e si aggiustano con il procedimento del capitolo 2. Qualunque cosa faccia un LLM, è fatta di questi mattoni: moltiplicazioni per pesi, somme, soglie.

Esci di casa e decidi se portare l'ombrello. Senza pensarci guardi tre cose: quante nuvole ci sono, che cosa dice la previsione, quanto vento tira. Ognuna la puoi misurare da 0 (per niente) a 1 (moltissimo).

Non tutte contano allo stesso modo. La previsione di pioggia conta molto, le nuvole un po' meno. Il vento conta al contrario: con il vento forte l'ombrello si rovescia, e ti passa la voglia di portarlo. Quanto conta ogni cosa si chiama peso: un numero grande se conta molto, vicino a zero se conta poco, negativo se spinge verso il no.

Un neurone artificiale fa esattamente questo conto. Moltiplica ogni ingresso per il suo peso, somma tutto e confronta il totale con una soglia: se il totale la supera, il neurone «si accende» e la risposta è sì. È un votante che ascolta tre consiglieri, dando a ognuno più o meno fiducia.

Laboratorio: il neurone dell'ombrello

matematica reale

Muovi il cursore del vento verso destra e guarda quando il neurone si spegne; poi prova a cambiare i pesi e la soglia.

Che tempo fa (gli ingressi)
Quanto conta ognuno per te (i pesi)

Nel disegno, lo spessore di ogni freccia è il peso: più è spessa, più quell'ingresso conta. Le frecce verdi spingono verso il sì, quelle rosse tratteggiate (peso negativo) verso il no. I numeri sono quelli veri del conto: un neurone artificiale fa proprio questo, niente di più.

Un neurone da solo sa fare poco. Il trucco è metterne tanti in fila, a strati: quello che esce dai neuroni di uno strato diventa l'ingresso dei neuroni dello strato dopo. Così il secondo strato non ragiona più su «nuvole» e «vento», ma su idee già un po' elaborate dal primo.

Nell'esempio qui sotto i tre ingressi vanno a due neuroni nel mezzo. Il primo dà molto peso a nuvole e pioggia: potremmo chiamarlo «sembra brutto tempo». Il secondo dà molto peso al vento: potremmo chiamarlo «è scomodo». Il neurone finale ascolta questi due e decide: ombrello sì o no.

Questa volta ogni neurone non dice solo sì o no, ma quanto è acceso, da 0 a 1, come una luce con il regolatore: il suo valore è il totale pesato, ma mai sotto 0 e mai sopra 1. Alla fine, se il neurone dell'ombrello arriva almeno a 0,5, si prende l'ombrello.

Laboratorio: una rete 3 → 2 → 1

matematica reale

Scegli un tempo o muovi i tre cursori e segui i numeri che scorrono da sinistra a destra, strato dopo strato.

I pesi sono scelti a mano perché la rete dia risposte sensate; in una rete vera li trova l'allenamento (capitolo 2). Anche i nomi «sembra brutto tempo» ed «è scomodo» li abbiamo dati noi, guardando i pesi: la rete non li conosce.

Le parole che si sentono in giro. I cerchi del disegno si chiamano nodi: sono i neuroni. Le linee che li collegano si chiamano archi: ogni arco porta un peso. Questa rete ha 8 pesi (6 tra ingressi e strato di mezzo, 2 verso l'uscita). Lo strato di mezzo si dice nascosto perché non lo si vede né all'ingresso né all'uscita. Una rete con tanti strati nascosti si dice profonda: è il «deep» di deep learning. Una rete grande ha miliardi di pesi, ma ogni neurone fa sempre il conto del laboratorio: moltiplica, somma, decide quanto accendersi.

In una rete vera nessuno decide che cosa debba fare un neurone nascosto. I «significati» dei neuroni li trova la rete da sola durante l'allenamento, e spesso non hanno un nome semplice. Per vedere una rete vera, abbastanza piccola da disegnarla tutta (8 ingressi, 6 neuroni nascosti, 4 uscite, 82 pesi), apri la guida sull'auto che impara a guidare, nella sezione sulla rete neurale.

Il primo modello neurale di linguaggio (Bengio e colleghi, 2003) fa la cosa più diretta: prende i vettori degli ultimi n token, li mette uno accanto all'altro in un unico vettore lungo n × d, lo passa attraverso una rete di uno o due strati, e dall'ultimo strato esce un punteggio per ogni token del vocabolario. Risolve la generalizzazione: «gatto» e «cane» entrano con vettori simili, quindi escono con previsioni simili, e la rete ha pochi milioni di pesi invece di 10¹³ celle. Ma eredita dalla tabella un limite: la finestra è fissa. Con n = 4 il modello non vede mai il quinto token indietro, e i pesi che leggono «il token due posizioni fa» sono diversi da quelli che leggono «il token tre posizioni fa», quindi la stessa parola spostata di un posto è, per la rete, un ingresso completamente diverso.

ultimi n token
finestra fissa
→ n vettori affiancati
n × d numeri
→ rete (1–2 strati)→ un punteggio per token del vocabolario

Facciamolo con numeri piccoli, perché qui si nasconde la prima domanda che viene a tutti: come si mettono insieme i vettori di più token? Nel modello a finestra fissa la risposta è la più semplice possibile: si concatenano. Se «il» ha vettore [1, 0] e «gatto» ha vettore [0, 1], l'ingresso della rete per il contesto «il gatto» è il vettore [1, 0, 0, 1]: le due coordinate del primo seguite dalle due del secondo. Non è una somma (la somma darebbe [1, 1], e non si saprebbe più chi era il primo e chi il secondo) e non ha nessuna proprietà matematica speciale: è mettere i numeri in fila. Il primo strato della rete deve quindi avere 4 ingressi, uno per numero.

Che cos'è W₁. Lo strato è fatto di neuroni, e ogni neurone ha un peso per ciascuno dei 4 ingressi. Se i neuroni sono 3, i pesi sono 3 × 4 = 12 numeri, e si scrivono in una tabella con una riga per neurone e una colonna per ingresso: la matrice W₁. Il conto dello strato è «ogni neurone moltiplica gli ingressi per la sua riga e somma», cioè il prodotto matrice × vettore h = W₁x: una tabella 3 × 4 per una colonna di 4 numeri dà una colonna di 3 numeri.

La regola delle dimensioni

La regola delle dimensioni è sempre la stessa: il numero di colonne di W deve essere uguale alla lunghezza del vettore che entra, il numero di righe è la lunghezza di quello che esce.

Il secondo strato riceve i 3 numeri e deve produrre un punteggio per ciascuno dei 5 token del vocabolario: W₂ è 5 × 3. I numeri dentro W₁ e W₂ non li sceglie nessuno: qui sotto sono stati trovati con il procedimento del capitolo 2 su cinque esempi e poi arrotondati a una cifra.

Calcolo · le dimensioni della rete a finestra fissa

ingresso x=[1, 0] ⊕ [0, 1] = [1, 0, 0, 1]
due vettori da 2 numeri messi in fila: 4 ingressi
pesi di W1=3 × 4 = 12
una riga per neurone, una colonna per ingresso
h = W1x=[3 × 4] · [4] = [3]
punteggi = W2h=[5 × 3] · [3] = [5]
un punteggio per ciascuno dei 5 token del vocabolario

Laboratorio: la rete a finestra fissa, numero per numero

matematica reale · pesi trovati con il training, arrotondati

Vocabolario di 5 token con vettori di 2 numeri. Scegli i due token del contesto e segui il conto: concatenazione, primo strato (W₁, 3 neuroni con ReLU), secondo strato (W₂, un punteggio per token), softmax. Poi passa a una finestra di 3 token e guarda che cosa succede a W₁.

1 · I vettori dei token (tabella E, 5 × 2) e la concatenazione
2 · Primo strato: h = ReLU(W₁ x)
3 · Secondo strato: z = W₂ h (5 × 3)(3 × 1) = 5 × 1
4 · Softmax: un punteggio per token → probabilità

Che cosa è reale: i vettori di E, la concatenazione, i due prodotti matrice × vettore, la ReLU, la softmax. I pesi sono stati trovati con la discesa del gradiente sui cinque esempi «il gatto → dorme», «gatto dorme → sul», «dorme sul → divano», «sul divano → il», «divano il → gatto»; su contesti mai visti la rete risponde comunque qualcosa, spesso senza senso, perché cinque esempi non bastano a generalizzare. Nel modello di Bengio i vettori erano 50–100 numeri, la finestra 4–5 token e lo strato nascosto aveva centinaia di neuroni; la forma del calcolo è questa.

Perché la concatenazione non scala. Con la finestra a 3 token W₁ ha bisogno di 6 colonne, e i 12 pesi della rete a 2 token non servono più: è una rete diversa, da addestrare da capo. Con i numeri di un modello vero il problema è enorme: 100 token di contesto con vettori di 768 numeri danno un ingresso di 100 × 768 = 76.800 numeri, e un primo strato di appena 512 neuroni avrebbe 512 × 76.800 ≈ 39 milioni di pesi solo lì; con 1.000 token, dieci volte tanto.

E c'è il difetto già visto: le colonne di W₁ che leggono il primo token sono diverse da quelle che leggono il secondo, quindi la rete deve imparare due volte che cosa significa «gatto», una per posizione. È per questi due motivi che un transformer non concatena i vettori: la frase entra come una matrice con una riga per token (3 token × 4 numeri), e ogni riga passa per gli stessi pesi; il legame tra le righe lo crea l'attention, come vedremo tra due sezioni.

Calcolo · il costo della concatenazione

ingresso=100 × 768 = 76.800 numeri
100 token di contesto, vettori da 768 numeri
pesi del primo strato=512 × 76.800 ≈ 39 milioni
solo lì, con appena 512 neuroni; con 1.000 token, dieci volte tanto

Una memoria che si aggiorna: le reti ricorrenti

Come si usa tutto il contesto, lungo quanto si vuole, senza una finestra fissa?

La risposta classica è la rete ricorrente (RNN, Recurrent Neural Network): si legge un token alla volta e si tiene un unico vettore di stato, una «memoria» di dimensione fissa. A ogni token lo stato viene ricalcolato da una rete che riceve lo stato precedente e il vettore del token nuovo: stato ← f(stato, token). Dopo aver letto «il gatto nero dorme sul», lo stato dovrebbe contenere, compresso in d numeri, tutto ciò che serve per prevedere «divano». Il contesto non ha più un limite di lunghezza, e gli stessi pesi servono per ogni posizione.

Per anni è stato il modo standard di fare modelli di linguaggio (nelle varianti LSTM e GRU), e ha tre difetti che si pagano sempre di più man mano che il contesto cresce. Comprime tutto in un vettore: ciò che è stato letto cento token fa deve sopravvivere a cento aggiornamenti dello stato, e in pratica svanisce. È sequenziale: per calcolare lo stato al token 1.000 bisogna aver calcolato i 999 precedenti, uno dopo l'altro, e le GPU, che eccellono a fare migliaia di operazioni in parallelo, restano ferme. È difficile da addestrare: i gradienti del capitolo 2 devono risalire la stessa catena di mille passi, e lungo la strada si spengono o esplodono.

stato₀→ + «il» → stato₁→ + «gatto» → stato₂→ …→ + «sul» → stato₅
tutto il passato, compresso
→ punteggi

L'attention: guardare indietro invece di ricordare

E se, invece di comprimere il passato in una memoria, lo tenessimo tutto a disposizione e lasciassimo che ogni token vada a guardare ciò che gli serve?

È l'idea dell'attention, ed è l'unica idea davvero nuova del transformer. Si tengono i vettori di tutti i token della frase, così come sono. Quando bisogna fare la previsione nella posizione di «sul», si costruisce il nuovo vettore di «sul» come media pesata dei vettori di tutti i token fino a lì, se stesso compreso. I pesi della media non sono fissi: vengono calcolati dal contenuto, in tre mosse.

  1. Dal vettore di «sul» si ricava una domanda: un vettore che dice che cosa «sul» sta cercando nel contesto. Si ottiene moltiplicando il vettore di «sul» per una matrice di pesi, Wq, che il training aggiusta. Nel modello in miniatura, la domanda di una preposizione cerca soprattutto la caratteristica «dormire».
  2. La domanda viene confrontata con il vettore di ciascun token precedente con un prodotto scalare (si moltiplicano le componenti a coppie e si sommano): il risultato è un punteggio alto se il token ha ciò che la domanda cerca, basso o zero altrimenti. Nel nostro esempio «dorme» ottiene un punteggio alto, «il», «gatto» e «nero» circa zero.
  3. I punteggi vengono trasformati in pesi che sommano a 1 con la softmax (e elevato a ciascun punteggio, diviso per la somma): i token con punteggio alto prendono la maggior parte del peso, gli altri quasi nulla.

Con i numeri del modello in miniatura, nella posizione di «sul» i pesi vengono: «il» 2%, «gatto» 2%, «nero» 2%, «dorme» 28%, «sul» 65%. Il nuovo vettore di «sul» è quindi 0,28 × vettore di «dorme» + 0,65 × vettore di «sul» + briciole: nelle dimensioni leggibili del modello, «dormire» passa da 0,30 a 0,48 e compare «luogo» 0,39 e «preposizione» 0,65. Il vettore di «sul» adesso contiene «dorme», e la contiene perché «sul» l'ha cercata, non perché una memoria l'ha trasportata fin lì. Un piccolo blocco di neuroni (lo strato successivo) legge questo vettore, trova «dormire + preposizione» e aggiunge «luogo»: il confronto finale con il vocabolario premia «divano» e «letto».

Calcolo · i pesi dell'attention nella posizione di «sul»

pesi=il 2% · gatto 2% · nero 2% · dorme 28% · sul 65%
punteggi trasformati dalla softmax in pesi che sommano a 1
nuovo vettore di «sul»=0,28 × vettore(dorme) + 0,65 × vettore(sul) + briciole
«dormire»=0,30 → 0,48
compaiono anche «luogo» 0,39 e «preposizione» 0,65

Perché risolve i tre difetti della memoria: niente compressione, il token a distanza mille è a disposizione quanto quello accanto, basta che la domanda lo trovi; tutto in parallelo, i pesi di ogni posizione sono prodotti scalari indipendenti, che una GPU calcola in un colpo solo per tutta la frase; gradienti brevi, da «sul» a «dorme» c'è un passo, non una catena. Il prezzo è il costo: ogni token confronta la propria domanda con tutti i precedenti, quindi il lavoro cresce con il quadrato della lunghezza della frase. È il compromesso che definisce gli LLM attuali.

vettore di «sul»→ domanda = vettore × Wq→ prodotto scalare con ogni token
il 0 · gatto 0 · nero 0 · dorme 1 · sul 2
→ softmax
2% 2% 2% 28% 65%
→ media pesata
«sul» contiene «dorme»

Un vettore lungo o una matrice? Vale la pena fissare la differenza con il modello a finestra fissa, perché è il punto in cui si fa più confusione. Lì i vettori dei token venivano concatenati in un unico vettore lungo, e la rete aveva un ingresso per ogni numero. Qui no: la frase entra come una matrice X con una riga per token (per «il gatto dorme» con vettori di 4 numeri, 3 righe × 4 colonne), e ogni riga passa per gli stessi pesi.

Il nuovo vettore di un token è una combinazione lineare pesata delle righe: 0,06 × riga di «il» + 0,78 × riga di «gatto» + 0,15 × riga di «dorme» (è il conto del laboratorio del capitolo 9: «dorme» va a cercare il suo soggetto), con i pesi calcolati dal contenuto e diversi per ogni token e per ogni frase. Non è una somma secca (che perderebbe chi conta di più), non è una concatenazione (che fisserebbe la lunghezza): è questa media pesata la «composizione del contesto» di cui si parla a proposito dei transformer. Il calcolo completo, con tutte le matrici e le loro dimensioni, numero per numero, è nel capitolo 9, sezione D.

Calcolo · «dorme» guarda indietro

X=3 righe × 4 colonne
«il gatto dorme», vettori da 4 numeri
nuovo vettore di «dorme»=0,06 × riga(il) + 0,78 × riga(gatto) + 0,15 × riga(dorme)
pesi calcolati dal contenuto: «dorme» va a cercare il suo soggetto

Che cos'è, allora, un transformer

Un transformer (Vaswani e colleghi, 2017, «Attention is all you need») è una rete neurale costruita così: i token diventano vettori; poi, per N volte di seguito, un blocco fatto di due parti ricalcola ogni vettore — prima l'attention, in cui ogni token raccoglie informazione dai precedenti con la media pesata appena vista, poi un piccolo gruppo di neuroni (l'MLP, Multi-Layer Perceptron) che elabora il vettore di ciascun token per conto suo; infine l'ultimo vettore viene confrontato con ogni riga del vocabolario per ottenere i punteggi.

Il nome dice quello che fa: trasforma una sequenza di vettori in una sequenza di vettori, della stessa lunghezza, N volte, arricchendola a ogni passaggio. Niente memoria da trascinare, niente finestra fissa, niente ciclo sequenziale: solo blocchi identici impilati, con pesi diversi.

Gli LLM come GPT, Llama o Claude sono transformer di questo tipo (detti decoder-only: ogni posizione vede solo i token alla sua sinistra, perché deve prevedere il successivo). Un modello da 7 miliardi di parametri ha N = 32 blocchi e vettori di 4.096 numeri; il modello in miniatura qui sotto ha N = 1 e vettori di 8 numeri. La struttura è la stessa, ed è riassunta in cinque passi.

1 · token → ID [L]
2 · ID → vettore: lettura delle righe di E [L × d]
Blocco 13 · attention: ogni token = media pesata dei precedenti → 4 · MLP: neuroni su ogni token[L × d] → [L × d]
Blocco 23 · attention → 4 · MLP[L × d] → [L × d]
⋮ (N blocchi, N = 32 in un 7B, N = 1 nel modello in miniatura)
5 · confronto con ogni riga del vocabolario [L × V] logit
softmax → una probabilità per ogni token del vocabolario
Il cuore del documento

Due cose vanno dette subito, perché sono il cuore di tutto il documento. Primo: in questi cinque passi non c'è una sola regola scritta a mano; ci sono solo moltiplicazioni e somme tra la frase e un insieme di numeri fissi, i pesi (la tabella E, la matrice Wq che costruisce le domande, i pesi dei neuroni dell'MLP). Secondo: il training cambia solo quei numeri, mai i cinque passi. Nel modello in miniatura i pesi li abbiamo scritti noi, a mano, perché si capisse che cosa fanno; in un modello vero li trova il procedimento del capitolo 2.

1 · Tokentesto → ID→ 2 · Vettoririga di E→ 3 · Attentionmedia pesata del contesto→ 4 · MLPneuroni su ogni token→ 5 · Confrontalogit → probabilità

Un modello in miniatura, numero per numero

Il modello qui sotto è un transformer con vocabolario di 12 token, vettori di 8 numeri e un solo blocco (attention + MLP a 7 neuroni). Per renderlo leggibile, le 8 dimensioni hanno un nome (animale, dormire, mangiare, luogo, preposizione, fine, articolo, cibo) e i pesi sono scelti a mano in modo che le dimensioni significhino qualcosa: in un modello vero le dimensioni sono 4.096, nessuna ha un nome, e i pesi li trova il training. Ma il calcolo è lo stesso dei cinque passi. Scegli una frase, clicca un token per vedere la previsione fatta in quel punto della frase, e segui i cinque pannelli: il pannello 3 è l'attention della sezione precedente con i numeri veri, il pannello 4 sono i neuroni della sezione sulla rete neurale.

Laboratorio: dalla frase al token successivo

calcolo reale · pesi scritti a mano
1 · Token e ID — clicca un token: il modello prevede che cosa viene dopo di lui, usando tutto ciò che lo precede
2 · Ogni ID diventa un vettore: la riga di E (12 righe × 8 colonne)
3 · Attention: quanto pesa ogni token nella media per l'ultimo
4 · MLP: sette neuroni leggono il vettore mescolato e aggiungono una correzione
5 · Confronta con ogni riga di E: punteggio (logit) → probabilità

Che cosa è reale e che cosa no. Reali: la lettura delle righe di E, i pesi del mescolamento (prodotto scalare tra la «domanda» dell'ultimo token e il vettore di ciascun token, poi softmax), la media pesata, il blocco di elaborazione (sette regole del tipo «se c'è X senza Y, aggiungi Z», realizzate come ReLU di un prodotto scalare, cioè esattamente come un neurone), i logit come prodotto scalare con le righe di E, la softmax. Scritti a mano: i valori di tutti questi pesi, e i nomi delle dimensioni. In un modello vero le dimensioni non si leggono e le regole non si elencano, perché emergono dal training distribuite su miliardi di numeri; ma la forma del calcolo è questa.

Dove sono i pesi, e che cosa fa il modello vero in più

Nel modello in miniatura i pesi sono di tre tipi, e in un modello vero sono gli stessi tre, solo enormemente più grandi.

I pesi del modello

Tabella E (embedding)Una riga di numeri per ogni token del vocabolario. Qui 12 × 8 = 96 numeri; in un 7B 32.000 × 4.096 = 131 milioni. Usata all'ingresso (passo 2) e, qui, anche all'uscita (passo 5).vocabolario × dimensione
Pesi del mescolamento (attention)La matrice che trasforma il vettore dell'ultimo token nella «domanda» con cui pesa i precedenti. Qui 8 × 8; in un 7B quattro matrici 4.096 × 4.096 per strato, per 32 strati.ripetuto per ogni strato
Pesi del blocco di elaborazione (MLP)Le regole «se X senza Y, aggiungi Z»: qui 7 regole su 8 dimensioni; in un 7B tre matrici 4.096 × 11.008 per strato (due allargano il vettore, una lo restringe). È qui che si pensa stia la maggior parte della conoscenza fattuale.circa 2/3 dei parametri
Un'analogia per i pesi

Un mixer audio con miliardi di manopole. All'inizio le manopole sono in posizione casuale e il suono è rumore. Il training gira ogni manopola di una frazione, miliardi di volte, finché il suono è quello giusto. Nessuno regola una manopola a mano, e nessuno sa che cosa rappresenti la singola manopola: hanno senso solo tutte insieme. Nel modello in miniatura le abbiamo regolate noi, 96 + 64 + 56 manopole, ed è per questo che le dimensioni hanno un nome; nel capitolo 3 c'è un modello con 225 manopole che si regolano da sole, e le puoi guardare mentre si muovono.

Che cosa fa in più un modello vero. Quattro cose, nessuna delle quali cambia la logica dei cinque passi:

  • Ripete i passi 3 e 4 molte volte. Un 7B ha 32 strati, ciascuno con i propri pesi di mescolamento e di elaborazione; l'uscita di uno strato è l'ingresso del successivo. Ogni strato aggiunge una correzione al vettore invece di sostituirlo (uscita = ingresso + contributo), così l'informazione si accumula strato dopo strato. I primi strati raccolgono grammatica e vicinanze, quelli centrali i fatti, gli ultimi preparano la scelta del token.
  • Mescola in parallelo con molte «teste». Nel passo 3 un modello vero non calcola un solo insieme di pesi ma 32 insiemi indipendenti per strato, ciascuno con la sua domanda: una testa segue il soggetto, un'altra la parola precedente, un'altra la punteggiatura.
  • Sa dove sta ogni token. La media pesata, da sola, non distingue «il cane morde l'uomo» da «l'uomo morde il cane». Il modello aggiunge un'informazione di posizione prima del mescolamento, così «quanto sei rilevante per me» può dipendere anche dalla distanza.
  • Calcola tutte le posizioni insieme. Qui abbiamo seguito un solo token alla volta; il modello vero esegue i cinque passi per ogni posizione della frase in un colpo solo (ogni posizione vede solo i token alla sua sinistra), il che conta moltissimo per il training, come vedremo nel capitolo 2.

Ciascuno di questi punti ha una sezione nel capitolo 9, con il calcolo completo dell'attention (query, key e value), la codifica della posizione (RoPE), il blocco MLP, la normalizzazione e i conti esatti dei 7 miliardi di pesi.

Dal token successivo al testo: la generazione

Il modello prevede un token. Come fa a scrivere una risposta di cento parole?

Ripetendo i cinque passi cento volte. Il token scelto viene aggiunto in fondo alla frase, e la frase allungata rientra nel modello dal passo 1: è ciò che fa il pulsante «Aggiungi il token previsto» del laboratorio. Si chiama generazione autoregressiva: ogni token prodotto diventa contesto per il successivo, finché il modello produce il token speciale di fine (<eos>, end of sequence). A ogni passo si può prendere il token più probabile (greedy) oppure estrarne uno a caso secondo le probabilità, eventualmente dopo averle rese più piatte o più appuntite con un parametro detto temperatura; è per questo che la stessa domanda può ricevere risposte diverse. Il costo è proporzionale: cento token, cento passaggi completi.

Laboratorio: tokenizzatore

approssimazione

I token di un modello vero non sono parole intere: sono frammenti presi da un vocabolario di 30.000–250.000 voci costruito con un algoritmo (BPE) che fonde le sequenze di caratteri più frequenti. Le parole comuni restano intere, quelle rare si spezzano, lo spazio fa parte del token che lo segue. Qui la divisione è simulata con una regola semplice; l'algoritmo vero, eseguibile passo per passo, è nel capitolo 9.

Le domande che vengono a tutti

Arrivati qui, quasi tutti si fanno le stesse sette domande. Le risposte sono brevi; non servono per andare avanti, ma tolgono di mezzo i dubbi più comuni.

«I tre numeri dell'ombrello sono i pesi?»

No, sono gli ingressi: quante nuvole ci sono, quanta pioggia è prevista, quanto vento tira. Cambiano ogni giorno, perché ogni giorno il tempo è diverso.

I pesi stanno sulle frecce e dicono quanto conta ogni ingresso. Sono della rete, non della giornata, e finito l'allenamento restano fissi. Lunedì e martedì il neurone riceve ingressi diversi, ma li moltiplica per gli stessi pesi.

Con il testo è lo stesso. I vettori dei token sono gli ingressi: quali vettori entrano dipende dalla frase che scrivi. I pesi sono la rete: la tabella E, la matrice che costruisce le domande, i neuroni dell'MLP, sempre gli stessi qualunque frase entri.

«La rete ha tanti nodi d'ingresso quanti numeri hanno tutti i vettori della frase?»

No. Una frase di 4 token porta 4 × 4.096 = 16.384 numeri, ma la rete non ha 16.384 ingressi. È un insieme di pesi fatto per un solo vettore da 4.096 numeri, e lo stesso insieme si applica a ogni vettore, tutti nello stesso momento: come quattro calcolatrici uguali che fanno lo stesso conto nello stesso istante.

Anche dentro la rete la larghezza resta quella. Tra uno strato e l'altro ogni vettore ha sempre 4.096 numeri. L'unico punto in cui si allarga è la parte in cui ogni vettore «ragiona da solo»: lì passa a 11.008 numeri e poi torna a 4.096. Non esiste un ingresso più grande o più piccolo del vettore: la rete è costruita su misura per lei.

Per questo una frase più lunga non cambia la rete. Con 4 token ci sono 4 vettori, con 400 ce ne sono 400: più vettori, stessi pesi. Cambia solo quanto lavoro c'è da fare. L'esempio con le matrici, numero per numero e con uno step di training su una frase corta e una lunga, è nel capitolo 2, nella sezione sulle frasi di lunghezza diversa.

«Dove stanno gli embedding? In memoria?»

La parola «embedding» indica due cose diverse, e stanno in posti diversi.

La prima è la tabella dei vettori: una riga per ogni token del vocabolario, 32.000 righe da 4.096 numeri, circa 131 milioni di numeri. Fa parte dei pesi del modello: sta su disco insieme a tutti gli altri pesi e viene caricata in memoria quando il modello si avvia. Durante l'uso non cambia mai.

La seconda sono i vettori del tuo prompt: le righe copiate dalla tabella per i token che hai scritto, poi trasformate strato dopo strato. Queste esistono solo mentre il modello fa i conti, nella memoria della GPU, e alla fine non vengono salvate.

C'è una riserva che dura un po' di più. Mentre scrive la risposta, un token alla volta, il modello conserva una parte dei conti già fatti per i token passati: i vettori «che cosa offro» e «che cosa passo» dell'attention (key e value, capitolo 9), per ogni strato. Quando arriva un token nuovo non deve ricalcolarli: li rilegge. Le domande invece non si conservano, perché servono una volta sola.

Questa riserva si chiama KV cache (key-value cache, la memoria delle key e dei value: le etichette e i contenuti) e viene buttata quando la risposta è finita; alcuni servizi la tengono per qualche minuto, per riusarla se il messaggio successivo comincia allo stesso modo. Quanto lavoro fa risparmiare e quanta memoria occupa lo spiega la guida sull'inferenza, nel capitolo sulla cache KV: è un approfondimento facoltativo.

«Spezzando la frase in token, non si perde l'ordine e la relazione tra le parole?»

No, per due motivi: la posizione e l'attenzione.

La posizione. Se ogni token diventasse solo il suo vettore (la riga di E), «cane morde uomo» e «uomo morde cane» darebbero gli stessi tre vettori, in un ordine diverso, e i conti dell'attention, che pesano e sommano, non avrebbero un modo diretto per sapere chi viene prima. Per questo a ogni vettore si aggiunge l'informazione su dove si trova nella frase: si chiama codifica posizionale.

In Llama si usa RoPE (Rotary Position Embedding, codifica della posizione per rotazione): le domande e le key dell'attention vengono ruotate di un angolo che dipende dalla posizione del token. Così il punteggio tra due token dipende anche da quanto sono lontani l'uno dall'altro.

L'attenzione. La relazione tra le parole non è scritta da nessuna parte all'ingresso: la rete la ricostruisce. In ogni strato i vettori si scambiano informazioni guardando a sinistra, con l'attention, e quello che ciascuno raccoglie finisce dentro il suo vettore. Alla fine il vettore di «sul» «contiene» anche il gatto e il dormire. Spezzare in token non perde la relazione, perché ogni vettore se la porta dietro.

Laboratorio: chi morde chi?

valori illustrativi

Accendi e spegni la posizione e cambia frase: guarda se i vettori delle due frasi restano uguali e se la domanda «chi morde?» riesce a rispondere.

Posizione
Domanda sulla frase

I vettori sono scritti a parole perché si possano leggere, e i punteggi sono inventati: il bonus di 2,2 per «viene prima di morde» è scelto perché esca 90%. Il passaggio dai punteggi alle percentuali è invece la softmax vera, fatto solo tra «cane» e «uomo». In Llama la posizione non è un'etichetta attaccata al vettore: RoPE ruota domande ed etichette di un angolo che dipende dalla posizione, in ogni strato. In un modello vero, dove ogni vettore guarda solo a sinistra, un indizio d'ordine trapela anche senza posizione (chi sta più a sinistra vede meno vettori), ma è debole e indiretto: per questo tutti i modelli moderni la aggiungono in modo esplicito.

«Se la frase è lunghissima, viene spezzata in pezzi?»

Il limite non è lo strato d'ingresso: come hai visto, la rete accetta quanti vettori vuoi, sempre con gli stessi pesi. Il limite è la finestra di contesto (context window): il numero massimo di token che il modello può guardare insieme, prompt e risposta compresi. Per Llama 2 è di 4.096 token.

Una coincidenza scomoda

Attenzione a una coincidenza scomoda: anche il vettore di ogni token, in Llama 2 7B, ha 4.096 numeri. Sono due cose diverse che per caso hanno lo stesso valore. La larghezza del vettore dice quanti numeri descrivono un token; la finestra dice quanti token possono stare insieme. In altri modelli i due numeri sono diversi: Llama 3.1 8B ha ancora vettori da 4.096 numeri, ma una finestra da 128.000 token.

Perché c'è un limite. Il primo motivo è il costo. Nell'attention ogni token confronta la sua domanda con i vettori di tutti i token che lo precedono, lui compreso. Con 4 token i confronti sono 1 + 2 + 3 + 4 = 10; con 1.000 token sono circa mezzo milione.

Calcolo · i confronti dell'attention

4 token=1 + 2 + 3 + 4 = 10 confronti
1.000 token=1 + 2 + … + 1.000 ≈ 500.000 confronti
2.000 token=1 + 2 + … + 2.000 ≈ 2.000.000 confronti
il doppio dei token, circa quattro volte i confronti, in ogni strato

Si dice che i conti dell'attention crescono con il quadrato della lunghezza.

Il secondo motivo è l'allenamento. Il modello ha imparato su testi lunghi al massimo quanto la sua finestra, e oltre non sa usare bene posizioni che non ha mai visto.

Che cosa succede se il testo non ci sta. Il modello non lo spezza in pezzi collegati tra loro: guarda una finestra sola. Quello che avanza viene tagliato, oppure il programma rifiuta il testo troppo lungo. Sono i programmi costruiti intorno al modello a decidere che cosa farci stare: per esempio riassumere le parti più vecchie di una conversazione, oppure cercare nei documenti solo i pezzi utili alla domanda e mettere nel prompt quelli. Questo secondo metodo si chiama RAG (Retrieval-Augmented Generation, generazione aiutata dalla ricerca).

Se vuoi vedere come si fa in pratica, c'è la guida sull'ingegneria dei sistemi basati sui modelli linguistici: il capitolo sul retrieval per il RAG, il capitolo sulla memoria per i riassunti e per la scelta di che cosa tenere. È un approfondimento facoltativo.

I modelli più recenti hanno finestre molto più ampie: da 128.000 a oltre un milione di token. Il principio non cambia: la finestra è grande ma finita, e quello che non ci entra il modello non lo vede.

«I vettori dei token si sommano? Si concatenano? Che cosa vuol dire "comporre il contesto"?»

Sono tre operazioni diverse, e il transformer ne usa una sola.

La somma ([1, 0] + [0, 1] = [1, 1]) butta via l'informazione su chi era chi e in che ordine: «cane morde uomo» e «uomo morde cane» darebbero lo stesso vettore. Nessun modello di linguaggio la usa così com'è.

La concatenazione ([1, 0] e [0, 1] → [1, 0, 0, 1]) conserva tutto ma fissa la lunghezza: una rete costruita per 2 token ha un primo strato con 4 colonne, e per 3 token servirebbe un'altra rete. È il modello a finestra fissa del laboratorio sulla rete numero per numero, e con 100 token da 768 numeri l'ingresso sarebbe di 76.800 numeri.

La combinazione pesata dell'attention tiene i vettori separati, uno per riga di una matrice, e costruisce il nuovo vettore di ogni token come somma dei vettori precedenti ciascuno moltiplicato per un peso che somma a 1 con gli altri: 0,06 × «il» + 0,78 × «gatto» + 0,15 × «dorme». I pesi non sono fissi: li calcola la rete dal contenuto (domanda · etichetta, poi softmax), quindi cambiano a ogni token e a ogni frase. È questo che si intende con «comporre il contesto», e non ha nessuna proprietà matematica misteriosa: è una media pesata, con pesi calcolati sul momento. Nel capitolo 9, sezione D, c'è il conto completo con tutte le matrici.

«Le matrici dell'attention vengono da tre training diversi? E come fa il training a "creare" Q, K e V?»

No: un solo training, e Q, K, V non vengono creati dal training ma calcolati a ogni passaggio. Conviene separare due famiglie di numeri.

I parametri sono i numeri che il modello possiede: la tabella E, le tre matrici Wq, Wk, Wv di ogni strato, i pesi dell'MLP. All'inizio sono casuali; esistono già prima di vedere qualunque frase; vivono su disco e vengono caricati in memoria. Le attivazioni sono i numeri che nascono quando una frase attraversa il modello: la matrice X dei vettori, poi Q = X Wq, K = X Wk, V = X Wv, i pesi dell'attention, l'uscita di ogni strato, i logit. Sono il risultato di moltiplicazioni tra la frase e i parametri, cambiano a ogni frase e alla fine si buttano.

Il training tocca solo la prima famiglia, e tutta insieme. Il modello riceve «il gatto», prevede «dorme» con probabilità 0,03, la loss è −log 0,03 ≈ 3,5; la backpropagation del capitolo 2 risale la catena loss → logit → uscita dello strato → attention → Q, K, V → Wq, Wk, Wv e consegna a ciascuna delle tre matrici la propria derivata; l'optimizer sposta tutte e tre di un passo nella direzione che abbassa quella stessa loss. Non c'è un «training per le query» e uno per le key: c'è un unico obiettivo, prevedere il token successivo, e ogni parametro che contribuisce alla previsione riceve la sua correzione. Al passaggio successivo, con i nuovi parametri, Q, K e V vengono semplicemente ricalcolati.

parametri casuali
E, Wq, Wk, Wv, MLP
→ frase → X→ Q = XWq · K = XWk · V = XWv
attivazioni, ricalcolate
→ attention → logit → loss→ backpropagation
una derivata per ogni parametro
→ parametri aggiornati, tutti insieme↺
Mappa concettuale · la frase e il token successivo
  • Prevedere il token successivo
    • primo tentativo Contare le sequenze
      • si rompe perché la tabella esplode (Vn)
      • e perché non generalizza
    • primo rimedio Vettori e rete neurale
      • fanno valere ciò che si impara sulle parole simili
      • ma con finestra fissa
    • altro rimedio Rete ricorrente
      • ha il limite di memoria compressa e sequenziale
    • idea nuova Attention
      • calcola media pesata dei precedenti
      • con pesi da domanda · token e softmax
    • costruisce Transformer
      • è fatto di N blocchi attention + MLP
      • cambia solo i pesi nel training capitolo 2
      • scrive un token alla volta

In sintesi · capitolo 1

Prevedere il token successivo contando le sequenze non scala e non generalizza; i vettori rendono simili le parole simili, la rete neurale costruisce la funzione che dai vettori del contesto produce i punteggi. Il modello a finestra fissa non vede lontano; la rete ricorrente vede tutto ma comprime il passato in una memoria, procede in sequenza e si addestra male. L'attention tiene tutti i vettori e lascia che ogni token costruisca il proprio come media pesata dei precedenti, con pesi calcolati dal contenuto: è così che «tutto il contesto» entra nella previsione. Il transformer è una pila di blocchi attention + MLP che trasformano una sequenza di vettori in una sequenza di vettori, seguita dal confronto con il vocabolario. Non ci sono regole scritte a mano, solo pesi; generare testo significa ripetere tutto un token alla volta.

Concetti chiave

  • Token e ID — il testo diventa una lista di interi tramite un vocabolario fisso
  • Embedding — la riga di E letta per ogni ID: un punto in uno spazio a d dimensioni, che all'ingresso non sa nulla dei vicini
  • Contare non basta — la tabella dei conteggi esplode (Vn) e non generalizza; i vettori risolvono la generalizzazione, la rete neurale costruisce la funzione
  • Finestra fissa e memoria ricorrente — i due modelli precedenti: la prima non vede oltre n token, la seconda comprime tutto in uno stato, è sequenziale e difficile da addestrare
  • Attention — media pesata dei vettori precedenti, con pesi calcolati dal contenuto (domanda · token, poi softmax): niente compressione, tutto in parallelo
  • Transformer — embedding, poi N blocchi (attention + MLP) che trasformano una sequenza di vettori in una sequenza di vettori, poi il confronto con il vocabolario
  • Neurone, strato, MLP — somma pesata + ReLU; regole «se X senza Y, aggiungi Z» uguali per tutti i token
  • Logit e softmax — punteggi per ogni token del vocabolario, trasformati in probabilità
  • Pesi — i soli numeri che il training cambia; i passi restano fissi
  • Generazione autoregressiva — un token alla volta, ognuno diventa contesto del successivo

Autodiagnosi · dovresti saper rispondere senza rileggere

  1. Perché un modello a bigrammi non può sapere che dopo «dorme sul» viene «divano», e perché non basta contare le terne?
  2. Che cosa fa di diverso l'attention rispetto a una rete ricorrente per usare un token lontano nel contesto?
  3. Nel laboratorio, quale passo porta l'informazione da «dorme» a «sul», e come vengono calcolati i pesi?
  4. Quali sono i tre tipi di pesi, e che cosa fa il training con i cinque passi?
  5. Perché la stessa domanda può ricevere risposte diverse dallo stesso modello?
Capitolo 2 · Come impara

Dall'errore su un token alla modifica di miliardi di pesi

All'inizio i pesi sono casuali e il modello dà a «Parigi» una probabilità del 2%, come a qualsiasi altro token. Alla fine gli dà il 90%. Che cosa è successo ai 7 miliardi di numeri nel frattempo, e chi ha deciso come cambiarli?

Nessuno li ha decisi. Il training è un ciclo meccanico che ripete quattro mosse: esegui il forward pass del capitolo 1 su un pezzo di testo, misura con un numero quanto la previsione è lontana dal token vero, calcola per ogni peso in che direzione spostarlo perché quel numero scenda, e spostalo di poco. Il ciclo gira milioni di volte. Questo capitolo lo smonta nei suoi pezzi, ciascuno con la sua domanda: da dove vengono gli esempi, come si misura l'errore, come si calcola la direzione (è qui che vive la backpropagation), quanto grande è il passo, con che ritmo si servono i dati. Il capitolo 3 rimette insieme i pezzi in un training vero, eseguibile nel browser.

Da dove vengono gli esempi: testo, e nessuna etichetta

Per imparare che dopo «La capitale della Francia è» viene «Parigi» servirebbe qualcuno che scriva milioni di coppie domanda → risposta. Chi le ha scritte?

Nessuno. Nel pre-training il dataset non contiene domande e risposte, né etichette. È solo testo: miliardi di documenti (pagine web, libri, articoli scientifici, codice sorgente), salvati di solito in file JSONL (JSON Lines, un oggetto JSON per riga), un documento per riga.

Le coppie «input → risposta attesa» si ricavano automaticamente dal testo stesso: per ogni posizione, l'obiettivo è semplicemente il token che viene dopo. Un documento di 1.000 token contiene 999 esempi, uno per posizione, tutti gratis. Se da qualche parte nel corpus c'è scritto «la capitale della Francia è Parigi», quella frase è già un esempio con la sua soluzione. Per questo si parla di apprendimento auto-supervisionato: il testo fa da domanda e da soluzione insieme.

Prima di arrivare al modello, il testo grezzo passa per una lunga pipeline di pulizia. È la parte meno visibile del lavoro, ma è quella che incide di più sulla qualità:

Raccolta (crawl del web, libri, repository di codice)→ Estrazione del testo dall'HTML→ Filtri di qualità e lingua→ Deduplicazione→ Rimozione di dati personali e contenuti tossici→ Tokenizzazione e divisione in shard (file-blocchi)

Una miscela tipica di pre-training

indicativa

Ogni laboratorio usa una sua «ricetta» e la tiene segreta. Le proporzioni indicano l'ordine di grandezza, non dati ufficiali. Verso la fine del pre-training si alza spesso la quota di dati di alta qualità (matematica, codice, testi curati): è la fase chiamata annealing o mid-training.

Com'è fatta una riga del dataset, fase per fase


    

Le tre voci SFT, DPO e RLVR anticipano la Parte II: le fasi successive usano dataset di forma diversa, e ogni forma corrisponde a un modo diverso di calcolare l'errore. Il meccanismo di questo capitolo resta lo stesso per tutte.

La loss: l'errore in un solo numero

Il modello dà a «Parigi» il 12% e a «Lione» il 30%. Quanto ha sbagliato? Serve un numero, perché solo un numero si può far scendere.

La loss (funzione di perdita) è quel numero. Negli LLM si usa quasi sempre la cross-entropy (entropia incrociata) sul token successivo, che guarda una cosa sola: la probabilità che il modello ha dato al token corretto. La formula è loss = −log p(token corretto). Se il modello dà il 100% al token giusto la loss è 0; con il 50% vale 0,69; con il 12% vale 2,12; con l'1% vale 4,6.

Calcolo · la loss per diverse probabilità

p = 100%=−log 1 = 0
p = 50%=−log 0,5 = 0,69
p = 12%=−log 0,12 = 2,12
il caso di «Parigi» al 12%
p = 1%=−log 0,01 = 4,6

Più la probabilità è bassa, più la loss sale, e sale sempre più in fretta: sbagliare «di molto» costa molto più che sbagliare «di poco». Che cosa facesse «Lione» non conta direttamente: conta solo che la sua probabilità ha rubato spazio a «Parigi».

Due proprietà la rendono adatta. È derivabile: cambiando di pochissimo un peso, la loss cambia di pochissimo e in modo calcolabile, ed è questo che permette il passo successivo. E ha un significato leggibile: e elevato alla loss è la perplexity, «tra quanti token equiprobabili il modello sta esitando». Loss 2,12 significa perplexity 8,3: come tirare a indovinare tra otto candidati. Un buon modello di pre-training arriva a una loss intorno a 2 sul testo web (perplexity ≈ 7): non può scendere a zero, perché il testo è davvero incerto (dopo «il» può venire quasi qualunque cosa).

Calcolo · dalla loss alla perplexity

perplexity=eloss
loss 2,12=e2,12 ≈ 8,3
come tirare a indovinare tra otto candidati
loss ≈ 2=e2 ≈ 7
un buon modello di pre-training sul testo web

La loss di un intero batch è la media delle loss di tutti i suoi token: migliaia o milioni di numeri riassunti in uno. Tutto il training consiste nel far scendere quel numero medio sui dati che il modello non ha ancora visto.

Il gradiente: in che direzione muovere ciascun peso

Ho un numero, la loss, e 7 miliardi di manopole. Per ogni manopola devo sapere: se la giro un po' a destra, la loss sale o scende? E di quanto? Provare una manopola alla volta richiederebbe 7 miliardi di forward pass per ogni step.

La risposta a quella domanda, per tutte le manopole insieme, è il gradiente: un numero per ogni peso, con lo stesso segno e la stessa proporzione di «quanto cambierebbe la loss se aumentassi questo peso di pochissimo».

Gradiente positivo: aumentando il peso la loss sale, quindi va diminuito. Gradiente negativo: va aumentato. Gradiente grande: quel peso conta molto per questo errore; gradiente zero: non c'entra. Il gradiente è la derivata della loss rispetto a ciascun peso, e la backpropagation (retropropagazione) è l'algoritmo che li calcola tutti con un costo pari a circa due forward pass, non sette miliardi.

Il punto di partenza è semplice. Per softmax seguita da cross-entropy, la derivata della loss rispetto a ciascun logit ha una forma che si può scrivere a mano: gradiente del logit j = p(j) − y(j), dove y è il vettore one-hot del token corretto (1 su «Parigi», 0 altrove). Con i nostri numeri: il logit di «Parigi» ha gradiente 0,12 − 1 = −0,88 (va alzato, e molto); quello di «Lione» 0,30 − 0 = +0,30 (va abbassato, in proporzione a quanto ha rubato); un token con probabilità 0,001 ha gradiente +0,001, cioè resta quasi fermo.

Calcolo · il gradiente sui logit

gradiente del logit j=p(j) − y(j)
y è il vettore one-hot del token corretto: 1 su «Parigi», 0 altrove
«Parigi»=0,12 − 1 = −0,88
va alzato, e molto
«Lione»=0,30 − 0 = +0,30
va abbassato, in proporzione a quanto ha rubato
token con p = 0,001=0,001 − 0 = +0,001
resta quasi fermo

Nessuna regola scritta a mano dice «premia Parigi, punisci Lione»: lo dice la derivata.

Poi si torna indietro, strato per strato. I logit sono il prodotto del vettore finale con la testa di output; il vettore finale è l'uscita del blocco 32, che dipende dall'uscita del blocco 31, e così via fino a E. Ogni operazione del forward pass è una funzione semplice (una moltiplicazione di matrici, una somma, una ReLU, una softmax) di cui si conosce la derivata.

La regola della catena dice che la derivata di una composizione è il prodotto delle derivate dei pezzi: per sapere quanto la loss dipende da un peso del blocco 12, si moltiplica «quanto la loss dipende dall'uscita del blocco 32» per «quanto l'uscita del 32 dipende da quella del 31» … per «quanto l'uscita del 12 dipende da quel peso».

Il backward pass percorre la rete all'indietro, dalla loss verso l'input, e a ogni strato fa due cose: calcola il gradiente dei pesi di quello strato (e lo mette da parte) e passa allo strato precedente il gradiente rispetto al suo ingresso. Ogni valore intermedio del forward pass serve a questo calcolo: per questo durante il training si tengono in memoria le attivazioni, e per questo il training costa molta più memoria dell'inferenza.

Il laboratorio seguente fa esattamente questo su una «rete» di due pesi, abbastanza piccola da seguire ogni moltiplicazione. La struttura è identica a quella di un transformer: una catena di funzioni, derivate locali, prodotto all'indietro.

Laboratorio: backpropagation su una catena di due pesi

matematica reale
a = w₁ · x  │  h = ReLU(a)  │  y = w₂ · h  │  loss = ½ (y − t)²  │  x = 1, obiettivo t = 1
Forward pass (da sinistra a destra: i valori) e backward pass (da destra a sinistra: i gradienti ∂loss/∂·)

Leggi i gradienti da destra verso sinistra: la loss dipende da y come (y − t); y dipende da w₂ come h e da h come w₂; la ReLU lascia passare il gradiente se a > 0 e lo azzera altrimenti; a dipende da w₁ come x. Il gradiente di w₁ è il prodotto di tutti i fattori lungo la catena: è la regola della catena. Prova a portare w₁ sotto zero: la ReLU si spegne, il gradiente di w₁ diventa 0 e quel peso non impara più da questo esempio, qualunque sia l'errore. In un transformer la catena ha centinaia di anelli, ma ogni anello è semplice come questi.

Perché costa «solo» due forward pass. Il backward pass esegue, per ogni matrice del forward, due moltiplicazioni di matrici della stessa dimensione (una per il gradiente dei pesi, una per il gradiente da passare indietro): circa il doppio del lavoro del forward. Il conto complessivo di uno step di training è quindi circa 6 operazioni per peso per token (2 del forward + 4 del backward), la formula che si usa per stimare il costo di un pre-training: 6 × parametri × token. Il training automatico delle derivate (autograd) è ciò che le librerie come PyTorch fanno per te: registrano ogni operazione del forward e applicano la regola della catena al contrario.

Calcolo · il costo di uno step

forward=2 operazioni per peso per token
backward=2 × 2 = 4 operazioni per peso per token
due moltiplicazioni di matrici della stessa dimensione per ogni matrice del forward
totale=2 + 4 = 6 × parametri × token
la formula per stimare il costo di un pre-training

Il gradiente di un batch è la media dei gradienti dei suoi esempi. Un peso che in un esempio dovrebbe salire e in un altro scendere riceve una spinta piccola: il modello impara ciò che è coerente tra gli esempi, non il caso singolo. Nel capitolo 3 lo vedrai nella matrice del gradiente: le celle dei token che non compaiono nel batch restano a zero.

Lo step: quattro mosse e un passo di lunghezza η

Ora so, per ogni peso, in che direzione muoverlo. Di quanto?

1 · forward passPrevisioneIl batch attraversa la rete; per ogni posizione esce un logit per ogni token del vocabolario.
2 · lossMisura dell'erroreLa media di −log p(token corretto) su tutti i token del batch.
3 · backward passGradientiLa backpropagation calcola, per ogni peso, in che direzione spostarlo per ridurre la loss.
4 · optimizer stepAggiornamentoL'ottimizzatore sposta ogni peso di un passo proporzionale al learning rate.

La regola base è w ← w − η · gradiente: ogni peso si muove nel verso opposto al suo gradiente, di una quantità proporzionale a esso e a un fattore globale, il learning rate η.

Il paesaggio della loss

Immagina la loss come un paesaggio collinare in 7 miliardi di dimensioni, dove ogni punto è una combinazione di pesi e l'altezza è la loss: il gradiente indica la salita più ripida, e il gradient descent (discesa del gradiente) fa un passo in discesa. Ma il gradiente è una pendenza locale, vale solo nei dintorni del punto: un passo troppo lungo atterra su un pendio diverso, magari più in alto; un passo troppo corto impiega un'eternità.

Il learning rate è il compromesso, ed è l'iperparametro più delicato di tutto il training: negli LLM vale tipicamente 10⁻⁴–10⁻³ nel pre-training e 10⁻⁵ nel fine-tuning, con pesi che stanno intorno a ±0,02.

La forma «stocastica» del nome, SGD (Stochastic Gradient Descent), ricorda che il gradiente è calcolato su un batch, un campione dei dati, e quindi è una stima rumorosa della pendenza vera. Gli LLM usano un ottimizzatore più sofisticato, AdamW, che adatta il passo a ogni singolo peso in base alla storia recente dei suoi gradienti (ne tiene una media mobile e una media dei quadrati): i pesi con gradienti sempre piccoli ricevono passi relativamente più grandi, quelli con gradienti grandi e oscillanti vengono frenati. Il principio però è lo stesso del laboratorio qui sotto.

Laboratorio: discesa su una loss a una dimensione

matematica reale
w ← w − η · ∂loss/∂w loss(w) = ½ (w − 1)² → ∂loss/∂w = w − 1

Il ritmo: esempio, sequenza, batch, step, epoch

Il dataset ha 15 mila miliardi di token. Non si può calcolare la loss su tutti insieme, né aggiornare i pesi dopo ogni singolo token. Con che ritmo si servono i dati al modello?

Questi cinque termini descrivono proprio quel ritmo, dal più piccolo al più grande:

Esempio (una previsione)
La coppia «contesto → token successivo». È l'unità minima su cui si calcola la loss.
«il gatto» → «dorme»
Sequenza
Un pezzo del flusso di token lungo quanto la context length (lunghezza del contesto) L. Una sequenza di L token contiene L esempi, perché ogni posizione predice la successiva, tutte in parallelo in un solo forward pass.
L = 8.192 token nei modelli attuali
Batch (gruppo di esempi)
Le B sequenze elaborate insieme prima di aggiornare i pesi. Si fa la media della loss su tutte, così il gradiente è meno «rumoroso» di quello di un esempio solo, e le GPU (Graphics Processing Unit) lavorano in parallelo.
B = batch size, in sequenze
Batch di token
È lo stesso batch, misurato in token invece che in sequenze: B × L. Negli LLM si parla quasi sempre così, perché le sequenze possono avere lunghezze diverse.
512 × 8.192 ≈ 4 milioni di token
Step (giro completo)
Un ciclo intero su un batch: forward pass, calcolo della loss, backward pass, aggiornamento dei pesi. Ogni step cambia i pesi una volta sola.
1 batch = 1 step = 1 aggiornamento
Epoch (epoca)
Un passaggio completo su tutto il dataset, cioè tutti i batch una volta. All'inizio di ogni epoch l'ordine delle sequenze viene rimescolato. Nel pre-training si fa di solito circa un'epoch sola (i dati sono troppi per ripeterli); nel fine-tuning 1–3.
step per epoch = token del dataset ÷ token per batch

Calcolatore: quanti step servono?

ordini di grandezza

Una frase lunga quanto si vuole, una rete con ingressi fissi: l'esempio con le matrici

Una rete ha un numero fisso di nodi d'ingresso. Come fanno una frase di 3 token e una di 6 a entrare nella stessa rete, e come fa la rete a imparare da tutte e due?

I nodi d'ingresso non contano i token: contano i numeri di un solo vettore. Nell'esempio qui sotto ogni token è un vettore di 2 numeri, quindi la rete ha 2 nodi d'ingresso. La frase entra come una matrice X con una riga per token e una colonna per nodo: 3 token danno una matrice 3 × 2, 6 token una matrice 6 × 2. Una frase più lunga aggiunge righe, mai colonne.

Il conto di uno strato è il prodotto X W. La matrice dei pesi W ha tante righe quante sono le colonne di X (2) e non sa quante righe ha X: si applica a ogni riga allo stesso modo, una riga alla volta, e restituisce una riga per token.

Un'analogia

È come una formula di un foglio di calcolo trascinata in basso: la formula è una sola, le righe sono quante ne hai.

Con la regola delle dimensioni del capitolo 1: (n × 2)(2 × 2) = n × 2, qualunque sia n.

C'è un solo punto in cui la grandezza dipende dalla frase: l'attention. Per far parlare i token tra loro serve una tabella con una casella per ogni coppia di token, quindi n × n: 3 × 3 per la frase corta, 6 × 6 per la lunga. Ma quella tabella non è fatta di pesi: si calcola ogni volta dalla frase, con i prodotti scalari tra le righe, come nella sezione sull'attention del capitolo 1. Cresce con la frase senza aggiungere niente da imparare.

E il training? Il bersaglio è la frase stessa spostata di un posto: la riga del token 1 deve prevedere il token 2, la riga del token 2 il token 3, e così via. Con n righe escono n previsioni e n errori, e la loss è la loro media. Il gradiente di W si calcola con un prodotto in cui n sparisce: (2 × n)(n × 2) = 2 × 2. In pratica è la somma dei suggerimenti di tutte le righe: ogni token dice di quanto vorrebbe spostare ciascuno dei 4 pesi, e i suggerimenti si sommano. Che le righe siano 3 o 6, il gradiente ha la forma di W e lo step W ← W − η × gradiente si fa sempre allo stesso modo.

Laboratorio: la stessa rete, una frase corta e una lunga

matematica reale

Passa dalla frase corta alla lunga e guarda quali dimensioni cambiano; poi premi «Uno step di training» qualche volta e torna all'altra frase: i 4 pesi di W sono gli stessi, e migliorano anche lì.

1 · X: righe di E
2 · A: pesi dell'attention
3 · M = A X
4 · W: i pesi che si imparano 2 × 2, sempre
5 · H = M W
6 · P = softmax(H Eᵀ): probabilità del token dopo
7 · Gradiente di W

Come si legge. Nel pannello 1 ogni riga è il vettore di un token, letto dalla tabella E (il 1 · 0, gatto 0,3 · 1, dorme −0,8 · 0,6, sul −0,8 · −0,6, divano 0,3 · −1). Nel pannello 2 la riga i dice quanto il token i guarda ciascun token fino a sé (le caselle in grigio sono i token futuri, che non può vedere); ogni riga somma a 1. Nel pannello 6 ogni riga è una previsione, con il bersaglio evidenziato: è la casella che il training vuole portare verso 1. Che cosa è semplificato: i punteggi dell'attention sono il prodotto scalare diretto tra i vettori (un modello vero li moltiplica prima per Wq e Wk, capitolo 9, sezione D), non c'è codifica della posizione, non c'è MLP, la tabella E è fissa e si allena soltanto W, con learning rate η = 1. In un modello vero si allenano tutti i pesi, e il gradiente di ciascuno ha la forma del suo peso per lo stesso motivo.

Calcolo · le dimensioni, qualunque sia n

strato XW=(n × 2)(2 × 2) = n × 2
una riga per token: la frase più lunga aggiunge righe, mai colonne
tabella dell'attention=n × n
3 × 3 per la frase corta, 6 × 6 per la lunga; non è fatta di pesi
gradiente di W=(2 × n)(n × 2) = 2 × 2
n sparisce: il gradiente ha sempre la forma di W

Frasi di lunghezze diverse nello stesso batch. Una sola frase può avere qualunque lunghezza; un batch no, perché le sequenze vengono messe una sopra l'altra in un tensore B × L × d, e una pila di matrici deve avere righe della stessa lunghezza.

Nel pre-training non è un problema: il testo dei documenti viene messo in fila, separato dal token di fine documento, e tagliato a pezzi di esattamente L token (si chiama packing).

Nel fine-tuning, dove ogni esempio è una conversazione con la sua lunghezza, le sequenze corte si allungano con un token di riempimento (padding) e una maschera esclude quelle posizioni dall'attention e dalla loss: le righe di riempimento esistono nei conti, ma non votano nel gradiente.

Allora perché esiste una lunghezza massima del contesto? Non per i pesi, che non cambiano con la lunghezza, ma per due altri motivi. Il primo è il costo: la tabella dell'attention è n × n, quindi raddoppiando la frase memoria e calcolo dell'attention si quadruplicano. Il secondo è l'esperienza: il modello ha imparato le posizioni solo fino alla lunghezza delle sequenze viste in training, e oltre quella la codifica della posizione gli presenta distanze che non ha mai incontrato.

Che cosa cambia nei pesi, e che cosa serve per farlo

Dopo milioni di step i pesi sono diversi. Ma «diversi» come? Si può vedere qualcosa di sensato in quei numeri?

Nei singoli pesi no: nessuna manopola significa qualcosa da sola. Nelle righe di E, però, qualcosa si vede. Ogni step aggiorna solo le righe dei token presenti nel batch, e token che compaiono in contesti simili (prima delle stesse parole, dopo le stesse parole) ricevono gradienti simili: i loro vettori si avvicinano.

Nessuno impone che «gatto» stia vicino a «cane»; emerge dal compito di prevedere il token successivo, perché prevedere bene ciò che segue «gatto» e ciò che segue «cane» richiede informazioni quasi uguali. È la stessa idea di word2vec, ma qui gli embedding si allenano insieme al resto del modello. Il laboratorio seguente è uno schema qualitativo di questo fenomeno: le posizioni finali sono disegnate a mano, ma proiettando con tecniche come PCA o t-SNE gli embedding di un modello vero si osservano raggruppamenti dello stesso tipo.

Laboratorio: gli embedding si organizzano durante il training

schema qualitativo · proiezione 2D

Quanta memoria serve per allenare. Il capitolo 1 diceva che i pesi di un 7B occupano 14 GB in bf16. Per allenarli non bastano: servono anche i gradienti (una copia della stessa forma dei pesi), le due medie mobili di AdamW per ogni peso, e di solito una copia «master» dei pesi in precisione piena (fp32, 4 byte) perché accumulare milioni di piccoli aggiornamenti in 16 bit perderebbe le cifre. In totale circa 16 byte per parametro: oltre 110 GB per un 7B, prima ancora di contare le attivazioni del forward pass da conservare per il backward. È il motivo per cui il training richiede molte GPU anche per modelli che in inferenza stanno su una sola, e per cui esistono tecniche come LoRA (sotto) che allenano solo una piccola frazione di pesi.

Calcolo · la memoria per allenare un 7B

per parametro=2 + 2 + 8 + 4 = 16 byte
peso bf16, gradiente bf16, due medie di AdamW in fp32, copia master in fp32
per un 7B=16 byte × 7 miliardi ≈ 112 GB
senza contare le attivazioni
Per ogni peso, durante il trainingBytePer un modello da 7B
Peso in bf16 (quello usato nel forward)214 GB
Gradiente in bf16214 GB
AdamW: media dei gradienti + media dei quadrati (fp32)856 GB
Copia master del peso in fp32428 GB
Totale (senza attivazioni)16≈ 112 GB
Mappa concettuale · come impara il modello
  • Ciclo di training
    • parte da Dati
      • sono solo testo, senza etichette
      • il bersaglio è il token successivo
    • misura l'errore con Loss
      • è la cross-entropy: −log p
      • si legge come perplexity
    • cerca la direzione con Gradiente
      • si calcola con backpropagation
      • parte da p − y sui logit
    • muove i pesi con Step
      • di lunghezza learning rate η
      • adattato da AdamW
    • serve i dati a Batch
      • un batch è uno step
      • tutto il dataset è un'epoch

Glossario dei termini che ritornano

Ottimizzatore (AdamW)
AdamW (Adam with decoupled Weight decay) adatta il passo a ogni peso tenendo una media mobile dei gradienti e della loro varianza. Costa 2 copie extra dei pesi in memoria, in fp32.
standard di fatto per gli LLM
Perplexity (perplessità)
È e elevato alla loss: quanti token equiprobabili il modello «sta considerando» in media. Perplexity 1 vuol dire certezza assoluta, 6 vuol dire tirare un dado a sei facce.
metrica classica del pre-training
Checkpoint
Un salvataggio dei pesi (e dello stato dell'ottimizzatore) a un certo step. Si riparte da lì se il training diverge o una macchina si guasta.
Train / validation
Si misura la loss anche su dati mai visti. Se la loss di training scende ma quella di validazione sale, c'è overfitting (sovradattamento): il modello memorizza invece di generalizzare.
Iperparametro
Un numero che non viene appreso ma scelto da chi allena: learning rate, batch size, numero di epoch, dimensione del vocabolario. Si distingue dai parametri, cioè i pesi.
Full fine-tuning vs LoRA
Il primo aggiorna tutti i pesi. LoRA (Low-Rank Adaptation, adattamento a basso rango) congela il modello e allena piccole matrici aggiuntive accanto a quelle originali: meno memoria, risultati spesso simili.
Attivazioni
I valori intermedi del forward pass (l'uscita di ogni strato per ogni token). Servono al backward pass e occupano memoria in proporzione a batch × context length.

In sintesi · capitolo 2

Il training non «insegna» nulla in senso umano: ripete un ciclo di quattro mosse. Il testo stesso fornisce gli esempi (il token successivo è la soluzione); la cross-entropy riassume l'errore in un numero, −log della probabilità data al token giusto; la backpropagation calcola, con la regola della catena percorsa all'indietro, quanto quel numero dipende da ciascuno dei miliardi di pesi (il gradiente), partendo dalla formula p − y sui logit; e ogni peso si sposta di un passo η nel verso opposto. I dati sono serviti in batch di sequenze, ogni batch è uno step, un giro completo del dataset è un'epoch. Dopo milioni di step la struttura emerge nei pesi senza che nessuno l'abbia scritta.

Concetti chiave

  • Auto-supervisione — gli esempi si ricavano dal testo: ogni token è il target dei precedenti
  • Cross-entropy — loss = −log p(token corretto); eloss è la perplexity
  • Gradiente — un numero per ogni peso: di quanto e in che verso cambierebbe la loss
  • Backpropagation — regola della catena all'indietro, dalla loss verso l'input; costa ~2 forward pass; punto di partenza p − y
  • Learning rate η e ottimizzatore — la lunghezza del passo; AdamW la adatta peso per peso
  • Batch, step, epoch — il ritmo con cui i dati vengono serviti e i pesi aggiornati
  • Memoria di training — ~16 byte per parametro più le attivazioni: molto più dell'inferenza

Autodiagnosi · dovresti saper rispondere senza rileggere

  1. Il modello dà al token corretto il 25%: quanto vale la loss? E la perplexity?
  2. Perché il gradiente del logit del token corretto è sempre negativo, e quello degli altri sempre positivo?
  3. Che cosa succederebbe con un learning rate dieci volte troppo grande? E dieci volte troppo piccolo?
  4. Perché il training di un 7B non sta in una GPU da 24 GB, se il modello in inferenza ci sta?
Capitolo 3 · Training dal vivo

Un training vero, dal dataset all'aggiornamento dei pesi

I capitoli 1 e 2 descrivono il meccanismo a parole. Si può vederlo girare, con numeri veri, senza fidarsi?

Sì. Qui sotto c'è un modello linguistico minuscolo che si allena davvero nel tuo browser: dataset, tokenizzazione, sequenze, batch, forward pass, loss, gradienti e aggiornamento, con la matematica reale del capitolo 2 (la formula p − y per il gradiente, la regola w ← w − η · gradiente per l'aggiornamento). Segui gli 8 passaggi con Avanti e confronta ogni schermata con la sezione corrispondente: i passi 1–3 sono i dati, il 4 è il forward pass del capitolo 1, il 5 la loss, il 6 il backward pass, il 7 lo step. Dopo il primo giro, il ciclo riparte dal passo 4 con il batch successivo; quando i batch finiscono, inizia una nuova epoch.

Semplificazione onesta: un transformer usa tutto il contesto a sinistra, mentre questo modello guarda solo l'ultimo token (un modello a bigrammi). I suoi pesi sono una tabella 15 × 15: riga = token attuale, colonna = token successivo, e il «forward pass» è leggere una riga e applicarle la softmax. Il flusso del training però è identico a quello di un LLM, e la loss, il gradiente e l'aggiornamento sono calcolati con le stesse formule.

    Loss per step

    Ogni punto è la loss di un batch, prima dell'aggiornamento. La linea tratteggiata è log 15 ≈ 2,71, la loss di un modello che tira a indovinare tra 15 token. Nota che non arriva a zero: dopo «il» il dataset stesso è ambiguo.

    I 225 pesi del modello

    Riga = token attuale, colonna = token successivo. Verde: peso positivo (successione favorita). Rosso: peso negativo. Passa sopra una cella per il valore. Sono le 225 «manopole» del capitolo 1.

    Prova il modello

    Allena il modello e poi genera: all'inizio le frasi sono casuali, dopo qualche epoch somigliano a quelle del dataset.

    La generazione è autoregressiva come in un LLM: si estrae un token secondo le probabilità, lo si usa come nuovo input, e si ripete fino a <eos>. Dopo 20 epoch il modello produce frasi del dataset e qualche ricombinazione plausibile («il cane dorme sul divano»): ha imparato le transizioni, non le frasi. Un LLM fa la stessa cosa con un contesto di migliaia di token invece di uno.

    Mappa concettuale · il training dal vivo
    • Training dal vivo
      • passi 1–3 Dati
        • diventano sequenze e batch capitolo 2
      • passo 4 Forward pass
        • legge una riga della tabella 15 × 15 e applica la softmax
      • passo 5 Loss
        • misura quanto la previsione è lontana dal token vero
      • passo 6 Backward pass
        • usa p − y per il gradiente
      • passo 7 Step
        • applica w ← w − η · gradiente
        • poi riparte dal passo 4 con il batch successivo; finiti i batch, una nuova epoch
    → Parte IIIl meccanismo è tutto qui. Quello che cambia da una fase di addestramento all'altra è soltanto da dove arrivano gli esempi e come si calcola l'errore: pre-training, SFT, DPO, RL e distillazione sono cinque risposte diverse a queste due domande, ciascuna nata da un limite della precedente.

    Parte II

    Le fasi: cinque modi di scegliere gli esempi e misurare l'errore

    Da qui in poi seguiremo un solo prompt, «Qual è la capitale della Francia?», e guarderemo che cosa risponde il modello dopo ogni fase. Per ciascuna fase le domande sono sempre le stesse quattro: quale problema lascia aperto la fase precedente; da dove arrivano gli esempi e com'è fatta una riga del dataset; come si calcola l'errore (la loss) e quindi che cosa viene rinforzato; quale limite resta, che la fase successiva dovrà affrontare.

    Fase 1 · Pre-training

    Prevedere il token successivo, migliaia di miliardi di volte

    Perché servono migliaia di miliardi di token di testo qualsiasi per un modello che alla fine deve «rispondere alle domande»? E che cosa esce, esattamente, da questa fase?

    Il problema di partenza. Un modello con pesi casuali non sa nulla: né grammatica, né fatti, né che cosa sia una domanda. Insegnargli tutto questo con esempi scritti a mano è impossibile per quantità: la conoscenza implicita in una lingua (concordanze, idiomi, fatti, modi di argomentare, convenzioni del codice) è troppo vasta per essere elencata. Il pre-training aggira il problema con l'auto-supervisione del capitolo 2: il testo esistente è già pieno di esempi, basta usare ogni token come obiettivo dei precedenti.

    I dati. Testo grezzo, nella forma vista nel capitolo 2: una riga JSONL per documento, nessuna etichetta, una miscela di web, codice, libri, articoli. La scala è il punto: Llama 2 è stato pre-addestrato su circa 2.000 miliardi di token, Llama 3 su 15.000 miliardi.

    Una regola empirica (lo studio «Chinchilla», 2022) suggerisce che, a parità di calcolo, convenga circa 20 token per parametro; i modelli recenti ne usano molti di più, perché un modello piccolo allenato a lungo costa meno da servire, e il costo di inferenza oggi pesa più di quello di training.

    La loss. Esattamente la cross-entropy del capitolo 2, su ogni token di ogni documento: il segnale più denso che esista, una correzione per ogni posizione. Minimizzarla su migliaia di miliardi di esempi costringe il modello a comprimere nel modo più efficiente possibile le regolarità del testo, e le regolarità del testo sono grammatica, fatti, stile, e i primi embrioni di ragionamento (per prevedere il token dopo «quindi 17 × 23 =» conviene saper moltiplicare). Nessuna di queste cose è un obiettivo esplicito: sono tutte scorciatoie per prevedere meglio.

    Il costo. Con la formula del capitolo 2 (6 operazioni per parametro per token): 6 × 7 miliardi × 2.000 miliardi ≈ 8 × 10²² operazioni, circa 184.000 ore di GPU A100 per il solo Llama 2 7B; i modelli di frontiera sono centinaia di volte più costosi.

    Calcolo · il costo del pre-training di Llama 2 7B

    operazioni=6 × 7 miliardi × 2.000 miliardi ≈ 8 × 1022
    6 operazioni per parametro per token, 2.000 miliardi di token
    tempo=circa 184.000 ore di GPU A100

    È la fase che si fa una volta, e da cui tutte le altre partono: le fasi successive costano in totale pochi punti percentuali di questa.

    Il learning rate nel tempo: warm-up e decadimento

    Nel capitolo 2 il learning rate era un numero. Perché nei training veri cambia durante il training?

    Per due motivi opposti, all'inizio e alla fine. All'inizio i pesi sono casuali, i gradienti sono enormi e le medie mobili di AdamW non si sono ancora stabilizzate: un passo pieno fin dal primo step spinge i pesi in direzioni sbagliate e la loss «esplode», talvolta fino a produrre NaN (Not a Number) e a dover ripartire da un checkpoint. Per questo il learning rate parte da circa zero e sale linearmente per qualche centinaio o migliaio di step: il warm-up.

    Un'analogia

    È come scaldare un motore a freddo prima di dare gas.

    Alla fine succede il contrario: con il passo pieno il modello continua a oscillare intorno al minimo senza assestarsi; riducendo η (decadimento coseno, oppure lineare) i pesi si posano nel punto migliore della valle. Llama 2, per esempio: picco 3 × 10⁻⁴, warm-up di 2.000 step, decadimento coseno fino al 10% del picco, batch da 4 milioni di token.

    Laboratorio: schedule del learning rate

    curve qualitative
    Learning rate
    Loss di training

    Le curve del learning rate sono quelle reali (lineare, coseno, WSD); la curva della loss è uno schema qualitativo che riproduce le forme osservate nei training veri, non il risultato di un modello. Prova a portare il warm-up a 0%: nei primi step la loss mostra picchi (spike) di instabilità. Con WSD (Warmup-Stable-Decay, riscaldamento-stabile-decadimento) la loss resta più alta nella fase piatta e cala di colpo nel decadimento finale; il vantaggio pratico è che puoi prolungare la fase stabile e decidere quando fermarti.

    Che cosa esce: un base model

    Il risultato è un base model: un modello che continua qualunque testo nel modo più probabile secondo il corpus. Sa moltissimo, ma non sa che cosa tu voglia da lui, perché non è mai stato addestrato su una «richiesta»: solo su testo che prosegue.

    Il nostro prompt dopo il pre-training

    Prompt: «Qual è la capitale della Francia?»
    Continuazione del base model: «Qual è la capitale della Germania? Qual è la capitale della Spagna? Qual è la capitale dell'Italia? Risposte a pagina 12.»

    Non è un errore: sul web una domanda del genere compare spessissimo dentro un quiz, seguita da altre domande. Il modello ha fatto la cosa per cui è stato ottimizzato, prevedere la continuazione più probabile. Sa la risposta (se gli scrivi «La capitale della Francia è» completa con «Parigi»), ma non sa che tu la vuoi. La conoscenza c'è; manca il comportamento.

    Due cose che si vedono in produzione. La mid-training o annealing: nell'ultima parte del pre-training si alza la quota di dati curati (matematica, codice, testi di qualità) mentre il learning rate decade, e il modello ne ricava un guadagno sproporzionato. E la valutazione: un base model si misura con la loss su un testo di validazione (perplexity) e con batterie di domande a scelta multipla completate come testo, non conversando con lui.

    Mappa concettuale · il pre-training
    • Pre-training
      • risolve pesi casuali
        • che non sanno né grammatica né fatti
      • usa Dati
        • sono testo grezzo, senza etichette
        • in quantità di migliaia di miliardi di token
      • minimizza Loss
        • è la cross-entropy su ogni token
      • costa 6 × parametri × token
        • regolato da learning rate: warm-up e decadimento
      • produce Base model
        • sa continuare il testo
        • non sa rispondere si risolve con l'SFT, capitolo 5
    → fase 2Il limite: il base model continua il testo, non risponde. Per trasformarlo in un assistente serve mostrargli come si comporta un assistente: esempi di richieste seguite da risposte, scritti apposta. È la fase successiva.

    In sintesi · fase 1

    • Problema — pesi casuali: il modello non sa nulla, e la conoscenza di una lingua è troppo vasta per essere scritta a mano
    • Dati — migliaia di miliardi di token di testo grezzo, nessuna etichetta; una riga JSONL per documento
    • Loss — cross-entropy su ogni token: il segnale più denso possibile
    • Dettagli pratici — warm-up e decadimento del learning rate; costo ≈ 6 × parametri × token; mid-training con dati curati
    • Risultato — un base model che continua il testo: sa, ma non risponde
    Fase 2 · SFT (Supervised Fine-Tuning, fine-tuning supervisionato)

    Il behavior shift: stesso sapere, altro comportamento

    Il base model sa che la capitale è Parigi ma risponde con altre domande. Come gli si insegna a rispondere, senza riaddestrarlo da capo?

    Il problema. Il comportamento «rispondi alla richiesta» non è nel corpus di pre-training, o lo è solo di rado e mescolato a tutto il resto. Ma il meccanismo del capitolo 2 non chiede che i dati siano testo trovato: chiede solo coppie contesto → token successivo. Se si costruiscono testi in cui a una richiesta segue una risposta ben fatta, e li si dà in pasto allo stesso ciclo di training, il modello imparerà a continuare una richiesta con una risposta. È un cambio di comportamento (behavior shift), non di conoscenza: la conoscenza è già nei pesi, si sta solo insegnando al modello in che forma tirarla fuori.

    I dati. Conversazioni scritte apposta: una richiesta e la risposta che vorremmo, redatte da annotatori umani o generate da un modello più forte e filtrate. Ogni esempio viene formattato con un chat template: token speciali che delimitano i ruoli (<utente>, <assistente>, <fine>), così il modello impara anche dove finisce la richiesta e dove deve fermarsi.

    La quantità è sorprendentemente piccola rispetto al pre-training: da qualche migliaio a qualche centinaio di migliaia di esempi (Llama 2 ne ha usati circa 27.000, scelti per qualità; lo studio LIMA ha mostrato risultati notevoli con 1.000). Conta la qualità: il modello imita esattamente quello che vede, errori e stile compresi.

    La loss. Sempre la cross-entropy sul token successivo, con una sola modifica: si calcola solo sui token della risposta. I token della richiesta entrano nel forward pass come contesto, ma la loro previsione non viene valutata (si dice che sono mascherati). Il motivo: non vogliamo che il modello impari a generare richieste, e le richieste scritte da utenti non sono un buon testo da imitare.

    Il learning rate è molto più basso che nel pre-training (10⁻⁵ contro 10⁻⁴), per 1–3 epoch: pochi aggiustamenti, perché si vuole spostare il comportamento senza cancellare il sapere.

    Dove si calcola la loss

    tok prompt: nessuna loss (maschera) tok risposta: loss di cross-entropy

    Nel forward pass tutti i 17 token vengono elaborati e per ciascuno esce una distribuzione sul token successivo; nel calcolo della loss si fa la media solo sulle 8 posizioni della risposta. Il token <fine> è incluso: il modello deve imparare anche a smettere.

    Laboratorio: come si sposta la distribuzione dell'output

    schema qualitativo
    Prompt: «Qual è la capitale della Francia?» — che tipo di continuazione genera?
    Continuazione più probabile

    Le percentuali sono uno schema qualitativo, non misure: mostrano il tipo di spostamento che l'SFT produce. All'inizio la massa di probabilità sta sulle continuazioni «da web» (quiz, articoli, forum); dopo poche migliaia di esempi si sposta sulla risposta diretta. La conoscenza (Parigi) non cambia: cambia la forma in cui viene emessa.

    Due usi che tornano. Il cold start dei modelli di ragionamento avviene qui: si aggiungono esempi con catene di ragionamento esplicite (CoT, Chain-of-Thought) per insegnare il formato «prima penso, poi rispondo», così che la fase di RL abbia da dove partire. E l'SFT è anche il modo in cui si fa la distillazione classica: le risposte le scrive un modello grande, e quello piccolo le imita (ne riparleremo nella fase 5).

    Il limite. Il modello imita e basta. Vede una sola risposta «giusta» per richiesta, quindi non impara che cosa renda una risposta migliore di un'altra, né può superare la qualità di chi ha scritto i dati.

    Un rischio sottile

    E c'è un rischio sottile: se gli esempi di SFT contengono fatti che il modello non aveva nel pre-training, impara che «rispondere con sicurezza anche quando non si sa» è il comportamento atteso, cioè impara ad allucinare. Per questo i dati di SFT devono insegnare la forma, non nuova conoscenza.

    Il nostro prompt dopo l'SFT

    Prompt: «Qual è la capitale della Francia?»
    Risposta: «La capitale della Francia è Parigi.»

    Risponde. Ma risponderebbe così anche se la domanda fosse ambigua, o se la risposta migliore fosse più lunga, o più breve, o chiedesse un chiarimento: non ha mai visto un confronto tra risposte, solo risposte.

    Mappa concettuale · l'SFT
    • SFT
      • parte dal base model
        • che continua, non risponde
      • usa Dati
        • sono conversazioni scritte apposta
        • formattate con chat template
      • calcola la loss solo sulla risposta
        • la richiesta è mascherata
      • produce un behavior shift
        • cambia il comportamento, non il sapere
      • ha come limite l'imitazione
        • porta il rischio di allucinare
        • si supera con le preferenze capitolo 6
    → fase 3Il limite: per andare oltre l'imitazione serve un segnale che dica non «ecco la risposta giusta» ma «questa è meglio di quella». È molto più facile da raccogliere (confrontare è più facile che scrivere) e porta informazione nuova: è la fase delle preferenze.

    In sintesi · fase 2

    • Problema — il base model continua, non risponde: manca il comportamento, non il sapere
    • Dati — conversazioni scritte apposta, formattate con un chat template; poche migliaia o centinaia di migliaia, di alta qualità
    • Loss — cross-entropy solo sui token della risposta (il prompt è mascherato); learning rate basso, poche epoch
    • Risultato — un assistente che imita le risposte viste; cold start del ragionamento
    • Limite — nessuna nozione di «meglio»; non può superare i dati; rischio di imparare a inventare
    Fase 3 · Preferenze · RLHF e DPO (Direct Preference Optimization, ottimizzazione diretta delle preferenze)

    Imparare dal confronto, senza scrivere la risposta giusta

    «Parigi.» e «La capitale della Francia è Parigi; è anche la città più popolosa del Paese, con circa 2 milioni di abitanti.» sono entrambe corrette. Quale preferiscono le persone? E come si insegna una preferenza, che non è un token da prevedere?

    Il problema. Molte qualità di una risposta (utilità, tono, lunghezza giusta, prudenza, sicurezza) non hanno una «risposta corretta» da imitare: sono relative. Ma chiedere a una persona quale di due risposte sia migliore è facile, veloce e affidabile, molto più che chiederle di scrivere la risposta ideale. Il dataset diventa quindi fatto di coppie: per lo stesso prompt una risposta preferita (chosen) e una scartata (rejected).

    Entrambe sono di solito generate dal modello stesso dopo l'SFT; il giudizio viene da annotatori umani o da un modello giudice (in quel caso si parla di RLAIF, Reinforcement Learning from AI Feedback).

    La strada storica: RLHF. Il primo metodo (InstructGPT, 2022) usava le coppie in due tempi. Prima si addestra un reward model, una copia del modello con in cima un solo numero in uscita, a dare punteggio più alto alla risposta preferita (loss di classificazione sulla coppia).

    Poi si usa l'apprendimento per rinforzo: il modello genera risposte, il reward model le valuta, e un algoritmo chiamato PPO (Proximal Policy Optimization) alza la probabilità delle risposte ben valutate, tenendo il modello vicino a quello di partenza con una penalità (la divergenza KL, spiegata sotto). Funziona, ma richiede quattro modelli in memoria, una generazione continua durante il training e una messa a punto notoriamente fragile.

    DPO: la scorciatoia. Nel 2023 un articolo ha mostrato che il giro si può saltare. L'obiettivo di RLHF, scritto per esteso, ha una soluzione in forma chiusa: il modello ottimo è quello per cui β · log( π(risposta) / πref(risposta) ) si comporta da reward.

    In parole: quanto il modello nuovo ha alzato la probabilità di una risposta rispetto al modello di riferimento (quello uscito dall'SFT, congelato) è già, implicitamente, il punteggio che le assegna.

    Allora si può addestrare direttamente il modello perché quel «reward implicito» sia più alto per la chosen che per la rejected, con una semplice loss di classificazione sulla coppia: niente reward model, niente generazione durante il training, niente RL.

    Perché «direct»: che cosa elimina rispetto a RLHF

    RLHF (Reinforcement Learning from Human Feedback) con PPO
    Coppie di preferenza→ Addestra un reward model→ Il modello genera risposte→ Il reward model le valuta→ Aggiornamento PPO + critic↺
    DPO
    Coppie di preferenza→ reward model generazione online→ Una loss di classificazione sulle coppie

    DPO dimostra che il modello stesso, confrontato con il riferimento congelato, contiene già un reward implicito. Basta una loss supervisionata, stabile ed economica, dello stesso tipo di quelle dei capitoli precedenti: forward pass su chosen e rejected (con il modello e con il riferimento), loss, backward, step.

    La loss, letta pezzo per pezzo. Per ogni coppia si calcola, con il modello e con il riferimento, la log-probabilità dell'intera risposta chosen e dell'intera rejected (somma dei log p dei suoi token, cioè la cross-entropy con il segno cambiato). Δc = log π(chosen) − log πref(chosen) dice quanto il modello ha alzato la chosen rispetto a com'era; Δr lo stesso per la rejected.

    Il margine è β · (Δc − Δr), e la loss è −log σ(margine): piccola se il margine è grande e positivo, grande se il modello preferisce la rejected. Il gradiente è pesato da σ(−margine): le coppie già separate contano poco, quelle sbagliate contano molto.

    β (tipicamente 0,1–0,5) regola quanto è «costoso» allontanarsi dal riferimento: più è alto, più basta un piccolo Δ per ottenere lo stesso margine, e meno il modello si sposta.

    Calcolo · la loss di DPO

    Δc=log π(chosen) − log πref(chosen)
    quanto il modello ha alzato la chosen rispetto a com'era
    Δr=log π(rejected) − log πref(rejected)
    lo stesso per la rejected
    margine=β · (Δc − Δr)
    loss=−log σ(margine)
    piccola se il margine è grande e positivo; il gradiente è pesato da σ(−margine)

    Laboratorio: la loss di DPO

    formula reale
    Prompt: «Spiegami cos'è un'API»
    ✓ chosen: «Un'API è un contratto che permette a due programmi di parlarsi. Esempio: l'app meteo chiede i dati al server…»
    ✗ rejected: «API significa Application Programming Interface.»
    reward implicito chosen
    reward implicito rejected
    margine
    loss
    peso del gradiente
    L = −log σ( β·[log π(yc)/πref(yc)] − β·[log π(yr)/πref(yr)] )

    Base model / modello di riferimento
    Il base model esce dal pre-training. Nel post-training si tiene una copia congelata del modello di partenza (reference, di solito quello uscito dall'SFT) per misurare quanto il modello nuovo se ne allontana.
    Divergenza KL
    La KL (Kullback-Leibler) misura quanto due distribuzioni di probabilità differiscono. Nel post-training fa da «guinzaglio»: impedisce al modello di allontanarsi troppo dal riferimento, cioè di dimenticare ciò che sapeva o di trovare scorciatoie assurde che piacciono al reward.
    Reward model
    Un modello addestrato sulle coppie di preferenza a dare un punteggio a una risposta. In RLHF è un modello separato; in DPO è implicito nel modello stesso.

    Il nostro prompt dopo le preferenze

    Prompt: «Qual è la capitale della Francia?»
    Risposta: «La capitale della Francia è Parigi. È anche la città più grande del Paese e ne è la capitale dal X secolo, salvo brevi interruzioni. Vuoi sapere qualcos'altro sulla Francia?»

    Il modello ha imparato che gli annotatori preferivano risposte complete ma non prolisse, cortesi, con un'apertura al seguito. Nessuno ha scritto questa risposta: è emersa dal confronto tra migliaia di coppie. Nota anche il rischio tipico: se gli annotatori preferiscono sistematicamente la risposta più lunga, il modello impara a essere lungo (length bias), anche quando non serve.

    Il limite

    DPO è offline: le coppie sono fisse, e il modello non genera nulla durante il training; dopo pochi step le risposte che produrrebbe non sono più quelle del dataset, e il segnale si allontana da ciò che fa davvero. Ed è soggettivo per costruzione: ottimo per stile, utilità, tono e sicurezza, ma per i compiti in cui esiste una risposta verificabile (matematica, codice, formati) il giudizio umano è lento, costoso e meno affidabile di un controllo automatico. Soprattutto, imitare o preferire non insegna a cercare: per problemi che richiedono tentativi, nessun dataset statico contiene i tentativi giusti.

    Mappa concettuale · le preferenze
    • Preferenze
      • partono da Dati
        • sono coppie chosen / rejected
        • giudicate da persone o modello giudice
      • via storica RLHF
        • è fatto di reward model e PPO
        • costa quattro modelli in memoria
      • scorciatoia DPO
        • usa come reward β · log(π / πref)
        • minimizza −log σ(margine)
      • β regola il guinzaglio
        • cioè la distanza dal modello di riferimento
      • ha come limite offline e soggettivo
        • non insegna a cercare si risolve con l'RL, capitolo 7
    → fase 4Il limite: servono un giudice che non si stanchi e non si sbagli, e un modello che produca lui stesso i tentativi da giudicare. È l'apprendimento per rinforzo con reward verificabili.

    In sintesi · fase 3

    • Problema — molte qualità sono relative: non esiste la risposta da imitare, ma si può dire quale di due è migliore
    • Dati — coppie prompt / chosen / rejected, giudicate da persone o da un modello
    • RLHF — reward model + PPO: funziona ma è costoso e fragile
    • DPO — il reward è implicito in β·log(π/πref); loss = −log σ(margine) sulla coppia; nessun reward model, nessuna generazione
    • Limite — offline, soggettivo, soggetto al length bias; non insegna a cercare
    Fase 4 · RLVR (Reinforcement Learning with Verifiable Rewards) con GRPO (Group Relative Policy Optimization)

    Il modello tenta, il verificatore giudica

    Per «Quanto fa 17 × 23?» non serve chiedere a nessuno quale risposta sia migliore: 391 è giusto e il resto è sbagliato. Si può usare questo fatto per far migliorare il modello, invece di fargli imitare soluzioni scritte da altri?

    Il problema. Nei compiti con una risposta verificabile (matematica, codice con test, formati strutturati, giochi) l'imitazione ha un tetto: il modello può al massimo diventare bravo quanto le soluzioni che vede, e le soluzioni scritte da persone non contengono i passi che a lui servirebbero (le sue esitazioni, i suoi controlli, i suoi errori tipici). Per superare il tetto bisogna lasciare che sia il modello a produrre i tentativi, e rinforzare quelli che funzionano. È l'apprendimento per rinforzo (RL, Reinforcement Learning), che qui ha un vocabolario suo.

    Policy
    Nel linguaggio dell'RL è il modello che si sta allenando, visto come regola di decisione: dato un contesto, «sceglie l'azione», cioè il token successivo.
    Rollout
    Una risposta completa generata dal modello durante il training, token per token, da valutare.
    Reward
    Un punteggio assegnato a un rollout intero: da un umano, da un reward model o, qui, da un verificatore automatico. Un solo numero per tutta la sequenza.
    Vantaggio (advantage)
    Quanto il reward di un rollout è migliore o peggiore di quanto ci si aspettava: è ciò che decide se rinforzarlo o scoraggiarlo.
    On-policy vs off-policy
    On-policy: si impara da testo generato dal modello stesso, adesso. Off-policy: da testo scritto da altri (persone, un altro modello, una versione vecchia). SFT e DPO sono off-policy; l'RL è on-policy.
    Online vs offline
    Online: il modello genera nuovi esempi durante il training (RL, OPD). Offline: il dataset è fisso fin dall'inizio (SFT, DPO).

    I dati. Il dataset contiene solo il problema e il modo di verificarlo: una domanda con la risposta finale attesa, oppure un esercizio di programmazione con i suoi test. Nessuna soluzione scritta per esteso. Le soluzioni le genera il modello, durante il training, e un programma (il verificatore) le controlla: per la matematica confronta il risultato con quello atteso, per il codice esegue i test, per un JSON controlla lo schema.

    Da qui il nome RLVR: il reward è verificabile, oggettivo, e per questo difficile da «truccare» (il reward hacking, in cui il modello trova un modo di ottenere punti senza risolvere il problema, resta possibile se il verificatore è lasco: per esempio un test troppo debole).

    Come si trasforma un reward in un gradiente. Qui c'è il passaggio nuovo rispetto a tutto il resto del documento. La loss dei capitoli precedenti confrontava la distribuzione del modello con un token obiettivo; qui non c'è un token obiettivo, c'è un numero alla fine della sequenza. L'idea del policy gradient è semplice: per ogni rollout, si calcola la log-probabilità che il modello ha dato ai propri token, e la si moltiplica per il vantaggio.

    Se il vantaggio è positivo, il gradiente spinge ad alzare la probabilità di quei token (come se fossero il target di un SFT); se è negativo, ad abbassarla. L'aggiornamento è la stessa mossa w ← w − η · gradiente di sempre: cambia solo come si costruisce il segnale.

    GRPO: il vantaggio si calcola dentro il gruppo. Perché serve «quanto ci si aspettava»? Se un problema è facile e il modello lo risolve 9 volte su 10, il decimo tentativo sbagliato è informativo, i nove giusti quasi no; se è difficile e lo risolve 1 volta su 10, è quel tentativo giusto a contare.

    Nel PPO classico questa aspettativa la stima un secondo modello (il critic), grande quanto la policy. GRPO (2024) la sostituisce con una media: per ogni prompt il modello genera un gruppo di N risposte, e il vantaggio di ciascuna è il suo reward meno la media del gruppo, diviso per la deviazione standard.

    Sopra la media si rinforza, sotto si scoraggia, e se tutte hanno lo stesso reward (tutte giuste o tutte sbagliate) il vantaggio è zero per tutte e quel gruppo non insegna nulla. Si aggiunge una penalità KL verso il modello di riferimento, per non allontanarsi troppo, e un clipping che limita quanto un singolo step può cambiare le probabilità.

    Calcolo · il vantaggio in GRPO

    vantaggio=Ai = ri − media del gruppo deviazione standard del gruppo
    ri è il reward dell'i-esima risposta delle N del gruppo: sopra la media si rinforza, sotto si scoraggia
    segnale per i token=log p(token) × Ai
    vantaggio positivo: si alza la probabilità; negativo: si abbassa
    tutte con lo stesso reward=A = 0 per tutte
    tutte giuste o tutte sbagliate: quel gruppo non insegna nulla

    Laboratorio: un passo di GRPO

    vantaggi reali · dinamica semplificata
    Prompt: «Quanto fa 17 × 23?» Verificatore: risposta_finale == 391

    Probabilità di risposta corretta nel tempo
    Ai = (ri − media(r)) / dev.std(r)

    I reward e i vantaggi sono calcolati davvero con la formula di GRPO; l'effetto dell'aggiornamento sulla probabilità di risposta corretta è una dinamica semplificata (nella realtà dipende dai gradienti sui pesi). Prova la difficoltà «Difficile»: quasi tutti i gruppi sono tutti sbagliati, i vantaggi valgono zero e il modello non impara niente. Per questo nell'RLVR si selezionano prompt di difficoltà intermedia (curriculum). Allo stesso modo, un prompt che il modello risolve sempre non insegna più nulla.

    Che cosa serve in memoria durante il training

    PPO
    Policy (si allena)Riferimento (congelato)Reward modelCritic / value model (si allena)

    Il critic stima «quanto mi aspetto di guadagnare da qui» ed è grande quanto la policy.

    GRPO + RLVR
    Policy (si allena)Riferimento (congelato)Verificatore (codice)critic

    La media del gruppo sostituisce il critic come baseline, il verificatore sostituisce il reward model: all'incirca metà della memoria.

    Che cosa emerge. Qui il modello non imita più: esplora. Genera ragionamenti suoi e rinforza quelli che portano alla risposta giusta, e così può superare i dati di partenza. È in questa fase che nei modelli di ragionamento (DeepSeek-R1 è il caso documentato più noto, 2025) compaiono comportamenti che nessuno ha scritto negli esempi: ricontrollare i passaggi, tornare indietro dopo un errore, provare una seconda strada, scrivere catene di ragionamento sempre più lunghe quando il problema lo richiede. Sono comportamenti che aumentano la probabilità di reward, e per questo vengono rinforzati.

    Il limite

    Serve un verificatore, quindi la fase funziona solo dove la correttezza è controllabile da un programma: non per un saggio, una consulenza, una conversazione. Il segnale è sparso: un numero per migliaia di token generati, e il modello deve scoprire da solo quale passo ha causato l'errore, con molti tentativi; per questo l'RL è la fase più costosa in calcolo dopo il pre-training, dominata dalla generazione dei rollout. E un modello così allenato è grande e lento da servire: la sua capacità di ragionare costa a ogni risposta.

    Il nostro prompt (uno verificabile) dopo l'RL

    Prompt: «Quanto fa 17 × 23?»
    Risposta: «17 × 23 = 17 × 20 + 17 × 3 = 340 + 51 = 391. Verifica: 391 ÷ 17 = 23 ✓. 391.»

    Il passo di verifica non era negli esempi: è stato rinforzato perché i rollout che ricontrollavano ottenevano reward più spesso.

    Mappa concettuale · l'RL con verificatore
    • RL con verificatore
      • risponde al limite dell' imitazione
        • lasciando che il modello produca i tentativi
      • giudica con un Verificatore
        • dà un reward verificabile
        • resta possibile il reward hacking
      • trasforma il reward con Policy gradient
        • moltiplica la log-probabilità per il vantaggio
      • calcola il vantaggio con GRPO
        • usa un gruppo di N risposte
        • al posto del critic
        • aggiunge penalità KL e clipping
      • fa emergere ragionamenti nuovi
        • ma serve un dominio verificabile; segnale sparso
    → fase 5Il limite: il modello che sa ragionare è grande e caro. Si può trasferire ciò che ha imparato a un modello piccolo, senza rifare l'RL da capo? È la distillazione, e il modo in cui la si fa cambia molto il risultato.

    In sintesi · fase 4

    • Problema — l'imitazione ha un tetto; nei compiti verificabili si può fare meglio lasciando tentare il modello
    • Dati — solo problema + verificatore; le soluzioni le genera il modello (on-policy, online)
    • Segnale — un reward 0/1 per rollout, trasformato in gradiente moltiplicando la log-probabilità dei token per il vantaggio
    • GRPO — vantaggio = reward relativo alla media del gruppo, normalizzato; niente critic; penalità KL e clipping
    • Risultato — comportamenti di ragionamento emergenti (verifica, backtracking)
    • Limite — solo domini verificabili; segnale sparso e costoso; modello grande da servire
    Fase 5 · Knowledge distillation e OPD (On-Policy Distillation, distillazione on-policy)

    Lo student scrive, il teacher corregge ogni parola

    Ho un modello da 70 miliardi di parametri che ragiona bene e uno da 7 che costa un decimo. Come trasferisco la capacità dal primo al secondo?

    Il problema. Rifare l'RL sul modello piccolo funziona male: un modello piccolo scopre da solo meno soluzioni, quindi riceve meno reward, quindi impara più lentamente. Ma il modello grande (il teacher) ha già le risposte, e molto di più: per ogni contesto ha un'intera distribuzione sul token successivo. La distillazione usa il teacher come fonte di segnale per lo student. Il punto delicato è chi scrive il testo su cui lo student impara.

    Distillazione classica (off-policy). Il teacher genera molte soluzioni, e lo student le imita con un SFT: segnale denso (ogni token), ma sulle traiettorie del teacher. Lo student vede solo ragionamenti perfetti. Quando poi, in inferenza, sbaglia un passo, si trova in un territorio mai visto in training e non sa recuperare: è l'exposure bias (distorsione da esposizione). L'errore si propaga.

    RL sullo student (on-policy, sparso). Lo student genera, il verificatore giudica. Impara sui propri errori, ma con un numero per sequenza: deve scoprire da solo, in molti tentativi, quale dei suoi passi era sbagliato.

    OPD: on-policy e denso. Lo student genera la soluzione; poi, per ogni token che ha scritto, il teacher dice quale distribuzione avrebbe avuto lui in quel punto, dato il testo dello student fino a lì.

    La loss confronta le due distribuzioni token per token con la divergenza KL inversa (reverse KL, KL(student ‖ teacher)): penalizza lo student dove assegna probabilità a token che il teacher riterrebbe improbabili.

    Il risultato è un segnale che ha le due qualità insieme: è sui propri errori (on-policy) ed è denso (ogni token). Un errore in un passo viene segnalato in quel passo, e i passi corretti successivi non vengono puniti, perché il teacher li giudica nel contesto dello student. I risultati pubblicati (2024–2025) riportano guadagni paragonabili all'RL con un ordine di grandezza in meno di calcolo.

    Laboratorio: tre modi di insegnare allo student

    esempio costruito · probabilità illustrative

    Le probabilità del teacher sono scelte a mano per un esempio leggibile (in un sistema reale sono i veri logit del teacher sul testo dello student), ma la logica delle tre modalità è esatta: chi genera il testo, e quanti numeri di feedback arrivano per sequenza.

    Chi genera il testoFeedbackPregioDifetto
    Distillazione off-policy (SFT sul teacher)Il teacherOgni tokenDenso, economicoExposure bias: lo student non vede i propri errori
    RL con verificatoreLo student1 numero per sequenzaSui propri erroriSparso: molti tentativi per capire dove si sbaglia
    OPDLo studentOgni token, dal teacherSui propri errori e densoServe un teacher migliore, e farlo girare su ogni token
    Il limite

    Lo student non supererà il teacher: la distillazione comprime, non scopre. E il teacher deve essere interrogato su ogni token generato dallo student, il che costa, anche se molto meno di generare i rollout dell'RL. In pratica le fasi si combinano: RL sul modello grande per scoprire, OPD per trasferire ai modelli piccoli.

    Mappa concettuale · la distillazione
    • Distillazione
      • trasferisce da teacher a student
        • perché l'RL sul piccolo funziona male
      • via classica SFT sul teacher off-policy
        • segnale denso
        • difetto exposure bias
      • via RL RL sullo student on-policy
        • segnale sparso: un numero per sequenza
      • via OPD On-policy e denso
        • la loss è la reverse KL token per token
        • lo student scrive, il teacher corregge ogni parola
      • ha come limite il teacher
        • lo student non lo supera

    In sintesi · fase 5

    • Problema — il modello che ragiona è grande e caro; l'RL diretto sul piccolo funziona male
    • Tre vie — SFT sulle soluzioni del teacher (denso, off-policy), RL sullo student (on-policy, sparso), OPD (on-policy e denso)
    • Loss di OPD — reverse KL tra student e teacher, token per token, sulle sequenze dello student
    • Limite — non supera il teacher; costa interrogare il teacher su ogni token

    Parte III

    Approfondimenti: dentro il modello, in dettaglio

    Capitolo 9 · Approfondimenti

    Che cosa c'è dietro i cinque passi di un transformer vero

    Il capitolo 1 ha mostrato i cinque passi su un modello in miniatura con pesi scritti a mano. Questo capitolo apre ciascun passo come è realizzato in un modello reale: come si costruisce il vocabolario (A), l'algebra che serve, in otto passi con laboratori (B), la matrice di embedding e la posizione (C), il calcolo completo di uno strato con attention a tre matrici, MLP, connessioni residue e normalizzazione (D), la testa di output con softmax e temperatura (E), i conti esatti di un modello da 7 miliardi di parametri (F), e la backpropagation su una rete a due strati con molti step (G). Si può leggere in qualsiasi ordine; ogni sezione è autonoma.

    A · Il tokenizer: come nasce il vocabolario (BPE)

    Nel modello in miniatura il vocabolario era di 12 parole intere. Un modello vero ne ha 30.000–250.000, e non sono parole: chi decide quali frammenti di testo diventano token?

    Nel capitolo 1 il passo 1 era dato per scontato: il testo viene spezzato in token, frammenti presi da un vocabolario fisso (tipicamente 30.000–250.000 voci), e ogni frammento è sostituito dal suo ID, la sua posizione nel vocabolario. Una frase come «La capitale della Francia è» diventa qualcosa come [1529, 8871, 503, 9412, 1032]: «La», «·capitale», «·della», «·Francia», «·è» (il punto · segna lo spazio, che fa parte del token seguente). In italiano un token corrisponde in media a 3–4 caratteri: le parole comuni restano intere, quelle rare si spezzano in pezzi.

    Perché token e non parole o lettere? Con le lettere le sequenze sarebbero lunghissime e ogni simbolo direbbe pochissimo; con le parole il vocabolario sarebbe sterminato e qualsiasi parola nuova, errore di battitura o nome proprio sarebbe irrappresentabile. I token sono il compromesso: frequenti abbastanza da avere un significato, piccoli abbastanza da comporre qualsiasi testo.

    Chi decide quali frammenti entrano nel vocabolario? Un algoritmo, il BPE (Byte Pair Encoding, codifica per coppie di byte), che si «allena» sul corpus prima del modello, una volta sola:

    1. Si parte dai simboli più piccoli: i singoli caratteri (nei tokenizer moderni, i singoli byte, così qualsiasi testo è rappresentabile).
    2. Si conta quale coppia di simboli adiacenti compare più spesso in tutto il corpus.
    3. Quella coppia viene fusa in un nuovo simbolo, che entra nel vocabolario. La regola di fusione (merge) viene salvata.
    4. Si ripete finché il vocabolario raggiunge la dimensione desiderata.

    Il risultato: le sequenze frequenti («gatt», «ione», «·della») diventano un token solo, mentre le parole rare vengono composte da pezzi. Per tokenizzare un testo nuovo si applicano le stesse regole di fusione, nello stesso ordine in cui sono state imparate. Il laboratorio qui sotto esegue l'algoritmo vero su un corpus minuscolo.

    Laboratorio: BPE passo per passo

    algoritmo reale
    Coppie adiacenti più frequenti
    Regole di merge imparate, in ordine
    Vocabolario attuale: token con il loro ID
    sp token specialea simbolo di baseab creato da un mergeab ultimo merge

    Il vocabolario parte dai simboli di base (i singoli caratteri presenti nel corpus) più i token speciali, e ogni merge aggiunge un token con un nuovo ID. I simboli di base non vengono mai tolti, anche quando nel corpus non compaiono più da soli: servono per scrivere parole mai viste. Il training del tokenizer si ferma quando il vocabolario raggiunge la dimensione scelta; da lì in poi ID e token non cambiano più.

    Il simbolo · rappresenta lo spazio: come nei tokenizer reali (GPT, Llama) lo spazio fa parte del token che lo segue, quindi «·gatto» e «gatto» sono token diversi. I tokenizer reali lavorano sui byte UTF-8 (Unicode Transformation Format, 8 bit) e fanno decine di migliaia di merge su gigabyte di testo, ma l'algoritmo è esattamente questo. Le coppie che compaiono una volta sola non vengono fuse (frequenza minima 2). Cambiando i due vincoli il laboratorio ripete da capo lo stesso numero di merge, così puoi confrontare i risultati.

    Il vocabolario dipende dal corpus, e poi si congela. Il tokenizer si allena su un campione rappresentativo dei dati di pre-training, una volta sola. Dopo, cambiarlo è impossibile senza riaddestrare il modello: ogni token ha la sua riga nella matrice di embedding e la sua uscita nell'ultimo strato, quindi un vocabolario diverso renderebbe inutili quei pesi. Un modello multilingua usa un solo vocabolario condiviso, allenato su una miscela bilanciata di lingue; per questo i vocabolari multilingua sono più grandi (128.000–256.000 token).

    Che cosa si configura. L'iperparametro principale è la dimensione del vocabolario, cioè quanti merge fare. La lunghezza dei singoli token non si fissa: emerge dalle frequenze. Nei fatti però è limitata dalla pre-tokenizzazione: prima del BPE un'espressione regolare divide il testo in blocchi (parole con lo spazio iniziale, numeri, punteggiatura) e i merge non superano mai quei confini. Alcune librerie offrono anche un tetto esplicito, facoltativo: max_sentencepiece_length in SentencePiece (default 16 caratteri) e max_token_length nel BpeTrainer di Hugging Face (default nessun limite).

    B · Richiamo di algebra: vettori, matrici, tensori

    Il capitolo 1 parla di liste di numeri moltiplicate per tabelle di pesi. In matematica una lista di numeri si chiama vettore e una tabella si chiama matrice. Questo richiamo costruisce, in otto passi brevi, le poche idee che servono per capire che cosa succede ai vettori dentro il modello. Basta la matematica delle superiori: ogni passo si apre con le tre cose da portarsi a casa, poi un esempio con numeri piccoli, poi la regola, e quasi sempre un laboratorio con la matematica vera.

    Ogni passo si chiude con un riquadro richiudibile, «Dove ritorna nel modello»: collega l'idea ai pezzi del modello e contiene i conti più avanzati. È chiuso e facoltativo: alla prima lettura puoi saltarlo, e riaprirlo quando un capitolo successivo ci rimanda.

    Se queste nozioni ti sono familiari, salta al Promemoria in fondo: raccoglie le definizioni in voci brevi, da riaprire quando un capitolo successivo ne usa una.

    1. Vettori: liste, frecce, punti somma, parole come punti
    2. Prodotto scalare: quanto due vettori sono d'accordo misurare la somiglianza
    3. Norma e coseno: lunghezza e direzione Pitagora, confrontare direzioni
    4. Una matrice è una trasformazione una macchina per vettori
    5. Tensori: tabelle con più indici pile di fogli di calcolo
    6. Matrice × matrice: la regola delle shape quando si può moltiplicare
    7. Perché serve una non linearità la piega che dà senso agli strati
    8. Basso rango: una matrice grande fatta di due sottili risparmiare numeri

    Vettori: liste, frecce, punti

    In tre frasi

    Un vettore è una lista ordinata di numeri, e la stessa lista si può vedere come un punto o come una freccia. Due vettori si sommano numero per numero, e moltiplicare un vettore per un numero allunga, accorcia o capovolge la sua freccia. Se le parole diventano vettori, le parole simili sono punti vicini, e perfino le frecce tra due parole possono avere un significato.

    Un vettore è una lista ordinata di numeri. Le coordinate di una città, [latitudine ; longitudine], sono un vettore di 2 numeri; il vettore di un appartamento, [metri quadri ; locali ; piano ; prezzo], un vettore di 4 numeri. Quanti numeri contiene si chiama dimensione del vettore: i vettori dei token del capitolo 1 sono vettori di dimensione 4.096.

    Tre modi di vedere la stessa lista. Con due numeri si può disegnare. [2 ; 1] si legge come una lista (è così che la vede il computer), come un punto del piano (2 passi a destra, 1 in su) o come una freccia che parte dall'origine e arriva in quel punto. Nella guida si passa dall'una all'altra: «due embedding vicini» è la lettura a punti, «due embedding che puntano nella stessa direzione» quella a frecce.

    Somma. Due vettori si sommano numero per numero: [2 ; 1] + [−1 ; 1,5] = [2 − 1 ; 1 + 1,5] = [1 ; 2,5]. Con le frecce: si appoggia l'inizio della seconda freccia sulla punta della prima, e il risultato va dall'origine all'ultima punta. La sottrazione funziona allo stesso modo, numero per numero.

    Moltiplicare per un numero. 2 · [−1 ; 1,5] = [−2 ; 3]: ogni elemento viene moltiplicato. La freccia si allunga (numero maggiore di 1), si accorcia (tra 0 e 1) o si gira dall'altra parte (numero negativo), ma resta sulla stessa retta. In questo contesto un numero singolo si chiama scalare.

    Calcolo · somma e prodotto per un numero

    somma=[2 ; 1] + [−1 ; 1,5] = [2 − 1 ; 1 + 1,5] = [1 ; 2,5]
    numero per numero
    per un numero=2 · [−1 ; 1,5] = [−2 ; 3]
    ogni elemento viene moltiplicato: la freccia si allunga ma resta sulla stessa retta

    Da 2 a 4.096 numeri. Uno spazio a 4.096 dimensioni non si può disegnare, ma le regole non cambiano: si somma e si moltiplica numero per numero. Un embedding da 4.096 numeri è un punto in quello spazio, e le parole usate in modo simile, come «gatto» e «cane», finiscono in punti vicini.

    Più avanti vedrai che dentro il modello si sommano molti vettori: è il motivo per cui la somma è così importante.

    Laboratorio: somma, scala e parallelogramma

    matematica reale

    Muovi i cursori di a e di b, poi il numero t per cui si moltiplica b: guarda dove finisce la punta della freccia scura a + t·b.

    In grigio tratteggiato c'è b prima di essere moltiplicato per t. I due lati tratteggiati colorati mostrano che si arriva nello stesso punto anche facendo prima t·b e poi a: la somma è la diagonale del parallelogramma che ha a e t·b come lati (regola del parallelogramma).

    Parole come punti: re − uomo + donna. È l'esempio del capitolo 1, riletto con le parole di questo passo. Ogni parola è un vettore di 2 numeri, [quanto è regale ; quanto è femminile]: uomo = [0,1 ; 0,1], donna = [0,1 ; 0,9], re = [0,9 ; 0,1], regina = [0,9 ; 0,9]. La freccia che porta da «uomo» a «donna» si calcola con una sottrazione, numero per numero; partendo da «re» e aggiungendo quella freccia si arriva su «regina».

    Calcolo · da uomo a donna, da re a regina

    donna − uomo=[0,1 − 0,1 ; 0,9 − 0,1] = [0 ; 0,8]
    re + (donna − uomo)=[0,9 + 0 ; 0,1 + 0,8] = [0,9 ; 0,9] = regina
    La freccia [0 ; 0,8] vuol dire «sali di 0,8 sull'asse del femminile». Scritto come re − uomo + donna è lo stesso conto in un altro ordine: prima si toglie uomo ([0,8 ; 0], resta la regalità), poi si aggiunge donna.
    0 0,51 0,51 quanto è regale → ↑ quanto è femminile uomo[0,1 ; 0,1] donna[0,1 ; 0,9] re[0,9 ; 0,1] regina[0,9 ; 0,9] donna − uomo= [0 ; 0,8] stessa freccia:re + [0 ; 0,8]

    Un piano con l'asse orizzontale «quanto è regale» e quello verticale «quanto è femminile», tutti e due da 0 a 1. Uomo in [0,1 ; 0,1] e donna in [0,1 ; 0,9], a sinistra; re in [0,9 ; 0,1] e regina in [0,9 ; 0,9], a destra. Da uomo a donna sale una freccia continua, donna − uomo = [0 ; 0,8]. Da re sale una freccia tratteggiata identica e parallela, che arriva esattamente su regina.

    Con numeri inventati il conto torna esatto. Con i vettori veri non è così: in un sistema chiamato word2vec (Mikolov e colleghi, 2013) si osservò che re − uomo + donna arriva vicino a «regina», che è solo la parola più vicina al punto calcolato, e molte analogie di questo tipo non funzionano affatto. I numeri veri sono centinaia o migliaia e nessuno ha dato loro un nome come «regale»: è un indizio che lo spazio degli embedding ha una struttura geometrica, non una regola esatta.

    Dove ritorna nel modello (si capisce meglio più avanti) somma di vettori negli strati · combinazione lineare · analogie

    Il residual stream è una somma di vettori. Dentro il modello (sezione D) il vettore di un token non viene sostituito strato dopo strato. Ogni strato calcola una correzione, cioè un altro vettore di 4.096 numeri, e la aggiunge al vettore che riceve: uscita = ingresso + correzione. Le correzioni sono due per strato: una dallo scambio di informazioni tra token (l'attention) e una dalla rielaborazione del singolo token (la MLP, Multi-Layer Perceptron, percettrone multistrato). Dopo N strati il vettore finale è quindi una somma di 2N + 1 vettori: l'embedding di partenza più tutte le correzioni. Questo flusso che si arricchisce si chiama residual stream («flusso residuo»).

    La somma aiuta anche il training. Nella somma l'ingresso passa invariato, quindi il segnale che dice a ogni peso come correggersi (il gradiente, sezione G) ha sempre una strada diretta che non viene moltiplicata da nessuno strato, e non si spegne attraversandone decine.

    Combinazione lineare. Mettendo insieme somma e moltiplicazione per un numero si ottiene s·a + t·b, una combinazione lineare di a e b. Se a e b non sono paralleli, scegliendo s e t si raggiunge qualsiasi punto del piano: due direzioni indipendenti bastano a descrivere uno spazio a due dimensioni. L'idea ritorna nel passo sulle trasformazioni qui sotto: il risultato di matrice × vettore è una combinazione lineare delle colonne della matrice.

    Una precisazione sull'analogia. Nei test di word2vec la parola più vicina a re − uomo + donna si cerca escludendo le tre parole di partenza: senza questa esclusione spesso la più vicina resterebbe «re» stesso. Le analogie che riescono sono una parte, non tutte, e la «direzione del femminile» è solo approssimativamente la stessa per tutte le coppie.

    Prodotto scalare: quanto due vettori sono d'accordo

    In tre frasi

    Il prodotto scalare prende due liste della stessa lunghezza, moltiplica i numeri a coppie e somma i risultati. Il totale è grande e positivo se le due liste «vanno d'accordo», vicino a zero se non hanno niente in comune, negativo se sono opposte. Con le frecce misura quanto due frecce puntano nella stessa direzione, tenendo conto anche di quanto sono lunghe.

    Due amici danno un voto da −2 a +2 agli stessi cinque film. Per capire se hanno gusti simili si moltiplicano i loro voti film per film e si sommano i prodotti: se un film piace a entrambi (+ × +) o non piace a nessuno dei due (− × −) il contributo è positivo, se sono in disaccordo è negativo.

    Con i numeri. Anna vota [2 ; 1 ; −1 ; 0 ; 2], Bruno [1 ; 2 ; −2 ; 1 ; 1]. Film per film: 2·1 + 1·2 + (−1)·(−2) + 0·1 + 2·1 = 2 + 2 + 2 + 0 + 2 = 8, un totale alto: gusti simili. Carla vota [−2 ; −1 ; 1 ; 0 ; −2], l'opposto di Anna: −4 − 1 − 1 + 0 − 4 = −10, gusti opposti. Questo totale è il prodotto scalare dei due vettori di voti.

    Calcolo · i gusti di Anna, Bruno e Carla

    Anna · Bruno=2·1 + 1·2 + (−1)·(−2) + 0·1 + 2·1 = 2 + 2 + 2 + 0 + 2 = 8
    Anna vota [2 ; 1 ; −1 ; 0 ; 2], Bruno [1 ; 2 ; −2 ; 1 ; 1]: un totale alto, gusti simili
    Anna · Carla=−4 − 1 − 1 + 0 − 4 = −10
    Carla vota [−2 ; −1 ; 1 ; 0 ; −2], l'opposto di Anna: gusti opposti
    a · b = a₁b₁ + a₂b₂ + … + adbd Si moltiplicano i numeri che stanno nella stessa posizione e si sommano i prodotti. Le due liste devono avere la stessa lunghezza d; il risultato è un numero solo.

    Con le frecce. Lo stesso numero si calcola anche con le lunghezze delle due frecce e l'angolo θ tra loro. Il coseno dell'angolo, cos θ, vale 1 se le frecce puntano nello stesso verso, 0 se sono perpendicolari, −1 se sono opposte:

    a · b = |a| |b| cos θ |a| e |b| sono le lunghezze delle frecce (come si calcolano lo spiega il prossimo passo), θ è l'angolo tra loro.

    Quindi il segno dipende solo dall'angolo: positivo sotto i 90°, zero a 90° (le frecce si dicono ortogonali, cioè perpendicolari), negativo oltre. La grandezza invece dipende anche dalle lunghezze: una freccia molto lunga dà prodotti scalari grandi anche con poca somiglianza di direzione. Per confrontare solo le direzioni serve il coseno del prossimo passo.

    L'ombra. Il laboratorio mostra un'altra lettura. Immagina di illuminare b dall'alto rispetto alla retta su cui sta a: l'ombra di b su quella retta è lunga |b| cos θ e dice quanta parte di b va nella direzione di a. Si chiama proiezione di b su a, e il prodotto scalare è la lunghezza di a moltiplicata per quell'ombra.

    Laboratorio: il prodotto scalare come misura di somiglianza

    matematica reale

    Ruota a e b e cambia la lunghezza di b: osserva l'ombra di b sulla retta di a (il segmento spesso) e il segno del prodotto scalare.

    a ha lunghezza fissa 1,2. Il segmento spesso sulla retta di a è l'ombra (la proiezione) di b: quando cade dalla parte opposta ad a, il prodotto scalare è negativo. Le due formule del riquadro danno sempre lo stesso numero.

    Dove ritorna nel modello (si capisce meglio più avanti) perché le due formule coincidono · dove si usa nel modello · la divisione per √dk

    Perché le due formule coincidono. Per il teorema di Carnot, il teorema di Pitagora generalizzato a un triangolo qualsiasi. Si scrive in due modi la lunghezza del terzo lato, a − b, e si confrontano le due righe:

    Calcolo · perché le due formule coincidono

    Carnot: |a − b|²=|a|² + |b|² − 2 |a| |b| cos θ
    per elementi: |a − b|²=Σ (aᵢ − bᵢ)² = |a|² + |b|² − 2 Σ aᵢbᵢ
    ⇒Σ aᵢbᵢ = |a| |b| cos θ
    Σ vuol dire «somma su tutti gli elementi». La seconda riga sviluppa i quadrati elemento per elemento; l'uguaglianza finale vale in qualsiasi numero di dimensioni.

    Calcolo · l'ombra di b su a

    lunghezza dell'ombra=|b| cos θ = a · b / |a|
    freccia dell'ombra=(a · b / |a|²) · a
    Se a è lungo 1, il prodotto scalare è la proiezione.

    Nell'attention: query · key. Negli strati (sezione D) ogni token calcola due vettori: una query, «che cosa sto cercando», e una key, «che cosa offro». Il punteggio con cui il token i guarda il token j è il prodotto scalare qᵢ · kⱼ, diviso per √dk: tanto più alto quanto più ciò che i cerca è allineato con ciò che j offre. Tutti i punteggi insieme sono un unico prodotto tra matrici, Q·Kᵀ (passo sulle shape).

    In uscita: un punteggio per ogni token. Il punteggio (logit) del token v è il prodotto scalare tra l'ultimo vettore del modello e la riga di v nella matrice di output: V prodotti scalari, uno per voce del vocabolario. Vince la riga più allineata; la softmax trasforma i punteggi in probabilità (sezione C e capitolo 2).

    Perché nell'attention si divide per √dk. Se query e key hanno dk elementi indipendenti, con media 0 e varianza 1, il loro prodotto scalare è la somma di dk termini casuali di varianza 1:

    Calcolo · perché si divide per √dk

    varianza(q · k)=dk   →   deviazione standard = √dk
    q · k / √dk→deviazione standard 1
    Con dk = 128: √128 ≈ 11,3.

    Senza la divisione, con dk = 128 i punteggi oscillerebbero di circa ±11, e una softmax su numeri così distanti mette quasi tutto il peso su un solo token: i gradienti verso gli altri diventano quasi nulli e il training si inceppa. Dividere per √dk ≈ 11,3 riporta la deviazione standard a 1, qualunque sia la dimensione (Vaswani e colleghi, 2017). È lo stesso fenomeno che, visto dall'altra parte, rende quasi perpendicolari i vettori casuali nel riquadro del prossimo passo.

    Norma e coseno: lunghezza e direzione

    In tre frasi

    La norma di un vettore è la lunghezza della sua freccia, e si calcola con il teorema di Pitagora. Dividendo un vettore per la sua norma si ottiene una freccia lunga 1 che punta nello stesso verso. La similarità coseno confronta due vettori guardando solo dove puntano, non quanto sono lunghi: 1 se puntano nello stesso verso, 0 se sono perpendicolari, −1 se sono opposti.

    Lunghezza con Pitagora. La freccia [3 ; 4] fa 3 passi a destra e 4 in su: è l'ipotenusa di un triangolo rettangolo con cateti 3 e 4, quindi è lunga √(3² + 4²) = √25 = 5. Con più numeri si fa lo stesso: si sommano i quadrati di tutti gli elementi e si prende la radice. La lunghezza di a si scrive |a| e si chiama norma.

    Calcolo · la norma

    |a|=√(a₁² + a₂² + … + ad²)
    |[3 ; 4]|=√(9 + 16) = 5
    |[1 ; 2 ; 2]|=√(1 + 4 + 4) = 3
    È anche √(a · a): il prodotto scalare di un vettore con sé stesso, sotto radice.

    Una freccia lunga 1. Dividendo ogni elemento per la norma, la freccia diventa lunga 1 senza cambiare direzione: [3 ; 4] / 5 = [0,6 ; 0,8]. Si chiama vettore unitario. È come portare tutte le frecce alla stessa lunghezza per confrontare soltanto dove puntano.

    Similarità coseno. a = [3 ; 4] e b = [6 ; 8] puntano nello stesso verso, ma b è lungo il doppio. Il prodotto scalare, 3·6 + 4·8 = 50, dipende anche dalle lunghezze. Dividendolo per le due norme, 5 e 10, si ottiene 50 / 50 = 1: stessa direzione. Con c = [4 ; −3], invece, a · c = 12 − 12 = 0: frecce perpendicolari, coseno 0.

    Calcolo · la similarità coseno

    a · b=3·6 + 4·8 = 50
    a = [3 ; 4] e b = [6 ; 8] puntano nello stesso verso, ma b è lungo il doppio
    cos θ=50 / (5 · 10) = 50 / 50 = 1
    le norme sono 5 e 10: stessa direzione
    a · c=3·4 + 4·(−3) = 12 − 12 = 0
    con c = [4 ; −3]: frecce perpendicolari, coseno 0
    cos θ = a · b / (|a| |b|) Il prodotto scalare diviso per le due lunghezze. Ignora quanto sono lunghe le frecce e va da −1 (versi opposti) a 1 (stesso verso).

    È la misura usata per cercare testi simili: si confronta il vettore di una domanda con quello di ogni documento e si tengono i documenti con il coseno più alto. Nel laboratorio del prodotto scalare, qui sopra, il coseno è l'ultima riga del riquadro grigio.

    In spazi con migliaia di dimensioni succede una cosa che il piano non lascia immaginare: due direzioni prese a caso sono quasi sempre quasi perpendicolari. Il riquadro qui sotto lo mostra con un laboratorio.

    Dove ritorna nel modello (si capisce meglio più avanti) la normalizzazione negli strati · alte dimensioni, con laboratorio

    Normalizzare dentro il modello. Negli strati (sezione D), prima di ogni calcolo il vettore di un token viene riportata a una scala standard con RMSNorm (Root Mean Square Normalization, normalizzazione per la radice della media dei quadrati). Calcola la grandezza tipica di un elemento, poi divide ogni elemento per quella e lo moltiplica per un guadagno gi imparato, uno per dimensione:

    Calcolo · la normalizzazione RMSNorm

    RMS(x)=√((x₁² + … + xd²) / d) = |x| / √d
    RMSNorm(x)i=gi · xi / RMS(x)
    x = [3 ; 4]: RMS=√(25 / 2) ≈ 3,54,   x / RMS ≈ [0,85 ; 1,13]
    In pratica sotto la radice si aggiunge una costante minuscola ε, che evita di dividere per zero.

    Senza i guadagni ogni vettore esce con norma esattamente √d (√2 nell'esempio): la direzione resta, la scala viene azzerata. Serve perché il residual stream (riquadro del passo sui vettori) è una somma che cresce strato dopo strato: senza normalizzazione ogni pezzo dello strato riceverebbe numeri su scale diverse, e i gradienti con loro.

    In alta dimensione quasi tutto è ortogonale. Prendi due direzioni a caso nel piano: l'angolo tra loro è uniforme, e coseni vicini a ±1 capitano spesso. In 4.096 dimensioni due vettori casuali sono quasi sempre quasi perpendicolari, con coseno tra −0,05 e +0,05. Il motivo: il prodotto scalare di due vettori casuali è una somma di d termini di segno casuale, che in parte si annullano e crescono solo come √d, mentre il prodotto delle norme cresce come d. Il rapporto va come 1/√d:

    Calcolo · il coseno in alta dimensione

    varianza del coseno=1/d   →   deviazione standard = 1/√d
    d = 4.096: 1/64≈0,0156
    Vale esattamente per direzioni uniformemente casuali.

    Perché conta. Se si accetta una piccola tolleranza (per esempio coseni entro ±0,1), il numero di direzioni «quasi indipendenti» che entrano in uno spazio cresce in modo esponenziale con d, ben oltre il numero delle dimensioni: è una conseguenza del lemma di Johnson-Lindenstrauss. La ricerca sull'interpretabilità suggerisce che i modelli sfruttino proprio questo spazio: rappresentano molti più concetti che dimensioni, ciascuno come una direzione quasi ortogonale alle altre, accettando una piccola interferenza (superposition, sovrapposizione; Elhage e colleghi, 2022). Vale anche al contrario: in 4.096 dimensioni un coseno di 0,2 tra due vettori non è «poco», è quasi 13 deviazioni standard sopra quello che darebbe il caso.

    Laboratorio: coseni tra vettori casuali

    matematica reale

    Sposta la dimensione d da 2 a 4.096 e guarda l'istogramma dei coseni di 1.000 coppie di vettori casuali stringersi intorno allo zero.

    Ogni elemento dei vettori è estratto da una gaussiana (media 0, varianza 1) con un generatore pseudo-casuale con seme (mulberry32) e la trasformazione di Box-Muller: lo stesso seme dà sempre lo stesso istogramma. La curva è la distribuzione esatta del coseno tra due direzioni casuali in d dimensioni, con densità proporzionale a (1 − x²)(d−3)/2. Gli embedding veri non sono vettori casuali: di solito condividono una componente comune, e il coseno tra due token non correlati spesso non è centrato sullo zero.

    Una matrice è una trasformazione

    In tre frasi

    Una matrice è una tabella di numeri che funziona come una macchina: entra un vettore, ne esce un altro. Ogni numero dell'uscita è il prodotto scalare tra una riga della matrice e il vettore d'ingresso. Una matrice con m righe e n colonne prende vettori di n numeri e restituisce vettori di m numeri.

    Un esempio 2 × 2. La matrice A = [[2, 1], [0, 1]] ha due righe: la prima contiene 2 e 1, la seconda 0 e 1 (in una riga di testo si scrive così, una coppia di parentesi quadre per ogni riga; «2 × 2» vuol dire 2 righe e 2 colonne). Entra il vettore x = [1 ; 1]. La prima riga per x dà 2·1 + 1·1 = 3; la seconda dà 0·1 + 1·1 = 1. Esce Ax = [3 ; 1].

    Calcolo · A · x, riga per riga e colonna per colonna

    riga 1 · x=[2, 1] · [1, 1] = 2 + 1 = 3
    riga 2 · x=[0, 1] · [1, 1] = 0 + 1 = 1
    riga per riga: A = [[2, 1], [0, 1]], x = [1 ; 1]
    1 · [2 ; 0] + 1 · [1 ; 1]=[3 ; 1]
    colonna per colonna: le colonne sono dove finiscono [1 ; 0] e [0 ; 1], cioè [2 ; 0] e [1 ; 1]
    yi = rigai · x   per ogni riga i L'uscita y = Ax ha un numero per ogni riga di A: ogni numero è il prodotto scalare di quella riga con x.

    Ogni riga è un rilevatore. Il prodotto scalare misura quanto due vettori vanno d'accordo, quindi ogni riga della matrice «misura» quanto il vettore d'ingresso le somiglia, e l'uscita è l'elenco delle misure. Una matrice con 32.000 righe, una per token del vocabolario, applicata al vettore finale del capitolo 1 dà 32.000 misure: sono i punteggi del passo 5.

    Colonna per colonna. Lo stesso risultato si ottiene prendendo x₁ volte la prima colonna più x₂ volte la seconda: 1·[2 ; 0] + 1·[1 ; 1] = [3 ; 1]. Le colonne dicono quindi dove finiscono le frecce [1 ; 0] e [0 ; 1].

    Che cosa fa al piano. In due dimensioni si vede che cosa fa una matrice a tutti i punti insieme: la griglia può ruotare, allungarsi, inclinarsi o schiacciarsi, ma le rette restano rette, le parallele restano parallele e l'origine resta ferma. Per questo si dice che una matrice è una trasformazione lineare. Quattro casi tipici, tutti nel laboratorio:

    • Rotazione: gira il piano senza cambiare lunghezze e angoli.
    • Scala [[s₁, 0], [0, s₂]]: allunga o accorcia ciascun asse per conto suo.
    • Taglio (shear) [[1, k], [0, 1]]: fa scivolare le righe orizzontali le une sulle altre, come un mazzo di carte spinto di lato.
    • Proiezione [[1, 0], [0, 0]]: butta via la seconda coordinata. Punti diversi finiscono nello stesso posto, quindi non si può tornare indietro: l'informazione è persa.

    Matrici non quadrate. Una matrice con 3 righe e 2 colonne prende vettori di 2 numeri e ne restituisce 3, uno per riga: può allungare o accorciare la lista. Dentro il modello capita spesso.

    Laboratorio: che cosa fa una matrice 2 × 2 al piano

    matematica reale

    Premi i pulsanti con le matrici di esempio, oppure muovi i quattro numeri di A: guarda come si deforma la griglia e dove finisce la freccia x = [1 ; 1].

    La griglia sottile di fondo è il piano di partenza, quella colorata è il piano dopo A. Le due frecce colorate sono le colonne di A, cioè dove finiscono [1 ; 0] e [0 ; 1]; il parallelogramma che formano è il quadratino di lato 1 dopo la trasformazione. Il numero «det A» nel riquadro grigio dice per quanto si moltiplica la sua area (si chiama determinante, vedi il riquadro in fondo al passo).

    Il caso più semplice: un vettore con un solo 1. Un vettore one-hot ha tutti 0 tranne un 1, per esempio [0 ; 0 ; 1 ; 0 ; 0]: uno solo è «acceso» (hot). Moltiplicandolo per una matrice, come nel laboratorio qui sotto, tutti i termini con lo 0 si annullano e resta solo la riga che corrisponde all'1. È così che il modello trova il vettore di un token: la tabella degli embedding (E) è una matrice con una riga per token, e l'ID dice quale riga prendere (sezione C).

    Laboratorio: one-hot × matrice = una riga

    matematica reale

    Scegli un token e guarda quale riga della matrice E sopravvive alla moltiplicazione.

    Il vettore one-hot «seleziona» una riga: moltiplicando, tutti i termini con lo 0 si annullano e resta solo la riga dell'ID acceso. Per questo, nella pratica, l'embedding di un token si ottiene leggendo direttamente la sua riga, senza fare davvero la moltiplicazione.

    Dove ritorna nel modello (si capisce meglio più avanti) determinante · l'ordine delle trasformazioni · matrici negli strati · one-hot nella loss

    Il determinante dice per quanto la trasformazione moltiplica le aree:

    det [[a, b], [c, d]] = ad − bc Il valore assoluto è il fattore per cui cambiano le aree; il segno dice se il piano viene ribaltato.

    Vale 1 per rotazioni e tagli, s₁·s₂ per la scala, 0 quando il piano viene schiacciato su una retta (la proiezione: il rango scende da 2 a 1, passo sul basso rango), negativo quando viene ribaltato come in uno specchio.

    Composizione: l'ordine conta. Applicare prima B e poi A equivale ad applicare una sola matrice, il prodotto A·B: A(Bx) = (AB)x, che si legge da destra a sinistra. Scambiare l'ordine cambia il risultato. Con R = [[0, −1], [1, 0]] (rotazione di 90°) e S = [[2, 0], [0, 1]] (raddoppia la prima coordinata):

    Calcolo · l'ordine delle trasformazioni conta

    S·R=[[0, −2], [1, 0]]   ma   R·S = [[0, −1], [2, 0]]
    (S·R) · [1 ; 0]=[0 ; 1]   ruotare e poi scalare
    (R·S) · [1 ; 0]=[0 ; 2]   scalare e poi ruotare
    S·R si legge da destra: prima R, poi S. Come si moltiplicano due matrici lo spiega la passo sulle shape.

    Due conseguenze: una pila di strati soltanto lineari collassa in una matrice sola (passo sulla non linearità), e nel calcolo all'indietro dei gradienti il segnale attraversa gli strati in ordine inverso, moltiplicato ogni volta per la trasposta Wᵀ, cioè la matrice dei pesi con righe e colonne scambiate (sezione G).

    Le matrici negli strati. Nella MLP di ogni strato (sezione D) una prima matrice allarga il vettore da d a un numero più grande (4d nel transformer originale, 11.008 ≈ 2,7d in Llama 2 7B) e una seconda la riporta a d; nell'attention ogni «testa» la proietta da d a pochi numeri (passo sul basso rango). Le rotazioni servono a RoPE (Rotary Position Embedding, embedding posizionale rotazionale), che ruota coppie di elementi di query e key di un angolo che dipende dalla posizione del token (sezione C). L'identità, la matrice che lascia tutto com'è, è ciò che fa la connessione residua sul suo «binario diretto».

    Il one-hot nella loss. Il one-hot compare anche nel calcolo dell'errore: è il vettore «obiettivo» y, con un 1 sul token giusto, con cui si confronta la distribuzione di probabilità p del modello; il gradiente rispetto ai punteggi è p − y (capitolo 2).

    Tensori: tabelle con più indici

    In tre frasi

    Un tensore è una tabella di numeri con un numero qualsiasi di indici: un numero solo ne ha zero, una lista uno, una tabella due, una pila di tabelle tre. La shape (forma) è l'elenco delle lunghezze, per esempio [2 × 3 × 4]: 2 tabelle di 3 righe e 4 colonne, 24 numeri in tutto. Dentro un LLM i dati viaggiano quasi sempre come tensori, perché si elaborano tante frasi e tanti token insieme.

    Un foglio di calcolo aiuta a vedere la scala. Una casella contiene un numero; una riga di caselle è una lista; un foglio è una tabella con righe e colonne; una cartella di fogli tutti uguali aggiunge una terza direzione, «quale foglio»; uno scaffale di cartelle ne aggiunge una quarta. In matematica sono lo scalare, il vettore, la matrice e poi i tensori con tre, quattro o più indici (si dice anche assi).

    2,7

    Rango 0 · scalare shape [ ], 1 numero. Per esempio l'errore medio del modello su un gruppo di frasi.

    d

    Rango 1 · vettore shape [d], d numeri. Il vettore di un token.

    dL

    Rango 2 · matrice shape [L × d]. I vettori di una frase di L token, una per riga.

    dLB

    Rango 3 shape [B × L × d]: B frasi elaborate insieme, ognuna una matrice L × d.

    ogni cubo: h × L × LB

    Rango 4 shape [B × h × L × L]: una fila di B cubi. Compare dentro gli strati (vedi il riquadro in fondo al passo).

    Cinque disegni affiancati, dal più semplice al più ricco. Lo scalare è una sola casella, con shape vuota. Il vettore è una fila di d caselle. La matrice è una griglia di L righe e d colonne. Il tensore di rango 3 è una pila di B griglie L × d: i suoi tre assi sono B (la profondità della pila), L (le righe) e d (le colonne). Il tensore di rango 4 è una fila di B cubi, ciascuno di forma h × L × L.

    Shape e numero di elementi. Due frasi di 3 token ciascuna, ogni token con un vettore di 4 numeri: il tensore ha shape [2 × 3 × 4] e contiene 2 · 3 · 4 = 24 numeri. In generale il numero di elementi è il prodotto delle lunghezze nella shape. Con le lettere della guida, [B × L × d] vuol dire B frasi, ciascuna di L token, ciascuno con un vettore di d numeri.

    Calcolo · gli elementi di un tensore

    shape=[2 × 3 × 4]
    due frasi di 3 token, ogni token con un vettore di 4 numeri
    elementi=2 · 3 · 4 = 24
    in generale è il prodotto delle lunghezze nella shape

    Il numero di indici si chiama rango del tensore. Attenzione: è un uso diverso della parola «rango» rispetto al passo 8, dove conta le direzioni indipendenti di una matrice.

    Indici e fette. Un singolo numero si trova con un indice per asse, contando da 0 come nei programmi: X[1, 2, 0] è il primo numero del vettore del terzo token della seconda frase. Fissare solo alcuni indici vuol dire prendere una fetta, con un asse in meno per ogni indice fissato:

    EspressioneShapeChe cos'è
    X[2 × 3 × 4]tutte e due le frasi
    X[1][3 × 4]la seconda frase: una matrice, un foglio della pila
    X[1, 2][4]il vettore del terzo token della seconda frase
    X[1, 2, 0][ ]un numero solo

    Un'avvertenza sul nome: in fisica «tensore» ha un significato più ricco; nel deep learning vuol dire soltanto tabella di numeri con più indici (in NumPy, la libreria di calcolo di Python, lo stesso oggetto si chiama ndarray, «array a n dimensioni»).

    Dove ritorna nel modello (si capisce meglio più avanti) i tensori di Llama 2 7B · le operazioni sui tensori · teste e stride, con laboratorio

    Non è il tensore della fisica. In fisica un tensore è un oggetto che cambia in un modo preciso quando si cambia sistema di coordinate, come lo sforzo dentro un materiale o la curvatura dello spazio-tempo. Nel deep learning la parola indica soltanto un array multidimensionale, senza nessuna regola di trasformazione. In PyTorch il rango si legge con ndim. Lo scalare ha shape vuota, [ ], e un solo elemento: il prodotto di nessun fattore vale 1. Un asse lungo 1 non cambia il numero di elementi ma cambia la shape: [L × d] e [1 × L × d] contengono gli stessi numeri, e il secondo è un batch di una sola sequenza.

    Dove compaiono in un LLM. Con le dimensioni di Llama 2 7B (d = 4.096, h = 32 teste dell'attention da dk = d/h = 128 numeri, vocabolario V = 32.000, contesto L = 4.096) e un batch (gruppo di sequenze, capitolo 2) di B = 8 sequenze:

    TensoreShapeCon i numeri di Llama 2 7BElementi
    Loss del batch[ ][ ]1
    Guadagni di RMSNorm, un bias[d][4.096]4.096
    ID dei token del batch[B × L][8 × 4.096]32.768
    Pesi di uno strato, per esempio WQ[d × d][4.096 × 4.096]16.777.216
    Matrice di embedding E[V × d][32.000 × 4.096]131.072.000
    Attivazioni (residual stream)[B × L × d][8 × 4.096 × 4.096]134.217.728
    Q, K o V divise in teste[B × h × L × dk][8 × 32 × 4.096 × 128]134.217.728
    Punteggi dell'attention, per blocco[B × h × L × L][8 × 32 × 4.096 × 4.096]4.294.967.296
    Logit[B × L × V][8 × 4.096 × 32.000]1.048.576.000

    Calcolo · le attivazioni di uno strato

    elementi=B · L · d = 8 · 4.096 · 4.096 = 134.217.728
    Circa 134 milioni di numeri, 268 MB in bf16 (brain floating point a 16 bit, 2 byte per numero), per ogni strato di cui si tengono le attivazioni.

    I pesi hanno shape fisse, decise dall'architettura; le attivazioni dipendono da B e L, cioè da quanto testo si elabora insieme. I punteggi dell'attention sono il tensore più grande perché crescono con L²: oltre 4 miliardi di numeri per blocco, che è il motivo per cui tecniche come FlashAttention evitano di scriverli tutti in memoria.

    Assi per posizione, e i due punti. In [B × L × d] l'asse 0 è il batch, l'asse 1 la posizione nella sequenza, l'asse 2 (o −1, «l'ultimo») la feature, cioè la coordinata del vettore. I due punti «:» vogliono dire «tutto l'asse»: X[:, l] ha shape [B × d] ed è il token in posizione l di ogni sequenza; X[:, :, j] ha shape [B × L] ed è la feature j di tutti i token.

    Le operazioni che servono davvero. Con i tensori un modello fa poche cose, sempre le stesse.

    1 · Elemento per elemento. Due tensori con la stessa shape si combinano casella per casella, e il risultato ha ancora quella shape: la connessione residua X + F(X) somma due tensori [B × L × d], e le funzioni non lineari del passo sulla non linearità si applicano a ogni numero separatamente.

    2 · Broadcasting. Quando le shape sono diverse, si allineano partendo da destra: ogni coppia di lunghezze deve essere uguale, oppure una delle due deve valere 1 o mancare. L'asse lungo 1 (o mancante) viene ripetuto quanto serve, senza copiare i dati. È così che un vettore di bias si somma a tutto il batch:

    X [B × L × d] + bias [d]
    bias letto come [1 × 1 × d], ripetuto B · L volte
    → X + bias [B × L × d] Allineate da destra, le due shape coincidono sull'ultimo asse (d); agli assi B e L il bias non ha lunghezza, quindi vale lo stesso vettore per ogni token. Allo stesso modo la maschera causale [L × L] si somma ai punteggi [B × h × L × L].

    3 · Prodotto matriciale in batch. L'operatore @ di PyTorch moltiplica le ultime due dimensioni con la regola delle matrici e tratta tutti gli assi precedenti come un elenco di prodotti indipendenti, da fare in parallelo. Gli assi di batch devono coincidere o potersi ripetere per broadcasting, come i pesi, che sono gli stessi per tutti:

    X [B × L × d] @ W [d × d] → [B × L × d]
    Q [B × h × L × dk] @ Kᵀ [B × h × dk × L] → punteggi [B × h × L × L] Nel primo prodotto W non ha assi di batch e viene riusata per tutte le B sequenze; nel secondo ci sono B · h prodotti [L × dk] · [dk × L], uno per esempio e per testa.

    4 · Reshape e transpose: dividere le teste. Per l'attention a più teste, il vettore di d numeri di ogni token si legge come h pezzi da dk = d/h, poi l'asse delle teste si porta davanti a quello dei token, così che ogni testa abbia la sua matrice [L × dk]:

    [B × L × d] → reshape → [B × L × h × dk] → transpose(1, 2) → [B × h × L × dk] In PyTorch: x.view(B, L, h, d_k).transpose(1, 2). Il numero di elementi non cambia mai: B · L · d = B · h · L · dk.

    Nessuno dei due passaggi sposta numeri in memoria. Un tensore è salvato come una sola fila di numeri, contigua, in cui l'ultimo indice è quello che varia più in fretta; lo stride di un asse dice di quante posizioni si salta per far avanzare di 1 quell'indice. Il reshape cambia solo il modo di contare le posizioni, il transpose scambia due stride:

    posizione in memoria di X[b, l, j] = b · (L·d) + l · d + j
    stride di [B × L × d]: (L·d, d, 1)
    dopo il reshape [B × L × h × dk]: (L·d, d, dk, 1)
    dopo il transpose [B × h × L × dk]: (L·d, dk, d, 1) Dopo il transpose gli stride non sono più in ordine decrescente: il tensore è non contiguo. Va bene per il prodotto in batch; per riportare l'uscita dell'attention a [B × L × d] serve invece una copia (contiguous()), perché quel reshape non si ottiene solo cambiando gli stride.

    5 · Riduzioni lungo un asse. Una somma, una media o un massimo lungo un asse lo fanno sparire: la somma sull'asse d trasforma [B × L × d] in [B × L], un numero per token. RMSNorm calcola la media dei quadrati sull'ultimo asse e tiene l'asse con lunghezza 1 (keepdim=True), così il risultato [B × L × 1] si può riusare per broadcasting per dividere ogni vettore. La softmax sull'ultimo asse è una riduzione a metà: la shape non cambia, ma ogni riga viene normalizzata in modo da sommare a 1. La loss, infine, fa la media su tutte le B · L posizioni e torna uno scalare.

    somma sull'asse d: [B × L × d] → [B × L]
    media dei quadrati con keepdim: [B × L × d] → [B × L × 1]
    softmax sull'ultimo asse: [B × h × L × L] → [B × h × L × L]
    media della loss: [B × L] → [ ] Ogni riduzione toglie l'asse su cui lavora (o lo lascia lungo 1); la softmax è l'eccezione, perché restituisce tanti numeri quanti ne riceve.

    Dove ritorna. X [B × L × d] @ W [d × d] è un prodotto tra matrici ripetuto per B sequenze con gli stessi pesi: shape e costo si contano come nel passo sulle shape, moltiplicando per B. Dopo reshape e transpose le h teste sono un asse in più, e Q·Kᵀ calcola B · h matrici di punteggi in un colpo solo; la softmax lavora sull'ultimo asse, riga per riga (sezione D).

    Laboratorio: un tensore [B × L × d] e quattro operazioni

    matematica reale

    Scegli le dimensioni e un'operazione, poi clicca una cella (o passaci sopra) per fissare gli indici b e l: guarda come cambiano shape, numero di elementi e stride.

    Ogni fetta della pila è una sequenza del batch: è disegnata a celle solo quella scelta con b, le altre ne mostrano il bordo. d scorre solo sui multipli di h, perché ogni testa riceve dk = d/h colonne. I valori sono interi casuali con seme fisso, gli indici contano da 0. Shape, stride e posizioni in memoria sono quelli di un tensore contiguo in ordine per righe, come lo crea PyTorch; in un modello vero d vale migliaia e le righe B · L sono milioni.

    Matrice × matrice: la regola delle shape

    In tre frasi

    Due matrici si possono moltiplicare solo se il numero di colonne della prima è uguale al numero di righe della seconda: [m × n] · [n × p] dà [m × p]. Ogni numero del risultato è il prodotto scalare di una riga della prima con una colonna della seconda. Serve a trasformare i vettori di tutti i token in un colpo solo, mettendole una sotto l'altra.

    Un esempio con i numeri. A ha 2 righe e 3 colonne, B ha 3 righe e 2 colonne:

    A [2 × 3]
    102
    011
    ×
    B [3 × 2]
    12
    01
    30
    =
    C [2 × 2]
    72
    31

    Calcolo · A · B, elemento per elemento

    riga 1 di A · colonna 1 di B=1·1 + 0·0 + 2·3 = 7
    riga 1 di A · colonna 2 di B=1·2 + 0·1 + 2·0 = 2
    riga 2 di A · colonna 1 di B=0·1 + 1·0 + 1·3 = 3
    riga 2 di A · colonna 2 di B=0·2 + 1·1 + 1·0 = 1
    risultato C = A · B=[[7, 2], [3, 1]]
    shape [2 × 2]

    La regola delle dimensioni interne. In [2 × 3] · [3 × 2] le due dimensioni «interne», 3 e 3, devono coincidere, perché sono la lunghezza dei prodotti scalari tra righe e colonne; nel risultato spariscono, e restano le «esterne»: [2 × 2]. [2 × 3] · [2 × 3] invece non si può fare: le righe della prima hanno 3 numeri, le colonne della seconda solo 2.

    A [m × n] · B [n × p] = C [m × p] L'elemento nella riga i e nella colonna j di C è il prodotto scalare della riga i di A con la colonna j di B. Le n interne devono coincidere.

    L'ordine conta. A·B e B·A in generale sono diversi. Nell'esempio, B·A si può calcolare ([3 × 2] · [2 × 3]) ma dà una matrice [3 × 3], non [2 × 2]. Il vettore del passo sulle trasformazioni qui sotto è solo il caso di una matrice con una colonna: [2 × 2] · [2 × 1] = [2 × 1].

    Perché serve: tutti i token insieme. Una frase di L token si scrive come una matrice X con una riga per token, cioè [L × d]. Moltiplicandola per una matrice di pesi W di shape [d × d] si trasformano tutti i vettori in un colpo solo: la riga i del risultato è il vettore del token i trasformata. Con la frase del capitolo 1: [4 × 4.096] · [4.096 × 4.096] = [4 × 4.096], quattro vettori entrano e quattro escono. È come una fabbrica che mette mille sedie sul nastro e accende la cabina di verniciatura una volta sola: le GPU (Graphics Processing Unit, processori grafici) fanno migliaia di moltiplicazioni in parallelo.

    Quanto costa. Ogni numero del risultato richiede n moltiplicazioni e circa altrettante somme, e il risultato ha m · p numeri: con le dimensioni di un modello vero il conto arriva a miliardi di operazioni per ogni token. I numeri precisi, e da dove viene la regola per cui allenare un modello costa circa 6 operazioni per peso per token, sono nel riquadro.

    Dove ritorna nel modello (si capisce meglio più avanti) l'attention in quattro prodotti · il costo in FLOP · il termine in L², con laboratorio

    Convenzioni. In questa guida i token sono righe e si scrive X·W; la libreria PyTorch salva la matrice di uno strato lineare come [uscite × ingressi] e calcola X·Wᵀ, che è la stessa cosa scritta al contrario. Quando le shape non tornano il codice si ferma con un errore, e seguire le shape passo per passo è il modo più rapido di capire un'architettura.

    L'attention in quattro prodotti. Negli strati (sezione D) tre proiezioni danno una matrice [L × d] per ciascuno dei tre ruoli (query, key, value), divisa poi tra h teste di dk = d/h colonne ciascuna con il reshape e il transpose del riquadro sui tensori. Per ogni testa i conti sono:

    Q = X·WQ   K = X·WK   V = X·WV   [L × d]
    punteggi = Q·Kᵀ / √dk   [L × L]
    uscita = softmax(punteggi) · V   [L × dk] L'elemento (i, j) dei punteggi è qᵢ · kⱼ: tutti i prodotti scalari tra coppie di token in un colpo solo. La softmax si applica riga per riga, dopo la maschera causale.

    Le uscite delle teste si affiancano di nuovo in [L × d] e passano per la quarta matrice, WO. Con un batch di B sequenze X diventa il tensore [B × L × d] e i punteggi [B × h × L × L]; le matrici dei pesi sono le stesse per tutte le sequenze, e il costo si moltiplica per B.

    Quanto costa, in FLOP. C [m × p] ha m·p elementi, ciascuno un prodotto scalare lungo n: n moltiplicazioni e n − 1 somme, cioè circa 2·n FLOP (floating-point operation, operazione in virgola mobile). I conti, dal singolo prodotto all'intero training, con N parametri:

    Calcolo · quanto costa un prodotto tra matrici

    A [m × n] · B [n × p]≈2 · m · n · p FLOP
    X [L × d] · W [d × d]≈2 · L · d² FLOP = 2 FLOP per parametro per token
    forward ≈ 2N   +   backward ≈ 4N→training ≈ 6N FLOP per token
    6 × 7·10⁹ parametri × 2·10¹² token≈8,4·10²² FLOP
    L'ultima riga è un modello da 7 miliardi di parametri allenato su 2.000 miliardi di token.

    Per uno strato lineare W ha d² parametri, quindi i suoi 2·L·d² FLOP sono una moltiplicazione e una somma per ogni peso e per ogni token. Vale per tutte le matrici del modello, quindi il calcolo in avanti (forward) di un modello con N parametri costa circa 2N FLOP per token. Il calcolo all'indietro (backward, sezione G) costa circa il doppio: per ogni strato servono due prodotti della stessa taglia, uno per il gradiente rispetto all'ingresso (con Wᵀ, da passare allo strato sotto) e uno per il gradiente rispetto ai pesi. In totale circa 6N FLOP per token: è la regola «calcolo ≈ 6 × parametri × token» delle scaling laws.

    Il termine che cresce con L². Due prodotti dell'attention non toccano nessun parametro: Q·Kᵀ e (pesi)·V costano circa 2·L²·d FLOP ciascuno per blocco, sommando tutte le teste. La regola dei 6N li ignora, e finché L è piccolo rispetto a d va bene; quando il contesto si allunga crescono con il quadrato di L e diventano la parte più cara. Il laboratorio lo mostra passaggio per passaggio.

    Laboratorio: tracciatore di shape per un blocco di attention

    matematica reale

    Cambia la lunghezza del contesto L, la dimensione d e il numero di teste, e segui shape e FLOP di ogni passaggio: le barre rosse sono quelle che crescono con L².

    Conti per una sola sequenza e un solo blocco; con un batch di B sequenze tutto si moltiplica per B, con N blocchi per N. La softmax, la maschera e la divisione per √dk costano pochi FLOP per elemento e non sono contate. Tecniche come FlashAttention evitano di salvare in memoria l'intera matrice dei punteggi, ma i FLOP restano proporzionali a L².

    Perché serve una non linearità

    In tre frasi

    Due moltiplicazioni per matrici di fila equivalgono sempre a una moltiplicazione sola: senza nient'altro, impilare tanti strati non servirebbe a niente. Per questo tra una matrice e l'altra si mette una funzione «con una piega», applicata a ogni numero separatamente; la più semplice è la ReLU, che trasforma i numeri negativi in 0. Con tante pieghe si può imitare quasi qualsiasi curva.

    Con le sole matrici un foglio si può ruotare, allungare e inclinare, ma non piegare: le rette restano rette. E due matrici applicate una dopo l'altra fanno esattamente quello che fa una matrice sola, il loro prodotto: dieci strati soltanto lineari in fila equivalgono a uno strato solo.

    Il collasso, con i numeri. Prendi W₁ = [[1, 2], [0, 1]] e W₂ = [[1, 0], [−1, 1]], e applicale in fila a x = [1 ; 1]; poi rifai il conto con il loro prodotto W₂W₁ (calcolato con la regola del passo sulle shape):

    Calcolo · due strati lineari collassano in uno

    due strati: W₁x=[3 ; 1],   W₂ · [3 ; 1] = [3 ; −3 + 1] = [3 ; −2]
    una matrice: W₂W₁=[[1, 2], [−1, −1]],   (W₂W₁) · x = [1 + 2 ; −1 − 1] = [3 ; −2]
    Lo stesso risultato con una matrice sola, e vale per qualsiasi x.

    Due strati con 8 pesi si comportano come uno con 4: la profondità non ha aggiunto niente.

    Una piega: la ReLU. La ReLU (Rectified Linear Unit, unità lineare rettificata) lascia passare i numeri positivi e trasforma i negativi in 0: ReLU(3) = 3, ReLU(−2) = 0. Su un vettore si applica a ogni numero: ReLU([−1 ; 2]) = [0 ; 2]. Il suo grafico è una retta con un gomito nello zero. Si mette tra due matrici:

    ReLU(x) = max(0, x)
    y = W₂ · ReLU(W₁x) max(0, x) vuol dire «il più grande tra 0 e x». La ReLU si applica a ogni elemento di W₁x separatamente.

    Con la piega in mezzo il collasso non avviene più. Per x = [1 ; −1]: W₁x = [1 − 2 ; −1] = [−1 ; −1], la ReLU lo porta a [0 ; 0] e W₂ dà [0 ; 0]. La matrice unica W₂W₁ darebbe invece [1 − 2 ; −1 + 1] = [−1 ; 0]. La piega ha impedito alle due matrici di fondersi in una.

    Calcolo · con la ReLU in mezzo il collasso non avviene

    x=[1 ; −1]
    W1x=[1 − 2 ; −1] = [−1 ; −1]
    ReLU(W1x)=[0 ; 0]
    W2 · [0 ; 0]=[0 ; 0]
    con la piega in mezzo
    (W2W1) · x=[1 − 2 ; −1 + 1] = [−1 ; 0]
    la matrice unica darebbe un altro risultato

    Tante pieghe, una curva. Ogni unità con la ReLU mette un gomito in un punto diverso, e la somma di tanti gomiti è una linea spezzata. Con abbastanza pezzi una spezzata segue bene quanto si vuole qualsiasi curva continua su un intervallo: è l'idea del teorema di approssimazione universale, e il laboratorio la costruisce a mano.

    Laboratorio: approssimare una curva con k unità ReLU

    matematica reale

    Aumenta il numero di unità k e guarda la spezzata colorata avvicinarsi alla curva grigia (sin x); poi passa a «Identità (nessuna)» e osserva che resta solo una retta.

    La rete è f(x) = b + Σ cⱼ · ReLU(x − xⱼ): ogni unità ha un gomito nel punto xⱼ e un peso d'uscita cⱼ. Qui i pesi non sono imparati: sono calcolati a mano perché la spezzata passi per sin x nei punti segnati, distribuiti a passo uguale su [−π, π]. In grigio tratteggiato i singoli gomiti cⱼ · ReLU(x − xⱼ), la cui somma è la curva colorata. Con il training (spiegato più avanti nel capitolo) una rete troverebbe da sola gomiti e pesi, di solito un po' migliori.

    Dove ritorna nel modello (si capisce meglio più avanti) la MLP di ogni strato · GELU, SiLU, SwiGLU · la ReLU nel calcolo dei gradienti

    I termini costanti non salvano. Aggiungere a ogni strato un termine costante (il bias) non cambia la conclusione: una funzione lineare più una costante, composta con un'altra della stessa forma, resta della stessa forma.

    Nella MLP di ogni strato. In ogni blocco del transformer la MLP (Multi-Layer Perceptron, percettrone multistrato) allarga il vettore da d a un numero più grande (4d nel transformer originale, 11.008 ≈ 2,7d in Llama 2 7B), applica la non linearità elemento per elemento e la riporta a d: in un modello da 7 miliardi di parametri sono circa 11.000 unità non lineari per token, in ogni strato (sezione D). I modelli moderni usano versioni più morbide della ReLU, come GELU (Gaussian Error Linear Unit) e SiLU (Sigmoid Linear Unit), o la variante «a cancello» SwiGLU (Swish-Gated Linear Unit), ma il ruolo è lo stesso. Anche l'attention ha una sua non linearità, la softmax.

    Nel calcolo dei gradienti. Nel backward la derivata della ReLU vale 1 dove l'unità è accesa e 0 dove è spenta: il gradiente passa oppure si ferma (sezione G).

    Come sono calcolati i pesi del laboratorio. Ogni unità ha peso d'ingresso 1 e bias −xⱼ; cⱼ è la variazione di pendenza della spezzata nel nodo j (interpolazione lineare a tratti). Raddoppiando le unità l'errore massimo si divide circa per 4, perché l'errore dell'interpolazione lineare cala con il quadrato del passo tra i nodi.

    Basso rango: una matrice grande fatta di due sottili

    In tre frasi

    Molte matrici grandi contengono tanti numeri ma poca informazione davvero indipendente. Una matrice grande si può allora ottenere moltiplicando due matrici sottili, e servono molti meno numeri per descriverla. Il prezzo è che le sue uscite possono muoversi solo in poche direzioni: quante, si chiama rango.

    La tavola pitagorica ha 100 caselle, ma per ricostruirla bastano 20 numeri, da 1 a 10 in riga e da 1 a 10 in colonna: ogni casella è il prodotto della sua riga per la sua colonna.

    Una colonna per una riga. Con la colonna u = [1 ; 2 ; 3] e la riga v = [1, 0, 2] si costruisce una tabella 3 × 3: la casella nella riga i e nella colonna j è uᵢ · vⱼ.

    Calcolo · una colonna per una riga

    u=[1 ; 2 ; 3],   v = [1, 0, 2]
    u·v=[[1, 0, 2], [2, 0, 4], [3, 0, 6]]
    Nove numeri determinati da sei: ogni riga è un multiplo della stessa riga [1, 0, 2]. È la regola delle shape con dimensione interna 1: [3 × 1] · [1 × 3] = [3 × 3].

    Qualunque vettore entri in questa matrice, l'uscita è sempre un multiplo di [1 ; 2 ; 3]: tutte le uscite stanno su una sola retta. Si dice che la matrice ha rango 1. In generale il rango è il numero di direzioni indipendenti in cui possono cadere le uscite.

    Due matrici sottili. Generalizzando: una matrice d × d si può costruire come B · A, con B di shape [d × r] e A di shape [r × d], e r piccolo. Per la regola delle shape il risultato è [d × d], ma servono solo 2·d·r numeri invece di d·d. Con d = 1.000 e r = 10: 20.000 numeri invece di 1.000.000, cinquanta volte meno.

    Calcolo · quanti numeri risparmia il basso rango

    numeri di B · A=2 · d · r = 2 · 1.000 · 10 = 20.000
    numeri di W=d · d = 1.000.000
    risparmio=1.000.000 / 20.000 = 50
    cinquanta volte meno
    W [d × d] = B [d × r] · A [r × d] 2·d·r numeri invece di d². Il risultato ha rango al massimo r.

    Applicarla è altrettanto economico: x passa prima per A, che lo riduce a r numeri (un collo di bottiglia), poi per B, che lo riporta a d.

    Calcolatore: matrice piena contro basso rango

    matematica reale

    Scegli la dimensione d e il rango r, e confronta quanti numeri servono per una matrice d × d piena e per la coppia di matrici sottili B·A.

    Dove ritorna nel modello (si capisce meglio più avanti) LoRA, il fine-tuning leggero · le teste dell'attention

    La proiezione ha rango 1. La proiezione vista nel passo sulle trasformazioni qui sotto è una matrice di rango 1: qualunque x entri, l'uscita cade sulla stessa retta. In notazione matematica una matrice di rango 1 si scrive u·vᵀ, dove vᵀ (la «trasposta» di v) è v scritto come riga.

    LoRA (Low-Rank Adaptation, adattamento a basso rango). Nel fine-tuning con LoRA (Hu e colleghi, 2021) la matrice originale W resta congelata e si allena solo una correzione a basso rango, con B inizializzata a zero, così all'inizio il modello è identico all'originale (il paper moltiplica anche B·A per un fattore di scala α/r). I conti per d = 4.096:

    Calcolo · LoRA con d = 4.096

    W'=W + B·A
    matrice piena: 4.096 × 4.096=16.777.216 pesi
    r = 8: 2 × 4.096 × 8=65.536 (0,39%)   r = 16: 131.072 (0,78%)
    W resta congelata; si allenano solo B [d × r] e A [r × d].

    Su un modello da 7 miliardi di parametri, LoRA con r = 16 sulle matrici WQ e WV di tutti i 32 blocchi allena circa 8,4 milioni di parametri, lo 0,12% del totale. Funziona perché la modifica che serve al fine-tuning ha, di fatto, un rango basso: nel paper anche valori di r molto piccoli danno risultati vicini al fine-tuning completo.

    Le teste dell'attention lavorano a basso rango. Negli strati (sezione D) ogni testa ha le sue proiezioni WQ e WK da d a dk = d/h numeri: in un modello da 7 miliardi di parametri, da 4.096 a 128. Il punteggio qᵢ · kⱼ usa quindi la matrice WQ·WKᵀ, grande d × d ma di rango al massimo 128: ogni testa confronta i token guardando solo un sottospazio di 128 direzioni, diverso da quello delle altre teste. Con 32 teste si ottengono 32 punti di vista diversi sugli stessi 4.096 numeri.

    Mappa concettuale · l'algebra del modello
    • Algebra per il modello
      • l'oggetto base è il Vettore
        • si combina con somma e moltiplicazione per un numero
        • si confronta con prodotto scalare
        • si normalizza con norma e coseno
      • lo trasforma una Matrice
        • ogni riga è un rilevatore
        • si moltiplica con la regola delle shape
      • i dati viaggiano come Tensori
        • descritti da shape e rango
      • tra le matrici serve una Non linearità
        • altrimenti gli strati collassano in uno
      • per risparmiare numeri Basso rango
        • è fatto di due matrici sottili
        • serve a LoRA e teste dell'attention

    Promemoria: le definizioni di algebra in breve

    Le stesse nozioni degli otto passi, in un vettore ciascuna, da riaprire quando un capitolo successivo le usa. Alcune voci citano pezzi del modello spiegati più avanti nel capitolo.

    Scalare
    Un singolo numero. Moltiplicare un vettore per uno scalare lo allunga, lo accorcia o lo gira dall'altra parte, senza cambiarne la retta.
    0,5 · il learning rate η · la loss
    Vettore
    Una lista ordinata di n numeri; n è la sua dimensione. Geometricamente è una freccia (o un punto) in uno spazio a n dimensioni. Si somma e si scala elemento per elemento. Un embedding è un vettore di d numeri.
    [0,2 ; −1,3 ; 0,7] → dimensione 3
    Matrice
    Una tabella di numeri con m righe e n colonne (si scrive m × n). Si può vedere come m vettori-riga impilati, o come una trasformazione che porta vettori di n numeri in vettori di m numeri.
    E: V × d, una riga per token
    Tensore e shape
    Un array di numeri con un numero qualsiasi di assi (il suo rango): scalare 0, vettore 1, matrice 2. [B × L × d] sono B matrici L × d, cioè B sequenze di L token, ciascuno con un vettore di d numeri. La shape (forma) elenca le lunghezze degli assi, e il loro prodotto è il numero di elementi. Fissare un indice dà una fetta con un asse in meno. Schema e laboratorio nel passo sui tensori.
    in PyTorch tutto è un tensore
    Vettore one-hot
    Un vettore lungo quanto il vocabolario, con tutti 0 tranne un 1 nella posizione dell'ID del token: uno solo è "acceso" (hot). Rappresenta una scelta tra V categorie senza introdurre un ordine: l'ID 7 non è "più grande" dell'ID 3. Moltiplicato per una matrice, ne seleziona una riga.
    ID 2 su V = 5 → [0, 0, 1, 0, 0]
    Prodotto scalare (dot product)
    a · b = a₁b₁ + a₂b₂ + … + aₙbₙ = |a| |b| cos θ: si moltiplicano gli elementi a coppie e si sommano. Misura quanto due vettori puntano nella stessa direzione: grande e positivo = simili, circa 0 = non correlati (ortogonali), negativo = opposti.
    [1, 2] · [3, −1] = 3 − 2 = 1
    Norma e similarità coseno
    La norma |a| = √(a · a) è la lunghezza del vettore. La similarità coseno a · b / (|a| |b|) confronta solo la direzione e va da −1 a 1. È la misura più usata nel retrieval (la ricerca dei testi più simili a una domanda). Tra vettori casuali in d dimensioni vale circa 0, con dispersione 1/√d.
    cos = 1 → stessa direzione
    Matrice × vettore
    Per righe: ogni elemento del risultato è il prodotto scalare di una riga della matrice con il vettore. Per colonne: il risultato è una combinazione lineare delle colonne, pesata dagli elementi del vettore. Una matrice m × n trasforma un vettore di n numeri in un vettore di m numeri: è così che uno strato "trasforma" un vettore.
    (3 × 4) · (4) → (3)
    Matrice × matrice
    A (m × n) · B (n × p) = C (m × p); l'elemento (i, j) è riga i di A · colonna j di B. Le dimensioni interne (n) devono coincidere. Costa circa 2·m·n·p operazioni. Serve a trasformare tutti i token di una sequenza in un colpo solo: è l'operazione che le GPU (Graphics Processing Unit, processori grafici) eseguono velocissime. L'ordine conta: A·B ≠ B·A.
    (L × d) · (d × d) → (L × d)
    Trasposta
    Aᵀ scambia righe e colonne: una matrice m × n diventa n × m. Nel backward il gradiente attraversa uno strato moltiplicato per la trasposta dei suoi pesi.
    Eᵀ: d × V
    Funzione non lineare
    Applicata a ogni elemento separatamente, per esempio ReLU(x) = max(0, x), o le versioni più morbide GELU e SiLU. Senza, impilare tante matrici equivarrebbe a una sola matrice, e il modello non potrebbe rappresentare relazioni complesse.
    ReLU([−1, 2]) = [0, 2]
    Gradiente
    Il vettore delle derivate parziali della loss: per ogni peso, di quanto cambia la loss se lo sposti di pochissimo. Ha la stessa shape dei pesi.
    un numero per ogni peso

    C · La matrice di embedding, da vicino

    Nel capitolo 1 ogni ID diventava una riga di una tabella di 12 × 8 numeri scritti a mano. Da dove vengono i 131 milioni di numeri della tabella di un modello vero?

    Il primo strato di ogni LLM sostituisce ciascun ID con un vettore di d numeri (d = 4.096 in un modello da 7B), cioè un punto in uno spazio a d dimensioni: l'embedding del token. Da questo momento il testo non esiste più: esistono L punti in uno spazio a 4.096 dimensioni, uno per token, e il resto del modello sposta e mescola questi punti.

    Come si calcola: non si calcola, si legge. Il modello contiene una matrice di embedding E con una riga per ogni token del vocabolario (V righe × d colonne). L'embedding del token con ID 9412 è semplicemente la riga 9412 di E. Matematicamente equivale a moltiplicare un vettore one-hot (tutti zeri, con un 1 in posizione 9412) per E, come mostra il laboratorio «one-hot × matrice» della sezione B; nella pratica si fa una lettura diretta (lookup), molto più veloce. La matrice di input [B × L] di ID diventa così un tensore [B × L × d] di vettori.

    Da dove vengono i numeri di E? Non esiste un embedding «giusto» da assegnare a un token: nessuno li sceglie. Il procedimento è puramente meccanico:

    1. Il BPE finisce e il vocabolario viene congelato: una lista di V token, ciascuno con il suo ID da 0 a V − 1 (compresi i token speciali come <eos> e i simboli di base).
    2. Si crea la matrice E con V righe e d colonne. La riga i appartiene al token con ID i: l'abbinamento è solo per posizione, come l'indice di un array.
    3. Si riempie E di numeri casuali piccoli, per esempio estratti da una distribuzione normale con media 0 e deviazione standard 0,02. A questo punto le righe non significano nulla: «·Francia» e «·martedì» sono vettori casuali qualsiasi.
    4. Il training aggiorna le righe a ogni step, insieme a tutti gli altri pesi, e il significato emerge poco a poco (lo vedremo nel capitolo 2).

    Laboratorio: dal vocabolario BPE alla matrice E

    inizializzazione reale

    Questa matrice è costruita sul vocabolario del laboratorio BPE qui sopra: se esegui altri merge, compaiono nuove righe. Qui d = 4 per leggibilità.

    Premendo «Ri-inizializza» i numeri cambiano completamente, e va bene così: all'inizio servono solo valori piccoli e diversi tra loro, così che ogni riga parta da un punto diverso. Anche i simboli di base (le singole lettere) hanno la loro riga, perché restano nel vocabolario per rappresentare le parole mai viste.

    Laboratorio: il lookup nella matrice E

    lookup reale · pesi iniziali casuali
    Frase in input (clicca un token)

    Statico all'ingresso, contestuale dopo

    La riga di E è identica ogni volta che il token compare: «banca» ha lo stesso embedding in «la banca del fiume» e in «il conto in banca». Sono gli strati successivi a mescolarlo con i token vicini, finché all'ultimo strato i due «banca» sono vettori diversi, uno vicino a «fiume», l'altro vicino a «conto». Nel modello in miniatura del capitolo 1 era il passo 3 a produrre questa differenza.

    La posizione si aggiunge a parte. La riga di E non sa dove si trova il token: «il cane morde l'uomo» e «l'uomo morde il cane» avrebbero gli stessi cinque vettori. I primi transformer sommavano un secondo vettore, l'embedding posizionale; i modelli attuali usano quasi tutti RoPE (Rotary Position Embedding, embedding posizionale rotazionale), che codifica la posizione ruotando i vettori dentro l'attention, in modo che il prodotto scalare tra due token dipenda dalla loro distanza.

    ID del token→ riga di E
    embedding statico
    → + informazione di posizione
    RoPE
    → N strati di attention + MLP→ vettore contestuale
    dipende dalla frase
    → confronto con il vocabolario
    logit
    Embedding di tokenEmbedding semantico (retrieval)
    RappresentaUn singolo token, senza contestoUn'intera frase o un documento
    Si ottieneLeggendo una riga di E, all'ingresso del modelloDall'ultimo strato di un modello, facendo la media (pooling) dei vettori contestuali di tutti i token
    Si allenaInsieme all'LLM, prevedendo il token successivoCon training contrastivo: frasi simili vicine, frasi diverse lontane
    Dimensioni tipicheV × d, es. 128.000 × 4.096 ≈ 524 milioni di pesiUn vettore da 384–3.072 numeri per testo

    La parola «embedding» indica entrambe le cose e genera confusione: quello di cui parla questo documento è il primo, la riga di E. Il secondo, usato nei sistemi di retrieval, è trattato nella guida sulle architetture LLM.

    D · Dentro uno strato: attention, MLP, residual stream

    Nel capitolo 1 il passo 3 «mescola il contesto» e il passo 4 «elabora». Come sono fatti davvero, in un transformer?

    Attraverso una pila di strati (layer). Uno strato è un blocco di calcoli con i propri pesi: riceve un vettore per ogni token e restituisce un vettore per ogni token, della stessa dimensione. Entra una matrice [L × d], esce una matrice [L × d]. Siccome ingresso e uscita hanno la stessa forma, gli strati si possono impilare: l'uscita di uno è l'ingresso del successivo. «Deep» in deep learning significa proprio questo: molti strati in fila. Un modello da 7B ne ha 32, i modelli più grandi oltre 100.

    ID dei token [L]
    Embedding: lettura delle righe di E [L × d]
    Blocco 1attention → MLP[L × d] → [L × d]
    Blocco 2attention → MLP[L × d] → [L × d]
    ⋮
    Blocco Nattention → MLP[L × d] → [L × d]
    Testa di output: × Wout [L × V] logit
    softmax → una distribuzione su V token per ogni posizione

    Ogni blocco del transformer contiene due sotto-strati, con ruoli diversi e complementari.

    1 · Attention: i token si scambiano informazioni. È l'unico punto del modello in cui un token «guarda» gli altri. Per ogni token il modello calcola tre vettori moltiplicando il suo vettore per tre matrici di pesi: una query («che cosa sto cercando»), una key («che cosa offro») e un value («che cosa passo se vengo scelto»). Il prodotto scalare tra la query di un token e la key di ciascun token precedente dice quanto quel token è rilevante; i punteggi vengono divisi per √d (per tenerli su una scala stabile) e una softmax li trasforma in pesi che sommano a 1; il nuovo vettore è la media pesata dei value.

    La causal mask esclude i token successivi: ogni posizione vede solo il passato, perché in generazione il futuro non esiste ancora.

    Nel modello in miniatura del capitolo 1 la «domanda» dell'ultimo token era la query, il vettore di ogni token faceva da key e da value insieme, e la matrice 8 × 8 era Wq: un transformer vero separa i tre ruoli con tre matrici distinte, così «che cosa cerco», «che cosa offro» e «che cosa passo» possono essere diversi.

    2 · MLP: ogni token elabora ciò che ha raccolto. Ogni vettore, da solo, viene moltiplicato per una matrice che lo allarga (d → 4d numeri nel transformer originale; in Llama 2 7B 4.096 → 11.008), passa per una funzione non lineare e viene moltiplicato per una seconda matrice che lo riporta a d numeri. Nella variante SwiGLU di Llama le matrici sono tre: due allargano, e una delle due fa da «cancello» che regola quanto passa dell'altra. Gli stessi pesi valgono per tutti i token. Le sette regole «se X senza Y, aggiungi Z» del modello in miniatura sono un MLP con 7 neuroni nascosti: la prima matrice calcola i gate (prodotto scalare + ReLU), la seconda aggiunge i contributi.

    Qui, si ritiene, avviene gran parte del «ricordare»: un vettore che contiene «capitale» e «Francia» viene trasformato in uno che contiene «Parigi». Gli studi di interpretabilità mostrano che i fatti sono distribuiti su molti pesi degli MLP dei blocchi centrali, non in una cella precisa.

    Connessione residua e normalizzazione. Ogni sotto-strato non sostituisce il vettore, ma gli aggiunge una correzione: uscita = ingresso + contributo. Il vettore di ogni token attraversa così tutti i blocchi come un «flusso» (il residual stream) che si arricchisce strato dopo strato; è anche ciò che permette ai gradienti del capitolo 2 di risalire cento strati senza spegnersi. Prima di ogni sotto-strato una normalizzazione (RMSNorm, Root Mean Square Normalization) riporta i numeri su una scala stabile.

    Laboratorio: il calcolo dell'attention

    matematica reale · vettori d = 4 scelti a mano
    Clicca un token: vedi come si calcola quanto peso dà a sé stesso e ai token precedenti

    Il calcolo (prodotto scalare query · key, divisione per √dk, softmax, media pesata dei value) è quello vero di una testa di attention. I vettori query e key dei sette token sono scelti a mano, con 4 dimensioni invece di 128, per imitare una testa che ha imparato a collegare verbi e soggetti: in un modello reale li producono le matrici Wq, Wk, Wv moltiplicate per il vettore del token, e il training le aggiusta. Un blocco ha molte teste in parallelo (32 in un modello da 7B), ognuna con le sue matrici: una segue il soggetto, un'altra la parola precedente, un'altra la punteggiatura. Nessuno le programma: i ruoli emergono dal training.

    Tutte le matrici in una volta, con le dimensioni scritte accanto. Nel laboratorio qui sopra query e key erano date; qui si parte un passo prima, dai vettori dei token, e si fa l'intero conto di una testa di attention su «il gatto dorme» con vettori di d = 4 numeri e query/key/value di 2 numeri. La frase è una matrice X di 3 righe × 4 colonne.

    Il modello possiede tre matrici di pesi 4 × 2, Wq, Wk, Wv; moltiplicando X per ciascuna si ottengono Q, K, V, tre matrici 3 × 2 (una riga per token, come X). Il prodotto Q Kᵀ è una matrice 3 × 3: nella casella (i, j) c'è il prodotto scalare tra la query del token i e la key del token j, cioè quanto i trova interessante j. Si trasforma «3 token × 4 caratteristiche» in «3 token × 3 relazioni».

    Dopo la divisione per √2 e la softmax riga per riga (con la maschera causale: un token non vede quelli dopo di sé) si ha la matrice A dei pesi; infine O = A V, ancora 3 × 2, dove la riga i è la combinazione pesata dei value: O₃ = a₃₁V₁ + a₃₂V₂ + a₃₃V₃. Niente, in questa catena, ha dimensioni «misteriose»: ogni prodotto è tra una matrice r × c e una c × s, e dà una r × s.

    Calcolo · le dimensioni di una testa di attention

    X=[3 × 4]
    «il gatto dorme»: una riga per token, vettori di d = 4 numeri
    Wq, Wk, Wv=[4 × 2]
    Q, K, V=[3 × 4] · [4 × 2] = [3 × 2]
    Q KT=[3 × 2] · [2 × 3] = [3 × 3]
    nella casella (i, j): la query del token i per la key del token j
    A=softmax(Q KT / √2) = [3 × 3]
    con la maschera causale: un token non vede quelli dopo di sé
    O = A V=[3 × 3] · [3 × 2] = [3 × 2]
    la riga 3 è O3 = a31V1 + a32V2 + a33V3

    Laboratorio: da X a O, tutte le matrici di una testa di attention

    matematica reale · pesi scelti a mano

    Clicca un token per seguire la sua riga attraverso tutte le matrici. «Pesi casuali» sostituisce Wq, Wk, Wv con numeri a caso, come all'inizio del training: il conto resta identico, l'attention diventa insensata; «Pesi del modello» li rimette. Questo è esattamente ciò che il training cambia: le tre matrici W, non le formule.

    X 3 × 4 · un token per riga
    Wq 4 × 2 · parametri
    Wk 4 × 2 · parametri
    Wv 4 × 2 · parametri
    Q = X Wq (3×4)(4×2) = 3 × 2
    K = X Wk 3 × 2
    V = X Wv 3 × 2
    Q Kᵀ / √2 (3×2)(2×3) = 3 × 3 · relazioni
    A = softmax per riga 3 × 3 · maschera causale
    O = A V (3×3)(3×2) = 3 × 2

    Che cosa è reale: tutti i prodotti, la divisione per √dk, la maschera, la softmax. Scelti a mano: i vettori di X e le tre matrici W, con numeri a una cifra per poterli seguire; in un 7B, d = 4.096, ogni testa ha query/key/value di 128 numeri, le teste sono 32 per strato e le loro uscite O vengono affiancate e moltiplicate per una quarta matrice Wo prima di essere aggiunte al residual stream. Il laboratorio precedente partiva da query e key già fatte: erano le righe di Q e K di questo.

    Parametri e attivazioni: due famiglie di numeri da non confondere

    La domanda «Wq, Wk, Wv vengono da tre training diversi?» nasce dal confondere le matrici dei pesi con le matrici che si calcolano da esse. I parametri esistono prima della frase, sono gli stessi per ogni frase, stanno su disco e cambiano solo durante il training. Le attivazioni nascono dalla frase, cambiano a ogni frase, vivono nella memoria della GPU durante il calcolo e si buttano alla fine (salvo K e V dei token passati, conservati nella KV cache durante la generazione). Il training ha un solo obiettivo, la loss sul token successivo, e la backpropagation consegna a ogni parametro la propria derivata nello stesso passaggio: Wq, Wk, Wv, E e i pesi dell'MLP si aggiornano insieme, a ogni step, perché tutti hanno contribuito alla stessa previsione.

    Parametri (pesi)Attivazioni
    EsempiE, Wq, Wk, Wv, Wo, le due matrici dell'MLP, i guadagni delle normalizzazioniX, Q, K, V, Q Kᵀ, A, O, l'uscita dell'MLP, il residual stream, i logit, le probabilità
    Quando nasconoAll'inizializzazione, con numeri casuali, prima di qualunque fraseA ogni forward pass, moltiplicando la frase per i parametri
    Dipendono dalla frase?No: identici per ogni inputSì: diversi per ogni frase e per ogni posizione
    Chi li cambiaSolo il training: optimizer, un passo per step, tutti insieme dalla stessa lossNessuno: si ricalcolano e si scartano (K, V dei token passati restano nella KV cache durante la generazione)
    Dove stannoSu disco (il file del modello) e in memoria quando il modello è caricatoSolo in memoria, durante il calcolo; nel training se ne tengono molte per la backpropagation
    Quanti in un 7B≈ 7 miliardi, fissiProporzionali a batch × lunghezza × d, per ogni strato
    Mappa concettuale · dentro uno strato
    • Blocco del transformer
      • primo sotto-strato Attention
        • usa query, key e value
        • pesa con prodotto scalare, divisione per √dk e softmax
        • esclude il futuro con causal mask
      • secondo sotto-strato MLP
        • allarga e restringe d → più largo (4d, o 11.008 in Llama 2 7B) → d
        • qui avviene gran parte del ricordare
      • attorno a entrambi Connessione residua
        • aggiunge una correzione al vettore
        • lascia ai gradienti una strada diretta
      • prima di ogni sotto-strato RMSNorm
        • riporta i numeri su una scala stabile
      • ha pesi chiamati Parametri
        • a differenza delle attivazioni, ricalcolate a ogni frase

    E · La testa di output: logit, softmax, temperatura

    Dopo 32 blocchi il vettore dell'ultimo token contiene tutto il contesto. Come diventa esattamente una probabilità per ogni token del vocabolario?

    Con un ultimo prodotto scalare, ripetuto V volte. La testa di output è una matrice con una colonna per ogni token del vocabolario: il vettore finale viene moltiplicato per ciascuna colonna, e ogni prodotto scalare è un logit, il punteggio grezzo di quel token come candidato. Un vettore finale «vicino» alla colonna di «·Parigi» produce un logit alto per «·Parigi».

    Alcuni modelli (GPT-2, Gemma) usano come testa di output la stessa matrice E dell'ingresso (weight tying, condivisione dei pesi): prevedere il token successivo diventa letteralmente «cercare la riga di E più simile al vettore prodotto». La maggior parte dei modelli grandi attuali, Llama compreso, tiene invece una matrice separata.

    I logit possono essere qualsiasi numero, positivo o negativo. La funzione softmax li trasforma in probabilità che sommano a 1: eleva e a ciascun logit e divide per la somma; sottraendo prima il massimo si evita l'overflow, senza cambiare il risultato.

    La temperatura T divide i logit prima della softmax: T < 1 esagera le differenze (il token migliore prende quasi tutto), T > 1 le appiattisce. Si usa solo in generazione: il training e la misura della loss lavorano sempre a T = 1. Il laboratorio qui sotto mostra entrambe le cose su sei candidati.

    Formula · softmax con temperatura

    pi=ezi / T Σj ezj / T
    z sono i logit; T = 1 è la softmax semplice. T < 1 esagera le differenze, T > 1 le appiattisce

    Laboratorio: softmax, temperatura e loss

    matematica reale · logit di esempio
    Contesto: «La capitale della Francia è» → token corretto: «Parigi»

    La softmax e la loss sono calcolate davvero sui sei logit mostrati (il vocabolario vero ne ha decine di migliaia; qui sei candidati bastano). Il cursore «avanzamento» scala i logit per simulare che cosa fa il training: all'inizio sono quasi uguali, ogni token ha probabilità ≈ 1/6 e la loss vale log 6 ≈ 1,79; il training li separa. La temperatura divide i logit prima della softmax e si usa solo quando il modello genera: sotto 1 rende l'output più deterministico, sopra 1 più vario. La riga «loss» è il numero del capitolo 2, −log p(token corretto).

    F · I conti: dove sono i 7 miliardi di pesi

    Ora che il percorso è chiaro, i numeri di un modello reale si possono leggere componente per componente. Llama 2 7B ha d = 4.096, 32 blocchi, vocabolario di 32.000 token, MLP interno di 11.008.

    Dove sono i 7 miliardi di pesi

    conti reali · Llama 2 7B
    ComponenteMatriciPesi
    Embedding E32.000 × 4.096131 milioni
    Attention (per blocco)4 matrici 4.096 × 4.096 (query, key, value, output)67 milioni
    MLP (per blocco)3 matrici 4.096 × 11.008135 milioni
    Un blocco completoattention + MLP≈ 202 milioni
    32 blocchi32 × 202 milioni≈ 6,48 miliardi
    Testa di output4.096 × 32.000 (non condivisa con E)131 milioni
    Totale≈ 6,74 miliardi → «7B»

    Oltre il 95% dei pesi sta negli strati, non nell'embedding; l'MLP ne contiene circa due terzi. Per generare un token il modello esegue circa 2 operazioni per peso, cioè ~14 miliardi di moltiplicazioni-somme: una GPU moderna le fa in pochi millisecondi, e il tempo di risposta è dominato dal leggere i 14 GB di pesi dalla memoria, non dal calcolo.

    G · Backpropagation su una rete a due strati, con più step

    Il capitolo 2 ha mostrato la regola della catena su due pesi e una ReLU, un passo alla volta. Qui la stessa cosa su una rete con una non linearità morbida (tanh), con la possibilità di fare molti step di seguito e di guardare la loss scendere.

    Un LLM ha miliardi di pesi distribuiti su decine di strati, e la loss dipende da ciascuno solo attraverso tutti gli strati che vengono dopo. La backpropagation (retropropagazione) è il modo di calcolare tutti quei gradienti in un colpo solo.

    L'intuizione: alla fine della catena c'è un errore, e la «colpa» di quell'errore viene distribuita all'indietro, strato per strato. Ogni strato riceve dal successivo quanto ha pesato la sua uscita sull'errore, ne prende la sua parte e passa il resto allo strato precedente.

    Derivata, in una riga. La derivata di f rispetto a w è la pendenza: se sposti w di un pochino ε, f cambia di circa (derivata × ε). Positiva vuol dire che aumentando w la loss sale, quindi il peso va abbassato.

    Regola della catena. Se la loss dipende da w solo attraverso una grandezza intermedia h, le pendenze si moltiplicano:

    ∂L/∂w = ∂L/∂h · ∂h/∂w Con tanti strati in fila: un fattore per strato, dall'uscita fino a w.
    Un ingranaggio

    Come un ingranaggio: se h gira 3 volte più veloce di w, e L 2 volte più veloce di h, allora L gira 6 volte più veloce di w. Con tanti strati in fila si moltiplicano tanti fattori, uno per strato.

    Una rete minuscola a due strati. Un ingresso x, un primo peso w₁, una non linearità tanh, un secondo peso w₂, un'uscita ŷ confrontata con l'obiettivo y:

    z = w₁·x   h = tanh(z)   ŷ = w₂·h   L = ½ (ŷ − y)² Quattro passaggi in fila: ogni grandezza dipende solo da quella prima, quindi la regola della catena li attraversa uno alla volta.

    Calcolo · forward e backward su una rete a due strati

    z=w1·x = 0,5 × 1 = 0,500
    forward, con x = 1, w₁ = 0,5, w₂ = 0,5, y = 1
    h=tanh(0,5) = 0,462
    ŷ=w2·h = 0,5 × 0,462 = 0,231
    L=½ (0,231 − 1)2 = 0,296
    ∂L/∂ŷ=ŷ − y = −0,769
    backward: dalla loss ai pesi, un fattore per strato
    ∂L/∂w2=∂L/∂ŷ · h = −0,355
    ∂L/∂h=∂L/∂ŷ · w2 = −0,384
    ∂L/∂z=∂L/∂h · (1 − h2) = −0,384 × 0,786 = −0,302
    ∂L/∂w1=∂L/∂z · x = −0,302

    Entrambi i gradienti sono negativi: alzare w₁ e w₂ avvicina ŷ a y. Il passo di discesa w ← w − η · ∂L/∂w lo fa per tutti e due insieme. Nota che il backward riparte da ∂L/∂ŷ e lo riusa: il gradiente di w₁ non si ricalcola da zero, si ottiene da quello già pronto per lo strato sopra. È questo che rende la backpropagation economica: costa circa quanto due forward pass, qualunque sia il numero di pesi.

    Perché il training consuma tanta memoria. Il backward usa i valori del forward: h per ∂L/∂w₂, (1 − h²) per passare attraverso tanh, x per ∂L/∂w₁. Per questo durante il training si tengono in memoria le attivazioni di tutti gli strati, per ogni token del batch, finché il backward non le ha consumate. In inferenza non serve: ogni strato può buttare via il suo ingresso appena ha prodotto l'uscita. Quando la memoria non basta si usa il gradient checkpointing: si salvano solo alcune attivazioni e le altre si ricalcolano durante il backward, scambiando calcolo con memoria.

    Gradienti che svaniscono o esplodono

    Con decine di strati il gradiente di un peso in basso è un prodotto di decine di fattori: se sono quasi tutti sotto 1 (per esempio una tanh saturata, dove 1 − h² ≈ 0) il prodotto svanisce e i primi strati non imparano; se sono sopra 1 esplode. Le due soluzioni sono quelle viste nella sezione D: la connessione residua (uscita = ingresso + contributo) dà al gradiente una strada diretta, senza moltiplicazioni, fino agli strati più bassi, e la normalizzazione tiene le attivazioni su una scala in cui i fattori restano vicini a 1.

    Non tutte le reti si allenano così. Nella guida sull'auto che impara a guidare i pesi si trovano senza calcolare nessun gradiente, per neuroevoluzione: funziona con 82 pesi, ma con miliardi di pesi la backpropagation è l'unica strada praticabile.

    Laboratorio: forward, backward e uno step su una rete a due strati

    matematica reale

    Muovi x, w₁, w₂ e y e guarda come cambiano i due gradienti; poi premi «Fai uno step» più volte e osserva la loss scendere.

    Forward
    Backward (regola della catena)
    Loss per step

    La «verifica numerica» ricalcola ogni gradiente come (L(w + ε) − L(w − ε)) / 2ε con ε = 0,0001, spostando davvero il peso e rifacendo il forward: è il controllo che si usa per verificare un'implementazione della backpropagation. Una rete vera fa le stesse moltiplicazioni con matrici al posto dei singoli numeri.

    Mappa concettuale · dentro il transformer vero
    • Il transformer vero
      • comincia dal Tokenizer (BPE)
        • costruisce un vocabolario poi congelato
      • trasforma gli ID con la Matrice E
        • è un lookup: una riga per token
        • la posizione si aggiunge con RoPE
      • ripete N volte lo Strato
        • è fatto di attention, MLP, residuo e norma
      • finisce con la Testa di output
        • produce logit, poi softmax e temperatura
      • si allena con la Backpropagation
        • distribuisce la colpa all'indietro, con la regola della catena

    In sintesi · capitolo 9

    • BPE — il vocabolario nasce fondendo le coppie di simboli più frequenti del corpus, una volta sola, poi si congela
    • Matrice E — V × d numeri inizializzati a caso e aggiornati dal training; il lookup equivale a one-hot × E; la posizione si aggiunge con RoPE
    • Attention — tre matrici (query, key, value); punteggi q·k/√d, softmax con causal mask, media pesata dei value; molte teste in parallelo
    • MLP, residual, norm — allarga, non-linearità, restringe; ogni sotto-strato aggiunge una correzione; RMSNorm stabilizza
    • Testa di output — un prodotto scalare per ogni token del vocabolario; softmax; temperatura solo in generazione; weight tying in alcuni modelli
    • 7B — 32 strati da ~202 milioni di pesi ciascuno, più E e la testa di output; oltre il 95% dei pesi sta negli strati
    • Backpropagation — la colpa dell'errore si distribuisce all'indietro moltiplicando le derivate locali; con tanh il gradiente si attenua dove la funzione è piatta
    Riepilogo

    Un solo meccanismo, cinque modi di scegliere gli esempi e misurare l'errore

    Ogni fase esegue lo stesso ciclo del capitolo 2: forward pass, un numero che misura l'errore, backpropagation, un passo sui pesi. Quello che la distingue è nelle due colonne centrali della tabella: da dove arrivano gli esempi e come si calcola l'errore. La colonna «densità» dice quanti numeri di feedback arrivano per sequenza, ed è la ragione per cui le fasi costano in modo così diverso.

    FaseProblema che risolveDatiErrore (loss)Chi generaDensità del segnaleLimite che lascia
    Pre-trainingPesi casuali: nessuna conoscenzaTesto grezzo, migliaia di miliardi di tokenCross-entropy sul token successivoNessuno (testo esistente)
    %D10%
    ogni token
    Continua, non risponde
    SFTManca il comportamento da assistentePrompt → risposta scrittaCross-entropy sui soli token della rispostaPersone o modello forte
    %D10%
    ogni token della risposta
    Imita; non sa che cosa è «meglio»
    DPOQualità relative: stile, utilità, sicurezzaCoppie chosen / rejected−log σ(margine) sul reward implicitoDataset fisso (offline)
    %D1%
    1 confronto per coppia
    Offline, soggettivo; non insegna a cercare
    RLVR + GRPOSuperare l'imitazione dove si può verificareProblema + verificatoreLog-prob dei token × vantaggio nel gruppoIl modello stesso (online)
    %D1%
    1 numero per sequenza
    Solo domini verificabili; modello grande
    OPDTrasferire la capacità a un modello piccoloPrompt + teacherReverse KL student ‖ teacher, per tokenLo student (online)
    %D10%
    ogni token dello student
    Non supera il teacher

    Lo stesso prompt, fase dopo fase

    Base model«Qual è la capitale della Germania? Qual è la capitale della Spagna? …» — continua il testo come un quiz.
    Dopo SFT«La capitale della Francia è Parigi.» — risponde, nella forma vista negli esempi.
    Dopo DPO«La capitale della Francia è Parigi. È anche la città più grande del Paese… Vuoi sapere altro?» — la forma che gli annotatori preferivano.
    Dopo RL (su un prompt verificabile)«17 × 23 = 340 + 51 = 391. Verifica: 391 ÷ 17 = 23 ✓» — ragiona e controlla, perché controllare dava reward.
    Dopo OPD (modello piccolo)Stesso stile di ragionamento del modello grande, a un decimo del costo per risposta.

    Nella pratica l'ordine non è rigido. Molti laboratori alternano più cicli di SFT e RL, applicano DPO dopo l'RL per sistemare lo stile, usano OPD al posto dell'RL per i modelli piccoli, e in alcune ricette recenti il post-training è una lunga fase di RL che ingloba le altre. Le fasi restano però cinque risposte alle stesse due domande: che esempi, e che misura dell'errore.