Keras est simple est puissant pour les réseaux de neurones en python. Essayez-le dans cette recette pas à pas
Dans mon article Reconnaissance de Chiffres Manuscrits avec scikit-learn, nous avons comment entraîner un réseau de neurones simple avec scikit-learn. Et nous avons pu classer des images de chiffres manuscrits avec une précision supérieure à 90%.
Mais scikit-learn n'est pas vraiment adapté aux réseaux de neurones.
Son but est en fait de fournir une interface pour l'entraînement et le test d'une grande variété d'algorithmes de machine learning : réseaux de neurones, mais aussi support vector machines, plus proches voisins, arbres de décision, etc. En effet, dans vos projets de machine learning, vous passerez le plus clair de votre temps à choisir le bon algorithme, et à le régler pour obtenir les meilleures performances. Scikit-learn a été conçu pour faciliter ces tâches au maximum.
Cependant, pour ce qui est des réseaux de neurones, scikit-learn a deux désavantages :
Dans cet article, nous allons répéter la classification des chiffres manuscrits avec Keras, une interface de haut niveau vers TensorFlow pour le deep learning. Vous apprendrez à :
Dans un futur article, nous verrons comment faire du deep learning avec Keras.
Prérequis:
Pour interagir avec ce notebook, le plus simple est de le faire tourner sur Google Colab en cliquant ici.
Si vous préférez le faire tourner sur votre machine, suivez les instructions ci-dessous.
D'abord, Installez Anaconda pour le Machine Learning et la Data Science avec python.
Créez un environnement pour ce tutoriel :
conda create -n hwd_keras
Activez-le :
conda activate hwd_keras
Installez les packages nécessaires dans l'environnement :
conda install keras scikit-learn jupyter matplotlib
Enfin, téléchargez ce notebook et ouvrez le avec jupyter notebook :
maldives-master
maldives-master/handwritten_digits_keras
jupyter notebook handwritten_digits_keras_fr.ipynb
Comme dans reconnaissance de chiffres manuscrits avec scikit-learn, nous allons utiliser l'échantillon de chiffres fourni avec scikit-learn. Les chiffres sont des images 8x8, et nous allons les traiter avec un réseau de neurones avec:
D'abord, initialisons nos outils et chargeons l'échantillon:
import numpy as np
import matplotlib.pyplot as plt
import os
# for some reason, the following
# is needed to run on mac os X
os.environ['KMP_DUPLICATE_LIB_OK']='True'
from sklearn import datasets
digits = datasets.load_digits()
La couche d'entrée requiert un tableau 1D de 64 valeurs, mais nos images sont 2D, avec 8x8 pixels. Nous devons donc les sérialiser:
x = digits.images.reshape((len(digits.images), -1))
x.shape
De plus, un peu de travail est nécessaire avant de pouvoir utiliser les étiquettes.
Pour l'instant, digits.target
contient le chiffre auquel correspond chaque image dans l'échantillon:
digits.target
Mais avec Keras, nous devons construire un réseau avec 10 neurones de sortie. C'est aussi le cas avec scikit-learn, bien que ce soit caché à l'utilisateur. Au cours de l'entraînement, Keras devra comparer les 10 valeurs de sortie de ces neurones à l'étiquette pour donner un retour au réseau et lui permettre de s'améliorer. Mais comment pouvons nous comparer un tableau de 10 valeurs à une seule valeur, celle de l'étiquette?
La solution est de traduire chaque étiquette en un tableau de taille 10 (une technique appelée one-hot encoding):
0
donne [1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
1
donne [0, 1, 0, 0, 0, 0, 0, 0, 0, 0]
9
donne [0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
Après cela, les valeurs des 10 neurones de sortie, qui sont des probabilités entre 0 et 1, peuvent être directement comparées aux 10 valeurs de l'étiquette.
De cette façon, pour un chiffre donné, par exemple 0, le réseau de neurones sera entraîné à donner une probabilité élevée sur le premier neurone de sortie, et une faible probabilité sur les neurones suivants.
Cet encodage se fait facilement avec les outils fournis par Keras:
from keras.utils import np_utils
y = np_utils.to_categorical(digits.target,10)
print(digits.target)
print(y)
Nous pouvons maintenant partager nos données entre un échantillon d'entraînement et un échantillon de test:
split_limit=1000
x_train = x[:split_limit]
y_train = y[:split_limit]
x_test = x[split_limit:]
y_test = y[split_limit:]
Les 1000 premières images et étiquettes seront utilisées pour l'entraînement, et les suivantes pour l'évaluation des performances de notre réseau.
Après avoir importé les outils nécessaires, créons le réseau de neurones.
from keras import layers, Model, optimizers, regularizers
# Création de la couche d'entrée
#
# On spécifie que cette couche doit
# avoir 64 neurones, un pour chaque
# pixel dans nos images.
# Les neurones d'entrée ne font rien,
# ils se contentent de transférer la
# valeur sur chaque pixel à la couche
# suivante.
img_input = layers.Input(shape=(64,))
# Création de la couche cachée
#
# Cette couche est dense, ce qui veut
# dire que chacun de ses neurones est
# connecté à tous les neurones de la
# couche précédente (la couche d'entrée).
# Nous parlerons de l'activation dans un
# futur post.
tmp = layers.Dense(15,
activation='sigmoid')(img_input)
# Création de la couche de sortie
#
# La couche de sortie est dense également.
# Elle doit avoir 10 neurones, correspondant
# aux 10 catégories de chiffres.
output = layers.Dense(10,
activation='softmax')(tmp)
# Création du réseau de neurones
# à partir des couches
model = Model(img_input, output)
# Impression d'une description du réseau
model.summary()
# =================================================
# Merci de pas prêter attention à cette partie.
# Nous parlerons de la régularisation plus tard.
# Pour l'instant, il suffit de noter que la
# régularisation aide le réseau à converger
# correctement.
# J'ai rajouté cette régularisation ici car elle
# est effectuée par défaut dans scikit-learn,
# et que nous voulons pouvoir comparer les résultats
# de keras et scikit-learn.
l2_rate = 1e-4
for layer in model.layers:
if hasattr(layer, 'kernel_regularizer'):
layer.kernel_regularizer = regularizers.l2(l2_rate)
layer.bias_regularizer = regularizers.l2(l2_rate)
layer.activity_regularizer = regularizers.l2(l2_rate)
# =================================================
# Définition de la méthode d'apprentissage,
# et compilation du modèle.
#
# Le modèle doit être compilé pour être
# entraîné et utilisé.
# Les arguments loss, optimizer, et metric
# seront couverts dans un futur post.
model.compile(loss='categorical_crossentropy',
optimizer=optimizers.SGD(lr=0.1, momentum=0.9),
metrics=['accuracy'])
Finalement, nous pouvons entraîner le réseau:
history = model.fit(x=x_train, y=y_train, validation_data=(x_test,y_test),
batch_size=100, epochs=50)
Les prédictions du réseau de neurones sont évaluées pour tous les exemples de l'échantillon de test:
predictions = model.predict(x_test)
print(predictions[3])
Pour chaque exemple, la prédiction est un tableau de 10 valeurs. Chaque valeur est la probabilité, estimée par le réseau, que l'image appartienne à une catégorie donnée.
La catégorie prédite est celle avec la probabilité la plus grande.
Écrivons maintenant une petite fonction pour afficher une image donnée, et imprimer la catégorie prédite ainsi que la catégorie réelle:
def plot_prediction(index):
print('predicted probabilities:')
print(predictions[index])
print('predicted category', np.argmax(predictions[index]))
print('true probabilities:')
print(y_test[index])
print('true category', np.argmax(y_test[index]))
img = x_test[index].reshape(8,8)
plt.imshow(img)
Dans cette fonction, on obtient la catégorie avec np.argmax
qui, pour un tableau, retourne l'index correspondant à la valeur maximum.
Utilisons cette fonction pour regarder quelques exemples (changez juste l'index pour choisir un autre exemple):
plot_prediction(3)
Enfin, calculons la précision, c'est à dire la probabilité de classer les chiffres correctement.
On calcule cette précision sur l'échantillon de test, qui n'a pas été utilisé dans l'entraînement du réseau. À nouveau, on utilise np.argmax
pour obtenir les catégories vraies et prédites pour chaque exemple.
# Le deuxième argument de argmax spécifie
# que l'on souhaite conserver la première
# dimension du tableau.
# Ainsi, argmax est calculé pour chaque
# exemple.
# Sans cet argument, argmax retournerait
# une seule valeur, la probabilité maximum
# dans le tableau complet,
# en considérant l'ensemble des exemples
y_test_best = np.argmax(y_test,1)
print(y_test_best.shape)
predictions_best = np.argmax(predictions,1)
from sklearn.metrics import accuracy_score
accuracy_score(y_test_best, predictions_best)
Vous devriez obtenir une précision autour de 91%, similaire à celle que nous avons obtenue dans les mêmes conditions avec scikit-learn.
Le résultat n'est pas reproductible, et la précision variera à chaque fois que vous ré-entraînerez un nouveau réseau. Personnellement, j'obtiens généralement une précision entre 90 et 93%.
Et pour vous, que se passe-t'il lorsque vous répétez l'exercice?
Dans ce post, vous avez entraîné votre premier réseau de neurones avec keras.
Keras est un outil incontournable, et nous l'utiliserons régulièrement sur ce blog.
Pour voir comment utiliser le deep learning pour la reconnaissance d'images avec Keras et TensorFlow, jetez un oeil aux articles suivants:
N'hésitez pas à me donner votre avis dans les commentaires ! Je répondrai à toutes les questions.
Et si vous avez aimé cet article, vous pouvez souscrire à ma newsletter pour être prévenu lorsque j'en sortirai un nouveau. Pas plus d'un mail par semaine, promis!
Rejoignez ma mailing list pour plus de posts et du contenu exclusif: