Récents articles

constitution audio spectrogramme image Cours théoriques - Deep learning

Conversion d’un audio en spectre

Pour comprendre mon cours pratique quant à la réalisation d’une reconnaissance vocale de mots clés via un réseau de neurones utilisant de la convolution, vous devez comprendre les différentes étapes de transformations, entre notre fichier audio de base, vers un tenseur d’ordre 3 compréhensible et utilisable par notre modèle.

 

Mais, c’est quoi le son ?

Les sujets autour du son et des ondes étant plus proche du domaine de la physique que de l’informatique, je vais simplifier au mieux. Un son est une variation de pression qui va entrainer une vibration dans nos molécules d’air, se propageant ainsi sous forme d’ondes. On peut définir et analyser ce signal qui est en faîte une amplitude en fonction du temps. Cette amplitude sonore nous donne une indication concernant la puissance de celle-ci, puisqu’elle représente la valeur de la pression la plus haute attend par l’onde. Concrètement, plus on produit un son fort, plus son amplitude est forte, et inversement.

amplitude d'un son
Src : poitauc

Ces enchaînements de montées et de descentes que l’on peut observer sur la courbe, représente les surpression et dépression du milieu, engendré par le déplacement de l’onde.

Nous venons de voir comment les signaux sont défini dans l’espace temporel, on va maintenant s’attarder sur ces signaux dans un espace fréquentiel.

 

Fréquence et spectre

La fréquence va nous permettre de définir et de classer si un son est aigu ou grave, nous donnant des informations supplémentaires qui vont être importante pour la suite. Elle se définit en hertz, et représente le nombre d’oscillations (période) par seconde.

frequence d'un son
Src : illusions-sonores

 

Types d’images utilisable

Je vais parler des 3 plus connues pour vous donner quelques pistes d’utilisations pour alimenter vos réseaux de neurones. On va utiliser des spectrogramme, qui sont calculés selon le type, via une transformation discrète de Fourrier, une transformation rapide de Fourrier, ou encore une transformation discrète de cosinus. Ce sont des photographies représentent le spectre d’un son. Ces type de spectrogramme vont nous permettre d’analyser des sons et de nous renvoyer :

  • Un temps
  • Une fréquence
  • Une intensité

Vous devriez vous demander d’où provient ce besoin de passer sur des spectres… Et bien pour pouvoir reconnaître des phonèmes ! Un phonème est la plus petite entité phoniques, un élément sonore du langage parlé, pour faire simple : un son, qui peut correspondre à plusieurs sons. C’est cette association de phonème entre eux qui permettent de constituer les mots. Il en existe dans la langue Française 16 de voyelles, 17 de consommes, et 3 de semi consonnes/voyelles.

mfcc spectrogramme mel phoneme

En prenant l’exemple ci-dessus, je vous montre une comparaison entre notre 3 types de spectrogrammes différents, sur le mot ‘bonbon’. Il est constitué de deux phonèmes de voyelle et de deux phonèmes de consonne.

 

Références

Un article extrêmement intéressant que je vous recommande est celui-ci, ‘Comparison of time frequency representations for environmental sound classification using convolutional neural networks’. Il va bench jusqu’à 8 types d’images d’entrée pour réaliser de la classification de son en utilisant un CNN.

constitution image rgb Cours pratiques - Deep learning

Composition et conversion d’une image

Lorsque l’on souhaite analyser des images, ce sont les réseaux de neurones à convolution qui s’en sortent le mieux. Ils sont basés grâce à des expériences effectué sur le cortex et le système de vision des animaux, ces réseaux sont beaucoup plus légers que leurs confrères composé de couche de neurones entièrement connectés les uns aux autres. Attention cependant à ne pas faire trop le rapprochement entre CNN (Convolutional Neural Networks) et images, car ceux-ci peuvent tout aussi bien être utilisé sur du texte, pour réaliser des analyseur de sentiments pour ne citer qu’un exemple. Mais ce n’est pas l’objectif de cet article-ci, j’en reparlerais dans des articles dédiés à ce sujet. 😉

Comme je disais, ces réseaux qui analysent des images, vont pouvoir extraire des caractéristiques propre à celle-ci et à l’ensemble des objets, personnes etc. la constituant. Cependant, comme je l’ai expliqué dans ce post-ci, les réseaux de neurones effectuent des calculs matricielles sur des tenseurs. Ce serait donc outrageux d’envoyer directement nos images tel quel, dans leurs formats natif comme jpg ou encore png (et de toute façon, ce n’est pas possible).

Je vais donc vous montrer comment est constitué une image, afin que vous compreniez les processus que j’effectue sur mes tutoriels pratiques, lorsque je convertis les images de mon jeu de données en tableaux de valeurs (fichier Numpy).

 

Comment est constitué une image ?

Premièrement, notre image est composée de pixel. Je ne vais vous faire la description globale de ce qu’est un Pixel (wikipedia le fera bien mieux que moi), mais c’est l’unité de base, qui définit une image. Une image ayant une taille de 50 par 50 veut dire qu’elle sera composée de 50 pixel par 50 pixel.

cannaux image rgb
Les 3 canaux RGB constituant une image

 

Ensuite, il faut savoir qu’une image en couleurs est composé de 3 canaux, le célèbre RGB (pour Rouge Vert Bleu). Vous aurez donc deviné, que pour une image en noir et blanc, celle-ci est composé exclusivement d’un seul canal.

Ainsi, on peut représenter chaque canaux par une matrice de dimension correspondant à la largeur et la hauteur de l’image. Chaque pixel de l’image va donc représenter une variable de la matrice, qui correspond à l’intensité de la couleurs à ce pixel précis. Petit rappel concernant ce sujet, un pixel peut être définit via une variable comprise entre 0 et 255, correspondant à l’intensité de sa couleur. Cependant, pour homogénéiser nos matrices, nous allons diviser par 255 chacune de nos valeurs, pour avoir à l’entrée de notre réseau de neurones, des matrices ayant l’ensemble de ses valeurs entre 0 et 1.

 

image tenseur cannaux rgb matrice
Empilement de chaque matrice de nos canaux qui forment un tenseur d’ordre 3

Nous nous retrouvons au final avec 3 matrices correspondant à nos 3 canaux de couleurs, qui seront empilés pour former ce qu’on appelle un Tenseur d’ordre 3. Et c’est sur ces structures algébriques que la magie de notre réseau va opérer. 😉

reconnaissance vocale tutoriel Cours pratiques - Deep learning

Reconnaissance vocale de mots clés

Pour ce second tutoriel, nous allons rester sur ces réseaux de neurones à convolution. On utilise le framework Tensorflow en backend, et Keras en API de haut niveau pour nous faciliter la création de l’ensemble de notre modèle. On associe généralement le traitement de la parole (NLP, Natural Language Processing) à des réseaux de neurones récurrents, mais je vais vous montrer tout un processus différent qui va nous permettre d’utiliser de la convolution.

Sur l’article suivant, on va se concentrer sur les différentes notions et étapes nécessaire pour pouvoir réaliser une telle reconnaissance de mots clés. Pour la partie technique et les plus impatients d’entre vous, je vous joint ici l’ensemble du code source du projet disponible sur mon Github. Le principe de construction de ce projet est semblable à celui du cours pratique sur la reconnaissance d’image, puisque on utilise le même type de réseau sur des spectres. On va alors s’attarder plutôt sur les différents principes de traitement des données, afin de passer nos audios d’entrée à notre réseau.

C’est parti ! 😉

 

Pré-requis

Pour la partie audio/spectre :

Pour la partie spectre/tableau numpy

 

Transformation de l’audio en spectre

La première étape va être la plus longue et la plus importante de ce chapitre. C’est cette phase de pré-traitement de nos données d’entrées qui va demander le plus de code. En lisant l’article pré-requis, vous aller devoir transformer avant tout nos audio en image, mais pas de n’importe quel façon. En effet, on souhaite utiliser de la convolution sur des spectres qui vont nous donner des informations sur l’audio. Vous avez l’excellente bibliothèque Librosa qui va nous permettre très simplement de créer nos différents spectres. Celle-ci vous propose plusieurs types de spectres, je vous laisse aller visiter la documentation mais je peux vous en conseiller les 3 principaux qui sont :

  • Le spectrogramme
  • Le mel spectrogramme
  • Le MFCC

Je vous conseille de lire l’excellent article scientifique que je vous ai mit en bas de l’article dans les références, il vous donnera un bench de leurs résultats pour comparer les performances qu’amène l’utilisation de tel ou tel type de spectrogramme. Pour avoir tester ces 3 là, j’ai eu des résultats différents selon le type d’utilisation que j’ai eu. J’ai eu l’occasion d’utiliser plutôt le MFCC sur un CNN qui prédisait 3 classes différentes, et de devoir changer pour utiliser le mel-spectro pour un CNN qui quant à lui, prédisait 10 classes. Vous aurez aussi de votre côté des résultats différents selon vos implémentations en fonction d’une problématique, le mieux reste de les essayer et de juger en fonction de vos résultats. Soyez rassuré, via Librosa le changement est très simple pour passer d’un type de spectrogramme à un autre.

En utilisant de l’entrainement supervisé, on va apprendre au réseau à reconnaître ces différents phonèmes. Il va ainsi être capable de pouvoir différencier tel ou tel mot.

mel spectrogramme chat chier

Je vous montre ci-dessus 2 mel-spectro sur le mot ‘chat’ et ‘chien’. On peut observer le même premier phonème de consonne /ʃ/ pour ‘ch’, qui est partagé et identique entre les 2 audio. Il s’en suivra un phonème de voyelle /a/ pour ‘chat’, et de /i/ et /ɛ̃/ pour ‘chien’. Ainsi en assemblant les différents phonèmes vous pouvez retrouver votre mot prononcé.

 

Conversion de notre dataset en tableau numpy

Nous allons dans un premier temps, devoir transformer nos images d’entrées. En effet, on ne peut charger nos images en format png directement dans notre réseau de neurones. Celui-ci ne fonctionne qu’avec des tenseurs. On va donc convertir nos images vers des matrices de valeurs qui vont être empilés. Je vous ait écrit un article à propos de la constitution d’une image et quant à sa conversion,  vers un tenseur de valeurs, qui correspondent aux intensités de couleurs des 3 différents canaux ( Rouge, Vert, Bleu ) correspondant pour chaque pixel composant l’image. Nous avons ainsi un fichier numpy par classe. D’habitude, la plupart des gens inclus ce processus directement dans le même fichier d’entrainement du modèle. Ce qui n’est pas optimisé puisque l’on est obligé de re-créer ces tableaux à chaque entrainement, ce qui est purement une perte de temps. Ainsi en faisant de cette manière, nous allons les créer une seule et unique fois.

 

Création du modèle

Je souhaitais reprendre le model d’alexNET. Mais étant donnée mon peu de donnée de 250Mo ( ce qui est ridicule en terme de donnée ), je suis parti sur un modèle extrêmement simple que j’ai pris au hasard. Du moins pas complètement au hasard, puisque on utilise un réseau à convolution, on doit respecter des templates concernant les empilement des différentes couches :

[ [Conv -> ReLU]*n -> Pool ] *q -> [FC -> ReLU]*k -> FC -> Softmax

  • Conv : couche de convolution
  • ReLU : fonction d’activation, Rectified Linear Unit
  • Pool : couche de convolution
  • FC : couche de neurones entièrement connecté
  • Softmax : fonction d’activation à sorties multiples

 

Entrainement du modèle

La partie rapide du projet. C’est simple, vous n’avez rien à faire, juste à attendre que votre réseau apprenne. Celui ci va se renforcer au fur et a mesure des itérations que va parcourir votre modèle sur votre jeu de donnée, devenant ainsi meilleur.

fin entrainement
Dernière itération de l’entrainement de mon réseau de neurones

 

Suivit de l’entrainement

Évolution de la perte au cours de l’entrainement
Évolution de la précision au cours de l’entrainement

Une fois le modèle entraîné, on va vouloir voir comment il s’est comporté durant l’entrainement. Que cela soit la fonction de perte ou de précision, on va pouvoir avoir de réels informations et indices sur le comportement de notre réseau, et ce sur le jeu de donnée d’entrainement et de validation.

On peut apercevoir que le modèle n’a pas finit d’apprendre, en effet la courbe concernant le jeu de donnée de validation connait une stagnation. Nous verrons plus loin dans l’article comment améliorer notre modèle.

 

Réaliser une prédiction

Enfin la partie intéressante ! Maintenant que notre modèle est entraîné, on va enfin pouvoir réaliser des prédictions sur de nouveaux audio. Pour cela, on va lancer notre fichier autoPredict.py qui va enregistrer le microphone sur une période de deux secondes. Celle-ci est importante, et doit correspondre à la même longueur que les extraits audio de notre jeu de donnée sur lequel notre réseau s’est entraîné. En effet, pour obtenir des résultats probants, il faut obligatoirement comparer des choses comparables, et donc avec des caractéristiques semblables (la durée dans notre cas). Nous aurons ensuite une conversion de ces audios en spectre, et enfin une dernière transformation en tenseur via Numpy. Nous aurons en sortie de notre réseau une probabilités selon nos 2 classes de sortie, qui sont Chat et Chien.

Résultat d’une prédiction d’une nouvelle donnée depuis mon réseau de neurones, pour le mot ‘Chat’

 

Validation de notre modèle sur un nouveau jeu de donnée

Maintenant que nous avons un modèle, on souhaite savoir comment il va se comporter sur de grandes quantités de nouvelles données. En effet, il serait dommage de perdre du temps de l’intégrer dans notre application pour se rendre compte bien plus tard que notre réseau n’est absolument pas fonctionnel. Perte de temps et d’argent garantie. 😉

On va donc recréer un dataset de nouveaux extraits audio, auxquelles notre réseau n’aura jamais vu auparavant, pour permettre de prédire au mieux comment notre réseau va se comporter en application réelle. Pour notre exemple, on va reprendre nos 2 types de classes, avec des audios que j’ai enregistrer via un camarade auquel le réseau n’a jamais entendu sa voix. Plus votre dataset sera important, et plus vous aurez une idée précise du comportement de votre réseau. Pour le cas du tutoriel ( et que je suis fenéant ), j’ai pris seulement 5 audios différents pour chacune des classes.

Le but de notre matrice ne va pas s’arrêter là. En effet, son application va aller bien plus loin. Il va nous permettre de mettre en évidence d’éventuel erreurs qui pourrait être critique ou acceptable, ce qui sont 2 choses réellement différentes, j’en écrirais un article d’ici peu pour de plus amples informations.

matrice de confusion

On obtient un score global de 70% de bonnes prédictions sur de nouvelles données. Nous pouvons nous rendre compte qu’il a donné de parfaite prédiction concernant la classe chat. Cependant, notre modèle est peu fiable, concernant la classe chien. Le but de ce procédé va donc être de viser une diagonale pour avoir des prédictions proche de 1.

 

Axe d’amélioration

  • OVERFITTING EN VUE MON CAPITAINE ! 😐 La data augmentation peut aider dans beaucoup de cas. Mais en abuser est dangereux pour notre réseau. On voit clairement sur nos 2 graphiques que le jeu de validation réussit mieux que le jeu d’entrainement, notre modèle apprends donc par coeur les données. Et pour cause, chaque classe de mon jeu de donnée ne contient que 50 extraits audio unique, pour 1000 extraits augmenté. Par manque de temps, j’ai utilisé des techniques de data augmentation pour me faciliter la vie. Pour cela, j’ai cloné chaque extrait de base en 20 nouveaux extraits, en y ajoutant des transformations audio pour créer artificiellement de la diversité au sein de mon dataset. Cependant, mon dataset en reste néanmoins pas assez diversifié et manque clairement de vrais extraits audio.
  • Augmenter la taille du réseau : n’ayant que très peu de données, mon choix d’un réseau aussi simple est justifié. Cependant si on augmente notre jeu de données, nous allons pouvoir augmenter la profondeur de notre réseau de neurones. Ajouter des couches va permettre au réseau d’extraire des caractéristiques plus complexes.
  • Augmenter la résolution de nos images d’entrées : n’ayant pas un GPU à disposition pour mes entraînements, je suis dans l’obligation d’utiliser seulement mon CPU, me limitant ainsi dans mes calculs de tenseurs. Cependant, augmenter la résolution des images va permettre au réseau de mieux s’en sortir. En effet, plus la qualité des images du dataset est haute, et plus les prédictions en seront bonne.

 

Vers une reconnaissance vocale continue ?

Je ne suis pas aller plus loin personnellement sur ce projet, mais je peux vous partager quelques idées pour vous permettre de construire une vraie reconnaissance vocale pour créer un Speech to Text en continu. Le but serait de reprendre le même principe de mon tutoriel, et d’entraîner cependant notre réseau non pas sur 2 classes mais sur l’ensemble des phonèmes que compose la langue française, soit 36 classes. Mais pourquoi entraîner là dessus ? Le fait d’entraîner notre réseau à les reconnaître, va nous permettre de reconstituer les mots, et donc les phrases, via un système de dictionnaire que l’ont mettrait en place pour faire la conversion.

Exemple sur un spectre du mot ‘bonjour’. On découpe notre spectro d’entrée en taille identique que l’on va envoyé à notre réseau :

decoupage extrait audio

 

On aurait par la suite une analyse des spectres découpé un à un par un réseau de neurone à convolution pour permettre d’extraire les phonèmes découverts :

decoupage phoneme

A la suite, notre dictionnaire de conversion des phonèmes nous permettrait de récupérer depuis les phonèmes les mots prononcés. On aurait forcement des effets de bords du fait que l’ont ait le même phonème sur plusieurs spectre, cela est en fonction de la taille de découpage de nos spectres ou encore caractérisé à la vitesse ou on parle si on accentue plus ou moins certains phonèmes :

dictionnaire phoneme conversion

Pour une meilleure visibilité, je ne vous ait mit seulement les phonèmes qui nous intéresse. Les cases blancs correspondent à des silences, et les cases rouges correspondent au phonème détecté par notre CNN sur un spectre.

Si on suit l’exemple que j’ai élaboré, cela nous donne la phrase :

_ B ON ON J OU OU OU R R _ _

Il faudrait alors s’en suivre une première étape de nettoyage de notre phrase, en supprimant les blancs :

B ON ON J OU OU OU R R

Et enfin une seconde étape de nettoyage pour supprimer les doublons :

B ON  J OU R 

Auquel cas on retrouve notre mot prononcé, ‘Bonjour’.

 

Je ne pense pas que l’ajout de cette étape, nous permettant de passer d’une simple reconnaissance vocale de mot à un réel speech to text soit si complexe que ça. Le seul point qui prendrait un peu de temps, serait de récolter assez de data pour chacun des phonèmes, afin d’entraîner notre modèle pour les reconnaître.

 

Conclusion

Je vous montre comment réaliser une simple reconnaissance vocale. Très simple à réaliser, si vous comprenez comment fonctionne ce projet, vous pouvez l’appliquer ailleurs. Vous pouvez très bien pousser le projet plus loin, et permettre de réaliser une vraie reconnaissance vocale appliqué sur des phrases entière, et non sur de simple mot, pré-défini en avance. Une chouette utilisation  de tel réseau peut être d’intégrer ces modèles pour réaliser des applications mobiles, ou encore faire un système de domotique avec un microphone associé à un RaspBerry pie pour fermer vos volets. 😎

Je vous joint ici l’ensemble de mon code source documenté et commenté sur mon profil Github, avec les informations nécessaire pour sa compilation et lancement. Vous aurez l’ensemble des informations nécessaire pour pouvoir en recréer un vous même. Je compte d’ailleurs sur vous pour me proposer d’éventuelles corrections et optimisations pour le miens. 🙂

reconnaissance d'image Cours pratiques - Deep learning

Classification d’images

Pour ce premier tutoriel , je vous proposer de réaliser très facilement avec Tensorflow en backend et Keras en API de haut niveau, un classificateur d’images, permettant de réaliser une reconnaissance d’images. Nous allons décortiquer comment réaliser l’ensemble du processus, allant du traitement des données, à l’entrainement de notre réseau de neurones, jusqu’au test de notre modèle dans de futures condition réelles pour pouvoir avoir une idée de comment se comporte notre algorithme avant même qu’il soit intégré dans une application.

N’ayant pas tellement la main verte ( en plus d’être daltonien ), on va créer un modèle permettant de reconnaître entre 5 fleurs différentes.

classificateur d image
Voici les différentes fleurs que l’on va apprendre à notre réseau de neurones à reconnaître

On va sur cet article se concentrer sur les différentes notions et étapes nécessaire pour pouvoir réaliser un tel classificateur d’image. Pour la partie technique et les plus impatients d’entre vous, je vous joint ici l’ensemble du code source du projet disponible sur mon Github.

C’est parti ! 😉

 

Pré-requis

Cours théorique sur la constitution et la conversion d’une image

 

Conversion de notre dataset en tableau numpy

Nous allons dans un premier temps, devoir transformer nos images d’entrées. En effet, on ne peut charger nos images en format png directement dans notre réseau de neurones. Celui-ci ne fonctionne qu’avec des tenseurs. On va donc convertir nos images vers des matrices de valeurs qui vont être empilés. Je vous ait écrit un article à propos de la constitution d’une image et quant à sa conversion,  vers un tenseur de valeurs, qui correspondent aux intensités de couleurs des 3 différents canaux ( Rouge, Vert, Bleu ) correspondant pour chaque pixel composant l’image. Nous avons ainsi un fichier numpy par classe. D’habitude, la plupart des gens inclus ce processus directement dans le même fichier d’entrainement du modèle. Ce qui n’est pas optimisé puisque l’on est obligé de re-créer ces tableaux à chaque entrainement, ce qui est purement une perte de temps. Ainsi en faisant de cette manière, nous allons les créer une seule et unique fois.

 

Pré traitement des données

On va devoir générer deux types différents de dataset à partir de nos fichiers Numpy :

  • Dataset d’entrainement
  • Dataset de validation

Le premier va permettre à notre réseau d’apprendre et d’extraire des caractéristiques distinctes de chacune de nos fleurs.

Le second quand à lui va servir à valider le modèle en fin de chaque itération au cours de l’entrainement. En effet, en montrant de nouvelles images à notre réseau, il va lui permettre de se recalibrer pour éviter de sur-apprendre les fleurs du jeu de données d’entrainement. Cette calibration va lui permettre de bien meilleurs généralisation de données.

Il faudra respecter un certain ratio entre ces deux jeux de données. A partir de notre dataset original, nous allons récupérer 80 à 90% des données pour le dataset d’entrainement, et donc de 10 à 20% pour le dataset de validation.
Notre réseau à convolution va avoir comme entrée un tenseur de la dimension suivante :

( n, w, h, c )

  • n : nombre total d’image de notre dataset
  • w : largeur en pixel de nos images
  • h : hauteur en pixel de nos images
  • c : nombre de canaux de nos images. Correspond donc à 1 pour du noir & blanc, et 3 pour des entrées en couleurs

Il faudra donc bien faire attention de reshape nos données en les récupérant depuis nos fichiers numpy.

 

Création du modèle

Je souhaitais reprendre le model d’alexNET. Mais étant donnée mon peu de donnée de 250Mo ( ce qui est ridicule en terme de donnée ), je suis parti sur un modèle extrêmement simple que j’ai pris au hasard. Du moins pas complètement au hasard, puisque on utilise un réseau à convolution, on doit respecter des templates concernant les empilement des différentes couches :

[ [Conv -> ReLU]*n -> Pool ] *q -> [FC -> ReLU]*k -> FC -> Softmax

  • Conv : couche de convolution
  • ReLU : fonction d’activation, Rectified Linear Unit
  • Pool : couche de convolution
  • FC : couche de neurones entièrement connecté
  • Softmax : fonction d’activation à sorties multiples

 

Entrainement du modèle

La partie rapide du projet. C’est simple, vous n’avez rien à faire, juste à attendre que votre réseau apprenne. Celui ci va se renforcer au fur et a mesure des itérations que va parcourir votre modèle sur votre jeu de donnée, devenant ainsi meilleur.

entrainement d'un réseau de neurone
Dernière itération de l’entrainement de mon réseau de neurones

 

Suivit de l’entrainement

graphique de suivi de metriques loss
Évolution de la perte au cours de l’entrainement
graphique de suivi de metriques precision
Évolution de la précision au cours de l’entrainement

Une fois le modèle entraîné, on va vouloir voir comment il s’est comporté durant l’entrainement. Que cela soit la fonction de perte ou de précision, on va pouvoir avoir de réels informations et indices sur le comportement de notre réseau, et ce sur le jeu de donnée d’entrainement et de validation.

On peut apercevoir que le modèle n’a pas finit d’apprendre, en effet la courbe concernant le jeu de donnée de validation connait une stagnation. Nous verrons plus loin dans l’article comment améliorer notre modèle.

 

Réaliser une prédiction

Enfin la partie intéressante ! Maintenant que notre modèle est entraîné, on va enfin pouvoir réaliser des prédictions sur de nouvelles images. Nous avons juste à le charger en mémoire, à transformer notre image au format jpg, vers un tableau numpy, puis de reshape sa dimension vu précédemment. Nous aurons en sortie un tableau de 5 valeurs, correspondant aux 5 neurones de la couche de sortie de notre modèle, et donc à nos 5 classes de fleurs. On aura pour chaque classe un pourcentage concernant sa prédiction. On prendra alors la valeur la plus élevée des 5, qui correspond donc à la prédiction effectué par notre modèle.

prediction d'un réseau de neurones
Résultat d’une prédiction d’une nouvelle donnée depuis mon réseau de neurones

 

Test de notre modèle sur un jeu de donnée entier

Maintenant que nous avons un modèle, on souhaite savoir comment il va se comporter sur de grandes quantités de nouvelles données. En effet, il serait dommage de perdre du temps de l’intégrer dans notre application pour se rendre compte bien plus tard que notre réseau n’est absolument pas fonctionnel. Perte de temps et d’argent garantie. 😉

On va donc recréer un dataset de nouvelles images, auxquelles notre réseau n’aura jamais vu auparavant, pour permettre de prédire au mieux comment notre réseau va se comporter en application réelle. Pour notre exemple, on va reprendre nos 5 types de fleurs différentes, avec des images que j’ai pu récupérer sur un moteur de recherche. Plus votre dataset sera important, et plus vous aurez une idée précise du comportement de votre réseau. Pour le cas du tutoriel ( et que je suis fenéant ), j’ai pris seulement 3 images différentes pour chacune des fleurs.

Le but de notre matrice ne va pas s’arrêter là. En effet, son application va aller bien plus loin. Il va nous permettre de mettre en évidence d’éventuel erreurs qui pourrait être critique ou acceptable, ce qui sont 2 choses réellement différentes, j’en écrirais un article d’ici peu pour de plus amples informations.

matrice de confusion

On obtient un score global de 93% de bonnes prédictions sur de nouvelles données. Nous pouvons nous rendre compte qu’il a donné de parfaite prédiction concernant 4 de nos classes. Cependant, notre modèle s’est trompé sur 1 fleur sur 3, concernant les tulipes. Le but de ce procédé va donc être de viser une diagonale pour avoir des prédictions proche de 1.

 

Axe d’amélioration

On voit sur les graphiques de suivi de métriques que notre courbe d’apprentissage laisse à désirer sur le jeu de données de validation, mais s’en sort plutôt bien sur notre jeu de données de test, de notre matrice de confusion. Pour le tutoriel, j’ai pris des photos relativement simple, ce qui peut justifier notre haut taux de reconnaissance. Il s’en sort beaucoup moins bien sur celui de validation. Je vais vous proposer plusieurs pistes pour corriger cela et vous permettre de développer un modèle bien plus robuste que le mien.

  • Augmenter notre jeu de données : en effet, on a entre 700 et 1000 fichiers pour chacune de nos classe, ce qui est extrêmement ridicule. Plus on va fournir un jeu de données important et diversifié, plus il pourra apprendre et donc réaliser de meilleurs prédictions. Vous pouvez soit en récupérer d’avantage vous même à la main. Ou si votre jeu de données est cependant limité ou impossible à étendre, vous pouvez toujours utiliser des techniques de data augmentation.
  • Augmenter la taille du réseau : n’ayant que très peu de données, mon choix d’un réseau aussi simple est justifié. Cependant si on augmente notre jeu de données, nous allons pouvoir augmenter la profondeur de notre réseau de neurones. Ajouter des couches va permettre au réseau d’extraire des caractéristiques plus complexes.
  • Augmenter la résolution de nos images d’entrées : n’ayant pas un GPU à disposition pour mes entraînements, je suis dans l’obligation d’utiliser seulement mon CPU, me limitant ainsi dans mes calculs de tenseurs. Cependant, augmenter la résolution des images va permettre au réseau de mieux s’en sortir. En effet, plus la qualité des images du dataset est haute, et plus les prédictions en seront bonne.

 

Conclusion

Je vous montre comment classifier des fleurs ( je vous l’accorde c’est absolument inutile ). Mais la principal chose est de comprendre la démarche du projet. Si vous comprenez comment fonctionne ce projet, vous pouvez l’appliquer ailleurs. Vous pouvez très bien faire votre propre réseau de neurones capable d’analyser des images médicales, telles que les radiographies et échographie, pour mettre en évidence d’éventuelles tumeurs qui aboutissent à des cancers pour ne donner qu’un simple exemple d’utilisation. Vous pouvez éventuellement installer des dizaines de caméras sur la voiture de votre mère, et créer votre propre voiture autonome si vous vous en sentez le courage. 😉

Je vous joint ici l’ensemble de mon code source documenté et commenté sur mon profil Github, avec les informations nécessaire pour sa compilation et lancement. Vous aurez l’ensemble des informations nécessaire pour pouvoir en recréer un vous même. Je compte d’ailleurs sur vous pour me proposer d’éventuelles corrections et optimisations pour le miens. 🙂

keras api installation Cours pratiques - Deep learning

Installation de l’API de haut niveau Keras

Il n’est pas toujours évident de commencer à développer nos premières applications d’intelligence artificielle. En effet, les codes natifs des framework de deep learning peuvent rapidement devenir complexe à l’utilisation. J’ai personnellement commencé avec la combinaison Tensorflow/Keras.

Keras

C’est une API de haut niveau qui va se superposer sur un framework de bas niveau (Tensorflow, CNTK, Theano). Il va servir de liaison, comme une sorte de wrapper. Il va pouvoir simplifier l’implémentation d’un réseau de neurone. C’est un peu à l’image entre le développement en C d’un côté, et de java de l’autre ; le niveau d’abstraction n’est pas le même. Il est d’ailleurs développé par un français, François Chollet, actuellement chez Google. Je vous recommande d’ailleurs son livre ‘Deep learning with python’ qui vous donnera de bonnes bases quant à l’utilisation de Keras.

 

Installation

Dans un précèdent chapitre, je vous ai d’ailleurs montré comment installer Anaconda. On va donc se servir de celui-ci pour installer Keras :

 

Version CPU ONLY 

  • conda install -c anaconda keras

VERSION GPU ONLY 

  • conda install -c anaconda keras-gpu

 

Vous n’aurez plus qu’à valider, vous devriez avoir plusieurs librairies annexes qui s’installeront en même temps et qui sont nécessaire au bon fonctionnement de Keras.

installation environnement python anaconda Cours pratiques - Deep learning

Installation de l’environnement Python

Présentation d’Anaconda

Anaconda est un gestionnaire de librairie, de la même façon qu’est NPM pour le web, Nugget pour C# ou encore apt-get pour linux. Il va nous permettre de créer facilement des environnements virtuels séparé selon nos utilisation. Ainsi, vous allez pouvoir installer, mettre à jour et supprimer via de simples lignes de commandes les bibliothèque nécessaire pour entraîner nos réseaux de neurones.

 

Installation d’Anaconda

Récupérer la dernière version sur le site Anaconda , et suivez les instructions d’installation.

 

Créer votre premier environnement virtuel

Lancer Anaconda Prompt via la recherche windows. C’est un cmd réservé pour Anaconda.

  • Conda create -n nonDeMonEnvironnement python=3.6

La spécialisation de version de python est optionnelle, mais ayant eu quelques soucis avec la 3.7, je vous conseille de rester sur la 3.6.

 

Activer votre environnement

Pour le moment vous êtes sur l’environnement de base. Pour switch, utilisez la commande :

  • Conda activate nonDeMonEnvironnement

 

Bibliothèque indispensable

Comme tout bon data scientist, vous allez avoir besoin d’un bagage minimal suivant à installer :
Numpy, Scikit-learn, Matplotlib, Pandas, Pilllow, h5py et bien d’autres.

 

Commandes utiles

Installer une bibliothèque :

  • Conda install nomDeLaBiblio

Lister l’ensemble des biblio installé : 

  • Conda list

Lister les environnements : 

  • Conda info –envs
fonction d activation Cours théoriques - Deep learning

Fonction d’activation

Description

Une fonction d’activation est une fonction mathématique utilisé sur un signal. Elle va reproduire le potentiel d’activation que l’on retrouve dans le domaine de la biologie du cerveau humain. Elle va permettre le passage d’information ou non de l’information si le seuil de stimulation est atteint. Concrètement, elle va avoir pour rôle de décider si on active ou non une réponse du neurone. Un neurone ne va faire qu’appliquer la fonction suivante :

X = ∑ ( entrée * poids ) + biais

C’est sur cette sortie que la fonction d’activation va s’appliquer.

 

Exemple de fonctions

Voici les principales fonctions d’activations que l’on peut trouver dans le domaine des réseaux de neurones :

 

  • Linear : Utilisé en couche de sortie pour une utilisation pour une régression. On peut la caractériser de nulle, puisque les unités de sortie seront identiques à leur niveau d’entré. Intervalle de sortie (-∞;+∞).

 

  • Step : Elle renvoi tout le temps 1 pour un signal positif, et 0 pour un signal négatif.

step heavyside

 

  • Sigmoid (logistic) : Fonction la plus populaire depuis des décennies. Mais aujourd’hui, elle devient beaucoup moins efficace par rapport à d’autre pour une utilisation pour les couches cachées. Elle perd de l’information due à une saturation que cela soit pour la phase de feed forward ou de backpropagation, en donnant des effets non linéaires au réseau due à un paramètre unique. Elle a aussi des soucis de gradient 0 avec des entrées étant très large, même si le soucis est minimalisé avec les système utilisant des batch par lots (mini batch). Utilisé en couche de sortie pour de la classification binaire. Intervalle de sortie : {0,1}logistic sigmoid

 

  • TanH : Utilisé pour des LSTM pour des données en continue. Intervalle de sortie : (-1,1)
    tanh

 

  • Softmax : Utilisé pour de la multi classification en couche de sortie. Intervalle de sortie (-∞;+∞).softmax

 

  • ReLU ( Rectified Linear Unit ) : Ce sont les fonctions les plus populaires de nos jours. Elles permettent un entrainement plus rapide comparé aux fonctions sigmoid et tanh, étant plus légères. Attention au phénomène de ‘Dying ReLU’, auquel on préférera les variations de ReLU. Plus d’informations en fin d’article. Très utilisé pour les CNN, RBM, et les réseaux de multi perceptron. Intervalle de sortie (0;+∞).rectified linear unit

 

  • Leaky ReLU : La Leakey Relu permet d’ajouter une variante pour les nombres négatifs, ainsi les neurones ne meurent jamais. Ils entrent dans un long coma mais on toujours la chance de se réveiller à un moment donné. Intervalle de sortie (-∞;+∞).leaky ReLU

 

  • PReLU (Parametric ReLU) : La paramétrique Leaky Relu permet quant à elle de définir alpha comme paramètre du modelé et non plus comme hyper paramètre. Il sera alors apprentis sable. Il sera ainsi modifié durant la rétro propagation du gradient. Le top pour de large datasheet, moins bon sur de petit, causant d’éventuelle sur ajustement. Intervalle de sortie (-∞;+∞).Parametric ReLU

 

  • TReLU (Thresholded ReLU) : Elle est identique à la simple ReLU. Mais la localisation de son seuil d’activation va être décalé, il n’est plus à 0, mais selon un paramètre theta.

 

  • RRELU (Randomized Leaky ReLU) : La Randomise Leakey Relu permet de choisir le hyper paramètre ALPHA. Durant l’entrainement alpha est choisi aléatoirement. Puis durant les tests, il est calculé via une moyenne. Intervalle de sortie (-∞;+∞).randomized leaky ReLU

 

  • ELU ( Exponential Linear Unit ) : Autre dérivé de la ReLU. Celle-ci va approcher les valeurs moyenne proche de 0, ce qui va avoir comme impact d’améliorer les performances d’entrainements. Elle utilise exponentiel pour la partie négative et non plus une fonction linéaire. Elle parait plus performante en expérimentation que les autres Relu. Pas de soucis de neurone mort (dying ReLU). Intervalle de sortie (-∞;+∞).exponential ReLU

 

  • SeLU (Scaled ELU) : C’est comme ELU en redimensionné mais avec en plus un paramètre ALPHA pré définit. Bon résultat, bonne vitesse, et évite les problèmes d’explosion et disparition de gradients en s’auto normalisant et gardant les mêmes variances pour les sorties de chaque couche, et ce tout au long de l’entrainement.

 

 

Problèmes récurrents

Les fonctions standards amènent au réseau la disparition ou l’explosion de gradient, et donc une saturation et entraîne un ralentissement de la back propagation dans les couches basses du réseau. Voici une liste d’éventuels problèmes que vous pouvez rencontrer concernant ce chapitre :

  • Problème de disparition de gradient : L’algorithme progresse vers les couches inférieures du réseau, rendant les gradients de plus en plus petits. La mise à jour donc par descente de gradient ne modifie que très peu les poids des connexions de la couche inférieur, empêchant une bonne convergence de l’entrainement vers la solution.

 

  • Problème d’explosion du gradient : Dans ce cas-ci, les gradients deviennent de plus en plus grands. Les couches reçoivent alors de trop gros poids, faisant diverger l’algorithme.

 

  • Dying ReLU : La Relu souffre d’un souci : saturation pour les nombres négatifs, ce qui entraîne la mort de certains neurones, ils arrêtent de produire autre chose que des 0. Dans certains cas, la moitié des neurones peuvent mourir durant un entrainement. Il est peu probable qu’il reprenne vie en cours d’entrainement, rendant le réseau passif. C’est là que les variantes sont utiles puisque leur principal idée est d’empêcher pour la partie négative d’avoir des gradient égale à zéro.

 

 

Recommandation personnel

Sur le papier, les ReLU fonctionnent bien mieux en pratiques que les fonctions standard. Mais ce n’est pas pour autant la peine d’en mettre à toute les sauces. Il faudra choisir la bonne fonction selon votre type de problème à résoudre. Mais si vous débuter et que votre choix n’est pas sûr, commencer par expérimenter alors avec la ReLU pour avoir un premier retour. Celle-ci fonctionnera très bien dans la plupart des cas.

Me concernant, les résultats de ELU sont meilleurs que les autres Relu pour avoir comparé personnellement l’ensemble des fonctions lors de mon stage sur un cas précis de NLP/CNN. Mais les calculs seront plus lents car on utilise exponentiel pour la partie négative, en ajoutant de la non-linéarité. Donc si vous avez le temps et la puissance de calcul nécessaire, je vous conseille l’ordre suivant d’utilisation :

 

  1. ELU
  2. SeLU
  3. PReLU
  4. Variante de ReLU ( Leaky ReLU, Randomized ReLU, Thresholded ReLU )
  5. ReLU
  6. TanH
  7. Sigmoid

Source image : wikipedia, stackexchange

data augmentation Cours théoriques - Intelligence artificielle

Data augmentation

Pour pouvoir entrainer nos modèles, il nous faut d’énormes quantités de données. En effet, la quantité et surtout la qualité de notre dataset va avoir un rôle majeur pour l’élaboration d’un modèle de bonne facture. En effet, il est logique d’avoir avoir des données qui soient comparable entre elle. Quand je dis comparable, c’est qu’elles aient le même format, la même taille et longueur, etc. Et c’est à partir de ces contraintes que commence les problèmes. En effet, avoir des data spécifique selon notre problème avec les points précèdent cité peut souvent relever de l’impossible. C’est là que la data augmentation va pouvoir nous être grandement utile.

Le principe de data augmentation repose sur le principe d’augmenter de façon artificielle nos donnée, en y appliquant des transformations. On va pouvoir augmenter la diversité et donc le champ d’apprentissage de notre modèle, qui va pouvoir mieux s’adapter pour prédire de nouvelles données. Le principe de cette méthode est relativement simple, celle-ci est montré par l’image suivante concernant de l’augmentation sur des images :

data augmentation sur image

En partant d’une simple image, nous pouvons la dupliquer autant de fois que nous avons des types de transformation différentes à lui appliquer. Et nous pouvons en augmenter davantage en croisant ces effets sur une même image, et en y appliquant différents valeurs de l’effet dans une fourchette donnée, pour avoir un résultat plus ou moins poussé.

 

Voici un exemple de mel-spectrogramme, dont on à appliquer des transformations à un extrait audio sain, sur le mot ‘Bonjour’. (Figure 1)

data augmentation sur audio

On peut aussi imaginer un grand nombre de transformation sur des données audios.
– Tempo : change la vitesse de parole de l’enregistrement sans en changer la longueur. (Figure 3)
– Pitch : change l’intonation de la voix (plus aigüe ou plus grave). (Figure 2)
Et la liste peut être plus longue : bandpass, equalizer, highpass, lowpass, chorus, delay, stretch, contrast, etc.

regularisation du réseau Cours théoriques - Deep learning

Régularisation du réseau

La régularisation du réseau a pour principal objectif de prévenir le sur apprentissage (overfitting). Celle ci, va pouvoir via différentes techniques, permettre de gérer les éventuels débordements des paramètres du réseau au cours de l’entrainement.

  • Dropout : On va souhaiter favoriser l’extraction de caractéristique de façon indépendante, afin d’apprendre des caractéristique plus général et plus diverse. Cela va consister à ‘éteindre’, à désactiver certains neurones du modèle, et ce de façon aléatoire d’une même couche, qui ne contribuera donc ni à la phase de feedforward, ni à la phase de backpropagation. D’un point de vue du réseau, cela revient à instancier la valeur en sortie d’une fonction d’activation à 0.
    Schéma du DropOut
    Schéma du DropOut. Source : StackExchange, @Matt Krause

     

  • DropConnect : On va reprendre le même principe que précédemment. Mais au lieu de désactiver des neurones, on va simplement désactiver les connexions entrantes (toujours de façon aléatoire) sur une couche depuis la précédente. D’un point de vue du réseau , cela revient à instancier les valeurs des poids des connexions à 0.
    Schéma du DropConnect
    Schéma du DropConnect. Source : StackExchange, @Matt Krause

     

  • L1 regularization (lasso regression) :  Cette méthode ci va plutôt avoir une action de prévention , pour contenir les variables du réseau dans des intervalles spécifique, afin que celle-ci ne deviennent au cours de l’entrainement trop extrêmes. Pour ce cas là, cette régularisation va ajouter un terme de régularisation à notre fonction de perte, correspond à la somme des valeurs absolues de nos poids. Approche les poids vers 0. Fonctionne bien lorsque on est dans un cas avec énormément de caractéristiques. Utile pour des réseaux dont les données sont espacés.

 

  • L2 regularization (ridge regression) : Celle ci va aussi ajouter une pénalité à notre fonction de perte, de sorte que l’ensemble des erreurs soient minimal, ou maximal, mais pas entre les deux. En effet, il correspond à la somme des valeurs au carré de nos poids. Utile pour des réseaux dont les données sont rapprochés.

 

  • Max-Norm regularization : Empêche les poids d’exploser lorsque on utilise de haut taux d’apprentissage. Très utile lorsque l’on utilise des optimizer avec decay ( optimizer avec un learning rate haut au départ, et qui diminue au fil des entraînements, ex : Adagrad, etc.), sans même l’utilisation de drop-out.

 

On peut combiner l’utilisation simultané de la régulation L1 et L2. Cependant en pratique, on note un avantage pour la L2 qui donne de meilleurs résultats.

neurone biologique et artificiel Cours théoriques - Deep learning

Fonctionnement du neurone artificiel

Représentation mathématique/informatique d’un neurone biologique
Représentation mathématique/informatique d’un neurone biologique

Le neurone artificiel va recevoir plusieurs entrées d’informations, plusieurs valeurs, qui vont être attaché à un poids qui peut être ajusté. Ces entrées correspondent aux dendrites, et les poids qui leurs sont associés, correspondent aux actions excitatrices ou inhibitrices des synapses, ils vont pouvoir amplifier ou minimiser un signal d’entrée. Le neurone dans sa forme basique, va effectuer une somme de l’ensemble de ces variables en fonction de leurs poids, correspondant au soma. Cette valeur passe ensuite par une fonction d’activation, qui en sera l’unique sortie. Celle-ci correspond au point de départ de l’axone qui est le cône d’émergence.

Le principe de ces réseaux va donc être d’assembler de grande quantité de neurone entre eux pour former des couches.

Il existe une grande variété de type de neurone, qui engendre selon leur agencement, différents type d’architecture.