Recherche de site Web

Reconnaissance de chiffres manuscrits à l'aide de réseaux de neurones convolutifs en Python avec Keras


Une démonstration populaire de la capacité des techniques d’apprentissage profond est la reconnaissance d’objets dans les données d’image.

Le « bonjour le monde » de la reconnaissance d'objets pour l'apprentissage automatique et l'apprentissage profond est l'ensemble de données MNIST pour la reconnaissance de chiffres manuscrits.

Dans cet article, vous découvrirez comment développer un modèle d'apprentissage profond pour obtenir des performances proches de l'état de l'art sur la tâche de reconnaissance de chiffres manuscrits MNIST en Python à l'aide de la bibliothèque d'apprentissage profond Keras.

Après avoir terminé ce tutoriel, vous saurez :

  • Comment charger l'ensemble de données MNIST dans Keras
  • Comment développer et évaluer un modèle de réseau neuronal de base pour le problème MNIST
  • Comment mettre en œuvre et évaluer un simple réseau de neurones convolutifs pour le MNIST
  • Comment mettre en œuvre un modèle d'apprentissage profond proche de l'état de l'art pour le MNIST

Démarrez votre projet avec mon nouveau livre Deep Learning With Python, comprenant des tutoriels pas à pas et les fichiers code source Python pour tous exemples.

Commençons.

  • Juin/2016 : Première publication
  • Mise à jour d'octobre 2016 : mise à jour pour Keras 1.1.0, TensorFlow 0.10.0 et scikit-learn v0.18
  • Mise à jour de mars 2017 : mise à jour pour Keras 2.0.2, TensorFlow 1.0.1 et Theano 0.9.0
  • Mise à jour de septembre 2019 : mise à jour pour l'API Keras 2.2.5
  • Mise à jour de juillet 2022 : mise à jour pour l'API TensorFlow 2.x

Notez que pour une version étendue de ce didacticiel, consultez :

  • Comment développer un CNN profond pour la classification des chiffres MNIST

Description du problème de reconnaissance des chiffres manuscrits du MNIST

Le problème MNIST est un ensemble de données développé par Yann LeCun, Corinna Cortes et Christopher Burges pour évaluer les modèles d'apprentissage automatique sur le problème de classification des chiffres manuscrits.

L'ensemble de données a été construit à partir d'un certain nombre d'ensembles de données de documents numérisés disponibles auprès du National Institute of Standards and Technology (NIST). C'est de là que vient le nom de l'ensemble de données, l'ensemble de données Modified NIST ou MNIST.

Les images de chiffres ont été prises à partir d’une variété de documents numérisés, normalisées en taille et centrées. Cela en fait un excellent ensemble de données pour évaluer les modèles, permettant au développeur de se concentrer sur l'apprentissage automatique avec un minimum de nettoyage ou de préparation des données requis.

Chaque image est un carré de 28 × 28 pixels (784 pixels au total). Une répartition standard de l'ensemble de données est utilisée pour évaluer et comparer les modèles, où 60 000 images sont utilisées pour entraîner un modèle et un ensemble distinct de 10 000 images est utilisé pour le tester.

Il s'agit d'une tâche de reconnaissance de chiffres. Il y a donc dix chiffres (de 0 à 9) ou dix classes à prédire. Les résultats sont rapportés en utilisant l'erreur de prédiction, qui n'est rien d'autre que la précision de la classification inversée.

D'excellents résultats permettent d'obtenir une erreur de prédiction inférieure à 1 %. Une erreur de prédiction de pointe d’environ 0,2 % peut être obtenue avec de grands réseaux neuronaux convolutifs. Il existe une liste des résultats les plus récents et des liens vers les articles pertinents sur le MNIST et d’autres ensembles de données sur la page Web de Rodrigo Benenson.

Chargement de l'ensemble de données MNIST dans Keras

La bibliothèque d'apprentissage en profondeur Keras fournit une méthode pratique pour charger l'ensemble de données MNIST.

L'ensemble de données est téléchargé automatiquement la première fois que cette fonction est appelée et stocké dans votre répertoire personnel dans ~/.keras/datasets/mnist.npz sous forme de fichier de 11 Mo.

C'est très pratique pour développer et tester des modèles d'apprentissage profond.

Pour démontrer à quel point il est facile de charger l'ensemble de données MNIST, écrivez d'abord un petit script pour télécharger et visualiser les quatre premières images de l'ensemble de données d'entraînement.

# 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()

Vous pouvez voir que télécharger et charger l’ensemble de données MNIST est aussi simple que d’appeler la fonction mnist.load_data(). En exécutant l'exemple ci-dessus, vous devriez voir l'image ci-dessous.

Modèle de base avec perceptrons multicouches

Avez-vous vraiment besoin d'un modèle complexe comme un réseau de neurones convolutifs pour obtenir les meilleurs résultats avec MNIST ?

Vous pouvez obtenir de très bons résultats en utilisant un modèle de réseau neuronal très simple avec une seule couche cachée. Dans cette section, vous allez créer un modèle de perceptron multicouche simple qui atteint un taux d'erreur de 1,74 %. Vous l'utiliserez comme base de référence pour comparer des modèles de réseaux neuronaux convolutifs plus complexes.

Commençons par importer les classes et fonctions dont vous aurez besoin.

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
...

Vous pouvez désormais charger l'ensemble de données MNIST à l'aide de la fonction d'assistance Keras.

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

L'ensemble de données d'entraînement est structuré sous la forme d'un tableau tridimensionnel d'instance, de largeur d'image et de hauteur d'image. Pour un modèle de perceptron multicouche, vous devez réduire les images en un vecteur de pixels. Dans ce cas, les images au format 28 × 28 auront des valeurs d'entrée de 784 pixels.

Vous pouvez effectuer cette transformation facilement en utilisant la fonction reshape() sur le tableau NumPy. Vous pouvez également réduire vos besoins en mémoire en forçant la précision des valeurs de pixels à 32 bits, la précision par défaut utilisée de toute façon par 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')

Les valeurs des pixels sont en niveaux de gris compris entre 0 et 255. C'est presque toujours une bonne idée d'effectuer une mise à l'échelle des valeurs d'entrée lors de l'utilisation de modèles de réseaux neuronaux. L'échelle étant bien connue et bien comportée, vous pouvez très rapidement normaliser les valeurs des pixels dans la plage 0 et 1 en divisant chaque valeur par le maximum de 255.

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

Enfin, la variable de sortie est un entier de 0 à 9. Il s'agit d'un problème de classification multi-classes. En tant que tel, il est recommandé d’utiliser un codage ponctuel des valeurs de classe, transformant le vecteur des entiers de classe en une matrice binaire.

Vous pouvez facilement le faire en utilisant la fonction d'assistance intégrée tf.keras.utils.to_categorical() dans Keras.

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

Vous êtes maintenant prêt à créer votre modèle simple de réseau neuronal. Vous définirez votre modèle dans une fonction. C'est pratique si vous souhaitez étendre l'exemple plus tard et essayer d'obtenir un meilleur score.

...
# 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

Le modèle est un simple réseau de neurones avec une couche cachée avec le même nombre de neurones qu'il y a d'entrées (784). Une fonction d'activation du redresseur est utilisée pour les neurones de la couche cachée.

Une fonction d’activation softmax est utilisée sur la couche de sortie pour transformer les sorties en valeurs de type probabilité et permettre de sélectionner une classe sur dix comme prédiction de sortie du modèle. La perte logarithmique est utilisée comme fonction de perte (appelée categorical_crossentropy dans Keras) et l'algorithme efficace de descente de gradient ADAM est utilisé pour apprendre les poids.

Vous pouvez maintenant ajuster et évaluer le modèle. Le modèle est adapté sur dix époques avec des mises à jour toutes les 200 images. Les données de test sont utilisées comme ensemble de données de validation, vous permettant de voir les compétences du modèle pendant son entraînement. Une valeur détaillée de 2 est utilisée pour réduire la sortie à une ligne pour chaque époque d’entraînement.

Enfin, l'ensemble de données de test est utilisé pour évaluer le modèle et un taux d'erreur de classification est imprimé.

...
# 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))

Après avoir lié tout cela ensemble, la liste complète des codes est fournie ci-dessous.

# 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'exécution de l'exemple peut prendre quelques minutes lorsque vous l'exécutez sur un processeur.

Remarque : Vos résultats peuvent varier en raison de la nature stochastique de l'algorithme ou de la procédure d'évaluation, ou des différences de précision numérique. Pensez à exécuter l’exemple plusieurs fois et comparez le résultat moyen.

Vous devriez voir le résultat ci-dessous. Ce réseau très simple défini en très peu de lignes de code atteint un taux d'erreur respectable de 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%

Réseau neuronal convolutif simple pour le MNIST

Maintenant que vous avez vu comment charger l'ensemble de données MNIST et y entraîner un modèle de perceptron multicouche simple, il est temps de développer un réseau neuronal convolutif ou modèle CNN plus sophistiqué.

Keras offre de nombreuses capacités pour créer des réseaux de neurones convolutifs.

Dans cette section, vous allez créer un CNN simple pour MNIST qui montre comment utiliser tous les aspects d'une implémentation CNN moderne, y compris les couches convolutives, les couches de pooling et les couches d'abandon.

La première étape consiste à importer les classes et fonctions nécessaires.

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
...

Ensuite, vous devez charger l'ensemble de données MNIST et le remodeler pour qu'il soit adapté à la formation d'un CNN. Dans Keras, les couches utilisées pour les convolutions bidimensionnelles attendent des valeurs de pixels avec les dimensions [pixels][largeur][hauteur][canaux].

Notez que vous forcez ce que l'on appelle l'ordre des canaux en dernier pour des raisons de cohérence dans cet exemple.

Dans le cas du RVB, les pixels de la dernière dimension seraient de 3 pour les composants rouge, vert et bleu, et ce serait comme avoir trois entrées d'image pour chaque image couleur. Dans le cas de MNIST, où les valeurs des pixels sont en niveaux de gris, la dimension des pixels est définie sur 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')

Comme auparavant, c'est une bonne idée de normaliser les valeurs des pixels dans la plage 0 et 1 et d'encoder à chaud les variables de sortie.

...
# 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]

Ensuite, définissez votre modèle de réseau neuronal.

Les réseaux de neurones convolutifs sont plus complexes que les perceptrons multicouches standards. Vous commencerez donc par utiliser une structure simple qui utilise tous les éléments pour obtenir des résultats de pointe. Ci-dessous résume l’architecture du réseau.

  1. La première couche cachée est une couche convolutive appelée Convolution2D. La couche comporte 32 cartes de caractéristiques, d'une taille de 5 × 5 et d'une fonction d'activation de redresseur. Il s'agit de la couche d'entrée qui attend des images avec la structure décrite ci-dessus : [pixels][width][height].
  2. Ensuite, définissez une couche de pooling qui prend le maximum appelée MaxPooling2D. Il est configuré avec une taille de piscine de 2×2.
  3. La couche suivante est une couche de régularisation utilisant le dropout appelée Dropout. Il est configuré pour exclure de manière aléatoire 20 % des neurones de la couche afin de réduire le surapprentissage.
  4. Vient ensuite une couche qui convertit les données matricielles 2D en un vecteur appelé Flatten. Il permet à la sortie d'être traitée par des couches standard entièrement connectées.
  5. Vient ensuite une couche entièrement connectée avec 128 neurones et une fonction d’activation de redresseur.
  6. Enfin, la couche de sortie comporte dix neurones pour les dix classes et une fonction d'activation softmax pour générer des prédictions de type probabilité pour chaque classe.

Comme auparavant, le modèle est entraîné à l'aide d'une perte logarithmique et de l'algorithme de descente de gradient 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

Vous évaluez le modèle de la même manière que précédemment avec le perceptron multicouche. Le CNN est réparti sur dix époques avec une taille de lot de 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))

Après avoir lié tout cela ensemble, l’exemple complet est répertorié ci-dessous.

# 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))

Après avoir exécuté l'exemple, la précision du test de formation et de validation est imprimée pour chaque époque, et à la fin, le taux d'erreur de classification est imprimé.

Remarque : Vos résultats peuvent varier en raison de la nature stochastique de l'algorithme ou de la procédure d'évaluation, ou des différences de précision numérique. Pensez à exécuter l’exemple plusieurs fois et comparez le résultat moyen.

L'exécution des époques peut prendre environ 45 secondes sur le GPU (par exemple, sur AWS). Vous pouvez voir que le réseau atteint un taux d'erreur de 1,19 %, ce qui est meilleur que notre simple modèle de perceptron multicouche ci-dessus.

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%

Réseau neuronal convolutif plus vaste pour le MNIST

Maintenant que vous avez vu comment créer un CNN simple, examinons un modèle capable d'obtenir des résultats proches de l'état de l'art.

Vous importerez les classes et les fonctions, puis chargerez et préparerez les données de la même manière que dans l'exemple CNN précédent.

# 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]
...

Cette fois, vous définirez une grande architecture CNN avec des couches convolutives supplémentaires, de pooling maximum et des couches entièrement connectées. La topologie du réseau peut être résumée comme suit :

  1. Couche convolutive avec 30 cartes de caractéristiques de taille 5×5
  2. Couche de pooling prenant le maximum sur 2*2 patchs
  3. Couche convolutive avec 15 cartes de caractéristiques de taille 3×3
  4. Couche de pooling prenant le maximum sur 2*2 patchs
  5. Couche d'abandon avec une probabilité de 20 %
  6. Aplatir le calque
  7. Couche entièrement connectée avec 128 neurones et activation du redresseur
  8. Couche entièrement connectée avec 50 neurones et activation du redresseur
  9. Couche de sortie
...
# 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

Comme les deux expériences précédentes, le modèle est ajusté sur dix époques avec une taille de lot de 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))

Après avoir lié tout cela ensemble, l’exemple complet est répertorié ci-dessous.

# 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'exécution de l'exemple imprime la précision des ensembles de données de formation et de validation de chaque époque et un taux d'erreur de classification finale.

Remarque : Vos résultats peuvent varier en raison de la nature stochastique de l'algorithme ou de la procédure d'évaluation, ou des différences de précision numérique. Pensez à exécuter l’exemple plusieurs fois et comparez le résultat moyen.

Le modèle prend environ 100 secondes pour s’exécuter par époque. Ce modèle légèrement plus grand atteint un taux d'erreur de classification respectable de 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%

Il ne s'agit pas d'une topologie de réseau optimisée. Il ne s’agit pas non plus d’une reproduction d’une topologie de réseau issue d’un article récent. Vous avez de nombreuses possibilités d’ajuster et d’améliorer ce modèle.

Quel est le meilleur score de taux d’erreur que vous puissiez obtenir ?

Postez votre configuration et votre meilleur score dans les commentaires.

Ressources sur le MNIST

L'ensemble de données MNIST est très bien étudié. Vous trouverez ci-dessous quelques ressources supplémentaires que vous pourriez consulter.

  • La page Web officielle de l'ensemble de données du MNIST
  • Page Web de Rodrigo Benenson qui répertorie les résultats de pointe
  • Concours Kaggle qui utilise cet ensemble de données (consultez les scripts et les sections du forum pour un exemple de code)
  • Modèle en lecture seule formé sur MNIST que vous pouvez tester dans votre navigateur (très cool)

Résumé

Dans cet article, vous avez découvert le problème de reconnaissance des chiffres manuscrits du MNIST et les modèles d'apprentissage profond développés en Python à l'aide de la bibliothèque Keras capables d'obtenir d'excellents résultats.

En suivant ce didacticiel, vous avez appris :

  • Comment charger l'ensemble de données MNIST dans Keras et générer des tracés de l'ensemble de données
  • Comment remodeler l'ensemble de données MNIST et développer un modèle de perceptron multicouche simple mais performant sur le problème
  • Comment utiliser Keras pour créer des modèles de réseaux neuronaux convolutifs pour MNIST
  • Comment développer et évaluer des modèles CNN plus grands pour le MNIST, capables d'obtenir des résultats proches de ceux de classe mondiale.

Avez-vous des questions sur la reconnaissance de l'écriture manuscrite avec le deep learning ou sur cet article ? Posez votre question dans les commentaires et je ferai de mon mieux pour y répondre.

Articles connexes