CAPIRE L’IA · 6 di N
Errore, gradiente e aggiornamento dei pesi: seguiamo un piccolo addestramento, un passo alla volta.
Nell’articolo precedente abbiamo costruito una rete neurale: due ingressi, tre unità nascoste, un’uscita e tredici parametri. Inserendo i numeri 2 e 1, la rete restituiva 1,5.
Adesso le forniamo un esempio accompagnato dal risultato atteso: per quell’ingresso vorremmo ottenere 2. La previsione è troppo bassa. Che cosa dobbiamo cambiare?
Non basta dire “aumenta i pesi”. Alcuni collegamenti hanno pesi negativi, alcune unità possono produrre zero, e lo stesso parametro può influenzare molti esempi in modi diversi. Serve un procedimento che misuri l’errore e calcoli come una piccola modifica di ciascun parametro lo influenzerebbe.
Qui entra il gradiente. Il suo ruolo diventa più chiaro se, prima di parlare di milioni di pesi, ne osserviamo uno solo.
Il ciclo: prevedere, misurare, derivare, aggiornare
Consideriamo un addestramento supervisionato. Disponiamo di ingressi e risultati attesi. La rete esegue il calcolo in avanti, produce una previsione e una funzione di perdita ne misura lo scostamento dal riferimento. Calcoliamo poi le derivate della perdita rispetto ai parametri e usiamo un ottimizzatore per aggiornarli.

Il processo si ripete sugli esempi disponibili. All’inizio i pesi di una nuova rete vengono in genere inizializzati con valori casuali secondo criteri appropriati; si può anche partire da un modello già addestrato. Nel nostro esperimento partiamo invece dai coefficienti scelti nell’articolo precedente, così possiamo seguire tutti i passaggi.
L’apprendimento avviene quando cambiano i parametri. Calcolare una previsione, da solo, non modifica la rete.
Dall’errore a una quantità da minimizzare
Indichiamo la previsione con ŷ, “y cappello”, e il risultato atteso con y. Lo scarto con segno è:
e = ŷ − y = 1,5 − 2 = −0,5
Il segno negativo indica una sottostima. Per misurare la perdita scegliamo:
L = (ŷ − y)² = (−0,5)² = 0,25
Elevare al quadrato evita che scarti positivi e negativi si annullino quando vengono mediati, e dà più peso agli scarti grandi. È una scelta adatta al nostro esempio numerico, non l’unica possibile: per altri compiti si usano altre perdite.
Lo scarto −0,5 e la perdita 0,25 non sono la stessa cosa. Il primo descrive quanto e in quale verso abbiamo sbagliato la previsione; la seconda quantifica ciò che l’addestramento cerca di ridurre.
Fermiamo dodici parametri e muoviamone uno
Per l’ingresso (2, 1), lo strato nascosto della nostra rete produce h₁ = 1, h₂ = 2 e h₃ = 0. L’uscita è:
ŷ = v₁h₁ + v₂h₂ + v₃h₃ + c
I valori iniziali sono v₁ = 2, v₂ = −0,5, v₃ = 1 e c = 0,5.
Teniamo fissi tutti i parametri tranne v₁, che per semplicità chiamiamo v. Poiché h₁ = 1, l’uscita si semplifica:
ŷ = v × 1 − 0,5 × 2 + 1 × 0 + 0,5
ŷ = v − 0,5
Con il bersaglio y = 2, la perdita diventa:
L(v) = (v − 2,5)²
Abbiamo ottenuto una parabola. Sull’asse orizzontale c’è un peso della rete, non un dato in ingresso; sull’asse verticale c’è la perdita. Il punto più basso si trova in v = 2,5. In questo caso lo vediamo subito, ma useremo comunque un procedimento iterativo per capire che cosa accade quando la soluzione non è evidente.

La derivata è una pendenza locale
La derivata della perdita rispetto a v è:
dL/dv = 2(v − 2,5)
Nel punto iniziale v = 2:
dL/dv = 2(2 − 2,5) = −1
Quel −1 ci dice che, nelle immediate vicinanze del punto attuale, aumentare v tende a diminuire la perdita. Non indica quanto siamo lontani dalla soluzione e non autorizza un salto arbitrariamente grande.
La lettura più precisa è: per una piccola variazione Δv, ΔL ≈ (dL/dv)Δv. È un’approssimazione locale. La funzione può cambiare pendenza mentre ci spostiamo, quindi dopo il passo dobbiamo ricalcolare.
Per visualizzarlo, immaginiamo una pallina su un pendio. La pendenza suggerisce una direzione di discesa; non fornisce una mappa completa del terreno. La metafora va usata con cautela: nell’algoritmo siamo noi a stabilire quanto muovere i parametri.
La regola di aggiornamento
La discesa del gradiente usa una regola semplice:
v nuovo = v attuale − η · dL/dv
η, la lettera greca eta, è il learning rate, o tasso di apprendimento. Regola l’ampiezza del passo.
Scegliamo η = 0,1. Otteniamo:
v nuovo = 2 − 0,1 × (−1) = 2,1
La nuova previsione è 2,1 − 0,5 = 1,6.
La nuova perdita è (1,6 − 2)² = 0,16.
La perdita è scesa da 0,25 a 0,16. Ora la derivata vale −0,8: un secondo aggiornamento porta il peso a 2,18. La previsione sale a 1,68 e la perdita scende a 0,1024. Ogni passo usa la pendenza nel punto raggiunto, non quella iniziale.
Il segno meno nella regola è importante: ci muoviamo nel verso opposto alla crescita locale della perdita. La diminuzione effettiva, però, dipende anche dall’ampiezza del passo.
Un passo troppo grande può peggiorare tutto
Ripartiamo sempre da v = 2 e confrontiamo tre valori di η. Con 0,1 ci avviciniamo gradualmente a 2,5. Con 0,8 oltrepassiamo il minimo e oscilliamo, ma con scarti sempre più piccoli. Con 1,1 le oscillazioni crescono: la perdita aumenta.

Nel terzo caso il primo aggiornamento porta v a 3,1. La perdita diventa (3,1 − 2,5)² = 0,36: è maggiore dello 0,25 iniziale. La direzione locale era corretta, ma il passo era troppo lungo.
Un dettaglio matematico da leggere con calma
Per questa parabola, la distanza con segno dal minimo segue la relazione:
v nuovo − 2,5 = (1 − 2η)(v attuale − 2,5)
Le distanze si riducono quando |1 − 2η| < 1, cioè 0 < η < 1. Se η = 0,5, questo particolare problema raggiunge il minimo in un solo passo.
Questa soglia dipende dalla forma e dalla scala della perdita. Non è una regola universale per le reti neurali. Anche moltiplicare la perdita per una costante modifica la scala del gradiente e quindi l’effetto dello stesso learning rate.
Da una derivata al gradiente
Nella rete completa i parametri sono molti. Li raccogliamo in un vettore θ, theta, che comprende pesi e bias. Il gradiente è il vettore delle derivate parziali della perdita rispetto a questi parametri:
∇L(θ) = (∂L/∂θ₁, ∂L/∂θ₂, …)
La discesa del gradiente diventa:
θ nuovo = θ attuale − η ∇L(θ attuale)
Ogni derivata parziale misura la sensibilità locale della perdita a un parametro, tenendo fissi gli altri. Nell’aggiornamento standard i gradienti sono calcolati nello stesso stato della rete e poi usati per modificare insieme i parametri.
La nostra parabola è quindi soltanto un taglio a una dimensione del problema. Con una rete completa la superficie può essere molto più complessa: non bisogna immaginarla necessariamente come una valle regolare con un unico fondo.
Come si calcolano tutte quelle derivate?
Per il peso finale del nostro esempio possiamo scrivere:
∂L/∂v = (∂L/∂ŷ) · (∂ŷ/∂v)
In partenza, ∂L/∂ŷ = 2(1,5 − 2) = −1 e ∂ŷ/∂v = h₁ = 1.
Quindi ∂L/∂v = −1 × 1 = −1.

È la regola della catena: il peso cambia la previsione e la previsione cambia la perdita. Moltiplichiamo gli effetti locali lungo quel percorso. Quando una quantità contribuisce attraverso più percorsi, si sommano i contributi.
La retropropagazione, o backpropagation, organizza questi calcoli partendo dalla perdita e risalendo il grafo delle operazioni. Riutilizza risultati intermedi, evitando di rifare separatamente gli stessi conti per ogni parametro. La distinzione fra propagazione in avanti e retropropagazione è illustrata in Dive into Deep Learning.
Possiamo vedere il principio anche dentro lo strato nascosto. Alla partenza, h₁ = ReLU(z₁), z₁ = 1 e il peso che collega h₁ all’uscita è 2. Dunque ∂L/∂h₁ = −1 × 2 = −2. Poiché ReLU ha derivata 1 in z₁ = 1, anche ∂L/∂z₁ = −2. Se w₁₁ moltiplica l’ingresso x₁ = 2, otteniamo ∂L/∂w₁₁ = −2 × 2 = −4.
Questo gradiente è calcolato nei valori iniziali della rete. Non lo abbiamo applicato nell’esperimento a un solo peso. Mostra però come l’informazione raggiunga un collegamento precedente, senza attribuirgli una “colpa” in senso umano.
Nella terza unità nascosta, z₃ = −1: la derivata di ReLU è zero e quel percorso non contribuisce al gradiente dei suoi pesi per questo esempio. Altri ingressi possono attivare l’unità. In zero ReLU non è derivabile; le implementazioni adottano una convenzione, comunemente una derivata impostata a zero.
Retropropagazione e ottimizzatore fanno lavori diversi
La retropropagazione calcola le derivate. L’ottimizzatore usa quelle derivate per aggiornare i parametri. La discesa del gradiente mostrata qui è una regola possibile; altri ottimizzatori usano anche informazioni accumulate nei passi precedenti.
Tenere separate queste due operazioni aiuta a capire perché possiamo cambiare il metodo di aggiornamento senza cambiare il significato delle derivate. Un gradiente descrive una sensibilità locale; l’ottimizzatore decide come sfruttarla.
Un esempio non basta: batch ed epoche
Abbiamo ripetuto i conti sullo stesso ingresso per rendere visibile il meccanismo. Un addestramento utile deve confrontarsi con molti esempi, che possono suggerire correzioni diverse. Spesso si lavora su piccoli gruppi, chiamati mini-batch, e si calcola la perdita media del gruppo.
LB(θ) = (1/|B|) ∑i∈B ℓ(fθ(xi), yi)
B è il gruppo di esempi; |B| è il suo numero di elementi. Il gradiente della media è la media dei gradienti degli esempi, con la consueta ipotesi di derivabilità nei punti considerati.
Con il batch successivo, la direzione può cambiare. Per questo la perdita osservata durante un addestramento può oscillare e non diminuire a ogni aggiornamento.
Un’epoca è, nel caso ordinario di un dataset finito, un passaggio completo sui dati di addestramento. Se abbiamo 1.000 esempi divisi in batch da 100 e aggiorniamo dopo ogni batch, un’epoca contiene 10 aggiornamenti. Non significa un solo aggiornamento.
Quando smettere di correggere?
La perdita di training ci dice come stiamo ottimizzando gli esempi usati. Non dimostra che la rete stia diventando più utile sui casi nuovi. Come abbiamo visto nell’articolo sulla generalizzazione, una rete può continuare a migliorare sul training mentre peggiora sulla validazione.
Durante lo sviluppo controlliamo quindi anche dati separati e possiamo scegliere un punto di arresto sulla base della validazione. Il test finale serve a valutare la soluzione già scelta, senza guidare ulteriori correzioni.
Nella nostra parabola il minimo si può individuare esattamente. In una grande rete non abbiamo la stessa garanzia di trovare il miglior risultato possibile, né una perdita bassa rende automaticamente corretto il compito che abbiamo formulato. L’ottimizzazione risponde all’obiettivo numerico scelto.
Tre cose da conservare
- La perdita misura ciò che cerchiamo di ridurre. Va distinta dallo scarto con segno della singola previsione.
- Il gradiente descrive la sensibilità locale della perdita ai parametri. La retropropagazione lo calcola; l’ottimizzatore usa il risultato per aggiornarli.
- Imparare richiede ripetere e verificare. Il passo di aggiornamento conta, e migliorare sul training non garantisce di generalizzare.
La rete era partita da 1,5. Modificando un peso siamo arrivati a 1,6, poi a 1,68. Sono cambiamenti piccoli, ma ora sappiamo da dove provengono: una misura dell’errore, una derivata e una regola di aggiornamento. Ripetuti su molti parametri ed esempi, questi passaggi sono alla base dell’addestramento di gran parte delle reti neurali contemporanee.
← Torna al percorso Capire l’IA


Lascia un commento