« SE5 ECEAI/eceai 2023/2024/Patrikeev-Mouton » : différence entre les versions

De wiki-se.plil.fr
Aller à la navigation Aller à la recherche
(séance 2)
 
(5 versions intermédiaires par 2 utilisateurs non affichées)
Ligne 72 : Ligne 72 :


Installation des packages python3, pip et tensorflow.
Installation des packages python3, pip et tensorflow.
=== Résultat final : ===
==== Calcul déporté ====
Les datasets ont été extraits par lecture du port série du STM32 grâce à minicom :<syntaxhighlight lang="shell">
minicom -b 460800 -D /dev/ttyAMA0 -C nom_dataset.txt
</syntaxhighlight>Le code du serveur d'IA et du convertisseur série->REST est dans un [https://archives.plil.fr/amouton/IA-scripts repo git].
Les dépendances suivantes sont nécessaires :
* python3-parse
* python3-serial
* python3-sklearn
* python3-numpy
===== Partie STM32 =====
Le STM32 capture une matrice de 8x8 distances 16 fois avant de les envoyer sur le port série (à 460800 bauds). Ces valeurs individuelles sont séparées par des virgules ','. Chaque échantillon de 1024 valeurs est séparé par un "\r\n".
===== Partie Raspberry PI =====
Le Raspberry PI écoute sur le port /dev/ttyAMA0 les valeurs envoyées par le STM32 via un script Python. Il vient les parser pour les formater. Les données formatées (time : l'epoch de la mesure, data : une liste des 1024 valeurs, board_id : un identifiant de la configuration) sont envoyées au serveur. Cet envoi se fait via une requête HTTP sur une API REST.
L'adresse du serveur auquel transmettre les données, ainsi que d'autres paramètres peuvent être configurés dans le fichier config.py
===== Partie Serveur =====
Un script python démarre un serveur HTTP minimal écoutant sur le port 8123. Au démarrage, le script python vient parser 3 fichiers de dataset (correspondant respectivement à "à gauche" "à droite" "rien"), puis vient entraîner un modèle avec la bibliothèque SKLearn. Une fois l'entraînement terminé, le modèle pourra prédire le mouvement qui a été effectué.
===== Performances et consommation =====
La Raspberry et le STM32 consomment en moyenne 3W.
La charge du script de traitement sur la VM est comprise entre 0 et 0.7%. Cependant la consommation réelle de la VM reste dure à évaluer.
=== Calcul sur STM32 ===
Grâce à NanoEdge AI Studio, nous pouvons déclarer un projet de reconnaissance nClass, avec le même dataset que pour le calcul déporté.
=== Production finale ===
Les meilleurs résultats semblent être obtenus avec la méthod SKLearn.
La vidéo de démonstration disponible [https://filature.mouton.tech/hacsfiles/temporaire/AMoutonIE.mp4 ici] (à télécharger, fichier MP4), il y est affiché l'historique des captations du serveur sur l'écran, et indique "Rien", "Gauche" ou "Droite" selon ce que le modèle prédit.
[[Fichier:Capture d’écran du 2024-01-28 17-09-59.png|vignette]]
Nous avons également implémenté un affichage des datasets. Afin de pouvoir trier les éléments qui ne nous semblaient pas pertinents (démarrage tardif, pas de mouvement, mauvaise capture...),  le serveur HTTP python est capable de convertir les datasets enregistrés en GIF et de les afficher sur une page web.
On y voit ci-contre la liste des GIFs obtenus pour le Dataset gauche, avec la première donnée ci-dessous.
Le GIF animé commence par une frame rouge, afin de marquer le début de la capture.
[[Fichier:Gauche.gif|gauche]]A noter qu'un nouveau dataset, différent de celui fait en cours a dû être réalise pour ce rendu. les 300 passes réalisées en classes sont toutes sur un même fond (la carte était à ~2m du plafond), différent du mien. Nous pouvons donc conclure un overfitting de notre modèle.
=== Pistes d'amélioration ===
Pour améliorer la performance de notre outil de détection, il pourrait être judicieux de transmettre un flux d'images captées, plutôt que d'en analyser un bloc de 16 captures. Cela rendrait le tout plus fluide, et indépendant du moment où on démarre le mouvement. (Ici, le mouvement ne doit avoir lieu que pendant la période de 16 images).
Nous pourrions aussi pré-traiter les images. Par exemple, les simplifier pour ne considérer qu'une "couleur de fond" et une "couleur de premier plan" (où aurait lieu le mouvement), au lieu d'envoyer les 8x8 distances (entiers compris entre 0 et 4000).
Cela permettrait de réduire la taille des messages, et de rendre immun notre modèle à la distance entre le capteur et le fond, et entre le capteur et la main. Cela pourrait se faire par recherche d'écart entre les valeurs.
Enfin, il est intéressant de questionner la pertinence de l'exercice réalisé. Dans notre cas, des algorithmes plus traditionnels (sans IA) auraient probablement donné de meilleurs résultats, plus fiables ou facilement mesurables/démontrables (ex, algorithme de recherche de centre de masse, puis suivi de ce centre de masse au cours du temps). Ce type d'algorithme plus légers pourraient facilement tourner directement sur le STM32, réduisant la consommation.
Cependant, il était intéressant de pouvoir construire une API pour remonter les valeurs du capteurs, et cela semble transposable à de nombreuses applications (remontée d'une image pour analyse, interfacer un modèle de LLM plus lourd sur un serveur, ...)

Version actuelle datée du 28 janvier 2024 à 16:57

Séance n°1:

Une machin virtuelle a été crée sur le serveur chassiron avec la commande :

xen-create-image --hostname g19 --force --dist bookworm --size 10G --memory 1G --dir /usr/local/xen --password glopglop --dhcp --bridge bridgeStudents
  • La machine virtuelle possède les propriétés suivantes:

Hostname       :  g19

Distribution    :  bookworm

Stockage  : 10G

Mémoire vive : 1G

Mot de passe : glopglop

Les fichier /etc/network/interfaces, /etc/resolv.conf et /etc/apt/sources.list on étés configurés comme demandé dans le sujet.

  • La Raspberry Pi 4 a été configurée et connectée au WiFi WIFI_IE_1.

Mot de passe : pasglop

Login : pifou

La communication entre la Raspberry et la machine virtuelle a été vérifiée avec une commande de ping.

  • Le STM32F401RE et le capteur de distance (Nucleo-53L5A1):

Les valeurs lues par le capteurs sont renvoyés par le port série du contrôleur STM32 vers le logiciel nanoedge.


Séance n°2:


Durant cette séance, nous nous sommes concentrés sur la création de programmes python qui seront par la suite implémentés sur la Raspberry et la machine virtuelle.

  • Écoute de la liaison série du STM32 vers le PC:

Des objets de type json sont créés pour chaque donnée reçue. Par la suite, l'information est envoyée en http vers l'adresse locale de la machine à l'aide d'un code python.

Ce programme sera destiné à la Raspberry par la suite.

    json_obj = { "time" : curr_time , "data" : liste_valeurs, "board_id" : config.BOARD_ID}
  • Écoute d'une requête http depuis le PC:

Création d'un code python pour écouter depuis un adresse et afficher les données reçue dans le terminal. Ce code sera destiné à la machine virtuelle par la suite.

  • Premier programme d’apprentissage IA avec Tensorflow2:

Nous aimerions être en mesure de reconnaître les mouvement de main suivants:

- de gauche à droite

- de droite à gauche

- de haut en bas

- de bas en haut

- du sol vers le plafond

- du plafond vers le sol

Un premier programme d'apprentissage a été créé pour être en mesure de faire de l'apprentissage de l'IA par la suite sur notre machine virtuelle.

Cependant nous avons besoin de plus de données pour effectuer un apprentissage de meilleur qualité.

  • Machine virtuelle:

Installation des packages python3, pip et tensorflow.

Résultat final :

Calcul déporté

Les datasets ont été extraits par lecture du port série du STM32 grâce à minicom :

minicom -b 460800 -D /dev/ttyAMA0 -C nom_dataset.txt

Le code du serveur d'IA et du convertisseur série->REST est dans un repo git.

Les dépendances suivantes sont nécessaires :

  • python3-parse
  • python3-serial
  • python3-sklearn
  • python3-numpy
Partie STM32

Le STM32 capture une matrice de 8x8 distances 16 fois avant de les envoyer sur le port série (à 460800 bauds). Ces valeurs individuelles sont séparées par des virgules ','. Chaque échantillon de 1024 valeurs est séparé par un "\r\n".

Partie Raspberry PI

Le Raspberry PI écoute sur le port /dev/ttyAMA0 les valeurs envoyées par le STM32 via un script Python. Il vient les parser pour les formater. Les données formatées (time : l'epoch de la mesure, data : une liste des 1024 valeurs, board_id : un identifiant de la configuration) sont envoyées au serveur. Cet envoi se fait via une requête HTTP sur une API REST.

L'adresse du serveur auquel transmettre les données, ainsi que d'autres paramètres peuvent être configurés dans le fichier config.py

Partie Serveur

Un script python démarre un serveur HTTP minimal écoutant sur le port 8123. Au démarrage, le script python vient parser 3 fichiers de dataset (correspondant respectivement à "à gauche" "à droite" "rien"), puis vient entraîner un modèle avec la bibliothèque SKLearn. Une fois l'entraînement terminé, le modèle pourra prédire le mouvement qui a été effectué.

Performances et consommation

La Raspberry et le STM32 consomment en moyenne 3W.

La charge du script de traitement sur la VM est comprise entre 0 et 0.7%. Cependant la consommation réelle de la VM reste dure à évaluer.

Calcul sur STM32

Grâce à NanoEdge AI Studio, nous pouvons déclarer un projet de reconnaissance nClass, avec le même dataset que pour le calcul déporté.

Production finale

Les meilleurs résultats semblent être obtenus avec la méthod SKLearn.

La vidéo de démonstration disponible ici (à télécharger, fichier MP4), il y est affiché l'historique des captations du serveur sur l'écran, et indique "Rien", "Gauche" ou "Droite" selon ce que le modèle prédit.

Capture d’écran du 2024-01-28 17-09-59.png

Nous avons également implémenté un affichage des datasets. Afin de pouvoir trier les éléments qui ne nous semblaient pas pertinents (démarrage tardif, pas de mouvement, mauvaise capture...), le serveur HTTP python est capable de convertir les datasets enregistrés en GIF et de les afficher sur une page web.

On y voit ci-contre la liste des GIFs obtenus pour le Dataset gauche, avec la première donnée ci-dessous.

Le GIF animé commence par une frame rouge, afin de marquer le début de la capture.

Gauche.gif

A noter qu'un nouveau dataset, différent de celui fait en cours a dû être réalise pour ce rendu. les 300 passes réalisées en classes sont toutes sur un même fond (la carte était à ~2m du plafond), différent du mien. Nous pouvons donc conclure un overfitting de notre modèle.

Pistes d'amélioration

Pour améliorer la performance de notre outil de détection, il pourrait être judicieux de transmettre un flux d'images captées, plutôt que d'en analyser un bloc de 16 captures. Cela rendrait le tout plus fluide, et indépendant du moment où on démarre le mouvement. (Ici, le mouvement ne doit avoir lieu que pendant la période de 16 images).

Nous pourrions aussi pré-traiter les images. Par exemple, les simplifier pour ne considérer qu'une "couleur de fond" et une "couleur de premier plan" (où aurait lieu le mouvement), au lieu d'envoyer les 8x8 distances (entiers compris entre 0 et 4000).

Cela permettrait de réduire la taille des messages, et de rendre immun notre modèle à la distance entre le capteur et le fond, et entre le capteur et la main. Cela pourrait se faire par recherche d'écart entre les valeurs.

Enfin, il est intéressant de questionner la pertinence de l'exercice réalisé. Dans notre cas, des algorithmes plus traditionnels (sans IA) auraient probablement donné de meilleurs résultats, plus fiables ou facilement mesurables/démontrables (ex, algorithme de recherche de centre de masse, puis suivi de ce centre de masse au cours du temps). Ce type d'algorithme plus légers pourraient facilement tourner directement sur le STM32, réduisant la consommation.

Cependant, il était intéressant de pouvoir construire une API pour remonter les valeurs du capteurs, et cela semble transposable à de nombreuses applications (remontée d'une image pour analyse, interfacer un modèle de LLM plus lourd sur un serveur, ...)