Archives par mot-clé : machine learning

Machine Learning avec le cloud Amazon AWS

Il fut un temps où l’étude de l’apprentissage automatique ou apprentissage statistique était mon quotidien. Depuis on est passé du machine learning au Deep Learning sous fond de  cloud computing. Beaucoup de mots nouveaux pour des concepts pas si neufs en fait. En revanche, je dois avouer que le syntagme « Deep Learning » est un tantinet de rien du tout plus bankable et sexy que le titre d’un mémoire tel que: « Optimisation d’ensembles de classifieurs non paramétriques avec apprentissage par représentation partielle de l’information« . Et pour être tout à fait honnête il ne s’agit pas non plus exactement de la même chose.

Il fut donc un temps pas si lointain où je m’intéressais de près aux problématiques d’apprentissage. Depuis, pour toutes sortes de raison dont celle-ci, j’ai commencé à m’intéresser aussi aux services de cloud computing (doit-on vraiment dire infonuagique ?), notamment ceux offerts par Amazon (un célèbre vendeur de chaussettes et autres bidules essentiels).

Ce vendeur de babioles toutes aussi nécessaires les unes que les autre offre aussi un ensemble de services infonuagiques (AWS) pas piqué des hannetons.

Récemment, au gré de mes pérégrinations autour dece service, je rencontre cette promesse: Amazon Machine Learning. Forcément, cela m’interpelle aussi tins-je mordicus à tenter l’expérience.

La promesse est donc la suivante: on fournit des données en entrée, Amazon fournit la capacité de calcul et le savoir faire pour créer un modèle de prédiction, ou de classification sans trop avoir besoin de s’encombrer des détails d’implémentation.

Je veux tester. Alors comment faire ?

Le plus évident me semble alors de ressortir de fond des boules à mites des données sur lesquelles j’ai déjà pu travailler. En l’occurrence une célèbre base de données étiquetées de chiffres manuscrits (MNIST) dont voici quelques exemples ci-dessous.

Exemples de chiffres issus de la base de données MNIST
Exemples de chiffres issus de la base de données MNIST

Je me propose donc ici de relater cette expérience. Cette base de données a été exploitée par de nombreux chercheurs, et notamment Luis Oliviera qui vers 2003 obtenait un taux de reconnaissance de plus de 99%. Moi-même, dans un contexte légèrement différent mais sur les mêmes données, j’arrivais autour de 97%. La question est donc la suivante: comment, hors des laboratoires de recherche et 10 à 15 ans plus tard, les services grand public performent-ils?

Préparation de la base de données

L’aide en ligne de Amazon ML stipule que les données d’apprentissage doivent être au format CSV (Comma-separated values). Chaque ligne représente une observation et les colonnes représentes les différentes caractéristiques extraites pour chacune des observations. Dans notre cas, j’utilise les concavités et countours présentés par Olivera dans l’article « A methodology for feature selection using multiobjective genetic algorithms for hand written digit string recognition« .

Il s’agit globalement d’histogrammes sur les concavités (6 vecteurs de 13 dimensions = 78 caractéristiques).

Histograme des concavités
Histogramme des concavités

Concaténés avec 6 autres vecteurs d’histogramme des contours (6 vecteurs de 8 dimensions = 48 caractéristiques).

Histograme des contours
Histogramme des contours

Finalement, l’aire (nombre de pixels noirs) de chacune des 6 régions est ajoutée pour donner créer un point dans un espace de 78 + 48 + 6 = 132 dimensions. Les différents histogrammes sont normalisés mais je laisse le lecteur curieux le soin de se référer à l’article original pour en connaitre tous les détails.

Chacune des observations, ici des chiffres manuscrits, est donc réduite à n’être plus qu’un point dans cet espace de 132 dimensions.

J’ai retrouvé quelques unes des ces bases de données avec les caractéristiques extraites. Il ne reste plus qu’à les restructurer légèrement afin que Amazon ML puisse les lire. Il me faut donc les transformer au format CSV. Puisque dans mes fichiers les champs sont séparés par une espace (j’insiste sur le caractère féminin de ce mot dans le contexte typographique) et non pas par une virgule, un petit coup de

 sed 's/ /,/g' TRAIN1k > TRAIN1k.csv
Remplacer les espaces par des virgules dans un fichier

fera l’affaire pour remplacer toutes les espaces par de virgules.

Il est aussi dit que chacune des colonnes doit être identifiée par un nom. Pour ce faire, il existe deux méthodes. La première consiste à mettre le nom de chacune des caractéristiques au format CSV sur la première ligne du fichier. La seconde est des mettre ces informations dans un second fichier au même format. J’opte pour la seconde méthode puisque qu’elle me permettra de réutiliser le même fichier pour différentes base de données (en faisant varier la taille des données d’apprentissage par exemple). L’alternative étant de coller cette en-tête au début de chaque nouveau fichier. Au final, je me suis aperçu que nommer les colonnes était tout à fait optionnel.

Nommer nos caractéristiques ne ressemble évidemment à rien dans notre cas quand on comprend comment elles ont été extraites. Je choisis donc de les nommer Feature_1, Feature_2, etc. La dernière colonne se nommera Target puisque c’est la cible (la bonne réponse, la classe recherchée). Le petit one liner (oserais-je un uniligne?) qui va bien est le suivant:

for I in `seq 132`; do echo -ne "Feature_$I,"; done > header.csv;  echo Target >> header.csv
Générations des noms de colonnes dans un fichier CSV

J’ai donc 133 valeurs séparées par des virgules, les 132 premières étant Feature_1, Feature_2, et la dernière Target. Ce qui correspond à mon fichier d’entrée.

Upload du fichier

Il faut le mettre dans S3 (ou Redshift). Par exemple j’en ai mis un ici. Le fichier d’en-tête est quant à lui ici.

Il faut bien s’assurer que Amazon ML a les permissions pour accéder aux fichiers déposés sur S3. Bizarrement, cela s’avère ne pas être trivial et je suis resté longtemps avec le message ci-dessous.

Message d'erreur Amazon ML
Message d’erreur Amazon ML

Une fois que le système est bien configuré, on arrive à ceci:

Capture d'écran d'Amazon ML qui est content d'avoir validé notre fichier d'entrée.
Capture d’écran d’Amazon ML qui est content d’avoir validé notre fichier d’entrée.

Attention à bien choisir le type de donnée pour la cible. Le système supporte comme entrées et sorties des valeurs binaires, des valeurs numériques, des classes et du texte.

target-data-type

 

En laissant par défaut une valeur numérique comme sortie attendue, on crée un système qui fait de la prédiction et non pas un classificateur (ou classifieur). Et on se retrouve avec des résultats farfelus comme le montre la figure plus basse (farfelu pour notre problème spécifique, la prédiction de valeur étant dans d’autres cas un excellent cas d’application de l’apprentissage supervisé).

2016-11-06-17_59_54-parametres

Ce graphique nous dit que si on confond 1 avec 2, c’est moins grave que si on confond 1 avec 9 (car 1 est plus proche de 2). En prédiction (par exemple si on cherche à prédire une grandeur physique comme une vitesse) ça peut avoir un certain sens. Par contre, en classification il n’y a pas ce genre de proximité. On a trouvé la bonne réponse ou pas. Soit c’est un 1, soit c’est un 2, mais ce n’est pas entre les deux.

Donc on reprend. On choisi bien une target qui sera une Category.

Une fois l’apprentissage terminé, on a intérêt tester avec une nouvelle base de données, appelée base de test (ou de validation mais n’entrons pas dans ces détails). J’ai créé un premier modèle à partir de 5000 observations (uniformément distribuées). Et un base de test de 25000.

Le processus est vraiment simple. Une fois la base de données accessible, on appuie sur bouton et l’apprentissage commence. Cela n’a pris que quelques minutes pour créer un modèle à partir de 5000 observations.

On ne sait rien du modèle généré mais on peut en récupérer le taux de reconnaissance. Dans ce cas, un peu moins de 95% sur la base d’apprentissage. Si on ne peut récupérer le modèle, on peut cependant l’utiliser pour faire 3 choses:

  • mesure sa performance en généralisation en lui passant une nouvelle base de données étiquetées
  • classifier des bases de données non-étiquetées
  • classifier en temps réel des observations (par exemple venant d’une application smartphone)

Je me suis arrêté à la mesure de performance en généralisation en faisant varier la taille de l’ensemble d’apprentissage. La figure plus bas montre les taux de reconnaissance obtenus sur les bases d’apprentissage et de test. On semble arriver à une asymptote autour des 98% de reconnaissance, ce qui est un score tout à fait honorable pour un classificateur complètement généraliste.

Taux de reconnaissance sur les base d'apprentissage et de test

Outre un taux de reconnaissance, Amazon ML permet de visualiser une matrice de confusion (voir ci-dessous) et même de télécharger l’ensemble des prédictions faites par le classificateur.

Matrice de confusion

Conclusion

Amazon offre la possibilité d’utiliser son infrastructure pour faire de l’apprentissage supervisé. Il n’est pas nécessaire de comprendre comment l’apprentissage se fait, il suffit d’avoir des données étiquetées, de les mettre au bon format et de les envoyer. Les résultats, du moins sur des bases issue de MNIST sont tout à fait respectables. Bien qu’on ne puisse pas récupérer les modèles, on peut les utiliser couplés avec les autres services AWS. En d’autre termes, tout un chacun peut maintenant avoir un service web basé sur de l’apprentissage supervisé sans avoir de compétences particulières dans le domaine. Il faut bien sûr des données étiquetés et surtout, de bonnes features  bien extraites. Sur ce dernier point, la prochaine étape sera peut-être un Amazon Deep Learning ou quelque service du genre, permettant de laisser au système le soin de déterminer la meilleure représentation des données.

Identification de la langue d’un texte

 Identification de la langue d’un texte

Récemment, un article m’a rappelé qu’il était serait amusant de faire un système pour détecter de manière automatique la langue dans laquelle un texte est écrit. L’article en question parlait de complètement autre chose et ne faisait que reprendre les résultats d’un blog anglophone. Cependant, en présentant d’une certaine façon les distributions d’occurrence des lettres au sein de quelques langues européennes, je me suis souvenu que ces distributions donnaient une signature qu’on pouvait utiliser pour reconnaitre la langue d’un texte. Ce peut aussi d’ailleurs être utilisé pour briser les codes simples comme le chiffre de César tel que Simon Singh nous l’expliquait dans son excellent livre sur l’histoire des codes secrets.

Pour créer les signatures, on peut analyser la fréquence d’occurrence des lettres individuelles, mais aussi des séquences de deux lettres consécutives. Par exemple en français, la séquence « ch » est plus fréquente que « sh » ou « cz ». D’autres langues présenteront d’autres proportions pour ces même suites. Et pourquoi s’arrêter à deux ? On peut aussi répertorier les séquences de trois, quatre ou N lettres consécutives. C’est ce qui s’appelle des  n-grams. Ça ne se résume pas qu’aux lettres et ça ne sert pas qu’à détecter une langue, mais c’est le contexte dans lequel le présent projet va les utiliser.

Sommairement, il s’agit donc de :

  • Créer des signatures basées sur les n-grams pour différentes langues
  • Extraire la signature d’un texte inconnu dont on veut identifier la langue
  • Comparer sa signature avec celles des langues « apprises »
  • En déduire l’idiome du texte

La signature n’étant que l’histogramme des fréquences d’occurrence des différents n-grams.

Heu… mais pour quoi faire ?

Clarifions tout de suite un point : je n’en ai personnellement aucune utilité. Ce n’est ni lié à des sujets professionnels, ni à un quelconque outil qui pourrait me servir. La recherche sur le sujet est bien avancée et je ne cherche pas à l’approfondir. Tous les jours on peut d’ailleurs voir à l’œuvre des sites qui ont de très bons résultats dans le domaine. Cependant, la (relative) simplicité de mise en œuvre d’une solution à un problème qui peut sembler aussi complexe est fascinante.  C’est donc en pur dilettante que j’ai envie de jouer un peu avec ce problème.

D’un autre côté, bien que la solution soit conceptuellement simple, quelques détails pratiques font qu’il y a tout de même quelques petits défis à relever et questions à répondre. Comment trouver des données d’apprentissage ? Comment gérer les caractères internationaux, l’Unicode et les codages à nombre variable d’octets (par exemple l’UTF-8) ? Que faire de la ponctuation, des espaces, ou même des tags HTML dans le cas où les données viendraient de source web ? Quelle technique choisir pour mesurer la similarité des signatures (vecteurs de cardinalité et de dimensions différentes) ? Comment présenter les résultats ? Bref, suffisamment d’interrogations pour rendre le projet intéressant.

 Étapes du projet

Avant de me lancer, j’ai détaillé sommairement les grands blocs ou thèmes sur lesquels il faut travailler. Je les présente ci-dessous, sachant que cela n’a rien de formel. Ce découpage est relativement orthogonal, ce qui permet de travailler indépendamment sur un sujet ou un autre.

    • Création des bases de données
      1. Obtenir des sources de texte
      2. Analyse des langues
      3. Stockage des résultats
    • Reconnaissance de la langue
      1. Analyse et création des signatures
      2. Comparaison avec les signatures en base de données
      3. Calcul des estimations de probabilité pour chaque langue
    • Interface et interaction
      1. Soumission des données à analyser
      2. Mise à jour de la base de données
      3. Affichage des résultats

 État des lieux

Corpus d’apprentissage

J’ai quelques pistes pour les corpus d’apprentissage. J’ai expérimenté un peu avec Wikipedia qui permet de télécharger l’intégralité de son contenu à un instant t. C’est trié par langue et de nombreuses langues sont disponibles. Pour récupérer le contenu de Wikipedia, c’est mieux que :

quirysse@beluga:~$ wget --random-wait -r -p -e robots=off -U mozilla http://en.wikipedia.org/wiki/Main_Page

Le problème c’est que c’est gros. Très gros.

wilhelm@beluga:~/WikiCrawl$ ll -h *xml
-rw-r--r-- 1 wilhelm woodself 46G Jul  9 00:58 enwiki-latest-pages-articles.xml
-rw-r--r-- 1 wilhelm woodself 12G Jul 16 21:00 frwiki-latest-pages-articles.xml
wilhelm@beluga:~/WikiCrawl$
Espace occupé par deux langues sur Wikipedia

 

De plus, les fichiers sont codés en XML dans le langage de Wikipedia, ce qui après quelques tests, même après avoir enlevé les tags XML, on trouve beaucoup d’occurrences de  » [[ »  et autres balises du genre. Ça reste quand même une option mais un peu de préparation de la base de données s’avèrera nécessaire. Il y a une piste avec European Parliament Proceedings Parallel Corpus 1996-2011. C’est d’ailleurs ce qui a été utilisé dans l’article cité plus haut.

Analyse

La génération d’histogrammes d’unigrammes, de bigrammes et de trigrammes n’est pas un souci en soi. Cependant, il faut penser au codage Unicode et comme l’UTF-8 semble tout indiqué, il faut gérer le fait qu’un caractère puisse être composé d’un nombre variable d’octets. Un article complet sur le sujet est en préparation, puisque grâce à cette bibliothèque on peut arriver rapidement  à une solution.

Stockage

Les histogrammes, on en fait quoi ? Ils peuvent être longs à générer. On peut vouloir les mettre à jour en utilisant de nouveaux corpus et de nouvelles langues. Alors SQL, fichier maison ? A voir.

Détection de la langue

De façon naturelle on pense au cosinus, mais ça cause certaines difficultés. Je pense plutôt à une erreur RMS ou une distance euclidienne sur les dimensions présentes dans le vecteur d’entrée. Et puis qu’est-ce qu’on fait des hapax et des n-grams très rares. On les garde ou on nettoie le vecteur d’entrée ? Rien n’est fixé mais on en reparlera.

Interface

Évidemment, tout commence toujours pas une série de petits scripts bash et 2 ou 3 mini programmes en C++. Mais au final, une API REST pour obtenir les probabilités des différentes langues sachant une signature pour un texte en entrée, ça serait sympa, non ? Et une page web où l’on verrait les probabilité évoluer en même temps qu’on entre du texte dans un champ, ça serait encore mieux ! C’est un dossier qui est encore un peu loin, mais il y a du potentiel pour faire un système agréable. Pour l’instant, on va en rester au bash…

Conclusion

Donc, voilà où on en est. L’UTF-8 est à peu près réglé (article à suivre). Reste à faire le reste. C’est à dire, à peu près tout…