Nel 2010 Xavier Glorot e Yoshua Bengio pubblicano un esperimento apparentemente banale: addestrano la stessa identica rete più volte, cambiando solo il modo in cui vengono estratti i valori iniziali dei pesi. I risultati sono tutt’altro che banali. Con certe inizializzazioni la rete impara; con altre, identica in tutto il resto, resta bloccata per epoche intere o non converge affatto. La lezione è scomoda ma chiara: prima ancora di vedere il primo dato, una rete neurale ha già fatto una scelta che può condannarla.
Segnale che svanisce o esplode, inizializzazione, batch normalization, dropout e gli ottimizzatori: il capitolo è nel libro.
Sembra un dettaglio implementativo, di quelli che i framework nascondono in una riga di default. E infatti oggi lo è: PyTorch e simili inizializzano bene senza chiedere niente. Ma capire perché quei default funzionano significa capire come l’informazione scorre dentro una rete profonda — ed è una delle chiavi per leggere quasi tutto il deep learning moderno, dalle skip connection alla batch normalization.
Perché non si può partire da zero
La tentazione più ovvia — inizializzare tutti i pesi a zero — è anche la più catastrofica. Se tutti i neuroni di uno strato partono identici, ricevono gli stessi input, producono gli stessi output e ricevono gli stessi gradienti. Aggiornamento dopo aggiornamento, restano identici per sempre: la rete ha mille neuroni ma si comporta come se ne avesse uno solo.
È il problema della simmetria: serve una rottura, e la rottura si ottiene con il caso. Si estraggono i pesi da una distribuzione casuale — gaussiana o uniforme — così che ogni neurone parta leggermente diverso dagli altri e possa specializzarsi in qualcosa di suo. Come una squadra di ricerca: se tutti partono dallo stesso punto e seguono le stesse istruzioni, esplorano tutti la stessa zona. Serve disperderli un po’, all’inizio, perché coprano territori diversi.
Il problema è la scala, non il caso
Risolto il problema della simmetria, ne emerge uno più sottile: quanto grandi devono essere questi valori casuali? Qui la questione diventa quantitativa, e la grandezza da tenere d’occhio è la varianza del segnale strato per strato.
Ogni neurone calcola una somma pesata dei suoi input. Se lo strato precedente ha molti neuroni, la somma ha molti addendi: la varianza dell’output cresce con il numero di input e con la grandezza dei pesi. Se i pesi sono troppo grandi, la varianza si amplifica a ogni strato — dopo dieci strati il segnale è esploso, le attivazioni sature, i numeri fuori scala. Se i pesi sono troppo piccoli, succede l’opposto: la varianza si restringe strato dopo strato e il segnale si spegne, fino a diventare indistinguibile dal nulla.
Un’analogia utile è una catena di amplificatori audio in serie. Ognuno applica il suo guadagno: se ogni stadio amplifica anche solo del 20%, dopo dieci stadi il segnale è distorto oltre ogni riconoscibilità; se ogni stadio attenua del 20%, alla fine resta un sussurro. L’unico modo per far arrivare il segnale integro in fondo è che ogni stadio abbia guadagno vicino a uno — non amplifichi né attenui. L’inizializzazione dei pesi è esattamente la manopola del guadagno di ogni strato.
Tre inizializzazioni a confronto su una rete di otto strati: pesi troppo grandi fanno esplodere la varianza del segnale, pesi troppo piccoli la fanno collassare verso zero. Le formule di Xavier e He la mantengono costante lungo tutta la profondità.
Xavier: la varianza giusta si calcola
L’intuizione di Glorot e Bengio è che la scala giusta non va cercata per tentativi: si può derivare. Se uno strato riceve n_in input, la varianza dell’output è circa la varianza dei pesi moltiplicata per n_in. Perché il segnale resti stabile — varianza in uscita uguale a quella in entrata — la varianza dei pesi deve valere circa 1/n_in. Facendo lo stesso ragionamento sul gradiente che scorre all’indietro si ottiene 1/n_out, e la formula di Xavier fa una media dei due vincoli: varianza pari a 2/(n_in + n_out).
Il messaggio importante non è la formula in sé, ma il metodo: trattare la rete come un sistema fisico in cui il segnale deve conservarsi, e ricavare i parametri iniziali da questa condizione di equilibrio. Uno strato con molti input deve avere pesi individualmente più piccoli, perché la somma li amplifica; uno strato stretto può permettersi pesi più grandi.
La scala giusta dei pesi iniziali non è una costante magica: dipende dalla larghezza dello strato e dalla funzione di attivazione. È geometria, non fortuna.
He: correggere per la ReLU
La derivazione di Xavier assume attivazioni simmetriche attorno allo zero, come la tanh. Ma la ReLU — che nel frattempo è diventata lo standard — non è simmetrica: azzera tutta la metà negativa del segnale. In media, quindi, dimezza la varianza che le passa attraverso. Se ogni strato dimezza e l’inizializzazione non compensa, dopo venti strati il segnale è ridotto a un milionesimo.
La correzione, proposta da Kaiming He e colleghi nel 2015, è quasi imbarazzante nella sua semplicità: raddoppiare la varianza, cioè usare 2/n_in invece di 1/n_in. Quel fattore 2 compensa esattamente la metà del segnale che la ReLU butta via. È l’inizializzazione standard per le reti con ReLU — in PyTorch gli strati lineari e convoluzionali usano di default uno schema della stessa famiglia (Kaiming) — ed è uno degli ingredienti che nel 2015 permisero di addestrare reti molto più profonde di prima — lo stesso anno, non a caso, delle ResNet.
Quanto conta ancora oggi
Verrebbe da pensare che con batch normalization e skip connection il problema sia superato: quelle tecniche ri-stabilizzano il segnale a ogni strato, rendendo la rete molto più tollerante a inizializzazioni imperfette. In parte è vero. Ma l’inizializzazione non è diventata irrilevante: è diventata invisibile, il che è diverso.
Nei transformer, per esempio, la scala iniziale di certi strati viene ancora regolata con cura — spesso riducendo i pesi degli strati residuali in funzione della profondità del modello — perché con centinaia di strati anche piccole derive si accumulano. E chi lavora con architetture non standard, attivazioni esotiche o reti senza normalizzazione riscopre in fretta che una inizializzazione sbagliata si manifesta nel modo peggiore: nessun errore, nessun crash, solo una loss che non scende e ore di debug su tutto tranne che sulla vera causa.
Cosa portarsi a casa
Per chi usa i framework moderni, la regola pratica è semplice: i default vanno bene quasi sempre, e chi cambia attivazione dovrebbe verificare che l’inizializzazione sia coerente (He per ReLU e parenti, Xavier per tanh e sigmoide). Ma il valore vero di questa storia è concettuale.
L’inizializzazione dei pesi è il primo posto dove il deep learning smette di essere alchimia e diventa ingegneria: una proprietà desiderata — il segnale che si conserva strato per strato — tradotta in una condizione matematica, e da lì in una formula. Quando un training non parte, la varianza delle attivazioni strato per strato è una delle prime cose da guardare. E quando leggerete di batch normalization, skip connection o degli schemi di inizializzazione dei grandi modelli linguistici, riconoscerete la stessa domanda sotto mentite spoglie: come si fa ad attraversare cento strati senza spegnersi né esplodere?

I commenti sono riservati agli iscritti.
Accedi per commentare