TP « neural computing » (4A)
FIchiers à downloader
- wii_move.tar.gz Fichiers à télécharger
Préambule important :
- TP à réaliser en binôme au maximum, vous
pouvez faire le TP tout seul si vous le désirez. Aucun de
groupe de 3 (ou plus) ne sera accepté ! - Vous devez absolument suivre scrupuleusement les indications
de ce document, car votre travail sera noté par un programme
(le programme « test » qui vous est fournit),
ainsi un programme qui plante, ou simplement qui utilise mal les
formats imposés donnera lieu à la note 0! Vous avez
les données et les programmes pour tout tester, faites le! - Votre programme ne doit pas planter (utilisez valgrind
pour vérifier votre utilisation de la mémoire), un
programme qui plante -> 0. Attention, un programme avec des
erreurs de pointeurs peut très bien marcher sur une machine
et pas sur une autre, ou même marche un jour et planter le
lendemain … Il n’y aura pas de réclamation possible dans ce
cas, à vous de vérifier que votre programme ne
comporte pas d’erreur de ce type, en utilisant valgrind. - Votre programme doit être léger (par opposition
à ce que j’appelle la « Loi
de Lourd ») : ça veux dire s’exécuter
suffisamment rapidement et utiliser une quantité mémoire
raisonnable. Si vous ne partez pas dans des « délires »
cette contrainte n’en est pas vraiment une, mais je préfère
prévenir depuis qu’un binôme de 2A m’ont « fièrement »rendu un programme censé faire un système d’écriture
intuitive pour téléphone mobile, nécessitant
1H30 pour composer le message « bonjour » …
Clairement vous me faites un truc pareil en 4A , c’est 0, direct et
non négociable. - J’encourage fortement les échanges d’idée,
surtout sur ce type de TP. Cependant notez que l’échange
d’idée s’arrête là ou commence la copie de codes
! J’utiliserai Baldrpour traquer les tentatives de fraudes.
Et maintenant qu’on en a finit avec les avertissements d’usage,
attaquons le plus intéressant …
Le Sujet
Introduction
Dans un jeux vidéo classique commandé par un clavier
ou un joystick, les données sont simple à interpréter,
c’est une simple variable qui est initialisé par une librairie
de gestion du joystick. Dans le cadre d’utilisation d’une Wiimote
les données sont d’un autre type, il s’agit d’une suite de
mesure d’accélération sur 3 axes. Voici ce que cela
donne graphiquement :
Voici trois occurences d’un même mouvement (un « oui »),
vu sous deux angles différents.
Et voici sous deux angles différents, les données
correspondant à trois mouvements de type « non »
Chaque graphique représente 3 répétitions
d’un même geste (en 3 couleur différentes). L’image de
gauche correspond à un geste que j’appelle un « oui »
(on incline verticalement la wiimote comme si c’était la tête
d’une marionnette disant oui). L’image de droite correspond à
un « non » (on oriente la wiimote à
droite puis à gauche alternativement comme une marionnette
ferait non de la tête). Note : il ne s’agit pas de la mesure
des déplacement de la wiimote mais les accélérations
mesurée (accélération != mouvements).
Il est manifeste ces 2 graphiques sont facilement différentiable
visuellement. Si on regarde un troisième graphique il est
facile , visuellement, de dire si le mouvement correspondant est un
« oui » ou un « non ».
Par contre écrire un algorithme (une suite d’instruction)
faisant automatiquement ce type d’analyse serait excessivement
complexe à mettre en oeuvre. Surtout, il faudrait écrire
du code pour chaque nouveau type de geste que l’on veux être
capable de reconnaître automatiquement. C’est pour cela qu’on
va utiliser des réseaux neuronaux. La spécificité
des techniques neuronales est qu’ils apprennent par des exemples.
Cela nous donnera la possibilité d’aborder ce problème
élégamment On ne codera pas une solution au problème
de reconnaissance d’un geste mais plutôt une chaîne
d’analyse de données neuronales qui sera re-utilisable. Ainsi
une fois cette chaîne écrite, on pourra gérer de
nouveaux gestes sans ajouter de nouvelle lignes de codes au
programme. Il suffira « d’enregistrer » des
exemples de nouveaux gestes et de relancer le programme
d’apprentissage, ce qui ne nécessitera aucune écriture
de code supplémentaire …
L’objectif
L’objectif de ce TP est de faire un système de
reconnaissance de geste utilisant une Wiimote.
L’évaluation de ce TP se fera via le calcul d’une matrice
de confusion, meilleur sera le système de reconnaissance
que vous aurez produit, meilleur sera votre note à ce TP. Pour
cela nous allons utiliser des librairies « open source »
:
- La libwiimote
: cette librairie permet d’accéder simplement aux données
que produit la wiimote. Les seules qui vont nous intéresser
ici sont les données de l’accéléromètre
3D. Cela veux dire qu’on dispose de mesures d’accélération
sur 3 axes, environ 100 fois par seconde. Pour le TP je vous
fournirait les données directement sous forme de fichier donc
vous n’aurez pas à vous occuper de cette partie. Si ce n’est
qu’a vous intéresser de savoir comment sont produites ces
données. Mais si vous voulez continuer après le TP ou
simplement vouloir tester vous même votre détecteur de
geste, vous aurez à installer cette librairie pour utiliser
une wiimote avec votre PC. Cette librairie s’appuie sur la librairie
bluez qui sert àcommuniquer en « bluetooth » avec la wiimote.
- La librairie FANN :
pour « Fast Artificial Neural Network », cette
librairie permet de programmer simplement des réseaux
neuronaux. Cette librairie que nous allons utiliser pour former le
coeur de notre système de reconnaissance. Cette librairie est
normalement déjà installé sur les machines de
TP.
Dans le cadre du TP nous n’auront besoin que de FANN. Vu que nous
avons un temps limité je vous fournis aussi quelques codes de
base. Nous n’auront pas besoin de tous ces codes dans le TP.
Typiquement la partie acquisition des données ne nous sera pas
utile dans le cadre de ce cours, mais je vous la met à
disposition, si vous avez envi de créer votre propre base de
donnée de mouvements.
Conseils pour aborder ce TP
- Essayer d’abord de faire tourner cette chaîne de
traitement sans aucune modification et essayez de bien comprendre
toutes les informations la composant. - Essayez ensuite d’apporter des modifications aux endroits
proposés dans le but d’améliorer le système de
reconnaissance. Ce faisant vérifiez bien que les nouvelles
sorties des programmes modifiés respectent bien les formats.
Ensuite déroulez toute la chaîne de traitement avec vos
modifications et vérifiez (avec le programme « test »
que cela améliore vraiment le système de
reconnaissance. - ATTENTION ! lors du rendu par mail, pensez bien à
envoyer :-
- votre fichier C de paramétrisation en attachement (1
seul fichier), avec en commentaire sur la première ligne de
votre code les noms composant le binôme. Le nom du
fichier doit être le nom de base de votre mail (par exemple
: « dupond.c » si votre mail est
dupond@et.esiea.fr .) - votre fichier de réseau neuronaux (le résultat
du programme « train »). Le nom du
fichier doit être le nom de base de votre mail.
(« dupond.net » si on reprend l’exemple du
point au-dessus). - Vérifiez bien qu’il s’agit bien des bonnes versions
de ces fichiers, car vous allez en générer un bon
paquet et les erreurs seront fréquentes, à vous
d’être rigoureux dans vos noms de fichier ainsi que dans le
déroulement de la chaîne de traitement. Je vous
conseille très fortement de dérouler completement la
chaîne de traitement du début à la fin jusqu’àl’étape finale de test, avant d’envoyer votre travail.
- votre fichier C de paramétrisation en attachement (1
-
Base de code
Voici la base de code que je vous fournit pour ce TP, seul les
programmes « param » et éventuellement
« train » sont à modifier. La suite de
logiciels, telle que fourni en l’état, est peu efficace car la
paramétrisation est « simplissime ». À
vous de l’améliorer. Le niveau de validation (en terme de
pourcentage de reconnaissance) minimum du module sera donné
une fois qu’on aura un peu progressé sur le problème.
Téléchargez l’archive attaché à ce
mail et installez la dans un répertoire, pour compiler les
codes C suivez les instructions en entête des fichiers. Il y a
un fichier « log.txt » qui vous montre les
étapes de base sur un ensemble de donnée de test.
wii_move
wii_move : ce programme vous
permet d’enregistrer des mouvements fait avec une wiimote. C’est avec
ce programme qu’on a crée les données de ce TP.
Il s’utilise en ligne de commande comme
cela :
./wii_move WII_ADDR username move1 move2 move3 [...]
Le premier argument (WII_ADDR) est l’adresse physique de la wiimote, elle s’obtient en lançant la commande :
hcitool scan
et en appuyant simultanément sur les boutons 1 et 2 de la wiimote, au bout de quelques seconde l’adresse de la wiimote s’affiche (ça ressemble à quelque chose du style : 00:19:1D:D5:0E:CF).
Il se peut que le service bluetooth ne soit pas démarré sur votre machine, faites alors (avant toutes les autres opérations), votre mot de passe vous sera demandé :
Le second paramètre est le nom de la personne qui fait les mouvements avec la wiimote, c’est une information importante dans la mesure ou les gestes dépendent de ceux qui les fonts… On peut même imaginer un système qui essaye de reconnaître non seulement les gestes, mais aussi qui les fait… Bref à notre niveau ce n’est pas primordial mais ça peut être utile plus tard…
Tous les paramètres suivants sont une liste de noms de gestes. Ces mots seront affichés dans un ordre aléatoire, il suffira alors de les exécuter avec la wiimote dans la main et la gâchette enfoncé (bouton « B ») tout au long du mouvement. A la fin de l’enregistrement de chaque mouvement la wiimote vibre légèrement pour indiqué que l’enregistrement du mouvement effectué est terminé. Ce programme crée à la fin de chaque mouvement un fichier dont le nom se compose comme ceci : « username_moveName_nbr.txt » (nom de l’utilisateur, puis le nom du mouvement, et enfin un compteur).
Cela fait un fichier par mouvement, le contenu des fichiers ressemble à ceci :
BEGIN 0.962 0.000 -0.308 0 0.462 0.200 -0.308 20 0.077 0.360 -0.192 30 -0.231 0.520 -0.192 40 -0.538 0.640 -0.269 44 -0.808 0.720 -0.154 62 -0.923 0.800 0.000 72 -1.115 0.800 0.115 81 -1.115 0.800 0.346 85 -1.115 0.720 0.462 103 END
Les mots clé, BEGIN et END sont là pour indiquer le début et la fin d’un mouvement, les données s’interprètent ligne par ligne, les trois premières colonnes correspondent aux accélérations mesurées sur les axes x, y, z, la quatrième colonne est le temps en microsecondes, mesuré depuis le moment où la gâchette (bouton « B ») à été enfoncé.
param
Préambule : Nous verrons en cours pourquoi nous ne pouvons pas directement utiliser directement les sorties de la wiimote en entrée du réseaux de neurones, et nous verrons en TP des pistes pour trouver une bonne paramétrisation. Pour le moment ce programme n’est qu’une coquille pratiquement vide, les paramètres extraits dans ce code ne sont que : le minimum, la moyenne et le maximum des accélérations sur les 3 axes. C’est clairement insuffisant : on ne peut résumer un mouvement complexe par ces simples trois paramètres. Ce sera à vous de trouver une paramétrisation plus fine, qui donnera de meilleurs résultats.
param : Ce programme est au coeur de ce TP, c’est celui qui transforme les sorties « brut » des accéléromètres de la wiimote en des entrées « compréhensible » par le réseau de neurones. Il s’utilise en entrée/sortie standard :
cat *_jump_*.txt | ./param 4 2 >> trainData.pat
Voilà comment interpréter cette ligne de commande : on prend tous les fichiers de type «*_jump_*.txt», on passe ces fichiers « au travers » l’application « param ». Celle-ci transforme les données brut, de manière à ce qu’elles soient utilisables par notre réseau de neurones, et les ajoute dans le fichier « trainData.pat ». Elle va écrire des données au format FANN. Ce format exige les informations suivantes pour chaque exemple :
*
Les données à mettre en entrée du réseau de neurones (les données de la wiimote) : il s’agit d’une suite de nombres, un vecteur.
*
comment classer ces données : la sortie attendu correspondant à l’entrée fournie. Cette information se fourni aussi sous forme de vecteur, il y a autant de composantes dans le vecteur qu’il y a de classes à reconnaître. Ce vecteur doit être à -1 sur toutes les composantes , sauf la composante correspondante à l’exemple traité( ou elle doit être à 1).
La ligne de commande précédente on créer des exemples pour le mouvement « jump » et il s’agit du mouvement numéro 3 sur un total de 4 mouvements différents. (Attention c’est le mouvement 3 et non pas 2 car on commence à compter à 0).
Voici un exemple d’un couple entrée/sortie au format FANN :
-0.577000 -0.040947 0.692000 -2.200000 -0.690823 0.200000 -0.654000 0.814953 2.462000 -1.000000 -1.000000 1.000000 -1.000000
La première ligne est constituée de données de la wiimote (transformé par le programme « param »).
La deuxième ligne correspond (puisqu’on fait de l’apprentissage supervisé) à la sortie attendue (ici le troisième ([2]) type de mouvement sur 4 possibles).
Un fichier de donnée d’apprentissage comporte toute une liste suite de couples exemples de ce type (parfois appelé « pattern »), avec en plus, une première ligne indiquant le nombre de couples total qu’il y a dans le fichier, ainsi que le nombre de composantes sur le vecteur d’entrée et de sortie. Cette entête sera en général créée « à la main » après avoir constitué le fichier d’exemples, car il est plus facile de savoir à posteriori combien d’exemples on utilisera…
Ici l’entête d’un tel fichier serait :
24 9 4
24 paires d’exemple, le réseau de neurones à 9 entrée et 4 sorties.
Et voici le début d’un fichier complet d’entraînement au format FANN
24 9 4 -0.577000 -0.040947 0.692000 -2.200000 -0.690823 0.200000 -0.654000 0.814953 2.462000 -1.000000 -1.000000 1.000000 -1.000000 -1.154000 -0.045991 0.769000 -3.800000 -0.718428 1.400000 -1.423000 0.791240 4.231000 -1.000000 -1.000000 1.000000 -1.000000 -1.269000 -0.079980 0.692000 -3.440000 -0.748824 1.120000 -1.038000 0.595402 3.654000 -1.000000 -1.000000 1.000000 -1.000000 [...]
Pour constituer un ensemble d’apprentissage il faudra donc utiliser ce type de commandes avec les données dont vous disposez et avec votre version amélioré du programme « param ». Je vous conseille éventuellement de faire un script qui enchaîne ces traitements, car sinon vous aurez vite fait de mélanger vos données, ce qui évidement n’aidera pas le réseau de neurones à fonctionner correctement …
BuildTrainData
Ce script permet d’automatiser la création d’ensembles d’apprentissage. Il utilise le programme « param » : Il compte combien il y a d’exemples, combien il y a de classes différentes , etc … Voir le fichier « log.txt » pour voir comment il s’utilise par l’exemple. Pour pouvoir utiliser ce script il faudra changer les droits du fichier pour le rendre executable.
chmod u+x buildTrainData.pl
train
train : ce programme effectue l’ « entraînement » d’un réseau de neurones. En voici un exemple d’appel :
./train trainData.pat testData.pat neuralNetworkOutput
Il demande l’entraînement d’un réseau de neurones, sur les données « trainData.pat ». Il affiche au fur et à mesure de l’apprentissage le taux d’erreur sur les données d’apprentissage, ainsi que le taux d’erreur sur des données de test (« testData.pat »). C’est en surveillant ces 2 suites de valeurs qu’on surveillera Principalement pour éviter le phénomène de sur-apprentissage vu en cours. Typiquement si le taux d’erreur descend sur l’ensemble d’apprentissage mais remonte sur l’ensemble de test, c’est qu’on est en sur-apprentissage et qu’un tel réseau fonctionnera très mal en réalité. C’est pourquoi ce programme ne produit pas un seul réseau final en sortie mais enregistre le réseau au fur et à mesure de sa convergence en concaténant un numéros à la fin du nom donné en dernier paramètre. Cela permet de choisir à quel moment le réseau semble offrir les meilleur performance en généralisation, c’est à dire quand le taux d’erreur est au plus bas sur l’ensemble « testData.pat ».
Voici un exemple de sortie du programme train :
Epochs 1. lr=0.700 trainError: 0.989182 : testError : 0.989392 : Epochs 10. lr=0.700 trainError: 0.979252 : testError : 0.976601 : Epochs 20. lr=0.700 trainError: 0.900293 : testError : 0.880573 : Epochs 30. lr=0.700 trainError: 0.734298 : testError : 0.727524 : Epochs 40. lr=0.700 trainError: 0.677639 : testError : 0.656639 : Epochs 50. lr=0.700 trainError: 0.569507 : testError : 0.546091 : Epochs 60. lr=0.700 trainError: 0.538132 : testError : 0.522665 : [...]
Je pense que l’augmentation des perfomance de reconnaissance du système se fera principalement en améliorant la partie paramétrisation (programme « param »), cependant je pense qu’il y a aussi une marge d’amélioration intéressante en modifiant ce programme. On peut modifier :
*
La topologie du réseau de neurones utilisé. (nombre et arrangement des neurones dans le réseau). J’ai mis par défaut 1 seule couche caché composé de 6 neurones (en plus de ceux défini par le fichier de données sur les couches d’entrée et sortie).
*
Le protocole d’apprentissage (nombre d’itérations, paramètres d’apprentissage, etc …) est aussi définit dans ce programme.
Vous pouvez donc modifier ce programme selon vos intuitions, mais attention veillez toujours à le tester via le programme test (non modifié) que je vous fournis, car c’est celui que j’utiliserai pour évaluer votre travail.
test
Attention : utilisez bien « ./test » et non « test » qui est une commande unix.
Ce programme permet de tester en détail l’efficacité d’un couple réseau de neurones / paramétrisation. Il calcule la matrice de confusion du système de reconnaissance. C’est ce que vous allez utiliser pour analyser les erreurs de votre système de reconnaissance de geste. C’est ce que j’utiliserai pour évaluer la qualité de votre travail. Il s’agit donc là de quelque chose de très important… Voilà comment il s’utilise :
./test validationData.pat neuralNetworkOutput4500.net
Il prend en paramètre un fichier de données d’exemple. Idéalement il faudrait que ce soit des données jamais utilisés au préalable. Ce fichier (« validationData.pat ») est le résultats de données « brut » paramétrés par le (votre) programme « param ». Tester un réseau de neurones ou n’importe quel système d’apprentissage avec des données utilisées lors de l’apprentissage est une erreur grave, car elle amène à surestimer la qualité du réseau. (un peu comme mettre le sujet de l’éval’ de l’an passé à un examen , c’est maladroit …). C’est pourquoi on façonnera notre système avec 3 ensembles de donnés :
*
un ensemble d’entraînement : pour construire le réseau
*
un ensemble de test : pour éviter le sur-apprentissage
*
un ensemble de validation : pour mesurer la réellement qualité du système. C’est cet ensemble que nous utiliseront
Voici un exemple de sortie de ce programme :
wassner@v1009:src$./test validateData.pat totoNN400.net confusion matrix : (13.00) 1.00 3.00 0.00 2.00 (13.00) 0.00 1.00 0.00 1.00 (2.00) 9.00 0.00 0.00 2.00 (15.00) normalised confusion matrix : (0.76) 0.06 0.18 0.00 0.12 (0.81) 0.00 0.06 0.00 0.08 (0.17) 0.75 0.00 0.00 0.12 (0.88) mean perf = 0.656556
C’est cette dernière valeur : « mean perf » (moyenne de la diagonale) qui sera utilisée pour noter votre travail. J’utiliserai un ensemble de donnés dont vous ne disposez pas pour évaluer votre travail, ce sera bien sûr des données du même type. Cela m’assurera que ce qui est mesuré c’est bien la capacité de généralisation de votre réseau, et non un apprentissage « par coeur » des données d’exemple.
runNN
Vous n’aurez à priori pas besoin de ce programme pour le TP, mais si vous disposez d’une wiimote et d’un ordinateur équipé bluetooth, je pense que vous aurez envi d’essayer votre programme en vrai. Pour faire le traitement complet il faut enchaîner le programme d’acquisition (wii_move), puis la paramétrisation (param), et enfin le réseau de neurones (runNN).
./wii_move 00:19:1D:D5:0E:CF | ./param | ./runNN wii320.net
Note : de même que lors de la phase d’enregistrement des données, il faut tenir la gâchette (bouton « B ») enfoncé lors du mouvement.
Chaîne de traitement
Si on résume, vous devez enchaîner une chaîne de traitement composé de 3 programmes :
*
la paramétrisation (param)
*
l’apprentissage (train)
*
l’évaluation (test)
Cela va vous amener à manipuler des fichiers, des formats et concepts intermédiaires. Il vous faudra être très sérieux dans la gestion de ces données, et prendre un maximum de notes sur tout ce que vous appliquez à vos données, pour être capable de vous souvenir où vous en êtes dans vos modifications…
Conclusion
Il s’agit d’un TP qui peut paraître difficile au premier abord. Je pense sincèrement qu’il n’est pas si difficile que ça si on suit bien la progression cours, TD, puis TP. Je donnerai des indices et de conseils durant les heures de TP. Dans la mesure ou je vous fournit une chaîne de traitement complète que nous n’aurez qu’à modifier, je pense que cela ne demandera que très peu de codage, et plus de réflexion … Je vous avez une semaine de délais après la dernière heure de cours ou TP pour rendre ce projet par mail. ce qui vous laissera le temps de réfléchir posément au problème pour essayer d’améliorer au mieux la chaîne de traitement. Cette note sera pondérée par votre note d’évaluation.
Vous pouvez bien sûr continuer ce projet en dehors de ce cours. Ce serait vraiment sympat’ de créer un jeu autour de ces fonctionnalités, je suis prèt à vous aider dans ce but. Si cela vous intéresse venez me voir on essayera de trouver un cadre pédagogique pour dégager le temps nécessaire à un tel projet.