Créer un modèle de vision par ordinateur avec TensorFlow

1. Avant de commencer

Dans cet atelier de programmation, vous allez créer un modèle de vision par ordinateur capable de reconnaître des vêtements avec TensorFlow.

Conditions préalables

  • Une connaissance approfondie de Python
  • Compétences de base en programmation

Points abordés

Dans cet atelier de programmation, vous allez:

  • Entraîner un réseau de neurones à reconnaître des articles de mode
  • Effectuez une série d'exercices pour vous guider dans l'expérimentation des différentes couches du réseau

Objectifs de l'atelier

  • Un réseau de neurones qui identifie les articles vestimentaires

Prérequis

Si vous n'avez jamais créé de réseau de neurones pour la vision par ordinateur avec TensorFlow, vous pouvez utiliser Colaboratory, un environnement basé sur un navigateur et contenant toutes les dépendances requises. Vous trouverez le code pour le reste de l'atelier de programmation en cours d'exécution dans Colab.

Sinon, le langage principal que vous utiliserez pour l'entraînement des modèles est Python. Vous devez donc l'installer. De plus, TensorFlow et la bibliothèque NumPy sont nécessaires. Pour en savoir plus et installer TensorFlow, Installez NumPy ici.

2. Commencer à coder

Commencez par parcourir le notebook Colab exécutable.

Commencez par importer TensorFlow.

import tensorflow as tf
print(tf.__version__)

Vous allez entraîner un réseau de neurones pour qu'il reconnaisse des vêtements dans un ensemble de données commun appelé Fashion MNIST. Il contient 70 000 vêtements dans 10 catégories différentes. Chaque vêtement se trouve dans une image en nuances de gris de 28 x 28 pixels. En voici quelques exemples:

Les libellés associés à l'ensemble de données sont les suivants:

Libellé

Description

0

T-shirt/Haut

1

Trouser

2

Pull

3

Robe

4

Coat

5

Sandales

6

Shirt

7

Baskets

8

Sac

9

Bottines

Les données Fashion MNIST sont disponibles dans l'API tf.keras.datasets. Chargez-la comme suit:

mnist = tf.keras.datasets.fashion_mnist

En appelant load_data sur cet objet, vous obtenez deux ensembles de deux listes : les valeurs training et les tests, qui représentent les images qui représentent des articles vestimentaires et leurs étiquettes.

(training_images, training_labels), (test_images, test_labels) = mnist.load_data()

À quoi ces valeurs ressemblent-elles ? Imprimez une image d'entraînement et un libellé d'entraînement pour les afficher. Vous pouvez tester différents index dans le tableau.

import matplotlib.pyplot as plt
plt.imshow(training_images[0])
print(training_labels[0])
print(training_images[0])

L'impression des données de l'élément 0 ressemble à ceci:

Notez que toutes les valeurs sont des entiers compris entre 0 et 255. Lors de l'entraînement d'un réseau de neurones, il est plus facile de traiter toutes les valeurs comprises entre 0 et 1, un processus appelé normalisation. Heureusement, Python permet de normaliser une liste de cette façon, sans boucle.

training_images  = training_images / 255.0
test_images = test_images / 255.0

Vous pouvez également examiner 42, un démarrage différent de celui à l'index 0.

Vous vous demandez peut-être pourquoi il existe deux ensembles de données : l'entraînement et le test.

L'idée est de disposer d'un ensemble de données d'entraînement et d'un autre ensemble de données que le modèle n'a pas encore trouvées afin de déterminer s'il est capable de classifier des valeurs. Après tout, lorsque vous avez terminé, vous souhaitez utiliser le modèle avec des données auxquelles il n'avait pas accès auparavant. De plus, sans données de test distinctes, vous courez le risque que le réseau ne mémorise que ses données d'entraînement sans généraliser ses connaissances.

3. Concevoir le modèle

Concevez maintenant le modèle. Vous avez trois calques. Parcourez-les une par une et explorez les différents types de calques et leurs paramètres utilisés.

model = tf.keras.models.Sequential([tf.keras.layers.Flatten(), 
                                    tf.keras.layers.Dense(128, activation=tf.nn.relu), 
                                    tf.keras.layers.Dense(10, activation=tf.nn.softmax)])
  • Sequential définit une séquence de couches dans le réseau de neurones.
  • Flatten prend un carré et le transforme en vecteur unidimensionnel.
  • Dense ajoute une couche de neurones.
  • Les fonctions Activation précisent comment procéder pour chaque couche de neurones. Il existe de nombreuses options, mais vous pouvez les utiliser pour le moment:
  • Relu signifie que si X est supérieur à 0, X renvoie. Sinon, renvoie 0. Il transmet uniquement les valeurs de 0 ou plus à la couche suivante du réseau.
  • Softmax utilise un ensemble de valeurs et choisit efficacement la plus grande. Par exemple, si le résultat de la dernière couche se présente comme suit : [0.1, 0.1, 0.05, 0.1, 9.5, 0.1, 0.05, 0.05, 0.05], cela vous évite de devoir trier pour la plus grande valeur : [0,0,0,0,1,0,0,0].

4. Compiler et entraîner le modèle

Maintenant que le modèle est défini, vous devez le créer. Créez un modèle en le compilant avec des fonctions optimizer et loss, puis entraînez-le sur vos données d'entraînement et vos étiquettes. L'objectif est de faire en sorte que le modèle détermine la relation entre les données d'entraînement et les étiquettes d'entraînement. Par la suite, vous voulez que votre modèle affiche des données qui ressemblent à celles de vos données d'entraînement, puis effectuer une prédiction sur ces données.

Vous remarquerez que metrics= est utilisé comme paramètre. Il permet à TensorFlow de générer des rapports sur la précision de l'entraînement en comparant les résultats prédits aux réponses connues (les étiquettes).

model.compile(optimizer = tf.keras.optimizers.Adam(),
              loss = 'sparse_categorical_crossentropy',
              metrics=['accuracy'])

model.fit(training_images, training_labels, epochs=5)

Lorsque model.fit s'exécute, vous constatez la perte et la justesse:

Epoch 1/5
60000/60000 [=======] - 6s 101us/sample - loss: 0.4964 - acc: 0.8247
Epoch 2/5
60000/60000 [=======] - 5s 86us/sample - loss: 0.3720 - acc: 0.8656
Epoch 3/5
60000/60000 [=======] - 5s 85us/sample - loss: 0.3335 - acc: 0.8780
Epoch 4/5
60000/60000 [=======] - 6s 103us/sample - loss: 0.3134 - acc: 0.8844
Epoch 5/5
60000/60000 [=======] - 6s 94us/sample - loss: 0.2931 - acc: 0.8926

Une fois l'entraînement terminé, vous verrez une valeur de précision à la fin de l'époque finale. Elle devrait ressembler à ceci : 0,8926 comme ci-dessus. Cela indique que votre réseau de neurones est environ 89% précis pour la classification des données d'entraînement. En d'autres termes, il a réussi à identifier une correspondance de structure entre l'image et les étiquettes qui fonctionnaient 89% du temps. Plutôt mal, mais pas mal, car elle n'a été entraînée que pendant cinq époques et a été réalisée rapidement.

5. Tester le modèle

Quelles seraient les performances du modèle avec les données qu'il n'a pas vues ? C'est pourquoi vous disposez d'un ensemble de test. Vous appelez model.evaluate et transmettez les deux ensembles, et il signale la perte pour chacun d'entre eux. Essayez cette commande :

model.evaluate(test_images, test_labels)

Et voici le résultat:

10000/10000 [=====] - 1s 56us/sample - loss: 0.3365 - acc: 0.8789
[0.33648381242752073, 0.8789]

Cet exemple a renvoyé une justesse de 0,8789, soit un taux de précision de 88 %. Les valeurs peuvent être légèrement différentes.

Comme prévu, le modèle n'est pas aussi précis avec les données inconnues qu'avec l'entraînement. À mesure que vous découvrez TensorFlow, vous découvrirez comment y remédier.

Pour aller plus loin, essayez les exercices à l'étape suivante.

6. Exercices d'exploration

Exercice 1

Pour ce premier exercice, exécutez le code suivant:

classifications = model.predict(test_images)
print(classifications[0])

Un ensemble de classifications est créé pour chacune des images de test, puis il imprime la première entrée des classifications. Après l'exécution, le résultat est une liste de nombres. À votre avis, qu'est-ce que cela signifie ?

Essayez d'exécuter print(test_labels[0]) pour obtenir un 9. Est-ce que vous comprenez pourquoi cette liste se présente comme prévu ?

Le résultat du modèle est une liste de 10 chiffres. Ces chiffres sont la probabilité que la valeur classée soit l'étiquette correspondante. Par exemple, la première valeur de la liste correspond à la probabilité que le vêtement soit de classe 0 et la suivante à 1. Vous remarquerez que ces probabilités sont très faibles, sauf une. De plus, en raison de Softmax, toutes les probabilités dans la liste correspondent à 1,0.

La liste et les étiquettes sont basées sur 0. Par conséquent, la cheville ayant l'étiquette 9 signifie que c'est le 10e des 10 cours. Si la liste présente le 10e élément avec la valeur la plus élevée, cela signifie que le réseau de neurones a prédit que l'élément qu'il classait est probablement une cheville.

Exercice 2

Examinez les couches de votre modèle. Testez différentes valeurs pour la couche dense avec 512 neurons.

Quels résultats obtiennent-ils pour la perte et la formation ? Pourquoi pensez-vous que c'est le cas ?

Par exemple, si vous passez à 1 024 neurons, il vous faut effectuer davantage de calculs, ce qui ralentit le processus. Toutefois, dans ce cas, elles ont un bon impact, car le modèle est plus précis. Mais cela ne veut pas dire que mieux c'est. Vous risquez de très vite diminuer les retours.

Exercice 3

Que se passe-t-il si vous supprimez la couche Flatten() ? Pourquoi pensez-vous que c'est le cas ?

Une erreur s'affiche concernant la forme des données. Même si les détails de l'erreur peuvent paraître vagues pour l'instant, cela renforce la règle selon laquelle la première couche de votre réseau doit avoir la même forme que vos données. À l'heure actuelle, vos données sont composées d'images 28 x 28 et de 28 couches de 28 neurons. Il est donc plus logique d'agréger ces dimensions de 28,28 dans un format 784 x 1.

Au lieu d'écrire tout le code, ajoutez le calque Flatten() au début. Lorsque les tableaux sont chargés dans le modèle ultérieurement, ils sont automatiquement aplatis.

Exercice 4

Examinez les couches finales (de sortie). Pourquoi ? Que se passerait-il si vous disposiez d'un nombre supérieur à 10 ?

Essayez d'entraîner le réseau avec 5. Vous obtenez une erreur dès qu'elle détecte une valeur inattendue. Une autre règle de base : le nombre de neurones dans la dernière couche doit correspondre au nombre de classes pour lesquelles vous effectuez une classification. Dans ce cas, il s'agit des chiffres de 0 à 9. Il y en a donc 10, et vous devez donc avoir 10 neurons dans votre couche finale.

Exercice 5

Tenez compte des effets des couches supplémentaires dans le réseau. Que se passera-t-il si vous ajoutez une couche comprise entre celle avec 512 et la couche finale avec 10 ?

Il n'y a pas d'impact significatif, car ces données sont relativement simples. Pour des données beaucoup plus complexes, il est souvent nécessaire d'ajouter des couches.

Exercice 6

Avant l'entraînement, vous avez normalisé les données en remplaçant les valeurs 0 à 255 par des valeurs comprises entre 0 et 1. Que se passerait-il si nous l'supprimions ? Voici le code complet pour essayer (notez que les deux lignes qui normalisent les données sont commentées).

Pourquoi pensez-vous que les résultats obtenus sont différents ? Il y a une bonne réponse sur cette page.

import tensorflow as tf
print(tf.__version__)
mnist = tf.keras.datasets.fashion_mnist
(training_images, training_labels), (test_images, test_labels) = mnist.load_data()
#training_images=training_images/255.0
#test_images=test_images/255.0
model = tf.keras.models.Sequential([
  tf.keras.layers.Flatten(),
  tf.keras.layers.Dense(512, activation=tf.nn.relu),
  tf.keras.layers.Dense(10, activation=tf.nn.softmax)
])
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy')
model.fit(training_images, training_labels, epochs=5)
model.evaluate(test_images, test_labels)
classifications = model.predict(test_images)
print(classifications[0])
print(test_labels[0])

7. Explorer les rappels

Plus tôt, lorsque vous vous êtes entraîné pour des époques supplémentaires, vous avez rencontré un problème dans lequel votre perte pouvait évoluer. Il peut s'écouler un certain temps avant que l'entraînement ait permis de le faire. Vous pensiez peut-être que vous pourriez arrêter l'entraînement lorsque vous atteignez la valeur souhaitée, par exemple une précision de 95 %. Si vous atteignez ce nombre après trois époques, pourquoi ne pas attendre que le processus se termine ?

Comme pour tout autre programme, vous avez des rappels ! Découvrez leur fonctionnement:

import tensorflow as tf

class myCallback(tf.keras.callbacks.Callback):
  def on_epoch_end(self, epoch, logs={}):
    if(logs.get('accuracy')>0.95):
      print("\nReached 95% accuracy so cancelling training!")
      self.model.stop_training = True

callbacks = myCallback()
mnist = tf.keras.datasets.fashion_mnist
(training_images, training_labels), (test_images, test_labels) = mnist.load_data()
training_images=training_images/255.0
test_images=test_images/255.0
model = tf.keras.models.Sequential([
  tf.keras.layers.Flatten(),
  tf.keras.layers.Dense(512, activation=tf.nn.relu),
  tf.keras.layers.Dense(10, activation=tf.nn.softmax)
])
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
model.fit(training_images, training_labels, epochs=5, callbacks=[callbacks])

8. Félicitations

Vous avez créé votre premier modèle de vision par ordinateur ! Pour savoir comment améliorer vos modèles de vision par ordinateur, consultez Créer des convolutions et effectuer des pools.