Salta al contenuto
Note per Studenti Esercizio - Rete feed-forward su MNIST con Keras

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 (70 00070\,000 immagini 28×2828\times28 in grigio, 60 00060\,000 per il training e 10 00010\,000 per il test, 1010 classi). Domande del laboratorio:

  1. Cosa succede se si toglie il dropout?
  2. Aggiungere altri strati densi aiuta?
  3. 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 [0,255][0,255]: si dividono per 255255 per averli in [0,1][0,1] (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 10%10\% ciascuna), quindi l'accuratezza è una metrica ragionevole; con classi sbilanciate servirebbero precision, recall, AUC.

python
(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.0

Modello

python
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 0,…,90,\dots,9 (non one-hot): è la cross-entropy −log⁡py-\log p_{y} della probabilità assegnata alla classe vera. Softmax in uscita per avere probabilità. Adam con learning rate predefinito 10−310^{-3}.

Parametri: 784⋅512+512=401 920784\cdot512+512=401\,920 nel primo strato e 512⋅10+10=5 130512\cdot10+10=5\,130 nell'uscita: 407 050407\,050 (dropout e flatten ne hanno 00).

Iterazioni per epoca. Con validation_split=0.1 il training scende a 54 00054\,000 campioni: ⌈54 000/32⌉=1 688\lceil54\,000/32\rceil=1\,688 iterazioni, quanto mostra Keras. Senza validazione si avrebbero 1 8751\,875.

Risultati e lettura

Nel laboratorio, a fine addestramento: accuratezza di test ≈0,984\approx0{,}984 (il notebook stampa 0,98370{,}9837; il valore cambia di poco a ogni esecuzione perché inizializzazione e ordine dei batch sono casuali). Alla prima epoca l'accuratezza di training è 0,8920{,}892 e quella di validazione 0,9700{,}970: 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 0,98150{,}9815
con dropout 0,50{,}5 0,98110{,}9811

Le due sono quasi uguali; senza dropout la loss di validazione risale (da 0,0940{,}094 a 0,1270{,}127 in dieci epoche mentre quella di training scende a 0,0260{,}026): la rete inizia a memorizzare. Il dropout non migliora l'accuratezza finale ma tiene la validation loss più bassa (0,0750{,}075-0,0840{,}084). Risposta alla prima domanda: l'accuratezza di test cambia poco; cambia la distanza tra training e validazione.

Più strati densi? Aggiungere uno strato da 256256 (535 818535\,818 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 99%99\%, 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: errorec=#{errori su c}/#{campioni di classe c}\text{errore}_c=\#\{\text{errori su }c\}/\#\{\text{campioni di classe }c\}. Le cifre più confuse sono quelle graficamente vicine (per esempio 44 e 99, 33 e 55, 77 e 22). 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 0,98370{,}9837 per i pesi ricaricati; 0,98270{,}9827 per il modello salvato dopo un altro addestramento). Le callback ModelCheckpoint salvano i pesi a ogni epoca e TensorBoard registra le curve.

Lezioni in cui compare

Teoria collegata