Comment construire un réseau de neurones pour reconnaître les chiffres manuscrits avec TensorFlow

introduction

Les réseaux de neurones sont utilisés comme méthode d’apprentissage en profondeur, l’un des nombreux sous-domaines de l’intelligence artificielle. Ils ont été proposés pour la première fois il y a environ 70 ans pour tenter de simuler le fonctionnement du cerveau humain, mais sous une forme beaucoup plus simplifiée. Des «neurones» individuels sont connectés en couches, des pondérations étant attribuées pour déterminer la façon dont le neurone répond lorsque des signaux sont propagés à travers le réseau. Auparavant, les réseaux de neurones étaient limités par le nombre de neurones qu’ils pouvaient simuler et, par conséquent, par la complexité de l’apprentissage qu’ils pouvaient atteindre. Mais au cours des dernières années, grâce aux progrès réalisés dans le développement de matériel, nous avons pu construire des réseaux très profonds et les former sur d’énormes jeux de données afin de réaliser des avancées décisives en matière d’intelligence machine.

Ces avancées ont permis aux machines d’égaler et de dépasser les capacités de l’homme à effectuer certaines tâches. Une de ces tâches est la reconnaissance d’objet. Bien que les machines aient toujours été incapables de faire correspondre la vision humaine, les progrès récents en apprentissage en profondeur ont permis de créer des réseaux de neurones capables de reconnaître des objets, des visages, du texte et même des émotions.

Dans ce tutoriel, vous allez implémenter une petite sous-section de reconnaissance de chiffre de reconnaissance d’objet. En utilisant TensorFlow, une bibliothèque Python à code source libre développée par les laboratoires Google Brain pour des recherches approfondies sur l’apprentissage, vous prendrez des images dessinées à la main des nombres de 0 à 9 et réseau de neurones pour reconnaître et prédire la bonne étiquette pour le chiffre affiché.

Bien que vous n’ayez pas besoin d’une expérience préalable dans l’apprentissage approfondi pratique ou dans TensorFlow pour suivre ce didacticiel, nous supposons une certaine familiarité avec les termes et concepts d’apprentissage automatique tels que la formation et les tests, les caractéristiques et labels, l’optimisation et l’évaluation. Pour en savoir plus sur ces concepts, consultez An Introduction à l’apprentissage automatique.

Conditions préalables

Pour compléter ce tutoriel, vous aurez besoin de:

  • Un environnement de développement Python 3 local, y compris https : //pypi.org/project/pip/ [pip], un outil pour installer des packages Python, et venv, pour créer des environnements virtuels.

Étape 1 - Configuration du projet

Avant de pouvoir développer le programme de reconnaissance, vous devez installer quelques dépendances et créer un espace de travail pour stocker vos fichiers.

Nous allons utiliser un environnement virtuel Python 3 pour gérer les dépendances de notre projet. Créez un nouveau répertoire pour votre projet et accédez au nouveau répertoire:

mkdir tensorflow-demo
cd tensorflow-demo

Exécutez les commandes suivantes pour configurer l’environnement virtuel de ce tutoriel:

python3 -m venv tensorflow-demo
source tensorflow-demo/bin/activate

Ensuite, installez les bibliothèques que vous utiliserez dans ce tutoriel. Nous utiliserons des versions spécifiques de ces bibliothèques en créant un fichier + Requirements.txt + dans le répertoire du projet, qui spécifie les exigences et la version dont nous avons besoin. Créez le fichier + Requirements.txt +:

touch requirements.txt

Ouvrez le fichier dans votre éditeur de texte et ajoutez les lignes suivantes pour spécifier les bibliothèques Image, NumPy et TensorFlow et leurs versions:

conditions.txt

image==1.5.20
numpy==1.14.3
tensorflow==1.4.0

Enregistrez le fichier et quittez l’éditeur. Puis installez ces bibliothèques avec la commande suivante:

pip install -r requirements.txt

Avec les dépendances installées, nous pouvons commencer à travailler sur notre projet.

Étape 2 - Importation du jeu de données MNIST

L’ensemble de données que nous allons utiliser dans ce didacticiel s’appelle MNIST et constitue un classique de la communauté de l’apprentissage automatique. Cet ensemble de données est constitué d’images de chiffres manuscrits, d’une taille de 28x28 pixels. Voici quelques exemples de chiffres inclus dans le jeu de données:

image: https: //assets.digitalocean.com/articles/handwriting_tensorflow_python3/wBCHXId.png [Exemples d’images MNIST]

Créons un programme Python pour travailler avec cet ensemble de données. Nous allons utiliser un fichier pour tout notre travail dans ce tutoriel. Créez un nouveau fichier nommé + main.py +:

touch main.py

Ouvrez maintenant ce fichier dans l’éditeur de texte de votre choix et ajoutez cette ligne de code au fichier pour importer la bibliothèque TensorFlow:

main.py

import tensorflow as tf

Ajoutez les lignes de code suivantes à votre fichier pour importer le jeu de données MNIST et stocker les données d’image dans la variable + mnist +:

main.py

...
from tensorflow.examples.tutorials.mnist import input_data


mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)  # y labels are oh-encoded

Lors de la lecture des données, nous utilisons un codage à chaud pour représenter les étiquettes (le chiffre réel tiré, par exemple). “3”) des images. One-hot-encoding utilise un vecteur de valeurs binaires pour représenter des valeurs numériques ou catégoriques. Comme nos étiquettes sont pour les chiffres de 0 à 9, le vecteur contient dix valeurs, une pour chaque chiffre possible. L’une de ces valeurs est définie sur 1 pour représenter le chiffre correspondant à cet index du vecteur et les autres sont définies sur 0. Par exemple, le chiffre 3 est représenté par le vecteur + [0, 0, 0, 1, 0, 0, 0, 0, 0, 0] +. Comme la valeur d’indice 3 est stockée sous 1, le vecteur représente donc le chiffre 3.

Pour représenter les images elles-mêmes, les 28x28 pixels sont aplatis en un vecteur 1D de 784 pixels. Chacun des 784 pixels composant l’image est stocké en tant que valeur entre 0 et 255. Cela détermine l’échelle de gris du pixel, car nos images ne sont présentées qu’en noir et blanc. Ainsi, un pixel noir est représenté par 255 et un pixel blanc par 0, avec les différentes nuances de gris quelque part entre les deux.

Nous pouvons utiliser la variable + mnist + pour déterminer la taille du jeu de données que nous venons d’importer. En examinant le + num_examples + pour chacun des trois sous-ensembles, nous pouvons déterminer que le jeu de données a été divisé en 55 000 images pour la formation, 5 000 pour la validation et 10 000 pour les tests. Ajoutez les lignes suivantes à votre fichier:

main.py

...
n_train = mnist.train.num_examples  # 55,000
n_validation = mnist.validation.num_examples  # 5000
n_test = mnist.test.num_examples  # 10,000

Maintenant que nos données sont importées, il est temps de penser au réseau de neurones.

Étape 3 - Définition de l’architecture du réseau de neurones

L’architecture du réseau de neurones fait référence à des éléments tels que le nombre de couches dans le réseau, le nombre d’unités dans chaque couche et la manière dont les unités sont connectées entre les couches. Comme les réseaux de neurones sont vaguement inspirés par le fonctionnement du cerveau humain, le terme unité est utilisé ici pour représenter ce que nous pourrions biologiquement penser à un neurone. Comme les neurones qui transmettent des signaux dans le cerveau, les unités prennent en entrée certaines valeurs des unités précédentes, effectuent un calcul, puis transmettent la nouvelle valeur en sortie aux autres unités. Ces unités sont superposées pour former le réseau, en commençant au minimum par une couche pour la saisie des valeurs et une couche pour la sortie des valeurs. Le terme "couche masquée" est utilisé pour toutes les couches entre les couches d’entrée et de sortie, c’est-à-dire ceux "cachés" du monde réel.

Différentes architectures peuvent produire des résultats très différents, car la performance peut être pensée en fonction de l’architecture, entre autres, comme les paramètres, les données et la durée de la formation.

Ajoutez les lignes de code suivantes à votre fichier pour stocker le nombre d’unités par couche dans les variables globales. Cela nous permet de modifier l’architecture du réseau en un seul endroit et à la fin du didacticiel, vous pourrez tester vous-même l’impact du nombre de couches et d’unités sur les résultats de notre modèle:

main.py

...
n_input = 784  # input layer (28x28 pixels)
n_hidden1 = 512  # 1st hidden layer
n_hidden2 = 256  # 2nd hidden layer
n_hidden3 = 128  # 3rd hidden layer
n_output = 10  # output layer (0-9 digits)

Le diagramme suivant montre une visualisation de l’architecture que nous avons conçue, chaque couche étant entièrement connectée aux couches environnantes:

image: https: //assets.digitalocean.com/articles/handwriting_tensorflow_python3/cnwitLM.png [Schéma d’un réseau de neurones]

Le terme «réseau neuronal profond» se rapporte au nombre de couches cachées, «superficiel» désignant généralement une seule couche cachée et «profond» faisant référence à plusieurs couches cachées. Avec suffisamment de données d’apprentissage, un réseau neuronal peu profond avec un nombre suffisant d’unités devrait théoriquement être en mesure de représenter toute fonction pouvant être gérée par un réseau neuronal profond. Mais il est souvent plus efficace en termes de calcul d’utiliser un réseau de neurones profonds plus petit pour réaliser la même tâche qui nécessiterait un réseau peu profond avec davantage d’unités cachées de manière exponentielle. Les réseaux neuronaux peu profonds rencontrent également souvent des problèmes de sur-adaptation, dans lesquels le réseau mémorise essentiellement les données d’entraînement qu’il a vues et n’est pas en mesure de généraliser les connaissances à de nouvelles données. C’est pourquoi les réseaux de neurones profonds sont plus couramment utilisés: les multiples couches entre les données d’entrée brutes et l’étiquette de sortie permettent au réseau d’apprendre des caractéristiques à différents niveaux d’abstraction, le rendant ainsi plus apte à généraliser.

Les autres éléments du réseau de neurones qu’il convient de définir ici sont les hyperparamètres. Contrairement aux paramètres qui seront mis à jour pendant l’entraînement, ces valeurs sont définies initialement et restent constantes tout au long du processus. Dans votre fichier, définissez les variables et valeurs suivantes:

main.py

...
learning_rate = 1e-4
n_iterations = 1000
batch_size = 128
dropout = 0.5

Le taux d’apprentissage représente le degré d’ajustement des paramètres à chaque étape du processus d’apprentissage. Ces ajustements sont un élément clé de la formation: après chaque passage dans le réseau, nous ajustons légèrement les poids pour essayer de réduire les pertes. Des vitesses d’apprentissage plus importantes peuvent converger plus rapidement, mais peuvent également dépasser les valeurs optimales à mesure qu’elles sont mises à jour. Le nombre d’itérations indique le nombre de fois où nous passons l’étape de formation et la taille de lot, le nombre d’exemples de formation que nous utilisons à chaque étape. La variable + dropout + représente un seuil auquel nous éliminons certaines unités de manière aléatoire. Nous allons utiliser + dropout + dans notre couche cachée finale pour donner à chaque unité 50% de chances d’être éliminée à chaque étape de l’entraînement. Cela aide à prévenir la suralimentation.

Nous avons maintenant défini l’architecture de notre réseau de neurones et les hyperparamètres qui ont une incidence sur le processus d’apprentissage. L’étape suivante consiste à créer le réseau sous forme de graphique TensorFlow.

Étape 4 - Construction du graphique TensorFlow

Pour construire notre réseau, nous allons configurer le réseau en tant que graphique de calcul à exécuter par TensorFlow. Le concept de base de TensorFlow est le tensor, une structure de données similaire à un tableau ou une liste. initialisés, manipulés au fur et à mesure qu’ils sont passés à travers le graphique et mis à jour au cours du processus d’apprentissage.

Nous commencerons par définir trois tenseurs en tant que placeholders, qui sont des tenseurs dans lesquels nous indiquerons des valeurs ultérieurement. Ajoutez ce qui suit dans votre fichier:

main.py

...
X = tf.placeholder("float", [None, n_input])
Y = tf.placeholder("float", [None, n_output])
keep_prob = tf.placeholder(tf.float32)

Le seul paramètre à spécifier lors de la déclaration est la taille des données que nous allons alimenter. Pour + X +, nous utilisons une forme de + [None, 784] +, où + None + représente toute quantité, car nous alimenterons un nombre non défini d’images de 784 pixels. La forme de + Y + est + [None, 10] + car nous allons l’utiliser pour un nombre indéfini de sorties d’étiquettes, avec 10 classes possibles. Le tenseur keep_prob + est utilisé pour contrôler le taux d’abandon. Nous l’initialisons comme un paramètre fictif plutôt que comme une variable immuable, car nous souhaitons utiliser le même tenseur à la fois pour la formation (lorsque + dropout + est défini sur +0.5+ `) et testing (lorsque + dropout + est défini sur + 1.0 + `).

Les paramètres que le réseau mettra à jour au cours du processus de formation sont les valeurs + weight + et + polarisation +. Nous devons donc définir une valeur initiale plutôt qu’un espace réservé vide. Ces valeurs correspondent essentiellement à l’apprentissage du réseau, telles qu’elles sont utilisées dans les fonctions d’activation des neurones, représentant la force des connexions entre les unités.

Puisque les valeurs sont optimisées pendant l’entraînement, nous pourrions les remettre à zéro pour l’instant. Mais la valeur initiale a en réalité un impact significatif sur la précision finale du modèle. Nous utiliserons des valeurs aléatoires à partir d’une distribution normale tronquée pour les pondérations. Nous voulons qu’ils soient proches de zéro afin qu’ils puissent s’ajuster dans un sens positif ou négatif, et légèrement différents, afin qu’ils génèrent des erreurs différentes. Cela garantira que le modèle apprend quelque chose d’utile. Ajoutez ces lignes:

main.py

...
weights = {
   'w1': tf.Variable(tf.truncated_normal([n_input, n_hidden1], stddev=0.1)),
   'w2': tf.Variable(tf.truncated_normal([n_hidden1, n_hidden2], stddev=0.1)),
   'w3': tf.Variable(tf.truncated_normal([n_hidden2, n_hidden3], stddev=0.1)),
   'out': tf.Variable(tf.truncated_normal([n_hidden3, n_output], stddev=0.1)),
}

Pour le biais, nous utilisons une petite valeur constante pour nous assurer que les tenseurs s’activent dans les étages initiaux et contribuent donc à la propagation. Les poids et les tenseurs de polarisation sont stockés dans des objets de dictionnaire pour faciliter l’accès. Ajoutez ce code à votre fichier pour définir les biais:

main.py

...
biases = {
   'b1': tf.Variable(tf.constant(0.1, shape=[n_hidden1])),
   'b2': tf.Variable(tf.constant(0.1, shape=[n_hidden2])),
   'b3': tf.Variable(tf.constant(0.1, shape=[n_hidden3])),
   'out': tf.Variable(tf.constant(0.1, shape=[n_output]))
}

Ensuite, configurez les couches du réseau en définissant les opérations qui manipuleront les tenseurs. Ajoutez ces lignes à votre fichier:

main.py

...
layer_1 = tf.add(tf.matmul(X, weights['w1']), biases['b1'])
layer_2 = tf.add(tf.matmul(layer_1, weights['w2']), biases['b2'])
layer_3 = tf.add(tf.matmul(layer_2, weights['w3']), biases['b3'])
layer_drop = tf.nn.dropout(layer_3, keep_prob)
output_layer = tf.matmul(layer_3, weights['out']) + biases['out']

Chaque couche masquée exécute la multiplication de matrice sur les sorties de la couche précédente et les pondérations de la couche actuelle, et ajoute le biais à ces valeurs. À la dernière couche masquée, nous appliquerons une opération de suppression en utilisant notre valeur + keep_prob + de 0,5.

La dernière étape de la création du graphique consiste à définir la fonction de perte que nous souhaitons optimiser. Un choix courant de fonction de perte dans les programmes TensorFlow est cross-entropy, également connu sous le nom de log-loss, qui quantifie la différence entre deux distributions de probabilités (les prédictions et les étiquettes). Une classification parfaite entraînerait une entropie croisée égale à 0, la perte étant totalement minimisée.

Nous devons également choisir l’algorithme d’optimisation qui sera utilisé pour minimiser la fonction de perte. Un processus nommé gradient descente optimization est une méthode courante pour trouver le minimum (local) d’une fonction en effectuant des étapes itératives le long du gradient dans une direction négative (décroissante). Plusieurs choix d’algorithmes d’optimisation de descente de gradient ont déjà été implémentés dans TensorFlow, et dans ce tutoriel, nous utiliserons l’optimiseur Adam. Cela s’étend lors de l’optimisation de la descente de gradient en utilisant la quantité de mouvement pour accélérer le processus en calculant une moyenne pondérée de manière exponentielle des gradients et en l’utilisant dans les ajustements. Ajoutez le code suivant à votre fichier:

main.py

...
cross_entropy = tf.reduce_mean(
   tf.nn.softmax_cross_entropy_with_logits(
       labels=Y, logits=output_layer
       ))
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)

Nous avons maintenant défini le réseau et l’a construit avec TensorFlow. L’étape suivante consiste à transmettre des données via le graphique pour le former, puis à vérifier qu’il a réellement appris quelque chose.

Étape 5 - Formation et test

Le processus de formation implique d’alimenter l’ensemble de données de formation via le graphique et d’optimiser la fonction de perte. Chaque fois que le réseau parcourt un lot d’images d’entraînement supplémentaires, il met à jour les paramètres afin de réduire les pertes afin de prédire avec plus de précision les chiffres affichés. Le processus de test implique l’exécution de notre ensemble de données de test via le graphe formé, et le suivi du nombre d’images correctement prédites, afin que nous puissions calculer la précision.

Avant de commencer le processus de formation, nous définirons notre méthode d’évaluation de la précision afin de pouvoir l’imprimer sur de mini-lots de données pendant la formation. Ces relevés imprimés nous permettront de vérifier que, de la première à la dernière itération, les pertes diminuent et que la précision augmente; ils nous permettront également de savoir si nous avons exécuté suffisamment d’itérations pour atteindre un résultat cohérent et optimal:

main.py

...
correct_pred = tf.equal(tf.argmax(output_layer, 1), tf.argmax(Y, 1))
accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))

Dans + correct_pred +, nous utilisons la fonction + arg_max + pour comparer les images prédites correctement en examinant les + output_layer + (prédictions) et + Y + (étiquettes), et nous utilisons les + égal + fonction pour renvoyer ceci sous forme de liste de Booleans. Nous pouvons ensuite convertir cette liste en flottants et calculer la moyenne pour obtenir un score de précision total.

Nous sommes maintenant prêts à initialiser une session pour exécuter le graphique. Au cours de cette session, nous alimenterons le réseau avec nos exemples de formation. Une fois formés, nous alimenterons le même graphique avec de nouveaux exemples de test afin de déterminer la précision du modèle. Ajoutez les lignes de code suivantes à votre fichier:

main.py

...
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init)

Le processus de formation en apprentissage en profondeur consiste essentiellement à optimiser la fonction de perte. Ici, nous visons à minimiser la différence entre les étiquettes prédites des images et les vraies étiquettes des images. Le processus comporte quatre étapes qui sont répétées pour un nombre défini d’itérations:

  • Propager les valeurs en avant sur le réseau

  • Calculer la perte

  • Propager les valeurs en arrière à travers le réseau

  • Mettre à jour les paramètres

À chaque étape de l’entraînement, les paramètres sont légèrement ajustés pour tenter de réduire les pertes pour l’étape suivante. Au fur et à mesure que l’apprentissage progresse, nous devrions constater une réduction des pertes. Nous pourrons éventuellement arrêter la formation et utiliser le réseau comme modèle pour tester nos nouvelles données.

Ajoutez ce code au fichier:

main.py

...
# train on mini batches
for i in range(n_iterations):
   batch_x, batch_y = mnist.train.next_batch(batch_size)
   sess.run(train_step, feed_dict={
       X: batch_x, Y: batch_y, keep_prob: dropout
       })

   # print loss and accuracy (per minibatch)
   if i % 100 == 0:
       minibatch_loss, minibatch_accuracy = sess.run(
           [cross_entropy, accuracy],
           feed_dict={X: batch_x, Y: batch_y, keep_prob: 1.0}
           )
       print(
           "Iteration",
           str(i),
           "\t| Loss =",
           str(minibatch_loss),
           "\t| Accuracy =",
           str(minibatch_accuracy)
           )

Après 100 itérations de chaque étape de la formation au cours desquelles nous alimentons un mini-lot d’images via le réseau, nous imprimons la perte et la précision de ce lot. Notez que nous ne devrions pas nous attendre à une perte décroissante ni à une précision croissante, car les valeurs sont par lot et non pour le modèle entier. Nous utilisons des mini-lots d’images plutôt que de les transmettre individuellement pour accélérer le processus de formation et permettre au réseau de voir un certain nombre d’exemples différents avant de mettre à jour les paramètres.

Une fois la formation terminée, nous pouvons exécuter la session sur les images de test. Cette fois, nous utilisons un taux d’abandon + keep_prob + de + 1.0 + pour nous assurer que toutes les unités sont actives dans le processus de test.

Ajoutez ce code au fichier:

main.py

...
test_accuracy = sess.run(accuracy, feed_dict={X: mnist.test.images, Y: mnist.test.labels, keep_prob: 1.0})
print("\nAccuracy on test set:", test_accuracy)

Il est maintenant temps de lancer notre programme et de voir avec quelle précision notre réseau de neurones peut reconnaître ces chiffres manuscrits. Enregistrez le fichier + main.py + et exécutez la commande suivante dans le terminal pour exécuter le script:

python main.py

Vous obtiendrez un résultat similaire à celui-ci, bien que les résultats individuels en termes de perte et de précision puissent varier légèrement:

OutputIteration 0     | Loss = 3.67079    | Accuracy = 0.140625
Iteration 100   | Loss = 0.492122   | Accuracy = 0.84375
Iteration 200   | Loss = 0.421595   | Accuracy = 0.882812
Iteration 300   | Loss = 0.307726   | Accuracy = 0.921875
Iteration 400   | Loss = 0.392948   | Accuracy = 0.882812
Iteration 500   | Loss = 0.371461   | Accuracy = 0.90625
Iteration 600   | Loss = 0.378425   | Accuracy = 0.882812
Iteration 700   | Loss = 0.338605   | Accuracy = 0.914062
Iteration 800   | Loss = 0.379697   | Accuracy = 0.875
Iteration 900   | Loss = 0.444303   | Accuracy = 0.90625

Accuracy on test set: 0.9206

Pour essayer d’améliorer la précision de notre modèle ou pour en savoir plus sur l’impact de l’optimisation des hyperparamètres, nous pouvons tester l’effet de la modification du taux d’apprentissage, du seuil d’abandon, de la taille du lot et du nombre d’itérations. Nous pouvons également modifier le nombre d’unités dans nos couches masquées et la quantité de couches masquées elles-mêmes afin de voir comment différentes architectures augmentent ou diminuent la précision du modèle.

Pour démontrer que le réseau reconnaît effectivement les images dessinées à la main, testons-le sur une seule image.

Si vous êtes sur un ordinateur local et que vous souhaitez utiliser votre propre numéro, vous pouvez utiliser un éditeur graphique pour créer votre propre image de 28 x 28 pixels d’un chiffre. Sinon, vous pouvez utiliser + curl + pour télécharger l’exemple de test ci-dessous sur votre serveur ou votre ordinateur:

curl -O https://raw.githubusercontent.com/do-community/tensorflow-digit-recognition/master/test_img.png

Ouvrez le fichier + main.py + dans votre éditeur et ajoutez les lignes de code suivantes en haut du fichier pour importer deux bibliothèques nécessaires à la manipulation d’images.

main.py

import numpy as np
from PIL import Image
...

Puis, à la fin du fichier, ajoutez la ligne de code suivante pour charger l’image test du chiffre manuscrit:

main.py

...
img = np.invert(Image.open("test_img.png").convert('L')).ravel()

La fonction + open + de la bibliothèque + Image + charge l’image de test sous la forme d’un tableau 4D contenant les trois canaux de couleur RVB et la transparence Alpha. Ce n’est pas la même représentation que celle que nous utilisions précédemment lors de la lecture de l’ensemble de données avec TensorFlow. Nous devons donc effectuer un travail supplémentaire pour correspondre au format.

Premièrement, nous utilisons la fonction + convert + avec le paramètre + L + pour réduire la représentation RGBA 4D à un canal de couleur en niveaux de gris. Nous stockons ceci dans un tableau + numpy + et l’inversons en utilisant + np.invert +, car la matrice actuelle représente le noir en tant que 0 et le blanc en tant que 255, alors que nous avons besoin du contraire. Enfin, nous appelons + ravel + pour aplatir le tableau.

Maintenant que les données de l’image sont correctement structurées, nous pouvons exécuter une session de la même manière que précédemment, mais cette fois-ci, l’alimentation d’une seule image à des fins de test.

Ajoutez le code suivant à votre fichier pour tester l’image et imprimer l’étiquette sortie.

main.py

...
prediction = sess.run(tf.argmax(output_layer, 1), feed_dict={X: [img]})
print ("Prediction for test image:", np.squeeze(prediction))

La fonction + np.squeeze + est appelée sur la prédiction pour renvoyer le nombre entier unique du tableau (c’est-à-dire pour aller de [2] à 2). La sortie résultante montre que le réseau a reconnu cette image en tant que chiffre 2.

OutputPrediction for test image: 2

Vous pouvez essayer de tester le réseau avec des images plus complexes - des chiffres qui ressemblent à d’autres chiffres, par exemple, ou des chiffres mal dessinés ou mal dessinés - pour voir si le résultat est bon.

Conclusion

Dans ce didacticiel, vous avez appris à un réseau de neurones à classer le jeu de données MNIST avec une précision d’environ 92% et à le tester sur une image de votre choix. Les recherches actuelles les plus récentes permettent d’atteindre environ 99% du même problème en utilisant des architectures de réseau plus complexes faisant appel à des couches de convolution. Celles-ci utilisent la structure 2D de l’image pour mieux représenter le contenu, contrairement à notre méthode qui aplatit tous les pixels en un vecteur de 784 unités. Vous pouvez en savoir plus sur ce sujet sur le site TensorFlow et voir les documents de recherche détaillant les résultats les plus précis sur le site http: // yann. .lecun.com / exdb / mnist / [site Web du MNIST].

Maintenant que vous savez construire et former un réseau de neurones, vous pouvez essayer d’utiliser cette implémentation sur vos propres données ou la tester sur d’autres jeux de données populaires tels que Google StreetView. Numéros de maison, ou le jeu de données CIFAR-10 pour une reconnaissance plus générale des images.