Ce repository contient le code source à analyser et compléter pour la journée perception du workshop ROS4PRO.
tensorflow* et keras sont deux modules Python qui permettent de construire des réseaux de neurones apprenants. Nous allons les utiliser pour entraîner un réseau de neurones à reconnaître des chiffres écrits manuellement au feutre avec différentes calligraphies, ce que l'on appelle aussi classifier.
- BAC+2 et +
- Bonne compréhension de Python et numpy
{{}}
Suivant ton expérience de Python et des modules nécessaires, tu pourras utiliser ces ressources :
-
Documentation générale sur numpy :
-
Pour la partie extraction des faces des cubes et pré-processing, nous utiliserons le module
scikit-image
: -
Enfin, pour la classification des images, nous utiliserons le module
keras
inclus dans le moduletensorflow
depuis sa version 2. Un point d'entrée sur l'API Séquentielle de keras peut être consulté sur cette page :
L'entraînement des réseaux de neurones avec le module tensorflow2
se fera de préférence dans un environnement virtuel Python (EVP) qui permet de travailler dans une environnement dédié.
Pour la compréhension et la création de ton EVP consulte la FAQ Python : environnement virtuel
Dans tout le document le prompt du terminal sera noté (tf2) jlc@pikatchou $
: le préfixe (tf2)
est là pour bien rappeler que le travail Python se fait
dans l'Environnement Virtuel Python tf2.
📥 Le code source à télécharger se trouve ici : télécharge l'archive zip, extrait le dossier ros_perception-master
par exemple dans ton dossier ~/catkin_ws
renome le sous le nom ros_perception
et installe les paquets Python complémentaires :
(tf2) jlc@pikatchou $ cd ~/catkin_ws
(tf2) jlc@pikatchou $ unzip ~/Téléchargements/ros4pro_perception-master.zip
(tf2) jlc@pikatchou $ mv ros4pro_perception-master ros4pro_perception
(tf2) jlc@pikatchou $ cd ros4pro_perception
(tf2) jlc@pikatchou $ pip install -r requirements.txt
Tape la commande jupyter notebook
dans le dossier ros4pro_perception
; tu peux alors charger les deux notebooks à trous pour la prise en main du machine learning avec tensorflow et keras :
-
notebook/TP1_MNIST_dense.ipynb
: utilise ce notebook pour l'acquisition des bases sur le machine learning- chargement et utilisation de la banque d'images MNIST utilisée pour l'entraînement des réseaux,
- construction, entraînement et exploitation d'un réseau de neurones dense conduisant à un taux de reconnaissance des images MNIST voisin de 98 %.
-
notebook/TP2_MNIST_convol.ipynb
: utilise ensuite ce notebook pour la construction d'un réseau convolutif, son entraînement avec les images MNIST et son exploitation, conduisant à un taux de reconnaissance voisin de 99 %.
Une fois familiarisé avec les principes de construction des réseaux denses et convolutifs, tu peux utiliser les programmes Python du répertoire ros4pro_perception/src/
.
-
Chargement des images MNIST
Ouvre maintenant le fichiersrc/learning.py
, prends connaissance du code, puis lance le programme.
Avant d'appuyer sur la touche ENTER, assure-toi que tu sais répondre aux questions :- Que contiennent les variables
x_train
ety_train
? - Pourquoi la fonction
load_data
renvoie-t-elle également les donnéesx_test
ety_test
? - Quelles sont les formes (shape) respectives de
x_train
ety_train
?
- Que contiennent les variables
-
Prévisualisation des données brutes
Appuye sur la touche ENTER pour continuer, et observe les images :- Quelles sont les valeurs des pixels blancs et noirs ?
- Observe les données et leurs labels. Toutes les images sont elles simples à classifier correctement ?
-
Préparation des données
Ferme la fenêtre et appuye à nouveau sur la touche ENTER :- Quelles sont les formes de
x_train
ety_train
maintenant ? - Pourquoi ces changements ?
- Quelles sont les formes de
-
Prévisualisation des données préparées
Appuye à nouveau sur la touche ENTER et observe les images :- Quelles sont les valeurs des pixels blanc et noirs maintenant ?
- Regarde la fonction
prepare_input
: quelle transformation des images est effectuée ?
-
Le modèle du réseau convolutif
- Arrête le script. Dans le fichier source
learning.py
modifie la fonctionbuild_model
pour implémenter un réseau convolutif semblable à celui implémenté dans le notebookTP2_MNIST_convol.ipynb
. - Relance le script et fait défiler jusqu'à la partie 5) (tu peux modifier
SHOW_SAMPLES
pour ne pas afficher toutes les fenêtres...) : vérifie les informations des couches sur le résumé du modèle...
- Arrête le script. Dans le fichier source
-
La fonction de coût et l'optimiseur
Arrête le script et vérifie :- la fonction de coût et l'optimiseur utilisés dans l'appel à
modele.compile(...)
- la fonction de coût et l'optimiseur utilisés dans l'appel à
-
Entraînement :
- Observe la fonction
train_model
: vérifie la présence et le paramétrage de la gestion de l'over-fit. - Relance le code jusqu'au déclenchement de la partie 7) : tu devrais voir les itérations d'entraînement se succéder et s'arrêter sur un événement early stopping.
- Observe la fonction
-
Poids appris
Appuye sur la touche ENTER pour visualiser les noyaux convolutifs appris par le réseau de neurones :- noyaux de la première couche : arrives-tu à distinguer le genre de features qui seront extraites par chacun ?
- Peux-tu faire de même pour la deuxième couche ?
-
Activations
Appuye sur la touche ENTER, puis entre un indice (un entier inférieur à 12000 (pourquoi 1200 ?)) :- Après la première couche de convolution, les features extraites correspondent-elles à celles que tu imaginais ?
- Après la première couche de pooling, les features présentes auparavant sont-elles conservées ?
- Après la deuxième couche de pooling, l'information spatiale est toujours présente ? Autrement dit, les activations ressemblent elles toujours à des images ?
-
Entraînement final
Arrête le script. Jusqu'à présent, nous avons travaillé sur l'ensemble des images montrant des chiffres de '0' à '9', mais pour la suite nous n'aurons besoin que des images de '1' et de '2' :- Change la valeur de la variable
CLASSES
pour ne garder que les classes qui nous intéressent. - Change
SHOW_SAMPLES
,SHOW_WEIGHTS
etSHOW_ACTIV
pour sauter les affichage graphiques... - Entraînne le réseau avec le nouveau jeu de données réduites, puis sauvegarde-le en donnant le nom d'un répertoire où stocker les fichiers du réseau entraîné.
- Change la valeur de la variable
Tu peux passer maintenant à la Partie Vision qui permettra, une fois achevée, d'observer les inférences du réseau avec les images des cubes correctement traitées...
Le but de la partie Vision est de traiter les images fournies par la caméra du robot :
pour trouver les contours des cubes :
et extraire des images compatibles MNIST :
qui seront envoyées au réseau de neurone pour classification en '1' ou '2'...
Ouvre le fichier src/detection.py
et lance le script. Une des images exemple issue de la caméra du robot apparaît :
-
Observe les valeurs de pixels ? Quelles sont les valeurs de pixels blancs et noirs ?
-
De manière générale, la face des cubes est-elle semblable aux images MNIST ?
Appuye sur la touche ENTER pour afficher l'image binarisée :
- Peux-tu penser à un algorithme permettant d'arriver à un résultat similaire ?
Dans le code, observe la fonction binarize
:
- À quoi sert la fonction
threshold_otsu
? (voir au besoin la documentationscikit-image
).
En commentant successivement les lignes les utilisant, observe l'impact de chacune des fonctions suivantes :
closing
clear_border
convex_hull_object
Pourquoi faut-il éviter d'avoir des cubes qui touchent les bords de l'image ?
Appuye sur la touche ENTER pour faire défiler quelques images dont les contours ont été détectés.
Observe la fonction get_box_contours
:
- À quoi sert la fonction
label
? - À quoi sert le paramètre
area
? - À quoi sert la fonction numpy
argsort
utilisée à la fin pour le ré-arragement des contours ? Pourquoi cette opération est elle importante ?
Appuye sur la touche ENTER pour faire défiler quelques images dont les vignettes ont été extraites.
Observe la fonction get_sprites
: qu'est ce qu'une "transformation projective" ?
Pendant la phase d'apprentissage, nous avons étudié la préparation qui était faite des images.
Les vignettes présentées au réseau de neurones doivent aussi être traitées pour avoir les mêmes caractéristiques que les images d'entrainement MNIST :
- complète la fonction
preprocess_sprites
pour effectuer ce traitement...
Une fois fait, exécute le script jusqu'à la fin et conclue sur l'allure des images traitées.
Tu peux maintenant ouvrir le fichier main.py
pour tester l'intégration de la détection et de la reconnaissance par réseau apprenant...
Il est maintenant temps d'intégrer les deux parties du pipeline pour l'utilisation finale. Ouvre le fichier main.py
à la racine du projet.
Pour que les deux parties du pipeline s'adaptent correctement, tu as complété la fonction preprocess_sprites
pour mettre les vignettes renvoyées par la partie détection dans un format compatible avec celui des images MNIST.
Exécute maintenant le programme main.py
: donne le chemin d'un dossier qui contient les fichiers du réseau entraîné et tu devrais commencer à obtenir la reconnaissance des chiffres '1' et '2' dans les images fournies.
Il faudra certainement refaire plusieurs fois l'entraînement du réseau en jouant sur plusieurs paramètres avant d'obtenir un réseau entraîné qui fonctionne correctement :
-
la valeur de la graine
SEED
peut conduire à un état initial des poids du réseau qui donne un entraînement meilleur ou pas... -
augmenter/diminuer
BATCH_SIZE
peut modifier les temps de calcul et la qualité du réseau entraîné... -
augmenter/diminuer le paramètre
patience
du callbackEarlyStopping
... -
enfin, tous les paramètres qui définissent les couches de convolution et de spooling du réseau convolutif sont autant de possibilités d'améliorer (ou pas) les performances du réseau entraîné....
À toi de jouer pour obtenir un réseau entraîné classifiant le mieux possible les chiffres '1' et '2' dans les images fournies par la caméra du robot...
Pour confirmer la qualité de ton réseau entraîné tu peux enregistrer tes propres fichiers PNG avec les images faites avec la caméra du robot en utilisant le service ROS /get_image
.
Aide-toi des indications du paragraphe 2.4. Récupérer les images de la caméra en Python dans la section Manipulation/Poppy Ergo Jr : tu peux ajouter une instruction cv2.imwrite(<file_name>, image)
pour écrire tes propres fichiers PNG dans le répertoire data/ergo_cubes/perso
et modifier en conséquence la variable img_dir
du fichier main.py
.
Lance le programme et observe les performances de ton réseau opérant sur tes propres images.