Ricerca nel sito web

Riconoscimento delle cifre scritte a mano utilizzando le reti neurali convoluzionali in Python con Keras


Una dimostrazione popolare della capacità delle tecniche di deep learning è il riconoscimento degli oggetti nei dati immagine.

Il “ciao mondo” del riconoscimento degli oggetti per l’apprendimento automatico e il deep learning è il set di dati MNIST per il riconoscimento delle cifre scritte a mano.

In questo post scoprirai come sviluppare un modello di deep learning per ottenere prestazioni quasi all'avanguardia nell'attività di riconoscimento delle cifre scritte a mano MNIST in Python utilizzando la libreria di deep learning Keras.

Dopo aver completato questo tutorial, saprai:

  • Come caricare il set di dati MNIST in Keras
  • Come sviluppare e valutare un modello di rete neurale di base per il problema MNIST
  • Come implementare e valutare una semplice rete neurale convoluzionale per MNIST
  • Come implementare un modello di deep learning quasi all'avanguardia per MNIST

Avvia il tuo progetto con il mio nuovo libro Deep Learning With Python, che include tutorial passo passo e i file codice sorgente Python per tutti esempi.

Cominciamo.

  • Giugno/2016: pubblicazione per la prima volta
  • Aggiornamento ottobre 2016: aggiornato per Keras 1.1.0, TensorFlow 0.10.0 e scikit-learn v0.18
  • Aggiornamento marzo/2017: aggiornato per Keras 2.0.2, TensorFlow 1.0.1 e Theano 0.9.0
  • Aggiornamento settembre/2019: aggiornato per l'API Keras 2.2.5
  • Aggiornamento luglio/2022: aggiornato per l'API TensorFlow 2.x

Nota: per una versione estesa di questo tutorial, vedere:

  • Come sviluppare una CNN profonda per la classificazione delle cifre MNIST

Descrizione del problema di riconoscimento delle cifre scritte a mano del MNIST

Il problema MNIST è un set di dati sviluppato da Yann LeCun, Corinna Cortes e Christopher Burges per valutare modelli di apprendimento automatico sul problema della classificazione delle cifre scritte a mano.

Il set di dati è stato costruito da una serie di set di dati di documenti scansionati disponibili presso il National Institute of Standards and Technology (NIST). Da qui deriva il nome del set di dati, il set di dati NIST o MNIST modificato.

Le immagini delle cifre sono state prese da una varietà di documenti scansionati, normalizzate nelle dimensioni e centrate. Ciò lo rende un set di dati eccellente per la valutazione dei modelli, consentendo allo sviluppatore di concentrarsi sull'apprendimento automatico con una pulizia o una preparazione minima dei dati richiesta.

Ogni immagine è un quadrato di 28×28 pixel (784 pixel in totale). Per valutare e confrontare i modelli viene utilizzata una suddivisione standard del set di dati, in cui vengono utilizzate 60.000 immagini per addestrare un modello e un set separato di 10.000 immagini per testarlo.

È un compito di riconoscimento delle cifre. Pertanto, ci sono dieci cifre (da 0 a 9) o dieci classi da prevedere. I risultati vengono riportati utilizzando l'errore di previsione, che non è altro che l'accuratezza della classificazione invertita.

Risultati eccellenti raggiungono un errore di previsione inferiore all'1%. Con reti neurali convoluzionali di grandi dimensioni è possibile ottenere un errore di previsione allo stato dell'arte di circa lo 0,2%. C’è un elenco dei risultati più aggiornati e collegamenti ai documenti rilevanti sul MNIST e altri set di dati sulla pagina web di Rodrigo Benenson.

Caricamento del set di dati MNIST in Keras

La libreria di deep learning Keras fornisce un metodo conveniente per caricare il set di dati MNIST.

Il set di dati viene scaricato automaticamente la prima volta che questa funzione viene chiamata e archiviato nella directory home in ~/.keras/datasets/mnist.npz come file da 11 MB.

Questo è molto utile per sviluppare e testare modelli di deep learning.

Per dimostrare quanto sia facile caricare il set di dati MNIST, scrivi innanzitutto un piccolo script per scaricare e visualizzare le prime quattro immagini nel set di dati di addestramento.

# Plot ad hoc mnist instances
from tensorflow.keras.datasets import mnist
import matplotlib.pyplot as plt
# load (downloaded if needed) the MNIST dataset
(X_train, y_train), (X_test, y_test) = mnist.load_data()
# plot 4 images as gray scale
plt.subplot(221)
plt.imshow(X_train[0], cmap=plt.get_cmap('gray'))
plt.subplot(222)
plt.imshow(X_train[1], cmap=plt.get_cmap('gray'))
plt.subplot(223)
plt.imshow(X_train[2], cmap=plt.get_cmap('gray'))
plt.subplot(224)
plt.imshow(X_train[3], cmap=plt.get_cmap('gray'))
# show the plot
plt.show()

Puoi vedere che scaricare e caricare il set di dati MNIST è facile come chiamare la funzione mnist.load_data(). Eseguendo l'esempio sopra, dovresti vedere l'immagine qui sotto.

Modello di base con percettroni multistrato

Hai davvero bisogno di un modello complesso come una rete neurale convoluzionale per ottenere i migliori risultati con MNIST?

Puoi ottenere ottimi risultati utilizzando un modello di rete neurale molto semplice con un singolo livello nascosto. In questa sezione creerai un semplice modello di percettrone multistrato che raggiunge un tasso di errore dell'1,74%. Lo utilizzerai come base per confrontare modelli di rete neurale convoluzionale più complessi.

Iniziamo importando le classi e le funzioni di cui avrai bisogno.

from tensorflow.keras.datasets import mnist
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.layers import Dropout
from tensorflow.keras.utils import to_categorical
...

Ora puoi caricare il set di dati MNIST utilizzando la funzione helper Keras.

...
# load data
(X_train, y_train), (X_test, y_test) = mnist.load_data()

Il set di dati di addestramento è strutturato come un array tridimensionale di istanza, larghezza e altezza dell'immagine. Per un modello di percettrone multistrato, è necessario ridurre le immagini in un vettore di pixel. In questo caso, le immagini di dimensione 28×28 avranno valori di input di 784 pixel.

Puoi eseguire facilmente questa trasformazione utilizzando la funzione reshape() sull'array NumPy. Puoi anche ridurre i requisiti di memoria forzando la precisione dei valori dei pixel a 32 bit, la precisione predefinita utilizzata comunque da Keras.

...
# flatten 28*28 images to a 784 vector for each image
num_pixels = X_train.shape[1] * X_train.shape[2]
X_train = X_train.reshape((X_train.shape[0], num_pixels)).astype('float32')
X_test = X_test.reshape((X_test.shape[0], num_pixels)).astype('float32')

I valori dei pixel sono in scala di grigi compresi tra 0 e 255. È quasi sempre una buona idea eseguire un ridimensionamento dei valori di input quando si utilizzano modelli di rete neurale. Poiché la scala è ben nota e ben gestita, è possibile normalizzare molto rapidamente i valori dei pixel nell'intervallo 0 e 1 dividendo ciascun valore per il massimo di 255.

...
# normalize inputs from 0-255 to 0-1
X_train = X_train / 255
X_test = X_test / 255

Infine, la variabile di output è un numero intero compreso tra 0 e 9. Questo è un problema di classificazione multiclasse. Pertanto, è buona pratica utilizzare una codifica one-hot dei valori della classe, trasformando il vettore degli interi della classe in una matrice binaria.

Puoi farlo facilmente utilizzando la funzione helper tf.keras.utils.to_categorical() incorporata in Keras.

...
# one hot encode outputs
y_train = to_categorical(y_train)
y_test = to_categorical(y_test)
num_classes = y_test.shape[1]

Ora sei pronto per creare il tuo semplice modello di rete neurale. Definirai il tuo modello in una funzione. Ciò è utile se desideri estendere l'esempio in un secondo momento e provare a ottenere un punteggio migliore.

...
# define baseline model
def baseline_model():
	# create model
	model = Sequential()
	model.add(Dense(num_pixels, input_shape=(num_pixels,), kernel_initializer='normal', activation='relu'))
	model.add(Dense(num_classes, kernel_initializer='normal', activation='softmax'))
	# Compile model
	model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
	return model

Il modello è una semplice rete neurale con uno strato nascosto con lo stesso numero di neuroni quanti sono gli input (784). Una funzione di attivazione del raddrizzatore viene utilizzata per i neuroni nello strato nascosto.

Una funzione di attivazione softmax viene utilizzata sul livello di output per trasformare gli output in valori probabilistici e consentire di selezionare una classe delle dieci come previsione di output del modello. La perdita logaritmica viene utilizzata come funzione di perdita (chiamata categorical_crossentropy in Keras) e l'efficiente algoritmo di discesa del gradiente ADAM viene utilizzato per apprendere i pesi.

Ora puoi adattare e valutare il modello. Il modello è adatto a dieci epoche con aggiornamenti ogni 200 immagini. I dati del test vengono utilizzati come set di dati di convalida, consentendoti di vedere le capacità del modello durante l'addestramento. Un valore dettagliato pari a 2 viene utilizzato per ridurre l'output a una riga per ogni epoca di training.

Infine, il set di dati del test viene utilizzato per valutare il modello e viene stampato un tasso di errore di classificazione.

...
# build the model
model = baseline_model()
# Fit the model
model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=10, batch_size=200, verbose=2)
# Final evaluation of the model
scores = model.evaluate(X_test, y_test, verbose=0)
print("Baseline Error: %.2f%%" % (100-scores[1]*100))

Dopo aver collegato tutto insieme, di seguito viene fornito l'elenco completo del codice.

# Baseline MLP for MNIST dataset
from tensorflow.keras.datasets import mnist
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.utils import to_categorical
# load data
(X_train, y_train), (X_test, y_test) = mnist.load_data()
# flatten 28*28 images to a 784 vector for each image
num_pixels = X_train.shape[1] * X_train.shape[2]
X_train = X_train.reshape((X_train.shape[0], num_pixels)).astype('float32')
X_test = X_test.reshape((X_test.shape[0], num_pixels)).astype('float32')
# normalize inputs from 0-255 to 0-1
X_train = X_train / 255
X_test = X_test / 255
# one hot encode outputs
y_train = to_categorical(y_train)
y_test = to_categorical(y_test)
num_classes = y_test.shape[1]
# define baseline model
def baseline_model():
	# create model
	model = Sequential()
	model.add(Dense(num_pixels, input_shape=(num_pixels,), kernel_initializer='normal', activation='relu'))
	model.add(Dense(num_classes, kernel_initializer='normal', activation='softmax'))
	# Compile model
	model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
	return model
# build the model
model = baseline_model()
# Fit the model
model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=10, batch_size=200, verbose=2)
# Final evaluation of the model
scores = model.evaluate(X_test, y_test, verbose=0)
print("Baseline Error: %.2f%%" % (100-scores[1]*100))

L'esecuzione dell'esempio potrebbe richiedere alcuni minuti se eseguito su una CPU.

Nota: i risultati possono variare a causa della natura stocastica dell'algoritmo o della procedura di valutazione o delle differenze nella precisione numerica. Considera l'idea di eseguire l'esempio alcune volte e confrontare il risultato medio.

Dovresti vedere l'output qui sotto. Questa rete molto semplice, definita in pochissime righe di codice, raggiunge un tasso di errore rispettabile del 2,3%.

Epoch 1/10
300/300 - 1s - loss: 0.2792 - accuracy: 0.9215 - val_loss: 0.1387 - val_accuracy: 0.9590 - 1s/epoch - 4ms/step
Epoch 2/10
300/300 - 1s - loss: 0.1113 - accuracy: 0.9676 - val_loss: 0.0923 - val_accuracy: 0.9709 - 929ms/epoch - 3ms/step
Epoch 3/10
300/300 - 1s - loss: 0.0704 - accuracy: 0.9799 - val_loss: 0.0728 - val_accuracy: 0.9787 - 912ms/epoch - 3ms/step
Epoch 4/10
300/300 - 1s - loss: 0.0502 - accuracy: 0.9859 - val_loss: 0.0664 - val_accuracy: 0.9808 - 904ms/epoch - 3ms/step
Epoch 5/10
300/300 - 1s - loss: 0.0356 - accuracy: 0.9897 - val_loss: 0.0636 - val_accuracy: 0.9803 - 905ms/epoch - 3ms/step
Epoch 6/10
300/300 - 1s - loss: 0.0261 - accuracy: 0.9932 - val_loss: 0.0591 - val_accuracy: 0.9813 - 907ms/epoch - 3ms/step
Epoch 7/10
300/300 - 1s - loss: 0.0195 - accuracy: 0.9953 - val_loss: 0.0564 - val_accuracy: 0.9828 - 910ms/epoch - 3ms/step
Epoch 8/10
300/300 - 1s - loss: 0.0145 - accuracy: 0.9969 - val_loss: 0.0580 - val_accuracy: 0.9810 - 954ms/epoch - 3ms/step
Epoch 9/10
300/300 - 1s - loss: 0.0116 - accuracy: 0.9973 - val_loss: 0.0594 - val_accuracy: 0.9817 - 947ms/epoch - 3ms/step
Epoch 10/10
300/300 - 1s - loss: 0.0079 - accuracy: 0.9985 - val_loss: 0.0735 - val_accuracy: 0.9770 - 914ms/epoch - 3ms/step
Baseline Error: 2.30%

Rete neurale convoluzionale semplice per MNIST

Ora che hai visto come caricare il set di dati MNIST e addestrare su di esso un semplice modello di percettrone multistrato, è tempo di sviluppare una rete neurale convoluzionale più sofisticata o modello CNN.

Keras offre molte funzionalità per la creazione di reti neurali convoluzionali.

In questa sezione creerai una semplice CNN per MNIST che dimostra come utilizzare tutti gli aspetti di una moderna implementazione CNN, inclusi i livelli convoluzionali, i livelli di pooling e i livelli di dropout.

Il primo passo è importare le classi e le funzioni necessarie.

from tensorflow.keras.datasets import mnist
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.layers import Dropout
from tensorflow.keras.layers import Flatten
from tensorflow.keras.layers import Conv2D
from tensorflow.keras.layers import MaxPooling2D
from tensorflow.keras.utils import to_categorical
...

Successivamente, è necessario caricare il set di dati MNIST e rimodellarlo per adattarlo all'addestramento di una CNN. In Keras, i livelli utilizzati per le convoluzioni bidimensionali prevedono valori di pixel con le dimensioni [pixel] [larghezza] [altezza] [canali].

Tieni presente che in questo esempio stai forzando il cosiddetto ordinamento degli ultimi canali per coerenza.

Nel caso dell'RGB, i pixel dell'ultima dimensione sarebbero 3 per i componenti rosso, verde e blu e sarebbe come avere tre input di immagine per ogni immagine a colori. Nel caso di MNIST, dove i valori dei pixel sono in scala di grigi, la dimensione dei pixel è impostata su 1.

...
# load data
(X_train, y_train), (X_test, y_test) = mnist.load_data()
# reshape to be [samples][width][height][channels]
X_train = X_train.reshape(X_train.shape[0], 28, 28, 1).astype('float32')
X_test = X_test.reshape(X_test.shape[0], 28, 28, 1).astype('float32')

Come prima, è una buona idea normalizzare i valori dei pixel nell'intervallo 0 e 1 e codificare a caldo le variabili di output.

...
# normalize inputs from 0-255 to 0-1
X_train = X_train / 255
X_test = X_test / 255
# one hot encode outputs
y_train = to_categorical(y_train)
y_test = to_categorical(y_test)
num_classes = y_test.shape[1]

Successivamente, definisci il tuo modello di rete neurale.

Le reti neurali convoluzionali sono più complesse dei percettroni multistrato standard, quindi inizierai utilizzando una struttura semplice che utilizza tutti gli elementi per risultati all'avanguardia. Di seguito viene riepilogata l'architettura della rete.

  1. Il primo livello nascosto è uno strato convoluzionale chiamato Convolution2D. Il livello ha 32 mappe di caratteristiche, con la dimensione di 5×5 e una funzione di attivazione del raddrizzatore. Questo è il livello di input che prevede immagini con la struttura delineata sopra: [pixel][larghezza][altezza].
  2. Successivamente, definisci un livello di pooling che accetta il massimo chiamato MaxPooling2D. È configurato con una dimensione della piscina di 2×2.
  3. Il livello successivo è un livello di regolarizzazione che utilizza il dropout chiamato Dropout. È configurato per escludere in modo casuale il 20% dei neuroni nel livello al fine di ridurre l'adattamento eccessivo.
  4. Il successivo è un livello che converte i dati della matrice 2D in un vettore chiamato Flatten. Consente l'elaborazione dell'output tramite livelli standard completamente connessi.
  5. Successivamente c'è uno strato completamente connesso con 128 neuroni e una funzione di attivazione del raddrizzatore.
  6. Infine, lo strato di output ha dieci neuroni per le dieci classi e una funzione di attivazione softmax per produrre previsioni probabilistiche per ciascuna classe.

Come in precedenza, il modello viene addestrato utilizzando la perdita logaritmica e l'algoritmo di discesa del gradiente ADAM.

...
def baseline_model():
	# create model
	model = Sequential()
	model.add(Conv2D(32, (5, 5), input_shape=(28, 28, 1), activation='relu'))
	model.add(MaxPooling2D(pool_size=(2, 2)))
	model.add(Dropout(0.2))
	model.add(Flatten())
	model.add(Dense(128, activation='relu'))
	model.add(Dense(num_classes, activation='softmax'))
	# Compile model
	model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
	return model

Valuti il modello nello stesso modo di prima con il percettrone multistrato. La CNN è adatta a dieci epoche con una dimensione batch di 200.

...
# build the model
model = baseline_model()
# Fit the model
model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=10, batch_size=200, verbose=2)
# Final evaluation of the model
scores = model.evaluate(X_test, y_test, verbose=0)
print("CNN Error: %.2f%%" % (100-scores[1]*100))

Dopo aver collegato tutto insieme, l'esempio completo è elencato di seguito.

# Simple CNN for the MNIST Dataset
from tensorflow.keras.datasets import mnist
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.layers import Dropout
from tensorflow.keras.layers import Flatten
from tensorflow.keras.layers import Conv2D
from tensorflow.keras.layers import MaxPooling2D
from tensorflow.keras.utils import to_categorical
# load data
(X_train, y_train), (X_test, y_test) = mnist.load_data()
# reshape to be [samples][width][height][channels]
X_train = X_train.reshape((X_train.shape[0], 28, 28, 1)).astype('float32')
X_test = X_test.reshape((X_test.shape[0], 28, 28, 1)).astype('float32')
# normalize inputs from 0-255 to 0-1
X_train = X_train / 255
X_test = X_test / 255
# one hot encode outputs
y_train = to_categorical(y_train)
y_test = to_categorical(y_test)
num_classes = y_test.shape[1]
# define a simple CNN model
def baseline_model():
	# create model
	model = Sequential()
	model.add(Conv2D(32, (5, 5), input_shape=(28, 28, 1), activation='relu'))
	model.add(MaxPooling2D())
	model.add(Dropout(0.2))
	model.add(Flatten())
	model.add(Dense(128, activation='relu'))
	model.add(Dense(num_classes, activation='softmax'))
	# Compile model
	model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
	return model
# build the model
model = baseline_model()
# Fit the model
model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=10, batch_size=200)
# Final evaluation of the model
scores = model.evaluate(X_test, y_test, verbose=0)
print("CNN Error: %.2f%%" % (100-scores[1]*100))

Dopo aver eseguito l'esempio, viene stampata l'accuratezza del test di addestramento e convalida per ciascuna epoca e, alla fine, viene stampato il tasso di errore di classificazione.

Nota: i risultati possono variare a causa della natura stocastica dell'algoritmo o della procedura di valutazione o delle differenze nella precisione numerica. Considera l'idea di eseguire l'esempio alcune volte e confrontare il risultato medio.

L'esecuzione di Epochs sulla GPU (ad esempio su AWS) può richiedere circa 45 secondi. Puoi vedere che la rete raggiunge un tasso di errore dell'1,19%, che è migliore del nostro semplice modello di percettrone multistrato sopra.

Epoch 1/10
300/300 [==============================] - 4s 12ms/step - loss: 0.2372 - accuracy: 0.9344 - val_loss: 0.0715 - val_accuracy: 0.9787
Epoch 2/10
300/300 [==============================] - 4s 13ms/step - loss: 0.0697 - accuracy: 0.9786 - val_loss: 0.0461 - val_accuracy: 0.9858
Epoch 3/10
300/300 [==============================] - 4s 13ms/step - loss: 0.0483 - accuracy: 0.9854 - val_loss: 0.0392 - val_accuracy: 0.9867
Epoch 4/10
300/300 [==============================] - 4s 13ms/step - loss: 0.0366 - accuracy: 0.9887 - val_loss: 0.0357 - val_accuracy: 0.9889
Epoch 5/10
300/300 [==============================] - 4s 14ms/step - loss: 0.0300 - accuracy: 0.9909 - val_loss: 0.0360 - val_accuracy: 0.9873
Epoch 6/10
300/300 [==============================] - 4s 14ms/step - loss: 0.0241 - accuracy: 0.9927 - val_loss: 0.0325 - val_accuracy: 0.9890
Epoch 7/10
300/300 [==============================] - 4s 14ms/step - loss: 0.0210 - accuracy: 0.9932 - val_loss: 0.0314 - val_accuracy: 0.9898
Epoch 8/10
300/300 [==============================] - 4s 14ms/step - loss: 0.0167 - accuracy: 0.9945 - val_loss: 0.0306 - val_accuracy: 0.9898
Epoch 9/10
300/300 [==============================] - 4s 14ms/step - loss: 0.0142 - accuracy: 0.9956 - val_loss: 0.0326 - val_accuracy: 0.9892
Epoch 10/10
300/300 [==============================] - 4s 14ms/step - loss: 0.0114 - accuracy: 0.9966 - val_loss: 0.0322 - val_accuracy: 0.9881
CNN Error: 1.19%

Rete neurale convoluzionale più ampia per MNIST

Ora che hai visto come creare una semplice CNN, diamo un'occhiata a un modello in grado di fornire risultati vicini allo stato dell'arte.

Importerai le classi e le funzioni, quindi caricherai e preparerai i dati come nell'esempio precedente della CNN.

# Larger CNN for the MNIST Dataset
from tensorflow.keras.datasets import mnist
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.layers import Dropout
from tensorflow.keras.layers import Flatten
from tensorflow.keras.layers import Conv2D
from tensorflow.keras.layers import MaxPooling2D
from tensorflow.keras.utils import to_categorical
# load data
(X_train, y_train), (X_test, y_test) = mnist.load_data()
# reshape to be [samples][width][height][channels]
X_train = X_train.reshape((X_train.shape[0], 28, 28, 1)).astype('float32')
X_test = X_test.reshape((X_test.shape[0], 28, 28, 1)).astype('float32')
# normalize inputs from 0-255 to 0-1
X_train = X_train / 255
X_test = X_test / 255
# one hot encode outputs
y_train = to_categorical(y_train)
y_test = to_categorical(y_test)
num_classes = y_test.shape[1]
...

Questa volta definirai un'architettura CNN di grandi dimensioni con livelli convoluzionali aggiuntivi, di pooling massimo e livelli completamente connessi. La topologia della rete può essere così riassunta:

  1. Strato convoluzionale con 30 mappe di caratteristiche di dimensione 5×5
  2. Il livello di pooling ottiene il massimo su 2*2 patch
  3. Strato convoluzionale con 15 mappe di caratteristiche di dimensione 3×3
  4. Il livello di pooling ottiene il massimo su 2*2 patch
  5. Strato di abbandono con una probabilità del 20%
  6. Strato appiattito
  7. Strato completamente connesso con 128 neuroni e attivazione del raddrizzatore
  8. Strato completamente connesso con 50 neuroni e attivazione del raddrizzatore
  9. Strato di uscita
...
# define the larger model
def larger_model():
	# create model
	model = Sequential()
	model.add(Conv2D(30, (5, 5), input_shape=(28, 28, 1), activation='relu'))
	model.add(MaxPooling2D(pool_size=(2, 2)))
	model.add(Conv2D(15, (3, 3), activation='relu'))
	model.add(MaxPooling2D(pool_size=(2, 2)))
	model.add(Dropout(0.2))
	model.add(Flatten())
	model.add(Dense(128, activation='relu'))
	model.add(Dense(50, activation='relu'))
	model.add(Dense(num_classes, activation='softmax'))
	# Compile model
	model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
	return model

Come i due esperimenti precedenti, il modello è adattato a dieci epoche con una dimensione batch di 200.

...
# build the model
model = larger_model()
# Fit the model
model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=10, batch_size=200)
# Final evaluation of the model
scores = model.evaluate(X_test, y_test, verbose=0)
print("Large CNN Error: %.2f%%" % (100-scores[1]*100))

Dopo aver collegato tutto insieme, l'esempio completo è elencato di seguito.

# Larger CNN for the MNIST Dataset
from tensorflow.keras.datasets import mnist
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.layers import Dropout
from tensorflow.keras.layers import Flatten
from tensorflow.keras.layers import Conv2D
from tensorflow.keras.layers import MaxPooling2D
from tensorflow.keras.utils import to_categorical
# load data
(X_train, y_train), (X_test, y_test) = mnist.load_data()
# reshape to be [samples][width][height][channels]
X_train = X_train.reshape((X_train.shape[0], 28, 28, 1)).astype('float32')
X_test = X_test.reshape((X_test.shape[0], 28, 28, 1)).astype('float32')
# normalize inputs from 0-255 to 0-1
X_train = X_train / 255
X_test = X_test / 255
# one hot encode outputs
y_train = to_categorical(y_train)
y_test = to_categorical(y_test)
num_classes = y_test.shape[1]
# define the larger model
def larger_model():
	# create model
	model = Sequential()
	model.add(Conv2D(30, (5, 5), input_shape=(28, 28, 1), activation='relu'))
	model.add(MaxPooling2D())
	model.add(Conv2D(15, (3, 3), activation='relu'))
	model.add(MaxPooling2D())
	model.add(Dropout(0.2))
	model.add(Flatten())
	model.add(Dense(128, activation='relu'))
	model.add(Dense(50, activation='relu'))
	model.add(Dense(num_classes, activation='softmax'))
	# Compile model
	model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
	return model
# build the model
model = larger_model()
# Fit the model
model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=10, batch_size=200)
# Final evaluation of the model
scores = model.evaluate(X_test, y_test, verbose=0)
print("Large CNN Error: %.2f%%" % (100-scores[1]*100))

L'esecuzione dell'esempio stampa la precisione sui set di dati di training e convalida di ogni epoca e un tasso di errore di classificazione finale.

Nota: i risultati possono variare a causa della natura stocastica dell'algoritmo o della procedura di valutazione o delle differenze nella precisione numerica. Considera l'idea di eseguire l'esempio alcune volte e confrontare il risultato medio.

Il modello impiega circa 100 secondi per funzionare per epoca. Questo modello leggermente più grande raggiunge un rispettabile tasso di errore di classificazione dello 0,83%.

Epoch 1/10
300/300 [==============================] - 4s 14ms/step - loss: 0.4104 - accuracy: 0.8727 - val_loss: 0.0870 - val_accuracy: 0.9732
Epoch 2/10
300/300 [==============================] - 5s 15ms/step - loss: 0.1062 - accuracy: 0.9669 - val_loss: 0.0601 - val_accuracy: 0.9804
Epoch 3/10
300/300 [==============================] - 4s 14ms/step - loss: 0.0771 - accuracy: 0.9765 - val_loss: 0.0555 - val_accuracy: 0.9803
Epoch 4/10
300/300 [==============================] - 4s 14ms/step - loss: 0.0624 - accuracy: 0.9812 - val_loss: 0.0393 - val_accuracy: 0.9878
Epoch 5/10
300/300 [==============================] - 4s 15ms/step - loss: 0.0521 - accuracy: 0.9838 - val_loss: 0.0333 - val_accuracy: 0.9892
Epoch 6/10
300/300 [==============================] - 4s 15ms/step - loss: 0.0453 - accuracy: 0.9861 - val_loss: 0.0280 - val_accuracy: 0.9907
Epoch 7/10
300/300 [==============================] - 4s 14ms/step - loss: 0.0415 - accuracy: 0.9866 - val_loss: 0.0322 - val_accuracy: 0.9905
Epoch 8/10
300/300 [==============================] - 4s 14ms/step - loss: 0.0376 - accuracy: 0.9879 - val_loss: 0.0288 - val_accuracy: 0.9906
Epoch 9/10
300/300 [==============================] - 4s 14ms/step - loss: 0.0327 - accuracy: 0.9895 - val_loss: 0.0245 - val_accuracy: 0.9925
Epoch 10/10
300/300 [==============================] - 4s 15ms/step - loss: 0.0294 - accuracy: 0.9904 - val_loss: 0.0279 - val_accuracy: 0.9910
Large CNN Error: 0.90%

Questa non è una topologia di rete ottimizzata. Né è la riproduzione di una topologia di rete tratta da un articolo recente. Ci sono molte opportunità per mettere a punto e migliorare questo modello.

Qual è il miglior punteggio di tasso di errore che puoi ottenere?

Pubblica la tua configurazione e il miglior punteggio nei commenti.

Risorse su MNIST

Il set di dati MNIST è molto ben studiato. Di seguito sono riportate alcune risorse aggiuntive che potresti voler esaminare.

  • La pagina web ufficiale del set di dati MNIST
  • Pagina web di Rodrigo Benenson che elenca i risultati all’avanguardia
  • Concorso Kaggle che utilizza questo set di dati (controlla gli script e le sezioni del forum per il codice di esempio)
  • Modello di sola lettura addestrato su MNIST che puoi testare nel tuo browser (molto interessante)

Riepilogo

In questo post hai scoperto il problema del riconoscimento delle cifre scritte a mano MNIST e i modelli di deep learning sviluppati in Python utilizzando la libreria Keras che sono in grado di ottenere risultati eccellenti.

Utilizzando questo tutorial, hai imparato:

  • Come caricare il set di dati MNIST in Keras e generare grafici del set di dati
  • Come rimodellare il set di dati MNIST e sviluppare un modello di percettrone multistrato semplice ma efficace sul problema
  • Come utilizzare Keras per creare modelli di rete neurale convoluzionale per MNIST
  • Come sviluppare e valutare modelli CNN più ampi per MNIST in grado di fornire risultati quasi di livello mondiale.

Hai domande sul riconoscimento della grafia con il deep learning o su questo post? Fai la tua domanda nei commenti e farò del mio meglio per rispondere.

Articoli correlati