Scarica in formato pdf o txt
Scarica in formato pdf o txt
Sei sulla pagina 1di 15

La mia prima CNN per la classificazione di immagini

Alex Alborghetti

Il dataset fashion_mnist, disponibile nella libreria keras, contiene immagini in bianco e nero di
70.000 articoli di moda presenti sul sito di Zalando classificate entro 10 categorie con etichetta
da 0 a 9. Le categorie sono le seguenti:

0: Maglietta 4: Cappotto 8: Borsa

1: Pantalone 5: Sandalo 9: Stivaletto

2: Pullover 6: Camicia

3: Abito 7: Scarpa

Importazione delle librerie utili

# importazione
from keras.datasets import fashion_mnist
import matplotlib.pyplot as plt

# processazione
import numpy as np
from keras.utils import to_categorical
from sklearn.model_selection import train_test_split

# rete neurale
import keras
from tensorflow.keras.layers import Input,BatchNormalization
from keras.models import Sequential,Model
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D, LeakyReLU

# rappresentazione grafica rete


import visualkeras

Importazione dei dati e visualizzazione


Vengono importati training e test set. Il set di addestramento ha 60.000 immagini, mentre quello
di verifica le restanti 10.000.
(train_X,train_Y), (test_X,test_Y) = fashion_mnist.load_data()
print('Training data shape : ', train_X.shape, train_Y.shape)
print('Testing data shape : ', test_X.shape, test_Y.shape)

Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/


train-labels-idx1-ubyte.gz
29515/29515 [==============================] - 0s 1us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/
train-images-idx3-ubyte.gz
26421880/26421880 [==============================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/
t10k-labels-idx1-ubyte.gz
5148/5148 [==============================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/
t10k-images-idx3-ubyte.gz
4422102/4422102 [==============================] - 0s 0us/step
Training data shape : (60000, 28, 28) (60000,)
Testing data shape : (10000, 28, 28) (10000,)

Nei set di training e di test si trovano rispettivamente 60.000 e 10.000 immagini con dimensione
28×28, mentre la variabile risposta è data da 60.000 e 10.000 etichette di categoria. Si visualizzano
qui sotto la prima immagine contenuta nel training set e la prima contenuta nel test set. La sintassi
del codice sottostante può essere spiegata nel seguente modo:

• Con la funzione plt.subplot specificando l'argomento 121 si suppone che la prima


immagine andrà in una finestra grafica con 1 riga e 2 colonne e sarà il primo elemento di
tale finestra.
• Con la funzione plt.imshow si dà in ingresso l'immagine in posizione 0 di ciascun set di dati
(ovvero la prima immagine contenuta in ciascun insieme di dati) e con cmap impostato su
'gray' si specifica che l'immagine è in bianco e nero.
• Con la funzione title si assegna il titolo a ogni grafico, con .format() si aggiunge al titolo
la categoria alla quale appartiene l'immagine.

plt.figure(figsize=[10,10])

plt.subplot(121)
plt.imshow(train_X[0,:,:], cmap='gray')
plt.title("Ground Truth : {}".format(train_Y[0]))

plt.subplot(122)
plt.imshow(test_X[0,:,:], cmap='gray')
plt.title("Ground Truth : {}".format(test_Y[0]))

Text(0.5, 1.0, 'Ground Truth : 9')


Sia nella prima immagine contenuta nel training set che nella prima immagine contenuta nel test
set si nota una calzatura corrispondente alla categoria 9: “Stivaletto” definita precedentemente.

Processazione dei dati


Con la funzione reshape si fa in modo che ogni matrice 28×28 contenuta nel set di dati e
rappresentante un'immagine sia letta come un tensore 28×28×1, questo perché la rete neurale
vuole in ingresso questo tipo di oggetti. Il primo parametro della funzione è -1 perché si vuole
indicare alla libreria NumPy di capire in autonomia quanti elementi (immagini) ci sono in ciascun
set di dati. Nel caso in questione, si è già notato come ci siano 60.000 immagini nel training set e
10.000 nel test set.
train_X = train_X.reshape(-1, 28,28, 1)
test_X = test_X.reshape(-1, 28,28, 1)
train_X.shape, test_X.shape

((60000, 28, 28, 1), (10000, 28, 28, 1))

Si nota come ora training set e test set siano formati rispettivamente da 60.000 e 10.000 "tensori"
di dimensioni 28×28×1. Per mandare i dati in input alla rete neurale occorre inoltre che il loro
formato sia float32 e che il valore di ogni punto della matrice non vari da 0 a 255 ma da 0 a 1.
Quindi, vengono applicate queste modifiche cambiando il formato dei dati con la funzione astype
e normalizzandoli dividendo per 255.
train_X = train_X.astype('float32')
test_X = test_X.astype('float32')
train_X = train_X / 255.
test_X = test_X / 255.

Bisogna ora trasformare il test set in una forma one-hot encoding. In altre parole, la rete neurale
non è in grado di lavorare direttamente con il valore della categoria (es. categoria 9) ma ha bisogno
per ciascuna immagine di un vettore risposta associato di dimensione pari al numero di categorie
nel quale sono presenti solo degli zeri fuorché un uno quando la categoria è quella di interesse. Ad
esempio, la categoria 9 sarà rappresentata dal vettore (0,0,0,0,0,0,0,0,0,1) . Per svolgere
questa ricofidica dei dati, si utilizza la funzione to_categorical.

Train_Y_one_hot = to_categorical(train_Y)
test_Y_one_hot = to_categorical(test_Y)

Si stampa quanto ottenuto per la categoria riferita alla prima immagine del training set, si ricorda
che tale categoria era la 9.
print('Categoria di appartenenza:', train_Y[0])
print('Codifica one-hot:', train_Y_one_hot[0])

Categoria di appartenenza: 9
Codifica one-hot: [0. 0. 0. 0. 0. 0. 0. 0. 0. 1.]

Infine, viene suddiviso ulteriormente il training set in due partizioni di proporzioni 80/20%
creando il validation set sul quale verrà testato il modello in fase di addestramento.
train_X,valid_X,train_label,valid_label = train_test_split(train_X, train_Y_one_ho
t, test_size=0.2, random_state=13)
train_X.shape,valid_X.shape,train_label.shape,valid_label.shape

((48000, 28, 28, 1), (12000, 28, 28, 1), (48000, 10), (12000, 10))

Si osserva che il training set ha ora 48.000 immagini, il validation set creato ne contiene quindi
12.000.

La rete neurale convoluzionale


In input viene inserita l'immagine 28×28 modificata nel formato, forma e valori descritti nella
processazione dei dati. La rete neurale che viene utilizzata ha tre layer:

• Il primo layer ha 32 filtri convoluzionali 3×3


• Il secondo layer ha 64 filtri convoluzionali 3×3
• Il terzo layer ha 128 filtri convoluzionali 3×3

Dopo ciascun layer di convoluzione abbiamo un layer di pooling con dimensione 2×2.

Poiché il training set è troppo grande per essere processato tutto in una volta, vengono definiti dei
sottoinsiemi di esso chiamati batch, in questo caso di dimensione 64, in modo da processare 64
immagini alla volta in fase di addestramento. Una volta che tutto il training set è stato processato,
si dice che è trascorsa un’epoca. Il numero di epoche per addestrare il modello è definito a priori,
in questo caso è pari a 20. Infine, in num_classes viene inserito il valore 10 poiché le categorie di
immagini sono 10 in totale (da 0 a 9).
batch_size = 64
epochs = 20
num_classes = 10

Si costruisce ora la rete neurale. Essa viene definita layer per layer: la si inizializza con la funzione
sequential e successivamente si aggiunge ciascun layer con il metodo .add.

fashion_model = Sequential()
fashion_model.add(Conv2D(32, kernel_size=(3, 3),activation='linear',input_shape=(2
8,28,1),padding='same'))
fashion_model.add(LeakyReLU(alpha=0.1))
fashion_model.add(MaxPooling2D((2, 2),padding='same'))
fashion_model.add(Conv2D(64, (3, 3), activation='linear',padding='same'))
fashion_model.add(LeakyReLU(alpha=0.1))
fashion_model.add(MaxPooling2D(pool_size=(2, 2),padding='same'))
fashion_model.add(Conv2D(128, (3, 3), activation='linear',padding='same'))
fashion_model.add(LeakyReLU(alpha=0.1))
fashion_model.add(MaxPooling2D(pool_size=(2, 2),padding='same'))
fashion_model.add(Flatten())
fashion_model.add(Dense(128, activation='linear'))
fashion_model.add(LeakyReLU(alpha=0.1))
fashion_model.add(Dense(num_classes, activation='softmax'))

Ogni layer convoluzionale è aggiunto con la funzione Conv2D, mentre ogni layer di pooling è
aggiunto con la funzione MaxPooling2D. Al termine di ogni layer viene applicata la funzione di
attivazione LeakyReLU che consente di rilevare linee di decisione non lineari. Questa funzione di
attivazione è una delle tante possibili (un'altra, ad esempio, è la sigmoide), ma la più utilizzata nelle
reti neurali convoluzionali. L'ultimo layer è definito con Dense e la funzione di attivazione softmax:
questa combinazione consente di eseguire una classificazione multiclasse come quella del
problema in oggetto. Una volta definita la rete neurale, essa va compilata.
fashion_model.compile(loss = keras.losses.categorical_crossentropy, optimizer = ke
ras.optimizers.Adam(), metrics=['accuracy'])

Uno dei compilatori più utilizzati è Adam. La funzione di perdita è la cross-entropia, molto
utilizzata nella classificazione di immagini. La metrica utilizzata è l'accuratezza. Viene restituito
ora un riassunto della rete neurale appena creata.

fashion_model.summary()

Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d (Conv2D) (None, 28, 28, 32) 320
leaky_re_lu (LeakyReLU) (None, 28, 28, 32) 0

max_pooling2d (MaxPooling2D (None, 14, 14, 32) 0


)

conv2d_1 (Conv2D) (None, 14, 14, 64) 18496

leaky_re_lu_1 (LeakyReLU) (None, 14, 14, 64) 0

max_pooling2d_1 (MaxPooling (None, 7, 7, 64) 0


2D)

conv2d_2 (Conv2D) (None, 7, 7, 128) 73856

leaky_re_lu_2 (LeakyReLU) (None, 7, 7, 128) 0

max_pooling2d_2 (MaxPooling (None, 4, 4, 128) 0


2D)

flatten (Flatten) (None, 2048) 0

dense (Dense) (None, 128) 262272

leaky_re_lu_3 (LeakyReLU) (None, 128) 0

dense_1 (Dense) (None, 10) 1290

=================================================================
Total params: 356,234
Trainable params: 356,234
Non-trainable params: 0
_________________________________________________________________

Si notano diversi layer con la loro forma e numero di parametri. Al termine, si è ottenuta una rete
con un numero di parametri totali pari a 356.234.

Addestramento della rete neurale


Viene utilizzato il metodo .fit per addestrare la rete neurale appena creata.
fashion_train = fashion_model.fit(train_X, train_label, batch_size=batch_size,epoc
hs=epochs,verbose=1,validation_data=(valid_X, valid_label))
Epoch 1/20
750/750 [==============================] - 113s 148ms/step - loss: 0.4662 - accura
cy: 0.8288 - val_loss: 0.3211 - val_accuracy: 0.8819
Epoch 2/20
750/750 [==============================] - 101s 135ms/step - loss: 0.2845 - accura
cy: 0.8966 - val_loss: 0.3586 - val_accuracy: 0.8707
Epoch 3/20
750/750 [==============================] - 101s 135ms/step - loss: 0.2380 - accura
cy: 0.9125 - val_loss: 0.2571 - val_accuracy: 0.9076
Epoch 4/20
750/750 [==============================] - 100s 134ms/step - loss: 0.2094 - accura
cy: 0.9226 - val_loss: 0.2598 - val_accuracy: 0.9103
Epoch 5/20
750/750 [==============================] - 99s 133ms/step - loss: 0.1821 - accurac
y: 0.9327 - val_loss: 0.2578 - val_accuracy: 0.9048
Epoch 6/20
750/750 [==============================] - 100s 133ms/step - loss: 0.1580 - accura
cy: 0.9416 - val_loss: 0.2209 - val_accuracy: 0.9223
Epoch 7/20
750/750 [==============================] - 100s 134ms/step - loss: 0.1386 - accura
cy: 0.9486 - val_loss: 0.2270 - val_accuracy: 0.9196
Epoch 8/20
750/750 [==============================] - 102s 135ms/step - loss: 0.1183 - accura
cy: 0.9555 - val_loss: 0.2427 - val_accuracy: 0.9229
Epoch 9/20
750/750 [==============================] - 100s 134ms/step - loss: 0.0999 - accura
cy: 0.9634 - val_loss: 0.2435 - val_accuracy: 0.9212
Epoch 10/20
750/750 [==============================] - 100s 134ms/step - loss: 0.0852 - accura
cy: 0.9684 - val_loss: 0.2712 - val_accuracy: 0.9243
Epoch 11/20
750/750 [==============================] - 100s 134ms/step - loss: 0.0728 - accura
cy: 0.9727 - val_loss: 0.2988 - val_accuracy: 0.9231
Epoch 12/20
750/750 [==============================] - 96s 127ms/step - loss: 0.0641 - accurac
y: 0.9763 - val_loss: 0.3000 - val_accuracy: 0.9212
Epoch 13/20
750/750 [==============================] - 95s 127ms/step - loss: 0.0520 - accurac
y: 0.9804 - val_loss: 0.3295 - val_accuracy: 0.9206
Epoch 14/20
750/750 [==============================] - 100s 133ms/step - loss: 0.0475 - accura
cy: 0.9821 - val_loss: 0.3674 - val_accuracy: 0.9193
Epoch 15/20
750/750 [==============================] - 96s 128ms/step - loss: 0.0426 - accurac
y: 0.9835 - val_loss: 0.3992 - val_accuracy: 0.9193
Epoch 16/20
750/750 [==============================] - 95s 127ms/step - loss: 0.0363 - accurac
y: 0.9867 - val_loss: 0.4027 - val_accuracy: 0.9215
Epoch 17/20
750/750 [==============================] - 100s 133ms/step - loss: 0.0370 - accura
cy: 0.9866 - val_loss: 0.4259 - val_accuracy: 0.9168
Epoch 18/20
750/750 [==============================] - 100s 134ms/step - loss: 0.0331 - accura
cy: 0.9878 - val_loss: 0.4092 - val_accuracy: 0.9222
Epoch 19/20
750/750 [==============================] - 100s 133ms/step - loss: 0.0320 - accura
cy: 0.9881 - val_loss: 0.4159 - val_accuracy: 0.9199
Epoch 20/20
750/750 [==============================] - 100s 133ms/step - loss: 0.0272 - accura
cy: 0.9897 - val_loss: 0.4589 - val_accuracy: 0.9187

Si nota che ad ogni epoca vengono processati 750 batch ciascuno contenente 64 immagini (64×750
= 48000, dimensione del training set). Ciò viene fatto per 20 epoche. L'accuracy finale ottenuta sul
training set è pari al 99%, mentre l'accuracy sul validation set è del 92%: sembra quindi essere
presente del sovradattamento. Osserviamo comunque i risultati della rete neurale sul test set.
test_eval = fashion_model.evaluate(test_X, test_Y_one_hot, verbose=0)
print(test_eval)

[0.49416348338127136, 0.9154000282287598]

La funzione di perdita utilizzata vale sul test set 0.49, mentre l'accuracy è del 92%. I risultati sono
buoni, ma la differenza tra i risultati nei due set evidenzia, come già accennato, un potenziale
problema di overfitting. Vengono ora rappresentati graficamente i risultati ad ogni epoca di
addestramento.
accuracy = fashion_train.history['accuracy']
val_accuracy = fashion_train.history['val_accuracy']
loss = fashion_train.history['loss']
val_loss = fashion_train.history['val_loss']
epochs = range(1, len(accuracy)+1)

plt.figure(figsize=[10,5])

plt.subplot(121)
plt.plot(epochs, accuracy, 'b', label='Training accuracy', color = "red")
plt.plot(epochs, val_accuracy, 'b', label='Validation accuracy')
plt.title('Training and validation accuracy')
plt.xlabel("Epoch")
plt.ylabel("Accuracy")
plt.xlim(0,21)
plt.legend()

plt.subplot(122)
plt.plot(epochs, loss, 'b', label='Training loss', color = "red")
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.xlabel("Epoch")
plt.ylabel("Funzione di perdita")
plt.xlim(0,21)
plt.legend()

<matplotlib.legend.Legend at 0x7f1196217dc0>

Si nota come la accuracy misurata sul validation set rimanga pressoché uguale dopo 4 o 5 epoche,
mentre la funzione di perdita inizia ad aumentare: tutti segni di potenziale overfitting.

Aggiunta di dropout
Il dropout consiste nel nascondere una certa frazione di neuroni dalla rete in modo casuale
durante la fase di addestramento. Questo serve per evitare il sovradattamento in fase di
allenamento della rete. Si sceglie una frazione del 30% di neuroni da escludere durante
l’addestramento.
Fashion_model = Sequential()
fashion_model.add(Conv2D(32, kernel_size=(3, 3),activation=’linear’,padding=’same’
,input_shape=(28,28,1)))
fashion_model.add(LeakyReLU(alpha=0.1))
fashion_model.add(MaxPooling2D((2, 2),padding=’same’))
fashion_model.add(Dropout(0.25))
fashion_model.add(Conv2D(64, (3, 3), activation=’linear’,padding=’same’))
fashion_model.add(LeakyReLU(alpha=0.1))
fashion_model.add(MaxPooling2D(pool_size=(2, 2),padding=’same’))
fashion_model.add(Dropout(0.25))
fashion_model.add(Conv2D(128, (3, 3), activation=’linear’,padding=’same’))
fashion_model.add(LeakyReLU(alpha=0.1))
fashion_model.add(MaxPooling2D(pool_size=(2, 2),padding=’same’))
fashion_model.add(Dropout(0.4))
fashion_model.add(Flatten())
fashion_model.add(Dense(128, activation=’linear’))
fashion_model.add(LeakyReLU(alpha=0.1))
fashion_model.add(Dropout(0.3))
fashion_model.add(Dense(num_classes, activation=’softmax’))

Si osserva quanto contenuto nella rete neurale creata:

fashion_model.summary()

Model: "sequential_1"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d_3 (Conv2D) (None, 28, 28, 32) 320

leaky_re_lu_4 (LeakyReLU) (None, 28, 28, 32) 0

max_pooling2d_3 (MaxPooling (None, 14, 14, 32) 0


2D)

dropout (Dropout) (None, 14, 14, 32) 0

conv2d_4 (Conv2D) (None, 14, 14, 64) 18496

leaky_re_lu_5 (LeakyReLU) (None, 14, 14, 64) 0

max_pooling2d_4 (MaxPooling (None, 7, 7, 64) 0


2D)

dropout_1 (Dropout) (None, 7, 7, 64) 0

conv2d_5 (Conv2D) (None, 7, 7, 128) 73856


leaky_re_lu_6 (LeakyReLU) (None, 7, 7, 128) 0

max_pooling2d_5 (MaxPooling (None, 4, 4, 128) 0


2D)

dropout_2 (Dropout) (None, 4, 4, 128) 0

flatten_1 (Flatten) (None, 2048) 0

dense_2 (Dense) (None, 128) 262272

leaky_re_lu_7 (LeakyReLU) (None, 128) 0

dropout_3 (Dropout) (None, 128) 0

dense_3 (Dense) (None, 10) 1290

=================================================================
Total params: 356,234
Trainable params: 356,234
Non-trainable params: 0
_________________________________________________________________

Si nota che il numero di parametri è rimasto invariato, mentre il dropout è stato aggiunto. Viene
visualizzata la struttura della rete neurale attraverso la funzione layered_view del pacchetto
visualkeras.

visualkeras.layered_view(fashion_model, legend = True)

Viene ora compilata la rete ed addestrata sul training set.


fashion_model.compile(loss=keras.losses.categorical_crossentropy, optimizer=keras.
optimizers.Adam(),metrics=['accuracy'])
fashion_train_dropout = fashion_model.fit(train_X, train_label, batch_size=batch_s
ize,epochs=epochs,verbose=1,validation_data=(valid_X, valid_label))
Epoch 1/20
750/750 [==============================] - 128s 169ms/step - loss: 0.5916 - accura
cy: 0.7788 - val_loss: 0.3616 - val_accuracy: 0.8673
Epoch 2/20
750/750 [==============================] - 121s 162ms/step - loss: 0.3725 - accura
cy: 0.8639 - val_loss: 0.3118 - val_accuracy: 0.8838
Epoch 3/20
750/750 [==============================] - 119s 158ms/step - loss: 0.3253 - accura
cy: 0.8812 - val_loss: 0.2750 - val_accuracy: 0.8984
Epoch 4/20
750/750 [==============================] - 115s 153ms/step - loss: 0.2990 - accura
cy: 0.8885 - val_loss: 0.2774 - val_accuracy: 0.8932
Epoch 5/20
750/750 [==============================] - 120s 160ms/step - loss: 0.2778 - accura
cy: 0.8958 - val_loss: 0.2483 - val_accuracy: 0.9093
Epoch 6/20
750/750 [==============================] - 119s 159ms/step - loss: 0.2662 - accura
cy: 0.9010 - val_loss: 0.2486 - val_accuracy: 0.9105
Epoch 7/20
750/750 [==============================] - 116s 154ms/step - loss: 0.2541 - accura
cy: 0.9042 - val_loss: 0.2252 - val_accuracy: 0.9155
Epoch 8/20
750/750 [==============================] - 115s 153ms/step - loss: 0.2455 - accura
cy: 0.9090 - val_loss: 0.2361 - val_accuracy: 0.9136
Epoch 9/20
750/750 [==============================] - 120s 161ms/step - loss: 0.2387 - accura
cy: 0.9109 - val_loss: 0.2214 - val_accuracy: 0.9187
Epoch 10/20
750/750 [==============================] - 119s 158ms/step - loss: 0.2332 - accura
cy: 0.9120 - val_loss: 0.2185 - val_accuracy: 0.9220
Epoch 11/20
750/750 [==============================] - 120s 160ms/step - loss: 0.2249 - accura
cy: 0.9153 - val_loss: 0.2142 - val_accuracy: 0.9198
Epoch 12/20
750/750 [==============================] - 117s 156ms/step - loss: 0.2215 - accura
cy: 0.9170 - val_loss: 0.2212 - val_accuracy: 0.9193
Epoch 13/20
750/750 [==============================] - 119s 159ms/step - loss: 0.2181 - accura
cy: 0.9170 - val_loss: 0.2182 - val_accuracy: 0.9243
Epoch 14/20
750/750 [==============================] - 119s 159ms/step - loss: 0.2143 - accura
cy: 0.9184 - val_loss: 0.2319 - val_accuracy: 0.9215
Epoch 15/20
750/750 [==============================] - 116s 155ms/step - loss: 0.2111 - accura
cy: 0.9214 - val_loss: 0.2181 - val_accuracy: 0.9212
Epoch 16/20
750/750 [==============================] - 115s 153ms/step - loss: 0.2088 - accura
cy: 0.9221 - val_loss: 0.2115 - val_accuracy: 0.9245
Epoch 17/20
750/750 [==============================] - 119s 159ms/step - loss: 0.2050 - accura
cy: 0.9227 - val_loss: 0.2106 - val_accuracy: 0.9262
Epoch 18/20
750/750 [==============================] - 115s 153ms/step - loss: 0.2027 - accura
cy: 0.9241 - val_loss: 0.2162 - val_accuracy: 0.9236
Epoch 19/20
750/750 [==============================] - 119s 159ms/step - loss: 0.2003 - accura
cy: 0.9252 - val_loss: 0.2174 - val_accuracy: 0.9228
Epoch 20/20
750/750 [==============================] - 115s 153ms/step - loss: 0.1973 - accura
cy: 0.9258 - val_loss: 0.2053 - val_accuracy: 0.9260

Il problema dell'overfitting sembra essersi risolto, dal momento che l'accuratezza sul training set e
sul validation set sono simili e pari al 92.5% circa. Si potrebbe salvare ora il modello, in modo che
possa essere utilizzato in seguito senza aver bisogno di riaddestrarlo ogni volta, dal momento che
il processo di addestramento è piuttosto lungo (ha richiesto circa mezz'ora).
# fashion_model.save("fashion_model_dropout.h5py")

Si valutano ora i risultati sul test set.


test_eval = fashion_model.evaluate(test_X, test_Y_one_hot, verbose=1)
test_eval

313/313 [==============================] - 10s 30ms/step - loss: 0.2142 - accuracy


: 0.9238

[0.21419931948184967, 0.923799991607666]

L’accuracy è aumentata rispetto a prima e la funzione di perdita è diminuita. L'aggiunta del dropout
ha portato quindi ad un modello più generalizzabile su nuovi dati.

Previsione di categorie
Si mostrano ora alcune previsioni che sono state effettuate sul test set da parte della rete neurale.
Si ricorda che l'output è codificato secondo il paradigma one-hot, di conseguenza si dovrà estrarre
per ciascun vettore in output la posizione della cella con valore 1 per trovare la previsione di
categoria del modello.
predicted_classes = fashion_model.predict(test_X)
predicted_classes = np.argmax(np.round(predicted_classes),axis=1)
predicted_classes[0:2]

313/313 [==============================] - 10s 31ms/step

array([9, 2])

Si nota, ad esempio, che le prime due immagini del test set sono state associate rispettivamente alla
categoria 9 e alla categoria 2. Si vanno ora ad estrarre le classi predette correttamente
confrontando i valori previsti sul test set con i valori reali e si rappresentano le prime 9 immagini
correttamente classificate nel test set.
correct = np.where(predicted_classes==test_Y)[0]
print("Found %d correct labels" % len(correct))
for i, correct in enumerate(correct[:9]):
plt.subplot(3,3,i+1)
plt.imshow(test_X[correct].reshape(28,28), cmap='gray', interpolation='none')
plt.title("Predicted {}, Class {}".format(predicted_classes[correct], test_Y[c
orrect]))
plt.tight_layout()

Found 9194 correct labels


Crediti: larga parte di questo lavoro è realizzata su istruzioni ed ispirazione dal seguente sito web:

https://www.datacamp.com/tutorial/convolutional-neural-networks-python

Potrebbero piacerti anche