Resúmenes
Apuntes universitarios en formato Markdown desde Obsidian.
Overfitting e Regolarizzazione
download Descargar MDLa questione fondamentale nell'apprendimento automatico è la tensione tra ottimizzazione e generalizzazione.
- L'ottimizzazione è il processo di adattamento di un modello per ottenere le migliori prestazioni possibili sui dati di addestramento (il learning vero e proprio).
- La generalizzazione si riferisce alla capacità del modello addestrato di performare bene su dati mai visti prima.
L'obiettivo finale è ottenere una buona generalizzazione, ma non possiamo controllarla direttamente; possiamo solo modificare il modello basandoci sulle sue prestazioni sui dati di addestramento. All'inizio dell'addestramento, ottimizzazione e generalizzazione sono correlate: più il modello apprende, meglio generalizza. Tuttavia, dopo un certo numero di epoche, si verifica un punto di rottura. Il modello inizia a overfittare (sovradattarsi): impara pattern specifici del training set che sono fuorvianti o irrilevanti per i nuovi dati (rumore).
Per impedire a un modello di apprendere pattern fuorvianti, la soluzione migliore è raccogliere più dati di addestramento. Quando ciò non è possibile, dobbiamo ricorrere alla regolarizzazione.
1. Ridurre la Capacità della Rete
Il modo più semplice per prevenire l'overfitting è ridurre la dimensione del modello, ovvero il numero di parametri apprendibili (numero di strati e numero di unità per strato). In deep learning, il numero di parametri è spesso chiamato "capacità" del modello. Intuitivamente:
- Un modello con troppi parametri ha una "capacità di memoria" elevata: può imparare facilmente una mappatura perfetta tipo dizionario tra input e output, senza alcuna capacità di generalizzazione.
- Un modello con pochi parametri sarà costretto a imparare rappresentazioni compresse che catturano gli aspetti più significativi dei dati.
Tuttavia, bisogna fare attenzione: se il modello è troppo piccolo, andrà in underfitting e non riuscirà ad apprendere nemmeno i pattern essenziali. Non esiste una formula magica per determinare la dimensione giusta; bisogna valutare diverse architetture (sul validation set).
Ecco come ridurre la dimensione di una rete in Keras:
from keras import models
from keras import layers
# Modello originale (riferimento)
original_model = models.Sequential()
original_model.add(layers.Dense(16, activation='relu', input_shape=(10000,)))
original_model.add(layers.Dense(16, activation='relu'))
original_model.add(layers.Dense(1, activation='sigmoid'))
# Modello più piccolo (minore capacità)
smaller_model = models.Sequential()
smaller_model.add(layers.Dense(4, activation='relu', input_shape=(10000,)))
smaller_model.add(layers.Dense(4, activation='relu'))
smaller_model.add(layers.Dense(1, activation='sigmoid'))
Confrontando le curve di perdita (loss) di validazione, vedremmo che il modello più piccolo inizia a overfittare più tardi rispetto a quello di riferimento e le sue prestazioni degradano più lentamente una volta iniziato l'overfitting.
2. Regolarizzazione dei Pesi (Weight Regularization)
Il principio del "Rasoio di Occam" suggerisce che, tra due spiegazioni per un fenomeno, la più semplice è solitamente quella corretta. Questo si applica anche ai modelli neurali: un modello semplice è meno propenso all'overfitting di uno complesso.
Un "modello semplice" in questo contesto è un modello in cui la distribuzione dei valori dei pesi ha un'entropia bassa (o che ha meno parametri). La regolarizzazione dei pesi consiste nel forzare i pesi della rete ad assumere solo valori piccoli, aggiungendo alla funzione di perdita un costo associato alla grandezza dei pesi stessi.
Esistono due tipi principali:
- Regolarizzazione L1 (Lasso): Il costo aggiunto è proporzionale al valore assoluto dei coefficienti dei pesi ($Cost = \lambda \cdot |w|$). Tende a spingere alcuni pesi esattamente a zero, rendendo il modello sparso.
- Regolarizzazione L2 (Ridge): Il costo aggiunto è proporzionale al quadrato dei coefficienti dei pesi ($Cost = \lambda \cdot w^2$). Tende a penalizzare pesantemente i picchi, distribuendo il peso su più connessioni e rendendoli piccoli ma non nulli.
In Keras, la regolarizzazione viene aggiunta passando un'istanza di regolarizzatore ai layer:
from keras import regularizers
l2_model = models.Sequential()
# Aggiungiamo regolarizzazione L2 con fattore 0.001
l2_model.add(layers.Dense(16, kernel_regularizer=regularizers.l2(0.001),
activation='relu', input_shape=(10000,)))
l2_model.add(layers.Dense(16, kernel_regularizer=regularizers.l2(0.001),
activation='relu'))
l2_model.add(layers.Dense(1, activation='sigmoid'))
l2(0.001) significa che ogni coefficiente nella matrice dei pesi del livello aggiungerà 0.001 * weight_coefficient_value alla perdita totale della rete.
3. Dropout
Il Dropout, sviluppato da Hinton e il suo team, è una delle tecniche di regolarizzazione più efficaci e comunemente usate. L'idea è semplice ma potente: durante l'addestramento, si azzerano casualmente (si "droppano") un certo numero di output del livello (spesso il 50%).
- Durante il training: Una frazione p (es. 0.5) delle unità viene spenta.
- Durante il test: Nessuna unità viene spenta, ma i valori di output vengono ridotti di un fattore p per bilanciare il fatto che ora sono attive più unità rispetto al training.
L'intuizione è che l'introduzione di rumore negli output di uno strato rompe le "cospirazioni" accidentali tra neuroni (pattern di attivazione che non sono significativi ma casuali). Costringe ogni neurone a imparare caratteristiche utili in modo indipendente dagli altri.
dpt_model = models.Sequential()
dpt_model.add(layers.Dense(16, activation='relu', input_shape=(10000,)))
# Aggiungiamo Dropout al 50%
dpt_model.add(layers.Dropout(0.5))
dpt_model.add(layers.Dense(16, activation='relu'))
dpt_model.add(layers.Dropout(0.5))
dpt_model.add(layers.Dense(1, activation='sigmoid'))