Un modello appena inizializzato è un disastro. Gli dai un’immagine e ti risponde a caso; gli chiedi di completare una frase e produce una sequenza di caratteri senza senso. Dopo qualche ora, o qualche settimana, di addestramento, lo stesso modello, con la stessa architettura, sbaglia poco. Nel frattempo nessun essere umano ha aperto il file dei parametri per scrivere «questo peso vale 0,3187». Nessuno gli ha detto la risposta giusta parametro per parametro. E allora: chi ha messo quei numeri lì? La risposta ha un nome preciso, ed è la discesa del gradiente.
In questo articolo scoprirai:
- All'inizio sbaglia tutto, poi smette di sbagliare: cosa accade nel mezzo
- Cosa succede davvero: la pendenza sotto i piedi, non la mappa
- Il conto: due passi di discesa del gradiente fatti a mano
- Learning rate troppo alto o troppo basso: dove si vede il passo sbagliato
- Cosa resta da sapere: con milioni di pesi serve la backpropagation
All’inizio sbaglia tutto, poi smette di sbagliare: cosa accade nel mezzo
La risposta è che i numeri li ha messi il modello stesso, spostandoli un po’ alla volta, e la cosa che gli dice di quanto spostarli è una misura del suo errore. È qui che entra la discesa del gradiente: il procedimento con cui una rete corregge i propri pesi partendo dall’unica informazione che ha davvero a disposizione, cioè quanto la sua risposta era lontana da quella attesa.
La divisione dei compiti è questa: come una rete calcola la sua risposta a partire da pesi già fissati è spiegato altrove, qui si spiega come quei pesi arrivano ai valori che hanno.
Chi ha letto come funziona un large language model sa che un modello è, alla fine, una lista enorme di numeri moltiplicati fra loro. Un modello da 8 miliardi di parametri ha 8 miliardi di numeri di quel tipo. Alla nascita sono estratti a caso da una distribuzione stretta intorno allo zero, ed è per questo che un modello non addestrato non è «poco preciso»: è casuale. La domanda vera non è «come impara», che è una parola comoda e vuota: è come si passa da 8 miliardi di numeri casuali a 8 miliardi di numeri che funzionano, senza che nessuno li scriva a mano.
La documentazione di Google descrive il ciclo in quattro mosse che si ripetono: si calcola la perdita con i parametri attuali, si determina in quale direzione spostare pesi e bias per ridurla, si aggiornano «di una piccola quantità» in quella direzione, e si ricomincia fino alla convergenza. Detta così sembra banale. Il punto interessante è il secondo passaggio: come fa a sapere in quale direzione, se ha davanti milioni di direzioni possibili.
Cosa succede davvero: la pendenza sotto i piedi, non la mappa
L’immagine classica è quella della collina nella nebbia: non vedi il fondovalle, senti solo la pendenza sotto i piedi, e fai un passo in giù. È un’immagine utile per trenta secondi, e va sostituita subito con il conto vero, perché quella pendenza non è una sensazione: è una derivata, e si calcola.
La discesa del gradiente è il procedimento con cui un modello aggiusta i propri parametri usando una funzione di perdita, cioè un numero che misura quanto la risposta prodotta è lontana da quella attesa. Il gradiente di quella funzione rispetto a ogni parametro dice in quale direzione la perdita crescerebbe più rapidamente; l’algoritmo sposta ciascun parametro nella direzione opposta, di una quantità proporzionale alla pendenza e a un fattore di scala chiamato learning rate. Ripetendo l’operazione molte volte la perdita scende, e i parametri finiscono in una configurazione che sbaglia poco.
Funzione di perdita e gradiente: due nomi per due cose diverse
Due termini vanno tenuti distinti. La funzione di perdita è il metro: per un problema numerico può essere l’errore al quadrato, per un modello di linguaggio è di solito la cross-entropy, che misura quanto il modello si è sorpreso della parola effettivamente arrivata. Il gradiente è il vettore che contiene tutte le derivate parziali della perdita, nel Deep Learning di Goodfellow, Bengio e Courville è definito esattamente così: «il vettore che contiene tutte le derivate parziali». Con 8 miliardi di parametri, il gradiente è un vettore da 8 miliardi di componenti, e ognuna risponde alla stessa domanda: se muovo questo numero di un pelo, la perdita sale o scende, e di quanto?
La regola di aggiornamento è una riga sola, ed è la stessa nella documentazione di Keras e in quella di PyTorch: w = w − learning_rate × g. Il segno meno è tutto il segreto: il gradiente punta in salita, quindi si va nell’altro verso.
Il conto: due passi di discesa del gradiente fatti a mano
Prendiamo un modello ridicolo, con un solo peso, e facciamo il calcolo per intero. Il modello moltiplica l’ingresso per il peso: previsione = w × x. L’unico esempio di addestramento è x = 2, risposta giusta y = 10. Quindi il valore corretto di w sarebbe 5, ma il modello non lo sa: parte da w = 1.
Perdita: l’errore al quadrato, L = (2w − 10)². Con w = 1 la previsione è 2, l’errore è −8, la perdita è 64.
La derivata di L rispetto a w si calcola con la regola della catena: dL/dw = 2 × (2w − 10) × 2 = 8w − 40. Con w = 1 vale 8 − 40 = −32. Negativa: significa che aumentando w la perdita scende.
Due passi di discesa del gradiente con learning rate 0,05
Scegliamo un learning rate η = 0,05 e applichiamo la regola:
- Passo 1: w = 1 − 0,05 × (−32) = 1 + 1,6 = 2,6. Previsione 5,2; perdita (5,2 − 10)² = 23,04.
- Passo 2: gradiente = 8 × 2,6 − 40 = −19,2. w = 2,6 − 0,05 × (−19,2) = 3,56. Previsione 7,12; perdita (7,12 − 10)² = 8,2944.
Il peso è passato da 1 a 2,6 a 3,56, avvicinandosi a 5. La perdita è passata da 64 a 23,04 a 8,2944: si moltiplica ogni volta per 0,36, che non è un caso ma il valore di (1 − 0,05 × 8)². Nessuno ha detto al modello che la risposta era 5. Gli è stato detto solo quanto si era sbagliato, e lui ha usato la pendenza.
Learning rate troppo alto o troppo basso: dove si vede il passo sbagliato
Il learning rate è la lunghezza del passo, e sullo stesso conto si vede benissimo cosa combina quando è tarato male.
Passo troppo lungo. Con η = 0,3, il primo aggiornamento porta w da 1 a 1 + 0,3 × 32 = 10,6. La previsione diventa 21,2 e la perdita 125,44: più del doppio di quella di partenza. Il passo successivo peggiora ancora, perché il fattore di moltiplicazione è (1 − 0,3 × 8)² = 1,96. Il modello non scende: rimbalza da una parete all’altra della valle e scappa via. Il caso limite è η = 0,25: il peso salta da 1 a 9 e poi da 9 a 1, all’infinito, con la perdita bloccata a 64 (è la linea tratteggiata nello schema). Le note del corso CS231n di Stanford descrivono questo comportamento in una frase che vale come diagnosi: c’è «troppa energia» nell’ottimizzazione e i parametri «rimbalzano caoticamente», incapaci di sistemarsi.
Passo troppo corto. Con η = 0,001 la direzione è sempre giusta, ma il fattore diventa 0,984064 per iterazione. Per portare la perdita sotto 0,01 servono 546 passi invece dei 9 necessari con η = 0,05: sessanta volte il lavoro per lo stesso risultato. Su un modello vero questo è il motivo per cui una curva di perdita che scende in linea retta e lentissima è un sintomo, non una virtù.
Che non esista un valore giusto universale lo dicono i default degli strumenti reali: PyTorch imposta lr=0,001 in torch.optim.SGD, Keras imposta learning_rate=0,01 nel suo SGD, due librerie industriali, un fattore 10 di differenza sulla stessa formula. Il valore giusto dipende dalla forma della perdita, e la forma dipende dai dati.
Il fondo di valle che non è il fondo vero
Terzo comportamento: la discesa si ferma dove la pendenza è nulla, non dove la perdita è minima. Quel punto può essere un minimo locale, un altopiano o un punto di sella. Su un modello lineare come quello del nostro conto il problema non esiste, perché la perdita è una parabola con un solo fondo; su una rete profonda esiste eccome. Ed è anche il punto in cui questo meccanismo incontra quando un modello impara troppo bene i casi che ha visto: la discesa minimizza la perdita sui dati di addestramento, e nient’altro. Se il metro è sbagliato, scendere bene lungo quel metro peggiora il modello, motivo per cui le metriche di valutazione vanno scelte prima di guardare la curva.
Cosa resta da sapere: con milioni di pesi serve la backpropagation
Nel nostro conto la derivata era immediata perché c’era un peso e una moltiplicazione. In una rete profonda ogni peso influenza l’uscita passando attraverso decine di strati, e calcolarne la derivata «a occhio» è impossibile. Il pezzo che risolve il problema si chiama backpropagation, e consiste nell’applicare la regola della catena in ordine inverso, la formulazione di riferimento è l’articolo del 1986 di Rumelhart, Hinton e Williams su Nature, e Hinton è poi diventato uno dei nomi del Nobel per la Fisica 2024. Il meccanismo: si parte dalla perdita in uscita, si calcola quanto ciascun neurone dell’ultimo strato ha contribuito all’errore, e si propaga quel contributo indietro fino all’ingresso. Ogni strato riusa il risultato dello strato successivo invece di ricalcolarlo, ed è per questo che si ottiene il gradiente di tutti i parametri con un costo dello stesso ordine di una singola previsione in avanti. Senza questa proprietà l’addestramento di reti profonde non sarebbe praticabile.
Backpropagation e discesa del gradiente: chi calcola e chi muove i pesi
Vale la pena tenere separate le due parole, perché nella pratica vengono confuse continuamente: la backpropagation calcola il gradiente, la discesa del gradiente lo usa per muovere i pesi. Sono due fasi distinte dello stesso ciclo, e in PyTorch corrispondono letteralmente a due chiamate diverse. Tutte le operazioni coinvolte, in avanti e all’indietro, sono moltiplicazioni fra matrici: è l’algebra lineare che sta sotto queste operazioni a rendere il tutto eseguibile su una GPU.
Quando la collina nella nebbia smette di funzionare come immagine
Qui la nota di falsificazione, ed è importante: l’immagine della collina vale in due o tre dimensioni, e in un modello vero le dimensioni sono milioni. Dire «la discesa del gradiente trova il punto più basso» è falso in due modi. Primo: non cerca il punto più basso, cerca un punto abbastanza basso, Goodfellow, Bengio e Courville lo scrivono esplicitamente, «non è importante trovare un vero minimo globale, quanto piuttosto trovare un punto nello spazio dei parametri con un costo basso ma non minimo». Secondo: l’intuizione bidimensionale sui minimi locali è fuorviante. Dauphin e colleghi hanno mostrato nel 2014 che in alta dimensione il problema serio non sono i minimi locali ma la proliferazione dei punti di sella, che creano «altopiani ad alto errore» capaci di rallentare drasticamente l’apprendimento dando «l’illusione di un minimo locale». Nel manuale il rapporto atteso fra punti di sella e minimi locali «cresce esponenzialmente con n». Se qualcuno vi spiega l’addestramento di un LLM con la valle e la pallina che rotola, ha descritto il caso a due dimensioni, non il caso reale.
Rimane un ultimo dettaglio pratico: nessuno calcola il gradiente su tutti i dati insieme. Si usa un sottoinsieme per volta, un minibatch, e il gradiente che ne esce è una stima rumorosa di quello vero. È la «discesa stocastica del gradiente», e quel rumore, controintuitivamente, aiuta: è una delle ragioni per cui i modelli non restano incastrati nel primo avvallamento che incontrano.
L’addestramento è il momento in cui i pesi diventano quelli giusti; poi però quei pesi vanno usati. Come funziona davvero un modello di AI racconta l’intero tragitto, addestramento incluso, fino alla risposta che leggi.
Fonti:
- Google Machine Learning Crash Course — Gradient descent: il ciclo di addestramento in quattro mosse
- Google Machine Learning Crash Course — Hyperparameters: cosa fa il learning rate
- Goodfellow, Bengio, Courville, Deep Learning, cap. 4 — Numerical Computation: la definizione di gradiente
- Goodfellow, Bengio, Courville, Deep Learning, cap. 8 — Optimization: minimi locali, punti di sella e costo «basso ma non minimo»
- Dauphin et al. (2014) — Identifying and attacking the saddle point problem in high-dimensional non-convex optimization
- Stanford CS231n — Neural Networks part 3: diagnosi del learning rate «con troppa energia»
- PyTorch —
torch.optim.SGD: regola di aggiornamento e defaultlr=0.001 - Keras — SGD optimizer: regola di aggiornamento e default
learning_rate=0.01 - Rumelhart, Hinton, Williams (1986) — Learning representations by back-propagating errors, Nature (testo integrale in PDF disponibile anche dall’archivio di Geoffrey Hinton: cs.toronto.edu/~hinton/absps/naturebp.pdf)
- NVIDIA Developer Blog — A Data Scientist’s Guide to Gradient Descent and Backpropagation Algorithms
Domande frequenti
Cos'è la discesa del gradiente in parole semplici?
È il procedimento con cui un modello aggiusta i propri parametri usando una funzione di perdita, cioè un numero che misura quanto la risposta prodotta è lontana da quella attesa. Il gradiente indica in quale direzione la perdita crescerebbe più rapidamente, e l'algoritmo sposta ogni parametro nella direzione opposta. Ripetendo l'operazione molte volte la perdita scende e il modello sbaglia meno.
Che differenza c'è fra backpropagation e discesa del gradiente?
Sono due fasi distinte dello stesso ciclo e vengono confuse continuamente. La backpropagation calcola il gradiente applicando la regola della catena in ordine inverso, dalla perdita in uscita fino all'ingresso. La discesa del gradiente usa quel gradiente per muovere effettivamente i pesi.
Cosa succede se il learning rate è troppo alto?
Il modello non scende: rimbalza. Sull'esempio con un solo peso dell'articolo, con learning rate 0,3 la perdita passa da 64 a 125,44 al primo aggiornamento, e peggiora ancora dopo. Con 0,25 il peso oscilla fra 1 e 9 all'infinito, con la perdita bloccata a 64. Un learning rate troppo basso invece funziona, ma richiede 546 passi dove ne basterebbero 9.
La discesa del gradiente trova il minimo globale della perdita?
No, e non è il suo obiettivo. Goodfellow, Bengio e Courville scrivono che non è importante trovare un vero minimo globale, quanto piuttosto un punto nello spazio dei parametri con un costo basso ma non minimo. In alta dimensione, inoltre, l'ostacolo principale non sono i minimi locali ma i punti di sella, come mostrato da Dauphin e colleghi nel 2014.



