Esercizio - Rete feed-forward su MNIST con Keras
Questa pagina non ha ancora la versione ripasso: qui sotto c'è il testo completo.
In questa pagina 4
Testo (laboratorio sulle reti neurali). Si costruisca, si addestri e si valuti con Keras una rete feed-forward per classificare le cifre scritte a mano di MNIST ( immagini in grigio, per il training e per il test, classi). Domande del laboratorio:
- Cosa succede se si toglie il dropout?
- Aggiungere altri strati densi aiuta?
- Ispezionare le cifre classificate male: le si riesce a riconoscere a occhio?
Si calcolino inoltre il numero di parametri e di iterazioni per epoca.
Teoria usata: Reti neurali - neuroni e funzioni di attivazioneUn neurone calcola $\hat y=g(w_0+w^\top x)$: somma pesata degli ingressi più bias, poi una funzione di attivazione $g$ non lineare (Perceptron a soglia, sigmoide, tanh, ReLU e varianti). Senza non linearità ogni rete è equivalente a un solo modello lineare. Una rete feed-forward impila strati di neuroni: $a^{(k)}=g(W^{(k)}a^{(k-1)}+b^{(k)})$; con uno strato nascosto è già un approssimatore universale, ma più strati rappresentano funzioni complesse con molti meno neuroni e imparano feature gerarchiche (bordi, parti, oggetti). Lo strato di uscita e la loss si scelgono dal compito: lineare+MSE (regressione), sigmoide+cross-entropy binaria, softmax+cross-entropy (multiclasse). Il numero di parametri di uno strato denso è $n_{in}n_{out}+n_{out}$. Nel lab (Keras, MNIST) una rete 784-512-10 ha 407 050 parametri e supera il 98% di accuratezza.Reti neurali - neuroni e funzioni di attivazione →, Addestramento delle reti neurali - backpropagation e ottimizzatoriAddestrare una rete significa minimizzare la loss empirica $J(W)=\frac1n\sum_i\mathcal L(f(x^{(i)};W),y^{(i)})$ con la discesa del gradiente $W\leftarrow W-\eta,\partial J/\partial W$; in pratica a mini-batch (SGD). Il gradiente di tutti i pesi si ottiene con la backpropagation, cioè la regola della catena applicata all'indietro: $\delta^{(L)}=\partial J/\partial a^{(L)}\odot g'(z^{(L)})$, $\delta^{(l)}=(W^{(l+1)\top}\delta^{(l+1)})\odot g'(z^{(l)})$, $\partial J/\partial W^{(l)}=\delta^{(l)}a^{(l-1)\top}$ (con sigmoide e cross-entropy $\delta=\hat y-y$). Per far funzionare reti profonde: attivazioni ReLU, inizializzazione di Xavier o He (varianza $2/(n_{in}+n_{out})$ e $2/n_{in}$), batch normalization, ottimizzatori con momento o adattivi (Momentum, AdaGrad, RMSProp, Adam con $\beta_1=0{,}9$, $\beta_2=0{,}999$, lr $10^{-3}$) e un learning rate che varia nel tempo (a gradini, coseno). Si addestra tenendo d'occhio la loss di training e di validazione.Addestramento delle reti neurali - backpropagation e ottimizzatori →, Metriche di classificazioneIn classificazione binaria ogni previsione è vero positivo (TP), vero negativo (TN), falso positivo (FP, errore di tipo I) o falso negativo (FN, errore di tipo II). Da queste quattro quantità: accuracy $=\frac{TP+TN}{TP+TN+FP+FN}$, specificità $=\frac{TN}{TN+FP}$, precision $=\frac{TP}{TP+FP}$, recall $=\frac{TP}{TP+FN}$, e la loro media armonica $F_1=\frac{2PR}{P+R}$. Con dati sbilanciati l'accuracy inganna (un modello che predice sempre la classe maggioritaria ha 99%): si usano precision, recall, F1, ROC-AUC, la cross-validation stratificata e il riequilibrio con undersampling o oversampling (non SMOTE). Cambiando la soglia sulla probabilità si ottiene la curva ROC (TPR contro FPR) e l'area AUC. Approfondimento: non nel programma di Telecomunicazioni.Metriche di classificazione →.
Preparazione dei dati
I pixel sono interi in : si dividono per per averli in (gli ingressi su scale grandi rendono l'addestramento instabile). Si controlla la distribuzione delle classi: nel training e nel test le dieci cifre hanno frequenze simili (circa ciascuna), quindi l'accuratezza è una metrica ragionevole; con classi sbilanciate servirebbero precision, recall, AUC.
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0Modello
model = Sequential([
Input(shape=(28, 28)),
Flatten(), # 784 ingressi
Dense(512, activation="relu"),
Dropout(0.2),
Dense(10, activation="softmax"),
])
model.compile(loss="sparse_categorical_crossentropy", optimizer="adam", metrics=["accuracy"])
history = model.fit(x_train, y_train, batch_size=32, epochs=10, validation_split=0.1)
test_loss, test_acc = model.evaluate(x_test, y_test)Scelte. La loss sparse_categorical_crossentropy serve perché le etichette sono interi (non one-hot): è la cross-entropy della probabilità assegnata alla classe vera. Softmax in uscita per avere probabilità. Adam con learning rate predefinito .
Parametri: nel primo strato e nell'uscita: (dropout e flatten ne hanno ).
Iterazioni per epoca. Con validation_split=0.1 il training scende a campioni: iterazioni, quanto mostra Keras. Senza validazione si avrebbero .
Risultati e lettura
Nel laboratorio, a fine addestramento: accuratezza di test (il notebook stampa ; il valore cambia di poco a ogni esecuzione perché inizializzazione e ordine dei batch sono casuali). Alla prima epoca l'accuratezza di training è e quella di validazione : la validazione è più alta perché il dropout è attivo in training e spento in validazione, e perché l'accuratezza di training è la media sull'epoca, mentre la rete migliora durante l'epoca.
Confronto, nel lab sulla regolarizzazione (stessa rete, dieci epoche):
| variante | accuratezza di test |
|---|---|
| senza dropout né regolarizzazione | |
| con dropout |
Le due sono quasi uguali; senza dropout la loss di validazione risale (da a in dieci epoche mentre quella di training scende a ): la rete inizia a memorizzare. Il dropout non migliora l'accuratezza finale ma tiene la validation loss più bassa (-). Risposta alla prima domanda: l'accuratezza di test cambia poco; cambia la distanza tra training e validazione.
Più strati densi? Aggiungere uno strato da ( parametri) ci si aspetta al più un piccolo miglioramento su MNIST (da verificare provando), perché una sola matrice densa è già molto vicina al limite delle reti non convolutive su questo dataset (le CNN arrivano oltre il , Reti neurali convolutive (CNN)approfondimento: non nel programma di Telecomunicazioni. Una rete convolutiva (CNN) sostituisce gli strati densi con filtri piccoli che scorrono sull'immagine: ogni neurone vede solo una patch locale (campo recettivo) e i pesi del filtro sono condivisi in tutta l'immagine, quindi i parametri non dipendono dalla dimensione dell'immagine ($K^2C_{in}C_{out}+C_{out}$ per strato) e si conserva l'informazione spaziale. Dimensione dell'uscita: $\lfloor(W-K+2P)/S\rfloor+1$. Pooling (max 2x2, stride 2) sottocampiona e dà invarianza locale; i filtri 1x1 riducono i canali; struttura tipica CONV+ReLU, POOL, ..., FLATTEN, FC, SOFTMAX, addestrata con cross-entropy e backpropagation. Tre strati 3x3 hanno il campo recettivo di un 7x7 con meno parametri e più non linearità (VGG). Architetture: LeNet, AlexNet (ReLU, dropout, data augmentation), VGG, GoogLeNet (moduli Inception), ResNet (blocchi residui $H(x)=F(x)+x$), EfficientNet. Nel lab: CNN su Fashion-MNIST (241 546 parametri) e su CIFAR-10 (122 570).Reti neurali convolutive (CNN) →). Più parametri aumentano però il rischio di overfitting e il tempo di calcolo: servono dropout o early stopping (Regolarizzazione delle reti neuraliUna rete con tanti parametri tende a memorizzare il training set (overfitting): la loss di training scende ma quella di validazione risale. Le tecniche di regolarizzazione limitano la capacità effettiva: penalità sui pesi ($\ell_2$: $J+\lambda|W|_2^2$, il passo diventa $W\leftarrow(1-2\eta\lambda)W-\eta\nabla J$; $\ell_1$: $J+\lambda|W|_1$, porta pesi esattamente a zero), early stopping (si ferma l'addestramento quando la validation loss smette di scendere, con pazienza e ripristino dei pesi migliori), dropout (in training si azzera a caso una frazione $p$ delle attivazioni e si riscala per $1/(1-p)$; in inferenza è spento), batch normalization (effetto collaterale) e data augmentation. Nel lab MNIST con $\lambda=0{,}01$ la penalità $\ell_1$ è troppo forte (accuratezza di test 0,844 contro 0,9815 senza regolarizzazione), mentre dropout e early stopping non peggiorano e tengono la validation loss più bassa.Regolarizzazione delle reti neurali →). Per rispondere con certezza si addestrano le due varianti e si confrontano le curve di validazione e la matrice di confusione.
Errori. Si calcola y_pred = np.argmax(model.predict(x_test), axis=1), si confronta con y_test e si contano gli errori per cifra: . Le cifre più confuse sono quelle graficamente vicine (per esempio e , e , e ). Guardando alcuni esempi sbagliati si vede che molti sono scritti in modo ambiguo, difficili anche per una persona: sono al limite della precisione ottenibile con quell'etichettatura.
Dopo l'addestramento
Salvare e ricaricare: model.save_weights(...) e load_weights su una rete con la stessa architettura, oppure model.save("modello.keras") e load_model. Verifica: il modello ricaricato dà la stessa accuratezza di test (nel lab per i pesi ricaricati; per il modello salvato dopo un altro addestramento). Le callback ModelCheckpoint salvano i pesi a ogni epoca e TensorBoard registra le curve.