Esercizio - CNN su CIFAR-10 con Keras (laboratorio 11)
Teoria: Deep learning - reti profonde, CNN e addestramento con KerasQuadro del deep learning nel corso di IA. Un neurone calcola la somma pesata degli ingressi e applica una funzione di attivazione non lineare (soglia, sigmoide, ReLU, tanh); un perceptron a soglia realizza AND, OR e NOT ma non lo XOR (non linearmente separabile), che richiede 3 neuroni su due livelli; due livelli bastano per approssimare ogni funzione continua. Uscite: lineare per la regressione, sigmoide per due classi, softmax per più classi, con perdita di entropia incrociata. Addestramento con SGD a minibatch e backpropagation (passaggio in avanti e all'indietro, gradienti che si moltiplicano: svaniscono con sigmoide e tanh). CNN: kernel appreso, stride, padding, uscita (n+2p-k)/s+1, pooling; tensori; transfer learning e dropout. RNN con stato nascosto z_t=f(z_{t-1},x_t) e BPTT, LSTM con porte, autoencoder, VAE, GAN, modelli linguistici e trasformatori con attenzione. Pipeline Keras del laboratorio 11: Sequential, Conv2D, MaxPooling2D, Flatten, Dense, compile (Adam, perdita), fit, evaluate, predict, save.Deep learning - reti profonde, CNN e addestramento con Keras →, sezioni 4 e 8. Sulle CNN: 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) → e Esercizio - Dimensioni e parametri di una CNN. Un'altra CNN in Keras è in Esercizio - CNN su Fashion-MNIST e CIFAR-10 con Keras. Nota: TensorFlow non è installato nell'ambiente in cui sono stati controllati questi appunti; il codice è quello del corso e gli output addestrati (perdite, accuratezze) sono quelli riportati dal notebook del corso. Forme dei tensori e numero di parametri sono invece ricalcolati a mano.
Testo. Creare una CNN con la libreria Keras con le seguenti specifiche.
(a) DATASET: caricare CIFAR-10, che contiene 60 000 immagini a colori in 10 classi, con 6 000 immagini per classe. Si può usare la funzione datasets.cifar10.load_data() dopo aver importato i dataset di Keras con from tensorflow.keras import datasets. Dividere il dataset in training e test. (b) Visualizzare alcuni campioni per vedere che tipo di dati ci sono. (c) Costruire e compilare un modello CNN composto da:
- Conv2D con 32 filtri, kernel , attivazione ReLU;
- MaxPooling2D con kernel ;
- Conv2D con 64 filtri, kernel , attivazione ReLU;
- MaxPooling2D con kernel ;
- Conv2D con 64 filtri, kernel , attivazione ReLU;
- livello Flatten;
- livello Dense con 64 neuroni e attivazione ReLU;
- livello Dense finale che restituisce 10 classi;
adamcome ottimizzatore.
(d) Addestrare e testare il modello su CIFAR-10 con 10 epoche per controllare le prestazioni. (e) Calcolare la matrice di confusione. (f) Provare il modello su nuove immagini delle classi disponibili, scaricabili dal web.
Soluzione
(a), (b) Dati
load_data() restituisce : 50 000 immagini di training e 10 000 di test (1 000 per classe nel test), ciascuna con valori interi in . Le classi, in ordine, sono: airplane, automobile, bird, cat, deer, dog, frog, horse, ship, truck (etichette 0-9). Per il punto (b) si disegnano le prime 25 immagini con plt.imshow(x_train[i].astype("uint8")) e il titolo class_names[int(y_train[i])].
Preprocessing: si dividono le immagini per 255 per portare i valori in (i valori grandi non sono ideali per una rete): il controllo stampa minimo e massimo sia per il training sia per il test.
(c) L'architettura
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers, models, datasets
import numpy as np
(x_train, y_train), (x_test, y_test) = keras.datasets.cifar10.load_data()
x_train = x_train / 255.0
x_test = x_test / 255.0
model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), 1, activation="relu", input_shape=(32, 32, 3)))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation="relu"))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation="relu"))
model.add(layers.Flatten())
model.add(layers.Dense(64, activation="relu"))
model.add(layers.Dense(10)) # nessuna attivazione: restituisce i "logit"
model.summary()
model.compile(optimizer="adam",
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=["accuracy"])Forme e parametri, livello per livello. Uscita di una convoluzione senza padding: (stride 1); del pooling : . Parametri di una convoluzione: ; di un Dense: .
| livello | forma di uscita | parametri |
|---|---|---|
| Conv2D 32, | ||
| MaxPooling | 0 | |
| Conv2D 64, | ||
| MaxPooling | 0 | |
| Conv2D 64, | ||
| Flatten | , cioè | 0 |
| Dense 64 | ||
| Dense 10 |
Totale: parametri, come nel model.summary() del corso. Il si arrotonda per difetto a (il pooling scarta l'ultima riga e l'ultima colonna). I parametri sono concentrati nel Dense 64 (più della metà), nonostante le convoluzioni riducano molto lo spazio: il pooling e il Flatten decidono quanti numeri entrano nella parte densa.
Perché from_logits=True e Sparse. L'ultimo livello Dense non ha attivazione, quindi restituisce 10 numeri qualsiasi (logit); la perdita applica il softmax internamente (più stabile numericamente). SparseCategoricalCrossentropy accetta le etichette come interi (non in one-hot). Perché il modello dia probabilità bisogna applicare un softmax; per la classe predetta basta np.argmax sui logit.
(d) Addestramento e test
history = model.fit(x_train, y_train, epochs=10)
score = model.evaluate(x_test, y_test, verbose=0)
print("Test loss:", score[0]); print("Test accuracy:", score[1])
y_predicted = np.argmax(model.predict(x_test), axis=1)Con la dimensione predefinita del batch (32) un'epoca fa passi, come nell'output. Output del corso:
| epoca | perdita | accuratezza (training) |
|---|---|---|
| 1 | ||
| 2 | ||
| 3 | ||
| 5 | ||
| 8 | ||
| 10 |
Sul test: perdita , accuratezza . La perdita di training scende a ogni epoca e l'accuratezza sale, ma l'accuratezza sul test () è circa 6 punti sotto quella di training dell'ultima epoca (): c'è un inizio di overfitting (il modello si adatta ai dati di training più che ai nuovi), come ci si aspetta da una rete da parametri addestrata per 10 epoche su sole 50 000 immagini; aggiungere data augmentation o dropout lo ridurrebbe (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 →). Il modello non ha dati di validazione: l'accuratezza stampata a ogni epoca è sul training.
(e) Matrice di confusione
from sklearn import metrics
disp = metrics.ConfusionMatrixDisplay.from_predictions(y_test, y_predicted)La matrice confronta le classi vere (righe) e predette (colonne); le righe sommano a 1 000 (le classi sono bilanciate). Dalla matrice il corso si aspetta le prestazioni peggiori per le classi 2 (bird), 3 (cat) e 5 (dog): animali con forme e sfondi simili, che il modello tende a scambiare tra loro, mentre automobile, ship e truck sono più distinguibili. Come tutti i risultati del notebook, i valori esatti della matrice dipendono dall'inizializzazione casuale dei pesi e non sono riportati nel materiale del corso (la figura non è disponibile).
(f) Immagini nuove
Il corso scarica 9 immagini da Google Drive (gdown), le legge con OpenCV (cv2.imread, e cvtColor da BGR a RGB perché OpenCV usa l'ordine BGR), le ridimensiona a con tf.image.resize(rgb_img, (32,32)) e predice con model.predict(np.expand_dims(resize / 255, 0)): l'immagine va divisa per 255 come in addestramento e va aggiunta la dimensione del batch (). L'etichetta predetta è class_names[np.argmax(pred)]. Le etichette vere sono: cat, dog, bird, truck, frog, frog, bird, horse, bird. L'output del notebook è nascosto (visibile solo su Colab). Osservazione utile: una foto grande ridotta a perde molto dettaglio e ha uno sfondo diverso da quelli di CIFAR-10, quindi la classificazione di immagini "dal web" è molto meno affidabile dell'accuratezza sul test.
Versione ripasso
Teoria: Deep learning - reti profonde, CNN e addestramento con KerasQuadro del deep learning nel corso di IA. Un neurone calcola la somma pesata degli ingressi e applica una funzione di attivazione non lineare (soglia, sigmoide, ReLU, tanh); un perceptron a soglia realizza AND, OR e NOT ma non lo XOR (non linearmente separabile), che richiede 3 neuroni su due livelli; due livelli bastano per approssimare ogni funzione continua. Uscite: lineare per la regressione, sigmoide per due classi, softmax per più classi, con perdita di entropia incrociata. Addestramento con SGD a minibatch e backpropagation (passaggio in avanti e all'indietro, gradienti che si moltiplicano: svaniscono con sigmoide e tanh). CNN: kernel appreso, stride, padding, uscita (n+2p-k)/s+1, pooling; tensori; transfer learning e dropout. RNN con stato nascosto z_t=f(z_{t-1},x_t) e BPTT, LSTM con porte, autoencoder, VAE, GAN, modelli linguistici e trasformatori con attenzione. Pipeline Keras del laboratorio 11: Sequential, Conv2D, MaxPooling2D, Flatten, Dense, compile (Adam, perdita), fit, evaluate, predict, save.Deep learning - reti profonde, CNN e addestramento con Keras →, 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) →.
Dati. CIFAR-10: 50 000 training e 10 000 test, immagini , 10 classi (airplane, automobile, bird, cat, deer, dog, frog, horse, ship, truck), 1 000 per classe nel test. Si divide per 255 (valori in ).
Modello. Conv2D(32, , ReLU), MaxPool , Conv2D(64, , ReLU), MaxPool , Conv2D(64, , ReLU), Flatten, Dense(64, ReLU), Dense(10). Compilazione:
adam,SparseCategoricalCrossentropy(from_logits=True)(etichette intere, uscita senza attivazione), metrica accuratezza.
Forme e parametri (convoluzione: ; uscita ; pooling ):
- : ; ;
- : ; ;
- : ; Flatten ;
- Dense 64: ; Dense 10: ;
- totale .
Addestramento (10 epoche, 1 563 passi per epoca perché ): perdita , accuratezza di training . Test: perdita , accuratezza : circa 6 punti sotto il training, inizio di overfitting (rimedi: data augmentation, dropout).
Matrice di confusione: ConfusionMatrixDisplay.from_predictions(y_test, y_predicted); classi peggiori attese: bird, cat, dog.
Immagini nuove: leggere con OpenCV e convertire BGR in RGB, ridimensionare a , dividere per 255, aggiungere la dimensione del batch; foto grandi ridotte a perdono dettaglio.
model.compile(optimizer="adam", loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True), metrics=["accuracy"])
history = model.fit(x_train, y_train, epochs=10)
y_predicted = np.argmax(model.predict(x_test), axis=1)Errori tipici: dimenticare di dividere per 255 (anche in predizione); from_logits=True con un'uscita già softmax; etichette in one-hot con la perdita Sparse; contare male le dimensioni dopo il pooling (, non ).