Publié par
Il y a 5 mois · 14 minutes · Data, IoT

Une application de classification automatique de signaux audio sur Raspberry Pi, a.k.a. Parenting 2.0

La XebiCon, la conférence organisée par Xebia, s’est déroulée cette année le 9 novembre. Au programme, cinquante et une conférences autour des nouvelles technologies proposées par des Xebians et leurs clients. Je vous propose dans cet article de revenir sur le projet que j’ai présenté : « Parenting 2.0 : calmer son bébé avec du Machine Learning et un Raspberry Pi ». Si vous êtes curieux, et j’espère que vous l’êtes, je vous invite à regarder la vidéo de la présentation !

Les objectifs du projet sont multiples. Très concrètement, le premier objectif est de faire de la reconnaissance de signaux audios en temps réel, suivie par le déclenchement d’une action. D’un point de vue global, l’objectif est de montrer l’implémentation d’un projet au croisement entre la Data Science et l’IoT, et de montrer comment combiner du Machine Learning avec un Raspberry Pi pour aborder une problématique de la vie de tous les jours, telle qu’un bébé qui pleure et qu’il faut calmer.

En bref, le projet consiste à enregistrer un bébé qui dort et analyser en continu l’enregistrement. Si le résultat de l’analyse est que le bébé a commencé à pleurer, une berceuse est lancée automatiquement pour essayer de le calmer. La partie analytique est donc implémentée avec un modèle de Machine Learning déployé sur un Raspberry Pi, tandis que la partie technique est supportée par le Raspberry Pi. À travers un microphone USB, le Raspberry Pi enregistre un signal audio qui est analysé grâce au modèle, et, en cas de pleurs détectés, il joue la berceuse.

schema-iot-raspberry-pi

Du point de vue du Machine Learning

Pour la reconnaissance des signaux sonores, il a fallu, tout d’abord, collecter des données pour entraîner un modèle de Machine Learning. J’ai trouvé sur Internet un jeu de données très pertinent : une collection de 50 types de sons d’environnement, parmi lesquels j’en ai choisi 10.

  • 5 sons d’environnement extérieur : sirène, klaxon, gazouillis d’oiseaux, cloches, orage
  • 4 sons d’environnement intérieur : verre qui se casse, miaulement, aboiement, ronflements
  • pleurs de bébé, classe cible du projet.

Mon choix a été motivé par la pertinence de ces catégories avec ce que l’on peut entendre autour d’un bébé qui dort.

Pour chaque classe ou type de son, il y a 40 enregistrements de 5 secondes chacun. Par conséquent, 400 enregistrements libellés avec leur classe d’appartenance sont disponibles pour l’entraînement d’un modèle de Machine Learning. Le fait que les données soient qualifiées, c’est-à-dire que l’information sur leur catégorie d’appartenance soit disponible, est très important. Le modèle se basera sur cette connaissance pour apprendre à distinguer les différentes catégories. Par contre, avant de pouvoir entraîner le modèle, il faut passer par l’étape de Feature Engineering. Cette étape consiste à transformer les données afin de les simplifier et enlever de l’information redondante. Cela et le paramétrage du modèle qui suit permettent de généraliser le résultat de l’apprentissage. En effet, l’objectif n’est pas d’avoir un modèle qui connaît par cœur le jeu d’entraînement, mais, au contraire, d’avoir un modèle suffisamment indépendant du jeu d’entraînement qui soit capable de reconnaître un son jamais entendu auparavant. Le Feature Engineering se révèle souvent être la clef de la réussite.

Dans le domaine du traitement du signal, et aussi spécifiquement pour le traitement de signaux sonores, une pratique commune est de recourir à la transformation en fréquence pour l’extraction de features. La fréquence permet, par exemple, de distinguer un son grave, caractérisé par des basse fréquences, d’un son aigu, caractérisé par des fréquences hautes. Pour l’analyse des signaux, j’ai utilisé des packages Python existants : pydub pour l’acquisition, et librosa pour le traitement et le Feature Engineering.

Librosa intègre un certain nombre de fonctions dédiées au Feature Engineering. J’ai extrait 17 features :

  • zero crossing rate
  • 13 Mel frequency cepstrum coefficients (MFCC)
  • spectral centroid
  • spectral rolloff
  • spectral bandwidth

Le zero crossing rate est la seule feature qui ne soit pas calculée dans le domaine de la fréquence, mais bien dans le domaine du temps. Il correspond au taux de changement du signe d’un signal. Toutes les autres features sont calculées dans le domaine des fréquences, et sont typiquement utilisées dans le domaine du Speech Recognition. Pour pouvoir obtenir ces features, il est nécessaire de transformer chaque signal à travers la Transformée de Fourier. C’est une transformation mathématique complexe qui est implémentée grâce à un algorithme nommé Fast Fourier Transform (FFT) qui permet l’extraction des composantes en fréquences d’un signal. Pour simplifier, cette opération nous donne un point de vue différent sur un signal. Regardons, par exemple, l’image suivante.

baby_cry_snoring_zoom.png

Dans le panneau en haut à gauche, on voit la représentation de 5 secondes d’un cri de bébé tel qu’il est enregistré. Dans le panneau du bas, toujours à gauche, le « spectre », on voit le même son transformé. Ainsi, on peut y reconnaître des bandes presque horizontales correspondant aux fréquences les plus représentées, autour de 900 Hz. Regardons maintenant le spectre d’un ronflement, en bas à droite. Il est plus grave qu’un cri de bébé, et on reconnaît tout de suite les bandes à des fréquences plus basses, pas loin du zéro.

Grâce au Feature Engineering, chaque son est maintenant caractérisé et représenté par 17 variables. Notez qu’avant cette étape, chaque son était représenté par 220500 variables (ce chiffre est calculé comme la durée du son, 5 secondes, multipliée par la fréquence d’échantillonnage, 44100 hertz). Il y a d’autres features que j’aurais pu calculer, comme par exemple l’auto-corrélation. Je vais sûrement explorer les autres possibilités. Il faut aussi considérer que toutes les transformations de données faites dans le cadre de l’entraînement du modèle seront à reproduire telles quelles, sur tous les nouveaux signaux dans le cadre de la prédiction. Les calculs pour transformer les données sont souvent très lourds, et un Raspberry Pi n’est pas aussi puissant qu’un ordinateur, du coup ces 17 features peuvent être un bon compromis pour commencer.

Pour l’entraînement du modèle, j’ai utilisé scikit.learn. J’ai entraîné plusieurs modèles, et le choix final a été une Support Vector Machine à kernel linéaire, pour apprendre à distinguer entre les dix classes de sons, la variable cible étant la catégorie « pleurs de bébé », « aboiement », « cloches », etc. Pour pouvoir évaluer le modèle, j’ai séparé les données en deux échantillons : un échantillon d’apprentissage (75 % des données)  et un échantillon de validation (25 % des données) en respectant la répartition de la variable cible. Pour le choix des paramètres du modèle, j’ai utilisé la validation croisée (10 folds). L’accuracy score donnée sur le jeu de données de test est de 68 %. Le choix de ce modèle est motivé par des contraintes techniques non négligeables. En effet, d’autres modèles avaient de meilleures performances, le Random Forest notamment, mais il y a un problème de compatibilité entre un système à 64 bits, tel que celui de mon ordinateur de bureau, et le système à 32 bits du Raspberry Pi. Tous les modèles entraînés sur un système à 64 bits ne sont pas compatibles avec le système à 32 bits.

Maintenant que le modèle est entraîné, je suis prête pour prédire si un vrai bébé est en train de pleurer ou pas. Pour ce faire, il faut enregistrer un signal qui doit être le plus proche possible des signaux du jeu de données d’entraînement : 5 secondes de durée, échantillonnage à 44100 Hz, mono canal. Comme mon intérêt est de distinguer uniquement les pleurs de bébé, et que 5 secondes peuvent ne pas être suffisantes, je suis allée au delà de la simple prédiction en sortie du modèle. Je fais enregistrer au Raspberry Pi 9 secondes de signal, découpé en 5 segments de 5 secondes chacun avec chevauchement. Le modèle fait la prédiction sur chaque segment, et seulement si au moins 3 des 5 segments ont une prédiction positive, alors la berceuse est lancée.

XebiCon-2016-Parenting-2.0.png

Du point de vue du Raspberry Pi

Un Raspberry Pi est un mini ordinateur qui coûte une trentaine de dollars. Initialement, le but était de rendre accessible l’apprentissage des sciences informatiques, mais les applications se sont multipliées et maintenant il est très utilisé dans le domaine de l’IoT. L’avantage d’un Raspberry Pi est qu’il est assez simple d’utilisation. Par contre, il faut tout installer pour pouvoir l’utiliser. Il faut donc commencer par l’installation d’un OS. Le lecteur peut suivre facilement l’un de nombreux tutoriels disponibles sur le web, comme le NOOBS setup proposé sur le site officiel ou ceux proposés par la communauté Raspbian France.

J’ai installé une distribution classique de Linux bien adaptée au Raspberry Pi, Raspbian dans sa dernière version, intitulée Jessie. Une fois l’OS installé et le Raspberry Pi connecté à Internet, il est possible de se connecter au Raspberry Pi en connexion ssh. Il faut juste connaître l’adresse IP associée au Raspberry Pi et le mot de passe. L’utilisateur par défaut étant pi, le mot de passe est raspberry. Ces paramètres peuvent être personnalisés, bien évidemment. Pour connaître l’adresse IP, dans la ligne de commande du Raspberry Pi, il suffit de lancer la commande ifconfig et lire l’adresse. Pour lancer la connexion ssh, de la ligne de commande de son propre ordinateur : ssh pi@xxx.xxx.x.xx.

Dans la distribution Raspbian, Python est déjà présent. Par contre, il lui manque beaucoup de libraires qui sont normalement déjà présentes dans un ordinateur plus puissant. Les trois librairies Python principales nécessaires pour le projet sont pydublibrosa et scikit.learn. Lancer les installations avec pip install ne va pas marcher tout de suite très probablement, à cause de dépendances non préalablement installées telles que mmfpeg, libavlivorbis. J’ai aussi rencontré des difficultés pour installer scipy, numpy et matplotlib. Heureusement, je n’était pas la première à me trouver dans cette situation, et la recherche des messages d’erreurs sur Internet m’a toujours aidé. Dans les quatre liens que je viens de proposer, vous pouvez trouver des infos utiles pour réussir les installations. Cette étape a été pour moi la partie la plus longue et problématique du projet.

Pour l’enregistrement audio, j’ai utilisé un microphone USB, Sienoc Mini-microphone, et le système de gestion audio incorporé dans le noyau linux, ALSA. Les commandes alsamixer, arecord et aplay permettent de visualiser si le microphone est reconnu par le Raspberry Pi, d’enregistrer et d’écouter un son.

L’exécution automatique

Le Raspberry Pi que j’ai utilisé est un modèle B avec un processeur à 900 MHz et 1 Go de mémoire vive, avec un système d’exploitation à 32 bits. Vous pouvez facilement vous rendre compte qu’il n’est pas adapté à l’entraînement d’un modèle de Machine Learning. C’est à cause des contraintes techniques imposées par le Raspberry Pi que j’ai partagé le travail entre mon ordinateur et le Raspberry Pi. En pratique, toute la partie de gestion du jeu de données d’entraînement et l’entraînement du modèle a été effectuée sur mon ordinateur. Une fois le modèle entraîné, je l’ai sérialisé grâce à pickle. Une fois sérialisé, le modèle n’est rien d’autre qu’un objet sauvegardé qui peut être déplacé et désérialisé ailleurs pour le rendre disponible. Ainsi, le modèle peut être utilisé pour prédire un nouveau son enregistré sur le Raspberry Pi. Il n’y a pas que le modèle qu’il est nécessaire de déplacer, il faut aussi avoir le code à exécuter sur Raspberry Pi. Pour ce faire, le code écrit sur ma machine à été packagé sous format egg et transféré sur le Raspberry Pi. Les tâches d’enregistrement et de prédiction sont donc faites par le Raspberry Pi.

Le code est entièrement disponible sur GitHub, et il est organisé selon le schéma suivant. Il y a quatre dossiers :

  • pc_main
  • pc_methods
  • rpi_main
  • rpi_methods

Les scripts dans les dossiers dont le nom commence par « pc » sont exécutés exclusivement sur ordinateur. Symétriquement, les scripts dans les dossiers dont le nom commence par « rpi » sont exécutés exclusivement sur Raspberry Pi. Dans les deux cas, le dossier « methods » contient les scripts qui sont appelés du main contenu dans le dossier « main » correspondant.

Sur ordinateur les étapes à suivre sont :

  • Acquisition de données
  • Feature Engineering
  • Entraînement et sérialisation du modèle

Toutes ces étapes sont réalisées avec du code Python.

Sur Raspberry Pi les étapes à suivre sont :

  • Enregistrement du signal (9 secondes)
  • Découpage du signal en 5 morceaux de 5 secondes
  • Feature Engineering
  • Prédiction des 5 morceaux
  • Vote majoritaire

Toutes les étapes, sauf la première, sont réalisées en Python, la première est gérée directement dans le Raspberry Pi.

Comme le processus sur Raspberry Pi est itératif, il faut qu’il soit lancé de façon automatique. En effet, après le premier enregistrement et la première prédiction, quel que soit le résultat de la prédiction, il faut recommencer à enregistrer, etc. À cet égard, j’ai mis en place un script shell qui lance l’enregistrement, lance la prédiction et, en cas de prédiction positive, lance la berceuse, et recommence. Le script est assez simple et, une fois lancé, il est interrompu avec un Ctrl + C tout simplement.

raspberry.pi

Conclusion, axes d’amélioration, et enseignements tirés

Finalement, pourquoi faire tout ce travail, tout en sachant que je n’ai même pas d’enfants ? Mes motivations sont multiples.

Avant tout, je voulais essayer de faire quelque chose de concret avec un Raspberry Pi et du Machine Learning, et je me suis amusée à mélanger les deux. J’ai eu la liberté de tout faire et défaire, de construire et détruire et d’apprendre beaucoup de choses qui étaient juste floues auparavant et qui sont bien plus claires maintenant. Je parle typiquement de l’exploration du système Linux et de la compréhension de l’utilisation de la ligne de commande, par exemple. Pour une fois, en tant que Data Scientist, j’ai mis de côté l’obsession des performances du modèle, pour laisser plus de place à la réflexion autour des contraintes techniques et de la reproductibilité de la prédiction, pour pouvoir achever le projet de bout en bout.

Il y a bien sûr beaucoup d’améliorations à apporter. Le système marche sur le jeu de données de test dérivé du jeu de données d’entraînement, mais dans un cas d’usage réel, les performances ne sont pas encore satisfaisantes. Je pense notamment que je pourrais travailler sur le pré-traitement du signal et le Feature Engineering pour commencer, pour après explorer d’autres modèles.

En conclusion, je veux aussi mettre en avant deux choses :

La première chose est qu’un projet Data Science peut aller bien plus loin qu’un défi de Data Science du style Kaggle. Rien contre Kaggle, bien entendu. Il représente une ressource d’apprentissage très riche, mais la Data Science n’est pas qu’un défi à la meilleure performance d’un modèle prédictif. Il y a aussi des projets plus vastes qui demandent de sortir de la zone de confort d’un Data Scientist car ils vont au delà du paradigme « explore and predict ».

Deuxièmement, même si simplifié, ce projet représente dans les grandes lignes le travail nécessaire dans le cadre d’un projet Big Data, où les données ont un volume beaucoup plus important, sont distribuées dans un cluster, qui souvent tourne sous Linux, et il y a des traitements automatiques mis en production à exécuter à plusieurs reprises. Dans ces cas, la reproductibilité et la propreté des tâches de Machine Learning sont essentielles. Dans ce cadre, c’est aussi essentiel pour un Data Scientist de savoir dialoguer avec les Data Engineers qui l’entourent pour que le projet puisse aboutir. Dans un contexte industriel, de tels projets sont de plus en plus nombreux et leurs enjeux business sont considérables.

Giulia Bianchi
Giulia est Data Scientist à Xebia depuis un an. Après deux ans d'experience professionnelle en bioinformatique, elle travaille actuellement sur des volumes de données plus importants en mettant en place des algorithmes de machine learning et en participant aux discussions avec les data ingénieurs pour la mise en production des modèles. Elle travaille surtout avec Python, Spark et R. Elle est passionnée par l'IoT et elle suit les nouvelles tendances du monde de la data en participant aux différents Meetups et en suivant des blogs.

Une réflexion au sujet de « Une application de classification automatique de signaux audio sur Raspberry Pi, a.k.a. Parenting 2.0 »

  1. Publié par Olivier M., Il y a 5 mois

    Très intéressant, j’avais commencé des choses en ce sens, le machine learning en moins : vivant à la campagne, j’étais parti pour simplement mesurer le niveau sonore (dans une plage de fréquence donnée) sur une certaine durée. Partant du principe qu’un bébé qui pleure, ça dure beaucoup plus longtemps qu’une voiture ou un tracteur qui passe. On gagne en simplicité ce qu’on perd en réactivité.

    Après, mon besoin était aussi plus modeste : m’envoyer un SMS quand bébé se réveille inopinément, que si je suis dans le jardin ou chez le voisin je puisse réagir quand même. Et un faux positif est acceptable dans ce cas.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *