Thématiques principales

Affichage des articles dont le libellé est Apprentissage. Afficher tous les articles
Affichage des articles dont le libellé est Apprentissage. Afficher tous les articles

mercredi 13 mars 2019

Math: La nature des données

Jusqu'à maintenant nous nous somme intéressé comment construire un outil capable de soit prédire des données futurs (avec des modèles de régression) soit prédire l’association de celle ci avec des ensembles divers (classification)

Ces deux types de modèles sont en fait typique de la nature des données manipulées ou de la nature des données de sorties souhaitées, ici respectivement des données quantitatives et qualitatives [1,2].

samedi 10 novembre 2018

La Veille Technologique

S’il fallait des raisons d’apprendre

La veille technologique est un processus incontournable aujourd'hui dans n'importe quel domaine et métier mais cette vérité est d'autant plus forte dans le monde de l'IT tant cet eco-système change vite et se transforme rapidement.

Les concepts changent, les processus changent, les technologies changent et tout cela en même temps et ne pas les suivre c'est s'exposer à devenir rapidement inadapté face, pour d'une part, à des besoins clients  en perpétuels évolutions mais aussi d'autre part à des exigences de performances qui doivent faire face a des enjeux de dimensionnement de plus en plus présent (comme avec l’essor du BigData et par extension du Machine Learning cette dernière décennie [1])

Ainsi ne pas faire de veille technologie, par extension, c'est s'exposer individuellement a l'inadaptation face à un marché de l'emploi qui lui aussi évolue vite. J'ai, moi même, comme j'en ai parlé dans mon article un peu auto-biographique [2], pu perdre a certains moment le fil de l'actualité du monde technologique et théorique. Ainsi selon mon évaluation (ça ne vaut que mon avis), aujourd'hui, si un individu s'endort pour quelques 2 a 4 années, alors le gap qu'il aura a combler sera pour lui équivalent a repasser une bonne année des études qu'il avait pu suivre lorsqu'il était étudiant!
Je n'imagine pas la masse de travail a faire si il s'endort plus longtemps car cela ne prend pas en compte bien d'autres phénomènes qui intervienne au delà de ne rien faire.

Un des premiers phénomènes est celui de l'oubli, après combien de temps parvenez vous encore a exploiter des connaissances que vous avez acquises quelques temps plus tôt? honnêtement? 1 mois? 3 mois ? 6 mois? 1 an? 3 ans? 5 ans? Bien sur ce qui est appris est globalement acquis, mais le temps est délétère et selon la manière que cette connaissance a été acquise, il en restera plus ou moins les bases au mieux et nécessitera des révisions.
Personnellement je pense que au delà 3 mois sans utilisation, une technologie nouvelle devra être révisé, et que pour une connaissance couramment utilisé, il faudra probablement 3 années d'inutilisations pour impliquer la nécessite d'une révision (si a ce moment la cette technologie ou connaissance est encore d'actualité!)
De plus, il existe des freins et des limites propres a l'hommes qui font qu'il est nécessaire de faire de la veille technologique régulièrement. Par exemple:
  • les biais cognitifs (bais de confirmations, préjugé, culture, etc...) qui auront altérer notre lecture initiale des faits et qui dans le temps ne feront que renforcer un point de vue sur un sujet qui sera peut être complètement erroné [3]. La veille technologique permet d'apprendre a réviser son jugement et ainsi passer outre nos préjugés (nous évitant alors de passer a coté de sujet intéressant voir même important 
  • le vieillissement est malheureusement un fait et comme on dit, parmi les génies, seuls ceux de moins de 40 ans ont réalisé des grandes choses et des bouleversements justifiant des changement de paradigme : il ne faut donc pas compter sur l'age pour nous aider a être plus performant. Pourtant, la veille technologique a l’intérêt, au delà du travail d'apprentissage de connaissances, d’entraîner le cerveau a réfléchir, a construire sa pensée, a imaginer, a se restructurer. 
  • la confiance en soit, peut être un frein a la connaissance, et la veille technologique peut permettre de gagner en confiance et être plus capable de se mettre en avant sur des sujets.
Au delà de l'acquisition de connaissance brut, la veille est donc un indispensable, elle permet de se maintenir a jour de l'actualité mais aussi de maintenir ses sens en éveil, se maintenir prêt a relever de nouveau défi quitte a même aller sur des sujet non connus!  C'est même la peut être la partie la plus utile de la veille technologique, garder l'esprit aguerri a la réflexion et a la résolution de problématiques sans avoir peur de sortir de son cadre.

WWWWH

Maintenant que l'on s'est donné (de bonnes) raisons de faire de la veille technologique, regardons un peu du coté du WWWWWH [4] pour creuser les axes de cette démarche.

Why ?

Evidemment nous n'allons pas refaire la partir introductive de cet article mais restons pragmatique, pourquoi faire de la veille technologique? Plusieurs points de vue peuvent être aborder:
  • Court terme : le besoin projet, c'est peut être ce qui est le plus pragmatique, pouvoir mettre directement en pratique ce que l'on apprend!
  • A moyen terme : Assouvir de la curiosité mais aussi se maintenir a jour techniquement et aussi parce qu’il ne faut pas attendre qui que ce soit pour préparer l'avenir, sachant que ce sont probablement ces connaissances qui permettront d’accéder a certains autres types de projets
  • A long terme : entretenir les connaissances, mais aussi alimenter la curiosité personnelle de façon a continuer a faire un métier qui nous passionne, un métier ayant du sens.

When ? Where ?

Inutile de dire que ce chapitre sera court! Tous le temps, Partout! Comme le disait Einstein (citation du livre d'Etienne Klein, le pays qu'habitait Albert Einstein [5]):
"L'essentiel dans l’existence d'un homme de mon espèce, réside dans ce qu'il pense et comment il pense, non dans ce qu'il fait ou souffre"
En substance, signifiant pour moi que peu importe le lieu et le temps pour quoique ce soit, l'essentiel est l'utilisation de sa pensée et la manière de la construire. Et autant cela n'engage que moi mais la veille technologique (tout apprentissage en fait) a un rôle structurant pour la pensée qui est important de développer.

What ?

La question du sujet de la veille technologique est compliqué. Il s'agit ici d'un élastique tendu au bout de lequel on trouvera d'un coté, les sujets d’intérêts et de l'autre les sujets utiles!
Toute la difficulté dans une carrière sera de réussir a reboucler cet élastique! On peut distinguer différents types de sujet:
  • les sujets généraux ou transverses
  • les sujets spécifiques ou ciblés
Les premiers auront généralement pour but de donner du sens a une activité de veille technologique. Ce seront donc des sujets plutôt de méthodologie, conceptuel, historiques, et ou posant un contexte. Nous sommes alors plus dans un contexte de vulgarisation.
Les second seront des ramifications des premiers en s'attachant a entrer dans l'intimité d'un aspect du domaine considérer. Il s'agira donc plutôt de sujets abordant certaines technologies, frameworks ou encore de sujets décortiquant une problématique données. Pour aborder ces points, il faudra généralement un certain bagage.

How 

La partie la plus intéressante! Comment réaliser sa veille technologique? Probablement en ne faisant pas faire n'importe quoi non plus! Il importe que ce travail d'apprentissage soit pertinent et efficace! 

Tout d'abord, passons en revu les basiques:
Il est évident qu'il faut avant toute chose identifier un sujet intéressant. On sait pertinemment que la capacité d'apprentissage sera directement conditionné par le taux d’intérêt qui sera alloué au sujet. Bien sur on nous dira:

"Parfois, certains sujets, même indispensable, ne sont pas intéressant! "

C'est vrai, parfois il faut effectuer des veilles technologiques sur des sujets peu ou pas intéressant parce que ce sont des choses déjà vu et qu'il faut alors réviser ou parce que simplement ce sont des pre-requis qui sont juste pas intéressant. Dans ce genre de situation, l’idéal est de coupler le sujet avec un autre pour lequel l’intérêt sera plus grand. Ainsi, l'utilisation du second sera un prétexte pour le premier. L’idéal est même que le second soit une technologie déjà un peu maîtrisée de façon a limiter la marche a gravir.
Une fois le sujet cerné, il importe d'identifier les bagages nécessaires pour l’appréhender. Autant commencer par le commencement! Cela mène à construire un programme pour sa veille technologique. Sans cela, le risque est de sortir du cadre du sujet que l'on souhaitait traiter, attiré par l'ensemble des sujets amont à celui ci, sans cela, le risque est de se retrouver, un mois plus tard, a finalement encore préparer la veille du sujet initial!
Apres il ne faut pas non plus être trop exigent avec soit même car parfois en vagabondant, on se découvre de nouveaux centres d'intérêts et de nouvelles choses a apprendre, c'est ca aussi la veille technologique, s'ouvrir a d'autres choses. 

Ainsi, il est bien de se planifier sa veille technologique mais pas trop afin d’être raisonnable et réaliste avec des objectifs atteignables! Cela évitera de se décourager et de perdre le rythme et finalement abandonné en pensant "je suis trop vieux pour ces conneries". 

Dans le cas ou il faut tout apprendre d'un sujet alors il sera préférable de se tourner vers des supports autres que internet de façon a avoir des sources plus englobante (on sera alors plus sur des sujet généraux comme ceux dont nous avons parlé précédemment)
Maintenant que l'on a cerner le sujet, et identifier les pré-requis, il va falloir trouver les moyens de s'informer. Bien sur la première approche est de se tourner vers internet. Effectivement, on y trouve beaucoup d'informations (peut être parfois trop) sous de nombreux formats:
  • l'article les articles sont souvent un peu plus généraux et donne une vision d'ensemble de sujet spécifique
  • la vidéo est un support un peu spécial, souvent pratique pour les sujets généraux car permettant de comprendre les tenant et aboutissant d'un sujet, par contre lorsqu'il s'agit d'entrer techniquement dans les sujets, cela devient plus compliqué a suivre et nécessite de jouer beaucoup avec le curseur d'avancement. Pas fan personnellement, je peux comprendre que d'autre y adhère plus facilement (que moi), question d'affinité.
  • le tutorial est un article exclusivement dédie a la démonstration, très pratique pour acquérir une expérience, elle ne permet pas forcement par contre de comprendre les concepts sous-jacent contrairement aux article
  • la présentation est un exercice délicat, elle doit marié un contenu intéressant et une bonne pédagogie. Elle apporte la possibilité de connaitre un point de vue spécifique peut être différent de sa propre compréhension et d’étayer le sujet avec l'interlocuteur. 
  • le blog souvent très pratique car regroupant des articles ou des tutoriaux, il permettent d’acquérir une connaissance très précise sur un sujet ou d'une problématique
  • la doc technique est exclusivement a réservé pour ceux qui ont déjà le bagage mais qui cherchent des détails ou qui sont dans une phase de POC
  • le mooc est une formation en ligne mixant articles, tutoriaux et vidéos. Souvent a réserver a des vielles technologiques conséquente, quand on part de loin sur un sujet.
Enfin, dans les cas difficile ou trop conséquent, il faudra préférer probablement s'appuyer sur un livre de façon a avoir un support couvrant l'ensemble des problématiques dans un formalisme homogène et cohérent.

Nous n'avons encore pas vraiment parler d'outils ou de méthode (enfin si avec cette article) cependant, il me semble que la phase de construction de la connaissance est une étape intime et que si vous en êtes la c'est que vous avez déjà depuis longtemps appris a apprendre et que vous vous connaissez et savez comment optimiser cette phase d'assimilation et de compréhension.

Pour ma part, elle se réalise assez simplement:
  • Identifications des sources intéressantes par une lecture rapide filtrante
  • Relecture approfondi par une prise de note
  • Synthèse général par quelques schéma (UML, Mindmap, ERA selon votre domaine de compétence et vos connaissances, nous verrons que cela sera utile par la suite)

Enfin suite a cela a priori, et c'est ce qui viendra en tête de tout le monde, il faut mettre en oeuvre ce qui est appris. C'est effectivement très important car au delà de nous permettre de comprendre les avantages et inconvénient d'une technologie, la mise en oeuvre permet aussi de consolider l'apprentissage en se confrontant aux lacunes de la compréhension que l'on a du sujet (prejugé, biais cognitif, etc...). 

La mise en oeuvre se réalise par un POC (Prove Of Concept).  Il va permettre de vérifier que la technologie offre bien les services qu elle annonce mais et surtout va permettre de savoir que l'on est capable de l'utiliser!

A ce stade alors on pourrait s'attendre à ce que le processus de veille soit a ce stade terminé... il n'en est rien, réaliser un POC est une chose mais le terme de la veille n'est pas cette phase. Finir correctement une veille technologique nécessite de transmettre ce qui a été appris.

Teach

Pour débuter ce paragraphe, je citerai Robert Heinlein :
"When one teaches, two learn" 
Oui, enseigner a d'autres ses connaissances c'est faire aussi de la veille technologique! 

Même si cela est fait très rarement par même ceux faisant de la veille technologique regulierement, la dernière phase d'un apprentissage quel qu'il soit est de démontrer sa capacité à restituer ce que l'on connait. Cela augmente significativement la maîtrise du sujet étudié pour les raisons suivantes:

  • Mon directeur de thése citait souvent Nicolas Boileau (que je paraphraserai pas): 
"Ce que l'on conçoit bien s'énonce clairement"
  • Faire une restitution des connaissances acquise impose de se confronter a la réalité de notre compréhension car en transmettant son savoir, on doit être en mesure de garantir celui-ci! Il faudra donc se pencher plus sur les détails de faire une préparation donnant du sens a l'ensemble, de la cohérence. 
  • Impose, contrairement au POC ou la mise en oeuvre ne permet que de démontrer notre capacité utiliser une technologie, d'en avoir compris les tenant et aboutissant, les éléments pivots, etc...
Donc enseigner va permettre de consolider sa propre connaissance mais aussi d’être face aux choses que l'on aura oublié, a coté duquel il est possible de passer, les subtilités car heureusement, les gens auquel la restitutions s'adressent ne sont probablement pas complètement vierge de connaissances sur le sujet! C'est même du coup la l'occasion de confronter des idées et des points de vue.


Comment transmettre? A qui?


Alors du coup finalement vient la question de comment transmettre? et a qui? Il s'agit d'une question a laquelle chacun doit donner une réponse selon le contexte dans lequel il évolue et les sujets qu'il traite!
Tout d'abord le comment. De la même manière que certaines sources d'informations ont permis d’acquérir des connaissances, rien n’empêche de produire le même genre de support. Ça peut être un blog (comme moi) ou des vidéos (dans la mouvance youtube) mais il faut garder en tête l'objectif de ce travail, le support ne doit pas devenir non plus plus complexe a mettre en oeuvre que le sujet lui même! 

Apres c'est selon l'envies mais il faut garder une chose importante en tête, la veille technologique, c'est pour vous. Le succès de transmettre ses connaissances est un plus si des gens y ont appris quelque chose, ce qui compte c'est le travail de formalisation, consolidation qui a été nécessaire.
Se poser la question de à qui enseigner ses connaissances acquises lors de la veille technologique, c'est avant tout et surtout une question cherchant a positionner le profil de l'interlocuteur cible.
On peut en définir plusieurs types:
  • le novice sur le sujet. Dans ce cas, la restitution de la veille technologique doit être très progressive, il s'agit de ne pas noyer l'interlocuteur. Cette approche progressive aura alors pour intérêt dans la veille technologique de démontrer la maîtrise globale et cohérente du sujet. On sera ici plutôt dans un exercice de vulgarisation.
  • l'expert du sujet. Il faudra pour un public aguerri être très prudent. Bien poser les concepts du sujets et être précis dans les démonstrations. L’intérêt de ce public est d'imposer a votre discourt un certain degré de justesse dans ce qui sera présenté car la critique pourrait être cinglante en cas de grosse bévue. Par contre les échanges seront plus pertinent et enrichissant.
  • l'inconnu. Ce sera l'interlocuteur le plus difficile, car faute de savoir se positionner, il faudra considérer un support de communication adapté au deux types d'interlocuteurs présentés précédemment.

Conclusion

Certains diront que la veille technologique est surement un indispensable mais qu'ils n'ont pas le temps. Effectivement, on a tous une vie en dehors du travail, cependant dans le monde de l'IT ou tout change très vite, on ne peut se satisfaire des formations d'entreprise pour se tenir a jour. De plus, la veille technologique est une activité complexe qui pour être efficace doit être mené régulièrement mais aussi avec de la méthode.
Dans cet article, a été présenté une approche (celle que je suis personnellement) permettant de mener cette veille tout en tachant de la rendre efficace au mieux. Elle consiste globalement a bien sur hiérarchiser les sujets mais aussi après en avoir pris connaissance et avoir fait une mise en oeuvre, a réaliser un travail de restitution.

Pour aller un peu plus loin, voici quelques articles et blog permettant de compléter et confronter mon point de vue [6], [7], [8]

Références

[1] Big data et Machine Learning, 2016, de Pirmin Lemberger (Auteur), Marc Batty (Auteur), Médéric Morel (Auteur), Jean-Luc Raffaëlli (Auteur)
[2] https://un-est-tout-et-tout-est-un.blogspot.com/2018/09/100-un-peu-dautobio.html
[3] http://www.psychomedia.qc.ca/memoire/2014-05-29/transformation-des-souvenirs
[4] https://un-est-tout-et-tout-est-un.blogspot.com/2017/12/qqoqccp.html
[5] Le pays qu'habitait Albert Einstein Broché – 19 octobre 2016, Etienne Klein
[6] https://www.camilleroux.com/2009/09/20/conseil-realiser-bonne-veille-technologique/
[7] https://linuxfr.org/news/methode-et-outils-pour-la-veille-technologique
[8] https://toiledefond.net/5-outils-pour-commencer-une-veille-sur-internet/

jeudi 4 octobre 2018

Meta-article : Rédiger des articles pertinent (essayer...)

Propos

Un article méta aujourd'hui: après avoir retiré le dernier article du blog sur les statistique, je me suis dit, non, la il faut plus de matière et moins de blabla, du coup on va essayer de se recentrer sur la qualité.

Forcement avec cette question vient celle de comment produire de la qualité lorsque nous réalisons un article et la je me suis souvenu toutes ces années de thèse ou inlassablement j'ai du réécrire, et réécrire mon manuscrit.

A l’époque, je n’étais pas le seul juge de ma qualité rédactionnelle. Aujourd'hui je suis un peu plus en roue libre et sur certains sujets, je pense que cela peut se ressentir et c'est d’ailleurs pour cela que j'ai retirer mon précédent article afin de monter un peu le niveau.

Du coup voila un article un peu méta puisqu'il va traiter de la manière d’écrire un article (ou un document en général quel qu'en soit le support), le rendre attrayant, et surtout mieux le structurer de façon a ce que son contenu soit pertinent (et dans une veille technologique , chose qui est le propos de ce blog, c'est mieux...)

Attention loin de moi de prétendre avoir une recette magique surtout que j'ai moi même beaucoup de mal à appliquer ce qui va suivre alors un peu d'indulgence et prenez ceci comme un ensemble d’ingrédients à tenter d'utiliser avant de vous attendre a ce que ce soit appliqué à la lettre (ce qui serait en plus absurde), L'idée ici est d’être pragmatique et de trouver un degré de suffisance afin d'avoir quelque chose ayant un fil conducteur, un fond intéressant et une forme porteuse du sujet traité.

Tout d'abord, qu'est ce qu'un document ou un article? C'est un support d'information ayant pour objectif principal (il peut en avoir d'autre) la transmission d'informations. Transmettre de l'information, cela relève de plein de domaines, la pédagogie, tout d'abord, mais aussi de la communication, du marketing etc.... Rassurez vous nous n'irons pas non plus sur ce terrain la!

Quel Objectif ?

Ecrire un document c'est avant toute chose se fixer un objectif qu'il va falloir avant toute chose formuler. Celui-ci doit être :

  • positif (nous élaborons des choses, il faut rester dans une démarche constructive)
  • défini dans un périmètre maîtriser ou du moins métrisable
  • suffisamment précis (pour être réalisable dans un temps raisonnable) 
  • mesurable en terme d'avancement afin de déterminer si et quand l'objectif est atteint

Bien sur la solution a notre objectif est ici la rédaction d'un document.

En somme, si nous reprenons les 4 points:

  • Nous nous doutons que la démarche de transmission et de consolidation de connaissance est une démarche positive (au delà de la pertinence du sujet traité). 
  • La définition du périmètre peut sembler une tache facile mais elle nécessite de bien poser les pré-requis en terme de connaissance nécessaire a la compréhension du document mais aussi d’être capable de mesurer le gap de connaissance acquis pendant la lecture de celui-ci:  Connaissance initiale + connaissance acquise. Tout ceci n'est pas simple à déterminer tant la connaissance initiale du lecteur peut être très différente de celle du rédacteur et qu'il est très très facile de digresser sur des sujets annexes.
  • C'est la que le sujet doit être précis, alors pas précis en terme de technicités mais en terme de clarté et de périmètre. Car autant un article général sur un sujet, peut avoir précisément pour objectif de survoler le sujet de façon a donner un tour d'horizon de l'ensemble des problématiques.
  • La mesurabilité est la aussi un problème: car bien que nous pouvons nous dire une fois qu'il est écrit le document, et bien, il est fini quoi.... bien non... il n'est pas si évident que ça de déterminer a quel moment un document est fini. D'une part il est possible de réécrire les paragraphes quasiment de façon infini, mais si nous faisons des fautes, a un moment, il faut savoir accepter que nous ne les corrigerons pas toutes, les schémas sont ils tous correctement fait? etc... etc... Et a l'inverse sur un document difficile a écrire nous pourrions être amener a vouloir finir en bâclant et la il est important de savoir si le degré de suffisance est quand même atteint. En fait, déterminer quel moment faut il s’arrêter est probablement la partie la plus compliqué.

Bien nous partons donc maintenant du principe que nous avons un objectif remplissant ces différents critères. Nous nous lançons donc dans notre document (article, présentation ou autre)

Le document

Première chose a ne pas faire: lui donner un titre! OK ça semble assez facile et quand nous avons définit notre objectif nous nous sommes dit: "tiens ça serait bien de traiter de ça" mais non en fait donner un titre tout de suite, c'est en réalité commencer par la fin.

Non pas de titre tout de suite mais un pitch! Il faut savoir que sur un document (de lecture ou auquel nous assistons comme une présentation), ce qu'il en reste c'est le 1/5 et le dernier 1/5 et encore leur rôle est différent :

  • le premier 1/5 a pour but de captiver l'interlocuteur, lui donner toutes les réponses qu'il attend et c'est sur cette base qu'il prendra la peine de poursuive sa lecture ou son écoute. C'est cela qui va le garder concentrer.
  • le dernier 1/5 est la fin du doc, s'il n'est pas gavé et qu'il a maintenu son intérêt alors ce seront probablement ce qui restera de votre travail dans sa tête (sinon au mieux c'est le premier 1/5). Il est important ici de reprendre le éléments essentiels pour clarifier le message (faire une redite histoire de marteler) et surtout ouvrir le débat afin de donner envie de revenir.

La Big Picture

Le premier 1/5 du document est la partie introductive. Elle est extrêmement importante car c'est la première chose qui sera lu ou écouté. En somme c'est la Big Picture du document:  elle doit répondre le plus rapidement possible au question QQOQCP [1] et doit positionner l'objectif qui sera atteint une fois le document parcouru. A la fin de cette partie, l'interlocuteur doit être capable de produire un résumer du document juste au travers de son idée importante, son message essentiel.

Un plan

Ensuite il faut présenter le plan du document, c'est important car cela va aider a ce que l'interlocuteur sache ou il va et ne se perde pas. On pourra même réintroduire les sous parties de la même manière que le traitement du premier 1/5 du document comme si le document n’était que la composition de sous documents.  Comme avec la Big Picture, cela permettra de relancer l’intérêt de l'interlocuteur a chaque chapitre.

Processus

Un fois l'introduction faites et le plan construit, il importe alors de jeter le plus rapidement possible le contenu du document dans son format choisi, le mieux étant de faire ce processus sans interruption afin de garder le fil conducteur dans la tête (sinon on met un temps fou a se reconcentrer). Ce qui compte c'est que le contenu et les idées soient positionnées peu importe la forme ou la façon.

C'est une fois que tout le contenu est posé qu'il est alors possible de peaufiner en réordonnant les chapitres mal structuré, réécrire les paragraphe peu clair et évidement corriger les fautes d'orthographe majeures. Attention a ne pas en faire trop, comme on dit 80 % du travail se réalise avec 20% de l’énergie et ce sont les 20 dernier % qui vont ensuite coûter les 80% d’énergie restant. Il importe donc de rester pragmatique et de ne pas en faire trop car, il advient souvent qu'a cette étape et dans les suivantes on continu des réécriture de fond importante ou des suppressions conséquentes. Inutile donc de corriger des erreurs qui seront par la suite potentiellement réintroduites ou de toute façon complètement supprimées.

Surtout que nous nous occupons ici encore du fond et non de la forme et il est très fastidieux de traiter les deux en même temps.

Dans le concret, pour peaufiner il faut se définir des critères de qualités :
  • simplicité: faire des phrases courtes en évitant le jargon ou les acronymes. Sinon bien les introduire  et les expliciter de façon a les rendre abordable et accessible (comme une évidence)
  • éliminer les informations n’étant pas directement pertinent avec le sujet traité. C'est le principe du rasoir d'Ockham. Il faut éviter la digression pour garder l'interlocuteur avec vous.
  • préférer l'utilisation du présent de narration et les tournures impersonnelles. Elles permettent de garder une distance entre l'idée et le narrateur de façon a ne pas faire de confusion dans la critique de l'individu et des idées relayées par celui-ci. 
  • Ne par énoncer la description de quelque chose mais a l'inverse de présenter cette chose comme se présentant elle même. Ainsi on ne dira pas:" sur le schéma, on peut voir ..." , mais plutôt "le schéma présente ....".
  • Supprimer tout ce qui ressemble a un jugement de valeur. Les faits sont ce qu'ils sont, leur interprétation mènent a des conclusions, votre avis importe peu.
  • En parlant des faits justement, il importe d'avoir une démarche causale dans la représentation des événements ou du processus de traitement des faits. Cela permet de partir des cas particuliers illustrés par les exemples afin de construire des conclusions (pour ne pas dire généralités) acceptable et vérifiable 

Les schémas

Les schémas, regroupant tableaux, dessins, illustrations etc... ont un rôle très important dans un document. C'est même pour cela que sont produit des présentations ou seul les schémas persistent et sont le support principal de l'argumentation. Pourtant, la aussi, il est nécessaire de suivre quelques règles.

Tout d'abord, pourquoi faire des schémas?
  • Parce que c'est synthétique
  • Ça nécessite un effort de lecture moindre facilitant la mémorisation
  • C'est un langage universel
Du coup faire des schémas, si ces derniers sont bien fait, fournira des documents plus plaisant, plus compréhensible et donc attise et maintien l’intérêt de l'interlocuteur tout en lui permettant de reprendre son souffle.

Par contre bien évidement, il ne faut pas en abuser. Ainsi, le bon ratio étant généralement entre 1/5 et 1/10 de l'espace du document.

Pour construire un bon schéma, la aussi, differentes règles sont à suivre. Elles sont proche de celui du document lui même:

  • Etre simple en limitant les concepts :pas de phrases, principe du 5+/-2 éléments clefs, charte des couleurs minimaliste (un arc en ciel est plus complexe a analyser qu'une image en noir et blanc...)
  • Aller a l'essentiel en se focalisant sur un minimum d'informations nouvelles. Trop d'information fera perdre l'objectif du schéma, il est plus pertinent d'en réaliser plusieurs construit autour de variation d'un même support afin de bien dissocier les préoccupations et les messages.
  • Etre rapidement compréhensible en un minimum de temps d'observation, l'interlocuteur doit avoir compris le message
  • Autonome ou autoporteur. Le schéma doit se suffire a lui-même c'est a dire que toute information explicative annexe est un problème de conception. Le schéma alimente l'argumentation mais l'argumentation ne doit pas le justifier.

Le cas du tableau (de données) est un peu particulier car celui-ci n'est pas un dessin ni du texte. Pourtant, il va suivre une règle simple qui va de soit avec tout ce que nous avons vu:

  • S'il faut exposer 3 a 5 nombres alors une phrase peut suffire
  • S'il faut exposer jusqu’à une vingtaine de nombre alors on fait un tableau
  • Au dessus de 20 nombres,  il faut faire un schéma de synthèse des données

Enfin vient le cas du schéma spécifique tel que ceux s'appuyant sur UML et nécessitant une connaissance technique du langage de schématisation. La règle est en fait la même, aller au plus simple, il importe d’être compris, tous les détails sont superflux s'il n’amène pas de la pertinence au message véhiculer par le document. Ainsi, pour ce genre de schéma, il faut simplifier et expliquer si celle-ci n'est pas possible.

Finalisation

Voila, maintenant il reste a effectuer les dernières lectures. Celle-ci ne doivent plus être tourné vers le fond mais quasi exclusivement sur la forme. C'est probablement la phase la plus fastidieuse car elle nécessite de prendre du recul sur le contenu. L'aide de quelqu'un complètement étranger au sujet peut être une bonne chose car n’étant pas du domaine, le fond sera moins impactant pour lui.

Une fois cette tache effectuée, reste a trouver un titre! il est fort probable qu'a ce stade celui ci soit assez évident. Alors attention, selon le public il faudra malgré tout composer avec quelques contrainte:

  • Si vous vous adressez a des experts, le titre doit être direct et remonter les mots clefs importants du document. On doit savoir de quoi ça parle juste en le lisant.
  • Par contre si le public est plus large et qu'il faut séduire et accrocher, il ne faut pas hésiter a tendre vers le "putaclic" [2] sans trop sur vendre le produit.... sinon gare a la déception des interlocuteurs...

Conclusion

Nous n'avons pas tout évoqué, et les techniques de vente d'un document sont très varié. Il me semble qu'avec cette approche, il est possible de fournir quelque chose d’honnête et de qualité. Il importe surtout de toujours savoir rester simple et de ne pas en faire trop, être pragmatique!

Apres peut être que certains points sont sujet a discussion, il me semble que tous font etat du bon sens mais on ne peut pas toujours être d'accord ni avoir toujours raison mais j’espère que cela donnera quelques premières armes pour écrire vos prochains documents.

Références

[1] https://un-est-tout-et-tout-est-un.blogspot.com/2017/12/qqoqccp.html
[2] https://fr.wiktionary.org/wiki/putaclic

samedi 15 septembre 2018

IA: Equation normale

Il y a quelques jours, j'avais parlé de l’équation normale dans la régression linéaire [1]. Nous n'avions pas traité de son utilisation dans la régression linéaire parque:
  • c'est la solution analytique et que du coup c'est la solution simple
  • elle ne s'applique qui si les jeux de données sont limitées
  • c'est pas fun car on voulait utiliser la descente de gradient.
Du coup nous l'avions laissé de coté, la pauvre....

Aujourd'hui on va rendre a l’équation normale ce qui appartient à l’équation normale, c'est a dire la régression linéaire.

Dans le principe, l’équation normale [2] est la résolution analytique parfaite des coefficients du modèle linéaire:



Avec Theta, le vecteur des coefficients du modèle, X le vecteur des données d'entrée et Y le vecteur des données de sortie attendues.

Pour illustrer cela, prenons un exemple en python:


1
2
3
4
5
6
7
import numpy as np
 
MAX=1000
    
X=  np.arange( 0, MAX )
T= 4+3*X  
Y= T + (np.random.rand(1,MAX)-0.5)[0]*3000 

Dans cet exemple, nous allons construire une série de valeur de 0 a 3000, on en calcule la série T équivalente selon une droite dont on va bruité les données: la série Y.

Représentons ces données:

1
2
3
4
5
import matplotlib.pyplot as plt
fig = plt.figure(1,figsize=(8,8))
plt.plot(X,T,"b-")# model lineaire
plt.plot(X,Y,"r.")# model lineaire bruité
plt.show(



Donc on a bien déployer nos données autour de la droite T. Avant de chercher des paramètres, en première approche, nous pourrions nous demander si l’équation normale est capable de nous retrouver les paramètres initiaux de la droite avant que celle ci ne soit bruitée.

Appliquons l'equation normale a (X,T) afin de voir si le Theta resultant est bien le couple (4,3):


1
2
3
4
5
Xmat=np.c_[np.ones((len(X),1)),np.mat(X).T]
Ymat=np.mat(T).T

Verif=np.linalg.inv(Xmat.T.dot(Xmat)).dot(Xmat.T).dot(T)
print(Verif)

De résultat:

[[4.]
 [3.]]

Cool! Au moins on sait que l'on sait retrouver nos paramètres! A noter la préparation des données avec la fonction c_ (concatenate) et ones qui permet de construire une matrice unitaire (rempli de 1). L'objectif de cette préparation est de permettre de produire une paire de valeur.

Maintenant reprenons nos données buitées et calculons nos paramètres, au passage calculons les valeurs résultants du modèle sur l'ensemble des valeurs d'entrées:

1
2
3
4
Xmat=np.c_[np.ones((len(X),1)),np.mat(X).T]
Ymat=np.mat(Y).T
TheTa=np.linalg.inv(Xmat.T.dot(Xmat)).dot(Xmat.T).dot(Ymat)
print(TheTa)

donnant:

[[-165.91134982]
 [   3.24312348]]

OK cela ne correspond pas a nos paramètres initiaux. Mais peut etre que cela donne une bonne approximation de nos données. Superposons les graphes:


1
2
3
4
5
6
ThetaD=np.array(TheTa[0])+np.array(TheTa[1])*X
fig = plt.figure(1,figsize=(8,8))
plt.plot(X,Y,"r.")# model lineaire bruité
plt.plot(X,T,"b-")# model lineaire
plt.plot(X,ThetaD.T,"y-") # taux erreur de base deux precedents
plt.show()

Effectivement nos deux droites ne sont pas les mêmes, cependant, au vue de la dispersion, celle estimé est une assez bonne approximation de la première. Bien sur c'est lorsque l'on sortira du périmètre de l'ensemble [0-1000] que les encarts se feront les plus important. Il faudra donc en tenir compte lors de l'utilisation du modèle résultant de façon a minimiser les erreurs.

Voila, en fournissant une solution analytique, l’équation normale fourni une approche assez immédiate pour la détermination des paramètres de notre modèle. Apres il reste comme tout autre approche limité par l'ensemble des données du jeu d’apprentissage dont la taille peut rendre celle ci rédhibitoire.

Références

[1] https://un-est-tout-et-tout-est-un.blogspot.com/2018/09/started-ia-neuromimetique-la-regression.html
[2] http://gilles.dubois10.free.fr/geometrie_affine/eucliequanorm.html

dimanche 9 septembre 2018

IA : Neuromimétique, la régression linéaire

Nous revoilà sur un sujet un peu plus sympa pour ce début septembre, la régression linéaire.

Cet article aurait du être publié en août mais le temps a manqué, et j'ai voulu profiter du précédent article sur les Streams [1] pour essayer une approche un peu différente de ce tour d'horizon de ce que l'on peut faire avec un neurone!

Du coup aujourd'hui, il s'agit de présenter la régression linéaire en s'appuyant sur les Streams Java. Comme nous l'avions vu dans les articles précédents sur l'IA [2], nous allons créer un jeu de données d'apprentissage et un jeu de donnée de test sur deux cas d'utilisations (en fait 3 nous verrons pourquoi):
  • l'un sur l'identification de paramètres : nous allons donc demander a notre neurone de nous donner les paramètres (a,b) d'une droite tel que y=a.x+b
  • l'un sur la construction d'un modèle prédictif partant d'une droite bruité artificiellement (nous traiterons ici de plusieurs cas différents afin de considérer les situations qui marchent bien de celles, moins pertinentes)
Pour cela, nous n’utiliserons qu'un seul modèle de fonction d’activation : le linéaire [3]. Nous pourrions utiliser le sigmoïde mais ça risque de faire vraiment long... peut être que dans un autre article nous nous intéresserons a cette dernière.

Enfin concernant le mode d'apprentissage, nous utiliserons un apprentissage supervisé. Nous n'avions pas beaucoup parlé de ce point dans nos précédents articles sur la classification [2] [4], ou nous avions élaboré un modèle basé sur une correction simple du vecteur des paramétrés portés par les dendrites du neurone. Ici ça sera l'occasion de découvrir la descente de gradient [5] et par la même occasion quelques fonctions de coût nous permettant d’évaluer l'efficacité de notre modèle.

Pour bien comprendre cet article, je vais d'abord en donner les lignes directrices:

  1. Tout d'abord, comme nous n'utilisons pas encore de frameworks spécifiques pour le machine learning (comme scikit-learn [6]) ou de framework de réseau de neurone comme Tensor-Flow [7] ou Keras [8]), il nous faut d'abord construire un  neurone, lui donner une implémentation pour la fonction d'activation, et lui donner une fonction d'apprentissage.
  2. Ensuite, nous tacherons de monitorer le neurone lors de son fonctionnement afin de nous permettre d'observer comment vont évoluer ses paramètres lors de l'apprentissage, et comment va évoluer son  efficacité en fonction de ses paramètres.
  3. Enfin, nous ferons une petite séance de visualisation de données sous python afin d'avoir des schémas explicatifs des données monitorées.

Voila, ça va être dense!

Le neurone

Nous en avions déjà fait un en python pour la classification. Ici on va aller a l'essentiel:

  • Un tableau de paramètre représentant les poids des dendrites (biais inclus).
  • Une fonction linearInfer permettant le calcul de la sortie du neurone (produit matricielle du vecteur d'entrée avec le vecteur des poids) inféré sur la fonction d'activation linéaire).
  • Une fonction d'apprentissage learnStep permettant la correction des poids selon des données étiquetés fourni par la classe Data
  • Quelques méthodes utilitaires comme la méthode reset permettant d'initialiser les données des poids de façon aléatoire.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class Neurone {

    public Double[] dendrites;

    public Neurone(int inSize)
    {
        this.reset(inSize);
        System.out.println(this);
    }

    public void setParameter(Double v,Double b)
    {
        this.dendrites[0]=v;
        this.dendrites[1]=b;
    }

    public void reset(int inSize)
    {
        this.dendrites= Stream.generate(() -> Math.random()/1000).limit(inSize+1).toArray(Double[]::new);
    }

    public Double linearInfer(Double[] stepInputs)
    {
        ...      
    }

    public void learnStep(Set<Data> datasSet)
    {
        ...
    }

}


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
public class Data {

    public Double[] input;
    public Double output;


    public Data(Double[] input,Double output)
    {
        this.input=input;
        this.output=output;

    }
}

Nous voila donc une ébauche de neurone et une structure de données pour gérer les données d'apprentissage.


mardi 17 juillet 2018

IA : Neuromimétique : classification sigmoide

Nous avons traité dans un article précédent de la classification de fruits (ananas et pastèques) avec un neurone en employant une fonction d'activation linéaire [1]

Nous avions évoqué la possible utilisation dans ce genre de problématique de fonctions d'activation de type sigmoide. Je vous propose donc de reprendre l'article précédent en appliquant ce type de fonctions a notre problème et comprendre leur fonctionnement, leur interprétation possible.

Considérons donc une autre manière d’implémenter nos neurones en vous proposant le rework suivant:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import math

def neuroneCore(entre,W,biais):
    return np.dot(entre,W.T)-biais
    
def limiter(a):
    if a > 0:
        return 1
    return 0

def sigmoid(a):
    return 1 / (1 + math.exp(-a))
    
def neuroneLim(entre,W,biais):
    a=neuroneCore(entre,W,biais)
    return limiter(a)

def neuroneSig(entre,W,biais):
    a=neuroneCore(entre,W,biais)
    return sigmoid(a)

Avec ce rework, on sépare d'un coté la fonction calculant la pondération des entrées par les dendrites et ensuite on applique dessus soit la fonction limiter soit sigmoïde. On a du coup deux types de neurones. Ce sera ici le seconde type qui nous intéressera.

Appliquons lui les poids initiaux que nous avions appliqués avec en entrée nos deux profils de fruits.

1
2
3
4
5
6
7
8
W=np.array([[1, 1, 1, 0]])
biais=1.5

pasteque=np.array([[0.2, 0.3, 0.2, 0.95]])
anana=np.array([[0.8, 0.65, 0.6, 0.8]])

print(neuroneSig(pasteque,W,biais))
print(neuroneSig(anana,W,biais))

1
2
0.31002551887238755
0.6341355910108007

Bon ceci signifie donc que la pastèque est a 31% un ananas et un ananas est un ananas a 63%. Oui n'oublions pas que avec le limiter, l'ananas valait 1 et la pastèque 0. Donc c'est assez logique donc que d'un coté le taux de similarité d'un pastèque avec un ananas soit prêt de seulement 30%... par contre il faut avouer que pour un ananas, on se serait attendu a être un peu plus ressemblant a un ananas!

N'oublions pas que ces taux sont issus d'un modèle produit a l'intuition. Essayons avec les poids issus de l'apprentissage en mode linaire pour rappel (W=[ 3.40784321 2.44027133 2.17143355 -1.26320997] )

1
2
3
W=np.array([[3.40784321, 2.44027133, 2.17143355, -1.26320997]])
0.12462296460187255
0.7340302487024424

Et bien, c'est évident que c'est mieux, 12% et 73% ! mais ce ne sont que des résultats obtenu sur les profils. Il faut regarder ce que nous donne ce modèle sur l'ensemble des données de test (oui car techniquement avec ce W on a déjà utilisé les 3/4 des données pour l'entrainement).

Mais comment évaluer l'efficacité du modèle? Comment évaluer la pertinence de ces différents taux ?

Ce que l'on peut imaginer pour valider ce nouveau type de neurone, faire c'est de construire un algorithme qui selon la valeur de la sortie du neurone,  classe en ananas ou en pastèque le fruit testé avec pour restriction qu'entre par exemple 40 et 60%, il faut considérer que le fruit est indiscernable et donc mis dans une autre catégorie erreur.

Mais attendez, on avait vu avec la matrice de confusion, qu'il était aussi possible que parfois lorsque l'on détecte un ananas, en fait c'est une pastèque et inversement! Il va nous falloir donc aussi des données étiquetées que nous confronterons avec la valeur prédite par le neurone quand celle ci est soit inférieur a 40% soit supérieur a 60%

Construisons d'abord nos données étiquetés, données d'entrainement et données de tests.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
pasteques=generateSet(pasteque,1999,4)
ananas=generateSet(anana,1999,4)
pasteques2=addEtiquette(pasteques,0)
ananas2=addEtiquette(ananas,1)

datas=pasteques2+ananas2
random.shuffle(datas)
print(len(datas))
datasApprentissage=datas[:3000]
datasTest=datas[3000:]
print(len(datasApprentissage)+len(datasTest))

La bien sur vous allez dire mais on a déjà un W, pourquoi refaire des données d'entrainement? Ba effectivement on va re-procéder a une phase d'entrainement de notre modèle car si nous avions trouvé un modèle intéressant dans l'article précédent, ici, il ne faut pas oublié que nous utilisons une fonction d’activation de type sigmoïde pour laquelle nous avons décidé que toute réponse comprise entre 40% et 60% serait ignoré. Ainsi pendant la phase d'entrainement, il semble pertinent de procéder a la même règle.

A noter de plus que sans nous en apercevoir, dans notre phase d'apprentissage avec un limiter, nous avions un peu mis de coté les corrections sur le biais! Corrigeons ça:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
biaisFactor=np.array([[1, 1, 1, 1]])
marjMin=0.25
marjMax=0.75

print("W initial:",W,biais)    
for (val,etiquete) in datasApprentissage:
    sortie=neuroneSig(val,W,biais)
    if(sortie < marjMin) or (sortie > marjMax):
        W=majW(W, sortie, etiquete,val)
        biais=(np.dot(W,biaisFactor.T))/2
    
print("W final:",W,biais)  

1
2
W initial: [[1 1 1 0]] 1.5
W final: [[16.20492332 10.44986249 12.34447655  2.96069606]] [[20.97997921]]

Par curiosité, que se passe t il si on applique ces paramètres sur nos profils? Regardons.

1
2
print(neuroneSig(pasteque,W,biais))
print(neuroneSig(anana,W,biais))

1
2
8.938402177973581e-05
0.9998068041389231

Wahou! Presque 0% et 99%! C'est prometteur!

Calculons notre matrice de confusion car c'est probablement trop beau.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
erreur=[]
patequesTestIsP=[]
patequesTestIsA=[]
ananasTestIsP=[]
ananasTestIsA=[]
#Revoir comment construire le taux d'erreur
for (val,etiquete) in datasTest:
    sortie=neuroneSig(val,W,biais)
    if (sortie > marjMin) and (sortie < marjMax):
        erreur.append(val)
    if (sortie < marjMin) :
        if etiquete == 0:
            patequesTestIsP.append(val)
        if etiquete == 1:
            patequesTestIsA.append(val)
    if (sortie > marjMax):
        if etiquete == 0:
            ananasTestIsP.append(val)
        if etiquete == 1:
            ananasTestIsA.append(val)

print(len(erreur),":",len(datasTest))
print(len(patequesTestIsP),":",len(datasTest))
print(len(patequesTestIsA),":",len(datasTest))
print(len(ananasTestIsP),":",len(datasTest))
print(len(ananasTestIsA),":",len(datasTest))

1
2
3
4
5
15 : 1000
471 : 1000
40 : 1000
22 : 1000
452 : 1000

Donc nous avons comme matrice de confusion les données suivantes:
  • 15 données indécidables
  • 471 pasteques qui sont bien des pasquetes!
  • 452 ananas qui sont bien des ananas!
  • 40 pasteques qui se prennent pour des ananas
  • 22 ananas qui se prennent pour des pastèques
Donc nous avons 471/(471+22)=0.95 de précision et 471/(471+40)=0.92 de rappel (nous ne comptons pas les données exclu puisque c'est justement le but)

C'est effectivement mieux que pour la classification avec une fonction d'activation limiter.

Maintenant essayons de comprendre comment ça marche. Visualisons un peu nos données.

1
2
3
4
5
6
7
8
9
fig = plt.figure(1,figsize=(12,12))

plt.plot(patequesTestIsP.T[0],patequesTestIsP.T[1],"b.")
plt.plot(ananasTestIsA.T[0],ananasTestIsA.T[1],"b.")
plt.plot(patequesTestIsA.T[0],patequesTestIsA.T[1],"r.")
plt.plot(ananasTestIsP.T[0],ananasTestIsP.T[1],"y.")
plt.plot(erreur.T[0],erreur.T[1],"g.")
plt.xlabel('rugausité')
plt.ylabel('couleur')

Produisant le graphe suivant:


Il faut avouer que ce n'est pas très parlant même si l'on devine une section de données jaune quasi verticales.

Il ne faut pas oublier que nous traitons de données selon 4 dimensions ainsi, dans cette projection, l'hyperplan séparateur des deux classes de fruit n'est probablement pas perpendiculaire au plan du graphique. Ainsi, il est difficile de vraiment visualiser le résultat (ou il faudrait identifier une transformation des données dans un base adéquat... vous savez, matrice de passages, etc... je laisse ça aux motivés mais ça serait intéressant de s'y attarder quand même un de ces quatre).

Simplification

Pour comprendre malgré tout notre problème, je vous propose de le simplifier et de travailler seulement en deux dimensions des le départ.

Reprenons donc nos données et recalculons nos ensembles:

1
2
3
4
5
6
7
8
W=np.array([[1, 1]])#, 1, 0]])
biais=1.5

pasteque=np.array([[0.2, 0.3]])#, 0.2, 0.95]])
anana=np.array([[0.8, 0.65]])#, 0.6, 0.8]])

print(neuroneSig(pasteque,W,biais))
print(neuroneSig(anana,W,biais))

On adapte la procédure d’apprentissage

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#On utilise l'algo en limiter

biaisFactor=np.array([[1, 1]])#, 1, 1]])
marjMin=0.25
marjMax=0.75

print("W initial:",W,biais)    
for (val,etiquete) in datasApprentissage:
    sortie=neuroneSig(val,W,biais)
    if(sortie < marjMin) or (sortie > marjMax):
        W=majW(W, sortie, etiquete,val)
        biais=(np.dot(W,biaisFactor.T))/2
    
print("W final:",W,biais)        

Ensuite on fait passer nos données de tests dans notre algorithme d’évaluation (voir précédent celui ci n'a pas changé) et on finit par afficher les données en adaptant forcement au fait que nous sommes maintenant en deux dimensions (au passage on utilise les paramètres du neurone pour dessiner la droite séparatrice).


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
fig = plt.figure(1,figsize=(12,12))

plt.plot(patequesTestIsP.T[0],patequesTestIsP.T[1],"b.")
plt.plot(ananasTestIsA.T[0],ananasTestIsA.T[1],"b.")
plt.plot(patequesTestIsA.T[0],patequesTestIsA.T[1],"r.")
plt.plot(ananasTestIsP.T[0],ananasTestIsP.T[1],"y.")
plt.plot(erreur.T[0],erreur.T[1],"g.")
plt.xlabel('rugausité')
plt.ylabel('couleur')

x=np.linspace(0,1,10)
plt.plot(x,(biais[0][0]-W[0][0]*x)/W[0][1])

Voyons donc ce que cela donne:


Ainsi, tout devient plus clair avec cette simplification. Pour rappel, en bleu nous avons les données correctement classées, en vert, les données écartées, en rouge et jaune, les faux positifs et les vrais négatifs.

Avec ce graphe on comprend tout de suite mieux l’intérêt de la fonction sigmoïde. Elle permet de construire une zone autour de la droite séparatrice dans laquelle on pousse le modèle a ne pas prendre de décision (ou du moins donner aux prédictions une crédibilité minimale) Bien sur en faisant de la sorte, on sacrifie potentiellement des prédictions justes, cependant, et c'est le contexte de métier qui l'impose, il est parfois préférable de ne pas décider plutôt que de faire une erreur.

Ainsi en utilisant une fonction d'activation de type sigmoïde, on améliore la qualité de la classification en se permettant de rejeter certaines prise de décisions.

Conclusion

Voila, nous avons fait un bon tour de la notion de classification a l'aide de modèle linéaire (ici un seul neurone) Dans les prochains articles je vous propose, maintenant que nous avons acquis les bases des concepts de la classification , d'une part de découvrir quelques outils et framework permettant un travail similaire, et d'autre part d’élargir nos types de modèles. A très bientôt.

Références

[1] https://un-est-tout-et-tout-est-un.blogspot.com/2018/07/ai-approche-neuromimetique-la.html

samedi 14 juillet 2018

IA : Neuromimétique, la classification linéaire

Dans un article précédent [1], nous avons abordé la structure d'un neurone. Nous n'avions pas vu d'exemple pour illustrer son fonctionnement. Dans ce présent article, je vous propose de le compléter  en traitant d'un exemple de classification. Cela nous permettra d'explorer d'une part le fonctionnement intime du neurone et, d'autre part les grandes lignes du processus de mise en oeuvre d'un modèle au travers d'un exemple simple, celui du tri (binaire) de fruits: des ananas et des pastèques.

Le problème


Imaginons donc que l’on cherche à différencier des pastèques et des ananas. Ces fruits sont assez particuliers donc a priori on pourra facilement mettre en oeuvre un moyen de les discerner. Entre autre en les observant, on peut positionner 4 caractéristiques qui vont nous servir de critères suivant les ensemble suivant :
  • la rugosité -> 0 lisse a 1 rugeux
  • la couleur -> 0 bleu a 1 rouge
  • la forme -> 0 rond a 1 alongé
  • le poid -> 0 (20gr) à 1 (2000gr)
Ainsi pour chacun de fruits, des caractéristiques seront extraites et injecter dans les entrées de notre neurone (le vecteur X) tel que 


Sur cette base, nous pouvons constater une chose importante le neurone s'accommode bien de la nature des données, il est possible de mélanger des choux et des carottes… A l'inverse, du fait de la nature de poids, il est important d'avoir des données normalisés (de même ordre de grandeur) afin de ne pas biaiser le système en faveur d'une caractéristique plutôt qu'une autre. C’est pour cela que l’on place toutes les valeurs entre 0 et 1 (on aurait pu aussi se placer entre -1 et 1).

Visualiser les données

Nous avons pas vraiment de fruits alors pour l'exercice, je vous propose de nous donner un profil de fruits a partir duquel nous produirons deux ensembles nous permettant de travailler. Pour cela, exécutons le code python suivant.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
from random import randint, seed
import random
from mpl_toolkits.mplot3d import axes3d

import matplotlib.pyplot as plt
import numpy as np


def generateSet(prototype,nbrEchantillon,coef):
    rand_value=np.random.randn(len(prototype),len(prototype[0]))/coef
    #print(rand_value)
    rand_set=prototype+rand_value
    if nbrEchantillon == 0 :
        return prototype
    else:
        return np.concatenate((rand_set,generateSet(prototype,nbrEchantillon-1,coef)))

1
2
3
4
pasteque=np.array([[0.2, 0.3, 0.2, 0.95]])
anana=np.array([[0.8, 0.65, 0.6, 0.8]])
pasteques=generateSet(pasteque,1999,4)# -> pour separer les ensembles
ananas=generateSet(anana,1999,4)

Ensuite visualisons nos données selon plusieurs angles

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
x=np.linspace(0,1,10)

fig = plt.figure(1,figsize=(15,15))
ax = plt.subplot(221, projection='3d')# equivalent a fig.addsubplot

ax.scatter(pasteques.T[0],pasteques.T[1],pasteques.T[2], c='b')
ax.scatter(ananas.T[0],ananas.T[1],ananas.T[2],c="r")
plt.xlabel('rugausité')
plt.ylabel('couleur')
ax.set_zlabel('forme')

ax = plt.subplot(222)
plt.plot(pasteques.T[0],pasteques.T[1],"b.")
plt.plot(ananas.T[0],ananas.T[1],"r.")
plt.xlabel('rugausité')
plt.ylabel('couleur')

ax = plt.subplot(223)
plt.plot(pasteques.T[0],pasteques.T[2],"b.")
plt.plot(ananas.T[0],ananas.T[2],"r.")
plt.xlabel('rugausité')
plt.ylabel('forme')

ax = plt.subplot(224)
plt.plot(pasteques.T[0],pasteques.T[3],"b.")
plt.plot(ananas.T[0],ananas.T[3],"r.")
plt.xlabel('rugausité')
plt.ylabel('poid')


Ainsi une pastèque aura le profil moyen autour des coordonnées [0.2, 0.3, 0.2, 0.95] et un ananas [0.8, 0.65, 0.6, 0.8] 

Bien sur l’exemple est simple et on se rend vite compte que d'une part les données sont déjà très séparées et que d'autre part certains critères seront plus utile que d’autre a la construction du paramétrage du neurone.

Paramétrage

Pour définir les paramètres du neurone, il faut avant tout choisir une fonction d’activation. Plusieurs choix se présente à nous, nous les avions vu dans l'article [1]: nous n'utiliserons pas une fonction linéaire car nous ne souhaitons pas prédire la taille des fruits mais les classer (nous reviendrons sur les prédictions dans un autre article sur la régression linéaire) donc il faut choisir entre une limiteur et une sigmoide. 

Commençons par le limiteur (nous regarderons plus tard ce que l'utilisation du sigmoïde apporte). Le limiteur à pour intérêt de fournir une réponse franche à notre problème de classification en nous donnant pour réponse soit 1 (on va dire une ananas) soit 0 on va dire une pastèque. A noter que si on voulait trier plus de type de fruits, ça ne serait pas possible et il faudrait considérer un nombre plus important de neurones mais faisons déjà avec un car maintenant que nous avons choisi une fonction d’activation, il nous reste encore à le paramétrer le neurone (les poids et le biais).

De façon empirique, la détermination des paramètres est la configuration permettant de discriminer les entrées pertinentes pour séparer les deux ensembles (ananas et pastèques) Ainsi, intuitivement et analytiquement on se rend compte que le plus simple est de s'appuyer sur les paramètres discriminant, et d’annuler ceux qui ne le sont pas. Pour le biais, tentons une moyenne des paramétrés choisis:

W=[1;1;1;0] avec un biais 1,5. Testons de facon analytique:

  • limiteur((Wt.pasteque)-biais)=limiteur( 0.4- 1.5) =limiteur(-1.1 )= 0
  • limiteur((Wt.anana)-biais)=limiteur( 2.35- 1.5) =limiteur(0.85 )= 1

Vérifions en le codant: (on implémente avant quelques fonctions permettant de calculer la sortie du neurone)

1
2
3
4
5
6
def neuroneLim(entre,W,biais):
    a=np.dot(entre,W.T)-biais
    #print("a neurone:",a)
    if a > 0:
        return 1
    return 0

1
2
3
4
5
6
#vecteur de classification
W=np.array([[1, 1, 1, 0]])
biais=1.5

print(neuroneLim(pasteque,W,biais))
print(neuroneLim(anana,W,biais))

Ok ça marche c’est cool mais on a paramétré un peu au pif (enfin pas tout à fait) mais essayons de comprendre pourquoi ça marche.

Interprétation

Pour comprendre pourquoi ça fonctionne, il faut s’intéresser au sens mathématique de l’opération de combinaison linéaire de l'entrée et des poids du neurone qui consiste en un produit scalaire. Ce produit va favoriser numériquement les vecteurs ayant une orientation perpendiculaire à une droite séparatrice qui modélisera la démarcation entre nos deux types de fruit. En utilisant le biais pour correctement ajuster la position de cette droite sur selon les ordonnées. 

Ainsi, si l’on représente W sur nos ensembles sous la forme de vecteur, on se rend compte, que orientation de celui ci suit un groupe et rejette l’autre:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
x=np.linspace(0,1,10)

fig = plt.figure(1,figsize=(15,15))
ax = plt.subplot(221, projection='3d')# equivalent a fig.addsubplot

ax.scatter(pasteques.T[0],pasteques.T[1],pasteques.T[2], c='b')
ax.scatter(ananas.T[0],ananas.T[1],ananas.T[2],c="r")
plt.xlabel('rugausité')
plt.ylabel('couleur')
ax.set_zlabel('forme')


ax = plt.subplot(222)
plt.plot(pasteques.T[0],pasteques.T[1],"b.")
plt.plot(ananas.T[0],ananas.T[1],"r.")
plt.xlabel('rugausité')
plt.ylabel('couleur')
plt.quiver(0.5,0.5,1,1,scale=5)
plt.plot(x,1-x)

ax = plt.subplot(223)
plt.plot(pasteques.T[0],pasteques.T[2],"b.")
plt.plot(ananas.T[0],ananas.T[2],"r.")
plt.xlabel('rugausité')
plt.ylabel('forme')
plt.quiver(0.5,0.5,1,1,scale=5)
plt.plot(x,1-x)

ax = plt.subplot(224)
plt.plot(pasteques.T[0],pasteques.T[3],"b.")
plt.plot(ananas.T[0],ananas.T[3],"r.")
plt.xlabel('rugausité')
plt.ylabel('poid')
plt.quiver(0.5,0.75,1,0,scale=5)
plt.plot(0.5+x*0,x+0.2)
Donc en fait regarder si un fruit est un ananas, c’est regarder le signe du produit scalaire des paramètres de ce fruit avec les paramètres du neurone…. cool! On a compris comment le neurone fonctionne pour séparer des classes mais…. À ce stade plein de questions devraient vous venir ! comme:
  • Comment mesurer l’efficacité du neurone? est il possible de faire des erreurs pourquoi et comment?
  • Si effectivement il y a des erreurs, alors comment déterminer le séparateur optimalement (ie déterminer de façon formelle les paramètres de W sans y aller à la louche)?

Efficacité et performance

Pour répondre la première question, c'est à dire mesurer l’efficacité d’un RN il faut aller interroger quelques algorithmes et concepts du machine learning. Dans le cadre de la classification, on pourrait se dire, bien il faut donner au neurone des fruits à trier et en connaissant les réponses, faire la différence des bonnes et mauvaises réponses. 

Effectivement c'est une idée, je vous invite a le faire mais sans surprise, nous avons que des 1 pour les ananas et que des 0 pour les pastèques. Cool en même temps ce n’est pas forcement très étonnant puisque nos ensemble sont bien linéairement séparable même en temps.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
resultP=[]
for val in pasteques:
    resultP.append(neuroneLim(val,W,biais))
   
resultA=[]
for val in ananas:
    resultA.append(neuroneLim(val,W,biais))

print("pasteques:",sum(resultP)," somme:", (2000-sum(resultP))*100/1999)
print("ananas:", sum(resultA),"somme:", sum(resultA)*100/1999)
    

1
2
pasteques: 71  somme: 96.49824912456228
ananas: 1815 somme: 90.79539769884943
Tiens pas complètement... Pourquoi?, avons nous négliger quelque chose? Pourtant nous avons construit nos ensembles nous même et on peut légitimement croire que nos données sont bonnes.

En fait, bien que séparable linéairement, nous avons produit nos données selon une loi normale. Il y a donc toujours une possibilité de superposition des composantes qui bien que peu marqué introduit une potentielle erreur. On le voit d’ailleurs sur certains graphes précédent. 

En fait tout n’est pas toujours aussi simple. On pourrait avoir une superposition des composantes? Que faire alors les éléments ne sont pas linéairement séparable?

Étudions cette nouvelle problématique en changeant un peu le coef de génération de familles de fruits rendant certains critères moins facile à discriminer. Reprenons nos scripts précédent et changeons le paramètre 10 par 4 (deuxième bloc de code).



Nos résultats, comme démontré par le schéma, ne sont plus les même car il existe des ananas ayant des caractéristiques proches de ceux des pastèques et réciproquement du coup le taux de capacité à les différencier passe à 97% et 90%... ça reste honnête malgré tout mais on sent bien que l’utilisation seule de ces taux n’est pas vraiment suffisant pour nous faire une idée de la qualité de notre configuration (surtout si elle est produite à la main) et puis pourquoi en avons nous deux? Il faut une autre approche.

La matrice de confusion

Pour évaluer correctement notre modèle de neurone, il existe en Machine learning un outil pour discriminer correctement les limites du classifier: la matrice de confusion.

Le matrice de confusion est un recueil statistique de la performance du modèle de classification en s'intéressant à la nature des prédictions en fonction des valeurs réelles.

Elle se composent ainsi d’une ligne par classe réelle et une colonne par classe prédite (une classe étant soit un type de classe où tout bêtement l’absence où la présence de la classe).

Dans notre cas, nous avons deux classes en exclusion mutuelle (2 types de fruits et si c’est pas l’un c’est l’autre) nous pouvons donc soit établir une matrice avec les deux fruits soit avec un seul fruit en considérant les classes présent et absent (qui facilite souvent la compréhension de la matrice).

Donc sur notre échantillon de 4000 fruits composé des 2000 pastèques et 2000 ananas, nous avons la matrice suivante:


  • 1938 Vrai Positif (c’est à dire les pastèques détectées comme tel)
  • 1798 Vrai Négatif (c’est à dire ananas détectés comme tel)
  • 62 Faux Négatif (c’est à dire une pastèque interprétées comme un ananas)
  • 202 Faux Positif (c’est à dire un ananas détectés comme une pastèque)
On se rend compte que nous avons une préférence pour les pastèques (enfin nous non, mais notre modèle oui!)  Pour affiner la matrice, nous allons ensuite définir deux critères supplémentaire:
  • la précision : VP/(VP+FP)= 1938/(1938+202) = 0.90 capacité à détecter des pastèques en présence d’ananas (0.90 de chance que le modèle réponde que le fruit est un ananas)
  • le rappel ou sensibilité : VP/(VP+FN)= 1938/(1938+62) =0.97 capacité à réellement détecter une pastèque dans un ensemble que de pastèques.
Ce qui signifie que quand le modèle déclare avoir une pastèque, il n’a raison que 90% du temps (ça veut dire que ça peut être aussi un ananas) et il n’est capable que d'en détecter que 97% parmi les seules pastèques. 

Sur la base de la précision et du rappel, on peut calculer F1 ou la moyenne harmonique qui permet de fournir une métrique combinant les deux taux:


L'analyse de ce taux permet de guider dans l'optimisation du modèle, cependant il faut garder a l'esprit précision et rappel sont deux facettes d'une même pièce et que l'augmentation de l'un amènera forcement a un diminution du résultat de l'autre mais selon le contexte, cela peut se justifier....

L'apprentissage

Maintenant que nous avons les moyens d’évaluer le modèle, il est nécessaire d'avoir une approche pour la définition des paramètres du neurone.

En effet, a l’aide de la matrice de confusion, on voit bien qu’il y a un problème, nous qui étions si confiant sur notre analyse et notre paramétrage. Sur un exemple aussi simple…. juste avec un neurone … qu’est ce qui se passé? Il faut croire que décidément, le gâteau est un mensonge et qu’il n’y a pas de repas gratuit!

Mais alors comment definir le parametrage?

En machine learning, pour optimiser le paramétrage des modèles, il existe des procédures d’entrainement. Elles se distinguent en 3 formes:
  • supervisés: on présente au modèle des entrées d'entrainement dont on connait la réponse (donc nos données d’apprentissages sont le couple (data,étiquette). En fonction de l’écart de réponse, on change le paramétrage selon un algorithme spécifique. 
  • non supervisé, le modèle va affiner par lui même les paramètres at runtime en détectant lui même les ensemble intéressant (approche par clustering)
  • semi-supervisé, où les deux approches précédentes sont associées
Allons au plus simple, considérons un apprentissage supervisé (nous aurons l'occasion d'explorer les autres) tel que:
  • si etiquete - sortie > 0 alors W=W+data 
  • si etiquete - sortie < 0 alors W=W-data
  • si etiquete - sortie = 0 alors W
Que l'on peut simplifier par l'algo suivant:

1
2
3
4
def majW(W, sortie, etiquette,entree):
    #print(W, sortie, etiquette,entree)
    return W+(etiquette-sortie)*entree
    

Ainsi l’algo d’apprentissage consiste a exposer le modèle à valeurs d'entraînements permettant la mise à jour de W en suivant les règles precedentes

Pour cela, il faut des données d’entrainement. On a déjà des données pour chaque fruit. on va donc étiqueter nos données et ensuite les mélanger afin d'éviter d’introduire un biais d’apprentissage en favorisant un fruit avant l’autre.

1
2
3
4
5
def addEtiquette(entreeSet,etiquette):
    dataEtiquete=[]
    for val in entreeSet:
        dataEtiquete.append([val,etiquette])
    return dataEtiquete

1
2
3
pasteques=addEtiquette(pasteques,0)
ananas=addEtiquette(ananas,1)
W=np.array([[1, 1, 1, 0]])


1
2
3
4
5
6
datas=pasteques+ananas
random.shuffle(datas)
print(len(datas))
datasApprentissage=datas[:3000]
datasTest=datas[3000:]
print(len(datasApprentissage)+len(datasTest))

Il nous faut penser à évaluer le modèle, donc de cet ensemble de données on ne va en prendre qu’une partie pour l’apprentissage et une autre pour évaluer la qualité de l’apprentissage en le testant.

Première phase: apprentissage supervisé


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
print("W initial:",W)    
for (val,etiquete) in datasApprentissage:
    sortie=neuroneLim(val,W,biais)
    W=majW(W, sortie, etiquete,val)

print("W final:",W)    
erreur=[0]


for (val,etiquete) in datasTest:
    sortie=neuroneLim(val,W,biais)
    #print(sortie,etiquete)
    if sortie != etiquete:
        erreur.append(erreur[len(erreur)-1]+1)
    else:
        erreur.append(erreur[len(erreur)-1])

Nous étions partie d'un W=[1 1 1 0] et nous avons maintenant W=[ 3.40784321 2.44027133 2.17143355 -1.26320997]

Deuxième phase test: 


1
2
3
4
5
6
erreur=[1]+[erreur[i]*100/i for i in range(1,1001)]
print(len(erreur))
fig = plt.figure(1,figsize=(15,15))
ax = plt.subplot(111)
index=np.linspace(0,1,1001)
plt.plot(index,erreur)

Avec ce diagramme, on visualise l’émergence de l'erreur au fur et a mesure que la quantité de données de test valide ou invalide le résultat de l’apprentissage. (donc même si on a le sentiment que l'erreur varie, intrinsèquement, celle du neurone est constante, c'est son évaluation qui s'affine).

Si on interprète le résultat en fonction de notre problématique de classification, on se rend compte que la superposition des classes pose un vrai problème pour le neurone qui reste incapable de séparer les deux ensembles. Il s'agit la d'une limitation classique de ce type de modèle.

Conclusion

Voila, nous sommes au bout de cet exemple qui complète l'article plus théorique sur la structure du neurone. Nous avons suivi un processus complet de traitement des données à classifier (en passant pas l'analyse, le POC et la visualisation) et réaliser des choix argumentés (a peu prêt) afin d’affiner et rendre plus pertinent notre modèle. Nous avons aussi utilisé des outils d’évaluation de notre modèle et considérer un algorithme simple d'apprentissage.

Bien sur nous devions également voir le cas de l'utilisation d'une fonction d'activation de type sigmoïde mais l'article est il me semble déjà assez long.... Je vous propose donc de revenir sur ces petits détails dans de futur (et pas trop lointain) articles.

Merci d'avance de ne pas hésitez a me donner des retours, qu'ils soient sur le fond comme sur la forme!

Références

[1] https://un-est-tout-et-tout-est-un.blogspot.com/2018/07/ia-approche-neuromimetique-le-neurone.html