In questo post viene letteralmente visualizzata un'affascinante tecnica che consente alle macchine di apprendere dai propri errori: la backpropagation.
Sebbene già nota in ristretti ambiti scientifici, è diventata famosa nel 1986 grazie ai lavori di Rumelhart, Hinton e Williams.
Ma come avviene questa misteriosa forma di apprendimento?
Pensate a come si impara a suonare il pianoforte: all'inizio si sbaglia la posizione delle dita, il ritmo è incerto, il tocco è troppo forte o troppo debole. Ma con il tempo, attraverso piccoli aggiustamenti, il nostro cervello affina il controllo e la musica prende forma.
La backpropagation segue lo stesso principio: confronta il risultato prodotto dalla rete neurale con quello desiderato, calcola l’errore e poi lo propaga a ritroso, correggendo passo dopo passo ogni parametro (aggiornamento dei pesi).
Ciò che rende questo meccanismo oggi così efficace è l’incredibile progresso tecnologico. Processori dedicati al calcolo tensoriale e la disponibilità di enormi quantità di dati hanno trasformato quella che un tempo era solo un’idea promettente in una vera e propria rivoluzione.
Grazie alla backpropagation, oggi abbiamo sistemi in grado di tenere conversazioni simili a quelle umane, riconoscere volti, tradurre lingue e persino guidare veicoli autonomamente.
Nella GIF animata si può osservare, come in una sorta di danza numerica, quello che avviene, nel corso di venti epoche, all'interno di una semplicissima rete neurale composta da soli 3 neuroni e 4 parametri.
Ancora una volta, la scienza ci sorprende con la sua combinazione di logica ed eleganza.
Struttura della rete neurale utilizzata per questo esperimento:
- Un input: un singolo valore.
- Un hidden layer: costituito da due neuroni (H1 e H2).
- Un output: un singolo neurone che fornisce il risultato finale.
Al confronto, altre reti neurali utilizzate negli esperimenti illustrati in altri post di questo blog arrivano fino a 60 milioni di parametri.
Come si evince dall'animazione, l'addestramento porta a una progressiva e significativa riduzione dell'errore.Le fasi descritte sono:
- Il forward pass
Calcolo dei neuroni del layer nascosto
Per ciascun neurone nascosto:
- H1:
h1 = σ(z₁) = σ(w₁·x)
- H2:
h2 = σ(z₂) = σ(w₂·x)
dove:
-
x
è il valore di input (nel codice 0.5),
-
w₁
e w₂
sono i pesi associati alle connessioni dall'input a H1 e H2,
-
σ(u) = 1/(1 + e−u)
è la funzione di attivazione sigmoide.- Calcolo del neurone di output
L'output finale viene calcolato combinando le uscite dei neuroni nascosti:
o = σ(zₒ) = σ(w₃·h₁ + w₄·h₂)
dove
w₃
e w₄
sono i pesi che collegano H1 e H2 al neurone di output.- Calcolo dell'errore
Una volta ottenuto l'output
o
, il passo successivo è confrontarlo con il target (valore desiderato, nel mio script 0.8). L'errore viene calcolato usando la funzione di errore quadratico:E = ½·(target-o)²
Questo valore misura quanto l'output della rete si discosta dal valore atteso.
- La backpropagation
La vera potenza della backpropagation sta nel modo in cui l'errore viene retropropagato attraverso la rete neurale per aggiornare i pesi.
Questo avviene tramite il calcolo dei gradienti, che indicano la direzione e l'intensità delle variazioni necessarie per ridurre l'errore.
a. Calcolo del delta per il neurone di output
Il primo passo è calcolare il delta dell'output:
δₒ = (o - target)·σ'(zₒ)
Essendo la derivata della funzione sigmoide:
σ'(zₒ) = o·(1 - o)
otteniamo:
δₒ = (o - target)·o·(1 - o)
b. Aggiornamento dei pesi nel layer di output
I gradienti per i pesi che connettono i neuroni nascosti al neurone di output sono:
∂E/∂w₃ = δₒ·h₁
∂E/∂w₄ = δₒ·h₂
Questi gradienti vengono poi utilizzati per aggiornare i pesi:
wnew = wold - η·(∂E/∂w)
dove
η
è il learning rate (nel nostro caso 0.1).
c. Propagazione dell'errore all'hidden layer
Per ciascun neurone nascosto, l'errore viene propagato indietro.
Ad esempio, per il neurone H1:
δh1 = δₒ·w₃·h₁·(1 - h₁)
Analogamente, per H2:
δh2 = δₒ·w₄·h₂·(1 - h₂)
d. Aggiornamento dei pesi dell'hidden layer
I gradienti per i pesi che collegano l'input ai neuroni nascosti sono dati da:
∂E/∂w₁ = δh1·x
∂E/∂w₂ = δh2·x
Anche in questo caso, i pesi vengono aggiornati usando la formula:
wnew = wold - η·(∂E/∂w)