Ladies AI Night 14 May 2018

May 24, 2018
Workshop Deep Learning avec la librairie Apache MXNet animé par Julien Simon, principal evangelist à AWS

Transcript

J'utilise peu le féminin. J'ai fait partie d'une promotion d'ingénieur où il y avait 150 hommes et 3 femmes. Donc, voilà, je n'ai pas grandi avec beaucoup de collègues féminines. Je vais faire un effort, mais il faudra m'excuser si de temps en temps, je me restreins au masculin. Alors, qui n'a jamais, jamais, jamais fait de machine learning dans sa vie ? Mais vraiment jamais. Levez la main, je peux la lever aussi, je suis un mystificateur. Ok. Trois... Ok. On va dire une douzaine. D'accord. Qui a déjà fait un peu de machine learning traditionnel, mais pas de deep learning ? Ok. Et qui a déjà fait du deep learning, qui a déjà entraîné des modèles, qui a déjà joué avec des réseaux à convolution, etc. Alors, ce qu'on va faire, il y a vraiment plusieurs volets dans cette histoire. Il y a un volet, on va dire un peu théorique, qui explique les bases du deep learning, en quoi le deep learning est différent du machine learning et en gros pourquoi ça marche. Je pense que c'est intéressant d'en parler un petit peu. Il y a un volet, qu'est-ce qu'on peut faire avec, quelles sont les applications du deep learning, etc. Puis après, il y a évidemment un volet, maintenant on veut coder, on veut entraîner des modèles et on veut que ça marche. Donc, ce que je propose, étant donné qu'on a quand même une grosse majorité de gens qui n'ont jamais touché au deep learning, c'est d'expliquer, mais de manière assez haut niveau et sans faire de maths, promis, on ne fera pas de maths ce soir. J'espère que personne n'est déçu. Je pourrais partager des articles à celles et ceux qui ont envie de faire des maths, mais là, ce soir, on va faire surtout du code. Je propose de prendre peut-être, je pense que je peux le faire en une demi-heure, de prendre une demi-heure pour poser le deep learning, les grands principes, pourquoi ça marche, et puis après on plongera directement dans le code. Si on plonge dans le code directement, vous allez exécuter du code, ça va marcher, mais je ne suis pas sûr que vous allez vraiment en retirer tout ce que vous pourriez en retirer ce soir. Donc, on va attaquer ça. Vous aurez toutes les slides, j'ai d'autres sessions vidéo qui ont été filmées, donc je vous partagerai tout ça après. Rassurez-vous, vous aurez tout le contenu et vous aurez aussi tout le code, évidemment, il est sur GitHub. Ok, alors on va essayer de le faire en une demi-heure, mais en même temps, si vous avez des questions, allons-y. Répondons aux questions, enfin, je veux dire, le code, ce n'est pas le problème, vous allez vite le comprendre. Quand on fait du machine learning ou du deep learning, le code, ce n'est pas le problème, le code, c'est généralement 50 lignes ou 30 lignes, donc on n'a pas de difficulté avec ça, la complexité est ailleurs, et je veux vraiment dans cette partie-là l'aborder, et faire en sorte que vraiment vous compreniez ces concepts. Donc on va parler de deep learning, on parlera très rapidement de quelques cas d'usage quand même pour vous donner un peu de recul sur à quoi ça sert, mais je passerai assez vite parce que ce n'est pas trop le sujet ce soir. Je voudrais commencer par ça, qui est sûrement un des trucs les plus importants à retenir ce soir, c'est pour ça que je le mets en premier slide, c'est la différence entre intelligence artificielle, machine learning et deep learning. Alors déjà, il y a un truc que je veux déminer tout de suite, c'est que ça n'a rien à voir avec les robots. Donc quand vous voyez des couvertures de magazines avec un robot, moi j'ai un bon conseil, c'est économiser votre argent, parce qu'ils sont probablement à côté de la plaque. La robotique, c'est encore un autre sujet. Oui, on peut combiner l'intelligence artificielle et les robots, mais c'est franchement deux sujets complètement séparés. Et l'immense majorité des IA aujourd'hui, elles n'ont absolument rien à voir avec les systèmes robotiques. Donc, qu'est-ce que c'est que l'IA ? L'IA, c'est une science qui a 60 ans maintenant. On peut dater sa naissance en 1956. Un séminaire qui a eu lieu aux États-Unis avec des chercheurs qui ont inventé le terme et qui ont commencé à le définir. Et le but de l'IA, en tout cas sa définition est assez simple, c'est de concevoir des systèmes qui présentent des comportements humains. Alors, qu'est-ce que c'est que des comportements humains ? Dans ce cadre, c'est surtout lié à la perception, c'est-à-dire être capable de voir, de reconnaître des images, de reconnaître des vidéos, être capable de comprendre le langage naturel, que ce soit en texte ou le langage parlé, être capable d'utiliser le langage naturel, donc à son tour de répondre soit avec des phrases en texte, soit avec du dialogue. Et bien sûr, c'est la capacité à raisonner, à démontrer des raisonnements compliqués, complexes, qui ne sont pas liés à une programmation. C'est-à-dire que quand vous écrivez du code, au bug près, le code fait exactement ce que vous aviez en tête. Mais quand on fait de l'IA, on ne va pas programmer explicitement les systèmes. Les systèmes vont apprendre. Et sur la base de ces apprentissages, ils vont nous démontrer des raisonnements, de l'intuition, des capacités à prédire, etc. C'est un domaine très vaste qui a 60 ans, ce n'est pas né hier. Il y a des dizaines de sous-domaines et à l'intérieur de ces sous-domaines, il y en a un qui s'appelle le machine learning et qui, comme son nom l'indique en français, apprentissage automatique, vise à permettre à des machines d'apprendre automatiquement des comportements sur la base d'un jeu de données. C'est-à-dire qu'au lieu d'écrire du code qui va explicitement réaliser une opération, on va utiliser des algorithmes standards. Ça peut être la régression linéaire, la classification, le clustering, etc. Il y a tout un tas d'algorithmes qui existent depuis bien longtemps. Et on va appliquer ces algorithmes standards que la plupart du temps, on ne va pas coder. Ils existent déjà dans les librairies, ils sont déjà là. On va les appliquer à un jeu de données. Et sur la base de ça, on va apprendre des comportements et faire des prédictions, faire de la classification, etc. Il y a une grosse partie de l'activité de machine learning, et les personnes qui en font déjà le savent bien, qui consiste à partir du jeu de données brut à extraire ce qu'on appelle des features. Les features ne sont jamais que des variables qui vont nous servir à construire le modèle. Imaginez un jeu de données très fouillis avec des sources très non structurées, du SQL, du JSON, etc. Vous n'allez pas pouvoir travailler directement avec ça, vous allez devoir analyser ces données, comprendre ce qu'il y a dedans, et à partir de ça, construire ce qu'on appelle des features, qui vont être des variables, qui sont les variables que vous allez présenter à l'algorithme qui doit construire le modèle. Et donc cette tâche de feature engineering, c'est sans doute le rôle numéro un de la data science. Et ce n'est pas ici qu'on va me contredire sur le sujet. Et c'est une tâche qui est assez intensive humainement, qui prend du temps et qui doit être réalisée explicitement par des ingénieurs. Et ça, ça pose un problème. Ça pose un problème parce que quand on travaille avec des données qui sont particulièrement complexes, par exemple de la vidéo, de la voix, du texte brusquant, on a du mal à faire émerger ces features. Je prends toujours le même exemple. Imaginez que je prenne une photo de cette salle, on va dire 1000 pixels x 1000 pixels, pour faire simple, et qu'à partir de cette photo, et de tout un tas d'autres photos, je vais entraîner un modèle qui va compter les visages qui sont présents dans cette image. Un machine learner traditionnel, et un naïf on va dire, machine learner débutant, il vous dirait, bon, ben, ok, donc il y a un million de pixels, alors il y a peut-être trois, parce que c'est une image en couleur, alors, ok, il y a trois millions de pixels, bon, ben, ça fait trois millions de features, alors je vais prendre mon algorithme traditionnel, je vais lui balancer trois millions de features, et puis il va apprendre. Sauf que ça ne marche pas. Ça ne marche pas, parce que trois millions de features, c'est un nombre absurde, et que jamais on n'arrivera à des bons résultats, dans un temps raisonnable et négatif, même probablement pas à des bons résultats tout court. Et donc, pareil avec de la voix, de la musique, etc., des données très complexes, où finalement, on n'arrive pas à faire émerger des features. On ne comprend pas quels pixels, par exemple, il faudrait garder dans l'image et lesquels on pourrait ignorer. Ce n'est pas évident. Ce n'est pas évident comme problème. Pourtant, quand vous aviez 5 ans ou 3, et que vous dessinez un bonhomme, vous faisiez quoi ? Vous faisiez un rond, une bouche, deux roues pour les yeux, un trait pour le nez. Et papa et maman disaient « Oh, il est beau le bonhomme. » Donc, ça prouve bien qu'il n'y a pas besoin d'un million de pixels pour voir que c'est un bonhomme. Pareil avec un chat, un chien, ou une maison, ou un arbre. Pensez à votre destin d'enfant. L'intuition est très importante dans le deep learning. Donc, on sent intuitivement qu'il n'y a pas besoin d'avoir toute l'information qu'on a à disposition, qu'il y a une grosse partie de cette information qui est inutile, redondante, gênante parce qu'elle va complexifier le traitement et allonger les temps de traitement. Et donc, il faut en jeter beaucoup, en garder très peu. Le problème, c'est que ce travail-là, ce n'est pas possible qu'un humain le fasse. Si je vous donne un million d'images avec 100 animaux différents à l'intérieur, je vous dis, voilà, apprenez à reconnaître les chats, les chiens, les tigres, les éléphants, les araignées, etc. Bon courage. Bon courage pour trouver un point commun entre les mille images de chiens, les mille images de chats. C'est un problème impossible. C'est pour ça que le deep learning est devenu populaire, parce qu'évidemment, on travaille de plus en plus avec des données qui sont comme ça aujourd'hui, des données qui sont complexes, extrêmement riches, avec une volumétrie également importante, une taille d'échantillon importante. Et donc, l'avantage du deep learning, c'est qu'il va automatiser l'extraction des features. Un réseau de neurones, puisque c'est la technologie qu'on utilise pour faire du deep learning, un réseau de neurones va apprendre automatiquement ce qui est important et ce qui ne l'est pas. Donc d'une certaine manière, il va rendre inutile le feature engineering. En tout cas, dans une grande partie, il va éliminer le besoin de faire du feature engineering. Et donc on va pouvoir balancer sur ces réseaux de neurones des données hyper compliquées, hyper déstructurées, très riches, et ces réseaux vont apprendre automatiquement quels sont les features qui doivent être conservés et quels sont ceux qui ne servent à rien. Et ça c'est la grande force du deep learning, c'est de la capacité à apprendre n'importe quoi, à grande échelle, et sans beaucoup de travail préliminaire sur les données. Donc voilà, maintenant, vous en savez déjà plus que beaucoup de gens qui ont machine learning dans leur job title. Donc gardez ces trois définitions en tête. Alors, ce qu'on va voir ce soir, ce qu'on va détruire aussi, c'est ça, et c'est pour ça que c'est très bien qu'il y ait beaucoup de gens qui débutent, c'est que l'IA, ce n'est pas du tout de la magie noire. Je déteste cette approche. Je la détestais dans d'autres sujets. Je la déteste toujours sur l'IA et le machine learning. On parle d'engineering, on parle de code, on ne parle pas de sorcellerie. Et tout le monde... si vous écrivez du code, si vous êtes capable d'écrire et de lire sans ligne de code, vous êtes capable de faire du machine learning et du deep learning. Donc voilà, moi je n'ai pas de PhD en quoi que ce soit, je n'en veux pas, je n'en ai pas besoin et ça ne m'empêche pas de faire des trucs rigolos. Donc ne vous laissez pas intoxiquer par, je vais aller au bout de ma pensée, une certaine élite, comme toujours, veut s'approprier la connaissance, pour son propre profit, parce que généralement, ces gens-là vont vous dire que c'est très compliqué, donc il faut que vous me payiez très très cher pour le faire. Voilà, ça c'est vraiment un comportement détestable, et surtout en engineering, ce n'est pas acceptable. Donc la réalité des choses, c'est que oui, l'IA et le machine learning, il y a un fondement mathématique, théorique, qui est utilisé lorsqu'on veut travailler dans ces couches-là, au plus bas niveau, lorsqu'on veut inventer de nouveaux algorithmes, inventer une nouvelle architecture de réseaux de neurones, etc. Ok, là, il faut un background solide, c'est complexe, il y a beaucoup de maths, etc. Mais je pense que 99%, 100% des gens qui sont là ce soir, ce n'est pas ça qu'ils veulent faire. Ce qu'ils veulent faire, c'est comprendre ce que c'est que cette techno, comprendre à quoi elle sert, comprendre comment ils peuvent l'utiliser, dans leur propre projet. C'est exactement la même chose que d'écrire un compilateur. Si vous voulez apprendre à programmer, le premier truc à faire, je suis désolé parce que c'est toujours ce qui est encore enseigné à la fac, je maintiens que le premier truc à faire, ce n'est pas d'apprendre à écrire des compilateurs. Quand on veut apprendre à conduire, on n'apprend pas à construire une voiture. On apprend à conduire. Quand on veut apprendre à développer, on apprend un langage, et on développe. Si après on veut s'intéresser à ce que c'est que la compilation, on le fait. Donc le machine learning et l'IA, c'est la même chose. Il y a des librairies de haut niveau qui existent aujourd'hui, on va revoir une ce soir, qui sont faciles à utiliser, qui ne nécessitent pas beaucoup de code, qui encapsulent et qui vont abstraire pas mal la complexité théorique du deep learning. Et en première analyse, ça nous suffit complètement. Donc c'est bien ça qu'on veut faire. Après, je vous en comprends. Plus tard à aller creuser, je vous partagerai des liens pour le faire, mais même à la limite si vous n'avez pas envie de le faire, ça ne me pose pas de problème. Moi, je n'ai jamais eu le fantasme d'écrire un langage de développement ou d'écrire un compilateur. Je suis très content de programmer avec les langages qu'on met à disposition. Donc l'IA, le machine learning, c'est la même chose. C'est un peu de science, beaucoup de code et évidemment un peu de matériel pour entraîner ces modèles. Ce soir, on va travailler avec des jeux de données qui sont minuscules. Donc je pense que tout le monde s'en sortira très bien avec son laptop, mais évidemment, lorsqu'on passe à l'échelle, on a besoin d'avoir des GPU et des machines plus puissantes. Alors allons-y. Donc on parle de réseau de neurones. Donc on va expliquer peut-être ce que c'est qu'un neurone avant de les mettre en réseau. Donc un neurone, c'est bête comme chou, c'est une petite fonction mathématique qui va produire des entrées, donc on voit sur la gauche, là, x1, x2, etc. À chacune de ces entrées, on associe un poids. Donc, les x et les w sont des valeurs numériques. Ce sont des valeurs flottantes qu'on va utiliser au fil du training. Donc, ces valeurs, qu'est-ce qu'on fait avec elles ? On fait une opération qui est hyper compliquée. On multiplie chaque entrée par son poids et on fait la somme. Ça, ça s'appelle multiply and accumulate. Le deep learning, c'est essentiellement des additions et des multiplications. Vous pourriez me dire que toute l'informatique, c'est des additions et des multiplications, parce que ça ne serait pas faux. Mais en l'occurrence, le deep learning, c'est surtout ça. Donc, si vous avez additionné et multiplié, c'est à peu près tout ce qu'on vous demande. Donc, c'est jouable. Donc, ça, ça me donne une valeur, une valeur U. Cette valeur U est le résultat de cette opération de multiply and accumulate. Le problème de cette valeur, c'est que cette fonction, multiply and accumulate, elle est linéaire. Donc elle a des entrées, les x, et des paramètres, les w. Donc si je fais varier mes w, mon résultat va varier linéairement. C'est une fonction linéaire. Donc ça va être une courbe, une ligne plus ou moins compliquée, mais elle est linéaire. Et ça, ça nous embête parce que si on essaye de construire quelque chose qui ressemble à un biologique, on voudrait que ce neurone s'active parfois et ne s'active pas le reste du temps. C'est ce qu'on nous apprend sur nos neurones, enfin les vôtres, parce que les miens, je ne sais pas. Mais un neurone, c'est activé ou pas. S'il est suffisamment stimulé, il produit un courant électrique. S'il n'est pas suffisamment stimulé, il ne produit rien. Ça, c'est un comportement qui n'est pas linéaire. Il y a une espèce de seuil en-dessous duquel il ne se passe rien. C'est pour ça qu'on a besoin de rajouter à la sortie du neurone ce qu'on appelle une fonction d'activation, qui est une petite fonction mathématique très simple. Au fil du temps, il y en a eu plein. Celle qui a le vent en poupe, encore aujourd'hui, c'est celle qui est tout en bas, qui s'appelle... C'est marrant, en français, c'est relou. Ou relu. Oui, c'est relu. Mais les Anglais disent relou. Enfin, relu. Donc, rectified linear unit. Alors, cette fonction, vous voyez qu'elle est super simple. Si en entrée, elle a une valeur négative, sa sortie vaut 0. Et si en entrée, elle a une valeur positive, sa sortie, c'est cette valeur. Donc, c'est à peu près ce qu'on veut. On veut qu'en dessous d'un certain seuil, lorsque la valeur U est négative, donc parce qu'elle est petite, le neurone n'est pas activé. Si la valeur est positive, le neurone est activé. Et si la valeur U est très très forte, c'est-à-dire que la stimulation de ce neurone est très très forte, il n'y a littéralement pas de limite à la sortie du neurone. On peut avoir des valeurs Y extrêmement élevées. Donc voilà ce que c'est qu'un neurone. C'est la combinaison de ce multiply and accumulate et de cette fonction d'activation. Et la logique, l'intuition, c'est si les signaux d'entrée sont suffisamment forts, je vais avoir une sortie. S'ils sont faibles, j'aurai rien. C'est une approximation extrêmement minimaliste et simpliste des neurones biologiques, mais c'est bien ça qu'on essaie de faire. Alors, si on les met en couche, parce que c'est bien ça qu'on veut faire. On veut faire des réseaux de neurones. Le réseau de neurones le plus simple qu'on peut construire, c'est ça. Une couche d'entrée sur laquelle on va placer les données qu'on veut soit apprendre, soit prédire. C'est selon. Une couche de sortie où on va lire les résultats. Et puis au milieu, ici, une seule. C'est vraiment le cas le plus simple. Une seule couche qu'on appelle une couche cachée qui est en plus ici, en bon français, « fully connected », c'est-à-dire que chaque neurone de la couche cachée est connecté à toutes les entrées et à toutes les sorties. Donc là, on a un maillage complet de la situation. Donc ça, c'est le réseau le plus simple qu'on peut construire. Alors comment est-ce qu'on s'en sert ? Il va falloir un jeu de données. Ce jeu de données, on va l'appeler le « training set ». Le jeu d'entraînement, ça va être très dur d'utiliser du français de bout en bout. Je vous présente mes excuses avant. Le training set va comporter les échantillons qui vont servir à entraîner le réseau. Donc appelons X. Dans cette matrice X, on a en ligne les différents échantillons et en colonne les features, les variables qui constituent chaque échantillon. Alors, prenons un exemple simple, imaginons qu'on veuille classifier des images, ce qu'on va faire tout à l'heure. Donc, on pourrait prendre des images, les aplatir pour en faire un vecteur, et puis chacun de ces x, 1, 1, x, 1, 2, etc. serait la valeur d'un pixel. Donc, imaginons que c'est ce qu'on a fait. Donc, chaque échantillon, c'est les valeurs de pixels d'une image qu'on a aplati et donc on a empilé comme ça toute une série d'images pour constituer le jeu de données. Et puis, comme on veut classifier, il va falloir qu'on entraîne le réseau à reconnaître les images. Alors imaginons qu'on ait des chats, des chiens, des éléphants, etc. Et évidemment, ces échantillons-là, on les connaît. Donc on sait que par exemple x1 à la première ligne on sait que c'est une image de chien par exemple, ok, on sait que x2 c'est un chat, d'accord, donc imaginons qu'au total j'ai peut-être 10 catégories, j'ai dix animaux différents dans mon jeu de données, donc j'ai créé un vecteur y qu'on appelle le label. Et en fait, ce qu'est ce que c'est qu'un label, c'est juste un numéro de catégorie qu'on va assigner à chaque échantillon. Donc l'échantillon qui est sur la première ligne X, il est de la catégorie 2, alors disons les chats. L'échantillon qui est sur la deuxième ligne, il est de catégorie 0, disons les éléphants, etc. Donc ça, c'est ce qu'on appelle de l'entraînement supervisé, de l'apprentissage supervisé. Vous comprenez bien pourquoi on appelle ça comme ça, parce qu'en fait, ici, on va fournir au réseau des données et on lui fournit aussi la réponse. Ce qu'on lui demande, c'est d'apprendre que cet échantillon-là est de la catégorie 2, que le suivant est de la catégorie 0 et que le dernier est de la catégorie 4. Ça, ça s'appelle l'apprentissage supervisé. Il y a une autre classe d'apprentissage, qui s'appelle l'apprentissage non supervisé, où là, on fournit juste des données et on ne donne pas de labels, mais on n'en parlera pas ce soir. C'est un peu plus complexe. Donc voilà mon jeu de données. Alors en pratique, on n'aime pas, et si vous avez déjà fait un peu de machine learning, vous le savez, on n'aime pas travailler avec des valeurs, quand on a des catégories comme ça, on n'aime pas travailler des variables de type catégorique, donc des variables qui décrivent des catégories, on n'aime pas travailler avec les numéros de catégorie. On préfère faire ce qu'on appelle du one-hot encoding, qui a l'air un truc compliqué, mais pas du tout. Alors, le one-hot encoding, c'est prendre un numéro de catégorie et le transformer en un vecteur. Alors, on a dit qu'on avait 10 catégories, par exemple, ici. Donc, on va le transformer en un vecteur de 10 éléments, qui sont des bits, donc 0, 1, et on va assigner à 1 le bit qui correspond à la catégorie. Alors n'oubliez pas qu'on commence à compter à 0. Donc si on prend la première ligne, catégorie 0, catégorie 1, catégorie 2. Donc le bit qui correspond à la catégorie 2, on l'allume. Pour la ligne d'en dessous, le bit qui correspond à la catégorie 0, on l'allume. Puis pour le dernier élément, pareil, 0, 1, 2, 3, 4, on le met à 1. Donc c'est le cinquième bit, mais c'est la catégorie 4. C'est la cinquième catégorie en réalité. Donc ça, c'est ce qu'on appelle le one-hot encoding, c'est utilisé en plein de cas de machine learning à chaque fois qu'on travaille avec des catégories. Alors pourquoi est-ce qu'on fait ça ? On fait ça parce que maintenant, cette matrice de machine learning, one-hot encoding, elle nous apprend beaucoup plus de choses en fait. Regardons la première ligne, on peut voir, on pourrait voir ces valeurs là, au lieu de les voir comme des 0 et des 1 bêtement, on pourrait dire mais en fait c'est des probabilités, c'est-à-dire que j'ai les 10 probabilités pour les 10 classes de mon problème. Donc le premier échantillon, il a 0% de chance d'être de la catégorie 0, 0% de chance d'être de la catégorie 1, 100% de chance d'être de la catégorie 2, etc. Le deuxième échantillon, il a 100% de chance d'être de la catégorie 0, puis 0% de chance d'être de toutes les autres. Et je le sais, puisque je les connais, ces labels. Donc l'avantage de cet encodage, c'est que maintenant, je vais pouvoir raisonner en probabilité d'appartenir à telle ou telle classe plutôt qu'en numéro de classe, ce qui est bien plus pratique. Et si vous êtes attentif et attentive, vous avez remarqué qu'ici j'ai dit il y avait N2 catégorie, alors disons 10, et si vous regardez la taille de la couche de sortie, vous voyez que j'ai N2 neurones. Ce n'est pas un hasard, parce qu'évidemment, lorsque je vais présenter sur un réseau qui a déjà été entraîné, lorsque je vais présenter un échantillon, je le passe à travers le réseau, je fais les multiplications, les accumulations, les activations, etc., ce que j'aurais envie de voir à la fin, c'est dans chacun des neurones de la couche de sortie la probabilité que cet échantillon appartienne à la classe en question. Ok, puis j'ai ça, c'est super super important. Ça m'a stoppé pendant des semaines. Donc lever la main si il y a un problème, y compris les amis d'en face. C'est bon ? Je viendrai vous voir après, rassurez-vous. C'est hyper désagréable d'être séparés comme ça. Vous avez l'impression que vous êtes punis ? Vous n'avez rien fait encore. Peut-être tout à l'heure, mais pour l'instant, vous n'avez rien fait. Bon, ok, donc, ça, c'est vraiment un truc clé à retenir, c'est que la couche de sortie, elle a autant de neurones que de classe, lorsqu'on fait un problème de classification, comme ici, et bien sûr, la couche d'entrée, elle a autant de neurones que vous avez de features. Donc, si j'ai L features, ici un L, si j'ai L features dans ma matrice X, il faut que j'ai L neurones sur ma couche d'entrée. Et si j'ai N2 catégories possibles dans mes labels, il faut que j'ai N2 neurones sur la couche de sortie. Et puis au milieu, je fais ce que je veux. Après, au milieu, c'est là que la magie s'opère. C'est là qu'on fait de la sorcellerie. Mais sur la couche d'entrée et la couche de sortie, on est contraint par la taille des données et le nombre de catégories. Donc le but du jeu, il va y en avoir deux, c'est évidemment d'arriver à entraîner tout bazar et puis ça va être de construire une architecture de réseau qui va me donner les bonnes prédictions. Donc ça va ressembler à ça, l'étendue de métal en powerpoint. Donc on va prendre un échantillon, on va le présenter sur la couche d'entrée donc mettre chacun des features dans un neurone. On va faire les multiplications, les accumulations, les activations et si tout va bien, si on a bien entraîné le réseau, on devrait avoir sur la couche de sortie les probabilités pour chacune des classes et on espère qu'il y en a une qui est très élevée et qui est la bonne. En pratique, vous verrez, on n'a jamais des 0 et des 1. C'est que dans les livres de maths. Dans le vrai monde, on a des nombres à virgules. Mais si celui-là, c'est 0, 99, 99, très bien. On est content. Ce qu'il faut, c'est qu'il y en ait une qui soit notoirement plus élevée que les autres. Et c'est à celle-là qu'on fera confiance. Et bien sûr, ce qu'on veut, c'est une bonne précision, c'est-à-dire, lorsqu'on va utiliser un autre jeu de données et qu'on va le passer à travers le réseau, on espère qu'on aura un grand nombre de prédictions correctes, si possible, 100%. Là, pareil, on n'atteindra jamais 100% de précision, mais on peut s'en approcher. C'est clair ? Ça va ? Alors, ça c'est les bisounours. Parce que bien sûr, initialement, le réseau ne sait rien du tout. Le réseau n'est pas initialisé. Donc, tous les poids, n'oubliez pas, chacune de ces flèches a un poids, un paramètre associé. Ces valeurs-là, initialement, sont complètement aléatoires. Donc, lorsqu'on va prédire un échantillon, on va avoir n'importe quoi. On n'aura pas 1, 0, 0, 0. Au début, on aura n'importe quoi. On aura des valeurs, des probabilités complètement aléatoires et qui ne ressembleront évidemment pas aux résultats qu'on espérait. Donc, lorsqu'on va appliquer la fonction représentée par le réseau de neurones à mon échantillon X1, je ne vais pas avoir Y1, je vais avoir Y'1, je vais avoir un autre truc. Mon vecteur de probabilité, ce n'est pas celui que j'attendais. Donc il va falloir que je mesure, lorsqu'on veut apprendre, il faut être capable de mesurer l'erreur. Ça, ça marche pour les enfants, les adultes et les réseaux de neurones. Donc il faut que vous mesuriez à quel point vous êtes trompé. C'est le point de départ pour ensuite corriger. Donc, on va utiliser ce qu'on appelle une loss function. Et rassurez-vous, vous n'avez pas besoin de l'implémenter. Elle est dans toutes les librairies. Il y en a plein, plein différentes. Donc, cette fonction, en fait, elle va mesurer la différence entre la prédiction et la vérité. Et gardez à l'esprit que y1, y'1, c'est des vecteurs. Donc, il ne s'agit pas juste de faire y1 moins y1. Il faut mesurer la distance entre deux vecteurs. On a une loss function qui va mesurer cette erreur. Cette erreur va être un chiffre, une valeur flottante qui va représenter la distance entre les deux vecteurs. On pourrait imaginer qu'on passe un échantillon à travers le réseau, on regarde l'erreur, et puis on ajuste les poids. On n'en a pas trop parlé encore. On a une façon d'ajuster les poids pour réduire l'erreur, puis après on refait la même chose avec l'échantillon d'après, puis on réajuste les poids, puis etc. On fait comme ça. En pratique, on ne fait pas ça, c'est trop long et ça ne marche pas toujours bien pour d'autres raisons. Donc ce qu'on va faire, c'est qu'on va utiliser ce qu'on appelle des lots d'échantillons. Donc en pratique, on va prendre un lot, alors un lot ça peut être 32 ou 64 échantillons. Donc on va les passer un par un dans le réseau et puis on va additionner toutes les erreurs pour ces 32 ou ces 64 échantillons. Et à ce moment-là, on va ajuster les poids. Et on verra que ce batch, c'est une notion importante. C'est une façon d'entraîner plus vite et aussi d'apprendre mieux. Donc, si on essaie de résumer tout ça de manière simple, le but du process d'entraînement, c'est de minimiser l'erreur de prédiction, d'accord, de manière itérative, en ajustant graduellement les poids. Parce qu'il ne faut jamais perdre de vue que ce réseau, c'est une fonction mathématique qui est paramétrique par tous les poids de toutes les connexions. Alors ici, je ne sais pas, il y en a peut-être une vingtaine ou 25. Donc, il y a cette fonction F, elle a 20 ou 25 paramètres. Donc, je peux ajuster ces 25 paramètres à la hausse, à la baisse, indépendamment, dans un sens qui, je l'espère, va réduire les erreurs de prédiction. Donc, c'est ça qu'on essaie de faire. Mais on ne peut pas le faire algébriquement parce que vous pourriez bien, bah oui, alors ok, cette fonction mathématique, ok, c'est une fonction avec une variable et puis 25 paramètres, donc peut-être qu'algébriquement je peux trouver les 25 paramètres qui minimisent la fonction. Bon bah la réponse je vous fais gagner du temps, la réponse est non, c'est pas possible de la calculer, c'est trop compliqué. Et donc on va devoir le faire de manière approximative et itérative. Et ça va être ça le but de l'entraînement. Donc l'entraînement, il va marcher comme je l'ai décrit. Donc on va découper notre dataset. Pensez à notre matrice de tout à l'heure. On va la saucissonner en batch. Et puis on va passer un premier batch à travers le réseau. On va additionner toutes les erreurs individuelles pour ces échantillons-là. Et on va ajuster les poids. Et on va utiliser un algorithme qui s'appelle la backpropagation. Alors, pourquoi backpropagation ? Parce que quand on envoie des échantillons dans le réseau, on part de la couche d'entrée, on va vers la couche de sortie, ça n'est pas raisonnable. Par contre, quand on ajuste les poids, on va le faire en sens inverse. On va partir de la sortie et on va remonter couche par couche, jusqu'à l'entrée. Je vais expliquer rapidement comment après. Et voilà le principe. Puis on recommence avec un autre batch, et hop, encore un coup de backpropagation. Si on prend les bonnes décisions à chaque fois, petit à petit, l'ensemble des valeurs de ces poids va converger vers un ensemble qui réduit de plus en plus les erreurs de prédiction, jusqu'à arriver aux erreurs les plus faibles possibles. On fait cela pour tout le dataset, jusqu'au bout. Quand on est arrivé au bout, c'est ce qu'on appelle une époque. Une époque, c'est avoir traité lot par lot l'ensemble du dataset. Généralement, on va entraîner des dizaines d'époques, car c'est un processus long. Comme on fait des petits ajustements sur les poids, il va nous falloir beaucoup d'étapes de backpropagation pour arriver aux bonnes valeurs. Dans les exercices qu'on va faire tout à l'heure, on va entraîner 50 époques, 100 époques. On peut le faire. C'est pour ça que sur des gros datasets, ça peut durer des jours, voire plus. Sur des très gros datasets, c'est très long. Il y a trois paramètres hyper importants dans cette histoire. Il y a la taille de batch. Si vous prenez une taille de batch trop petite, par exemple un, vous allez faire la backpropagation autant de fois qu'il y a d'éléments dans le dataset, ce qui prend un certain temps. Si vous prenez une taille de batch trop grande, pour une époque, vous n'aurez pas beaucoup d'opportunités de faire la backpropagation, donc vous n'apprendrez pas vite non plus. Paradoxalement, avec des batchs plus grands, on pourrait penser qu'on apprend plus vite, mais ce n'est pas le cas. Il faut trouver un compromis raisonnable, pas trop grand et pas trop petit. Des valeurs raisonnables sont 32, 64, 128. Le deuxième paramètre important est le learning rate, qui conditionne l'ampleur des ajustements sur les poids. Si vous avez un learning rate tout petit, vous allez faire varier les poids tout doucement. Si vous avez un learning rate plus grand, ils vont varier plus vite. On verra que cela peut poser des problèmes si on choisit mal. Le nombre d'époques est le nombre de fois où on va faire tourner la machine. On verra que ce n'est pas facile de choisir et de se dire quand on s'arrête. Est-ce qu'il en faut 10, 20, 50, 200 ? On n'en sait rien, donc on va voir comment faire. Il faut respirer un petit coup. C'est ce que vous verrez de pire ce soir, je vous promets. En français, c'est dur. Ce qu'on essaie de faire, c'est trouver le minimum de la fonction d'erreur. La fonction d'erreur est paramétrée par tous les poids du réseau. Chacune des flèches du réseau a un poids, et ces poids conditionnent l'erreur que l'on fait lors de la prédiction. Ce qu'on veut, c'est la meilleure précision possible, autrement dit, la plus petite erreur possible. On cherche donc le minimum de la fonction d'erreur. C'est un problème d'optimisation mathématique. On a une fonction hyper compliquée, paramétrée par un grand nombre de paramètres, et pour un jeu de données, on cherche les paramètres qui donnent le minimum de la fonction d'erreur. C'est tout ce qu'on fait. Pourquoi c'est compliqué ? Parce qu'on a des millions de paramètres et que le jeu de données peut avoir des millions d'échantillons. Mais fondamentalement, ce n'est pas plus dur que ce qu'on faisait en seconde lorsqu'on cherchait le minimum d'une parabole. On cherche le minimum d'une fonction. On ne peut pas le faire algébriquement parce que c'est trop compliqué, il y a trop de dimensions. Trouver le minimum d'une parabole, on peut le calculer, mais trouver le minimum d'une fonction à un million de paramètres, on ne peut pas le calculer. On va donc l'approximer de manière itérative. Imaginez que cette jolie courbe soit la représentation en 3D de la fonction d'erreur. Ici, x et y sont toutes les valeurs de paramètres possibles, et voilà la fonction d'erreur. Au début, les paramètres ont des valeurs aléatoires, donc on démarre n'importe où sur cette surface. L'objectif est d'arriver en bas, mais on ne sait pas où il est. On va faire des petits pas, tâter le terrain, et dans chacune des directions x et y, on va chercher où c'est en bas. Imaginez-vous sur une montagne, dans le brouillard, et vous ne voyez rien. Vous tâtez du pied si ça monte ou si ça descend. Vous tâtez un peu, là ça monte, non c'est pas là, là ça a l'air de descendre, ok. Et vous faites un petit pas. Puis vous recommencez. Et vous faites ça des millions de fois. Si vous êtes discipliné et que vous suivez bien toujours la pente descendante, vous allez arriver en bas. Mathématiquement, c'est très simple. On cherche la pente et on veut que la pente descende. On calcule la dérivée, qui donne la pente. Une fois qu'on a la pente, on sait s'il faut aller à gauche ou à droite pour descendre, et on le fait dans chacune des dimensions. Ce sont des dérivées partielles. Si vous n'avez pas poursuivi vos études mathématiques, vous n'avez rien perdu, c'est pas grave. La dérivée partielle, c'est simplement dériver la fonction par rapport à chacune des dimensions. On dérive la fonction d'erreur pour chacun des paramètres, on regarde la pente, et une fois qu'on a la pente, on sait s'il faut augmenter ou réduire le paramètre pour descendre la pente. La bonne nouvelle, c'est que des bibliothèques comme TensorFlow, AmixNet, etc., font cela pour nous. Si vous voulez optimiser la backpropagation, il faudra le faire, mais ce n'est pas ce qu'on veut faire ce soir. Ce qu'on veut faire, c'est comprendre comment ça marche et savoir ce qu'on fait avec. Le fondement du deep learning est la forward propagation, multiply and accumulate, backward propagation, dérivée partielle, et ajuster les poids dans le bon sens de la pente. C'est tout ce qu'il y a à comprendre. En faisant cela de manière répétée, on va arriver en bas. La taille des pas est conditionnée par le learning rate. Si vous avez un learning rate minuscule, vous allez faire des tout petits pas et mettre un sacré temps à arriver tout en bas. Si vous faites des pas trop grands, vous allez rebondir entre les piques. Il faut donc faire des pas raisonnables, ni trop petits, ni trop grands, pour arriver en bas en temps et en heure. Évidemment, ce n'est pas aussi simple. Les courbes de ces fonctions d'erreur ne sont pas toujours régulières. Il peut y avoir plusieurs minimums. On pourrait tomber dans un minimum local et être coincé, même si la dérivée nous dit qu'il n'y a pas plus bas. Il y a aussi des points de selle, qui sont des points où la dérivée est nulle, mais ce n'est pas un minimum. En pratique, ces cas existent, mais ils ne gênent que marginalement l'entraînement pour plusieurs raisons. Une fois l'entraînement terminé, on veut mesurer la précision du modèle avec un dataset de validation, qui est un dataset que l'on a gardé de côté et que l'on n'a pas utilisé pour l'entraînement. On fait cela à la fin de chaque époque pour voir si on progresse. Si on entraîne trop longtemps, on peut avoir de l'overfitting, où le modèle ne généralise plus bien à de nouveaux échantillons. Le modèle que l'on veut garder est celui qui a la meilleure précision de validation, car c'est celui qui généralise le mieux. Le deep learning, c'est trouver un minimum pour la fonction d'erreur, un minimum qui généralise bien, avec un bonus pour le trouver rapidement et de manière fiable. On ne dit pas "le minimum absolu" car trouver le minimum global dans un espace à 10 millions de dimensions est NP hard. On va donc trouver un minimum qui marche bien et qui généralise bien. Si on arrive à le trouver vite, c'est très bien. Si on arrive à entraîner rapidement et à converger vers ce résultat de manière déterminée, c'est magnifique. On va utiliser une librairie de deep learning open source appelée MXNet, qui est la librairie préférée d'AWS. On va utiliser cette librairie pour exécuter le code. On va commencer par vérifier que tout le monde a installé ce qu'il faut. Si vous avez des problèmes, levez la main. On va vérifier que vous pouvez importer MXNet et afficher sa version. Si cela marche, on est bien. On va ensuite cloner mon repository sur GitHub, qui contient les exemples dont vous avez besoin. Vous allez dans le répertoire AWS/MXNet, puis dans Intro, et vous ouvrez firstexample.py. On va lire le code ensemble et l'exécuter. C'est bon ? D'accord ? Donc une dernière fois, X, c'est une matrice 10 000 lignes sans colonne, que j'ai coupée en deux, 8 000, 2 000, pour avoir training, validation, et j'ai un vecteur de label avec 10 000 catégories entre 0 et 9, que je vais couper aussi en deux. D'accord ? Oui ? Ça va en face ? Et là, vous vous dites, mais merde, je pourrais être devant la télé, là. Qu'est-ce que j'ai fait, là ? Je me suis fait U. Bon. Mais non, mais non. Vous allez voir. Vous serez fiers de vous à la fin. Pas de souci. Bon. Donc, ma X et Y, il va falloir que je les crée. Il va falloir que je les remplisse. Là, je vais utiliser une fonction de l'API ndArray. MX, c'est MXNet qu'on a importé. ND, c'est l'API ndArray. Uniforme, c'est une fonction qui va tirer aléatoirement des valeurs sur une distribution uniforme entre 0 et 1. Je vais remplir ma matrice qui a, donc, SampleCount, 10 000 lignes, FeatureCount, 100 colonnes. Donc, si je sais compter, ça fait 1 million. Donc, je vais tirer 1 million de valeurs aléatoires entre 0 et 1 et je les mets dans ma matrice. Ensuite, je vais créer mon label, mon vecteur de label. Donc, je crée un vecteur vide de 10 000 éléments, ligne 22, et puis ensuite, ligne 23-24. 24, je tire aléatoirement 10 000 catégories entre 0 et 9. Voilà mon dataset synthétique. Si jamais vous n'avez pas entendu le terme synthétique, ça veut juste dire qu'on l'a créé de toute pièce. Ce n'est pas un vrai dataset. Ensuite, il faut qu'on coupe en deux, training et validation. Ça, c'est ce qu'on fait ligne 27 à 31. Donc on utilise une API de NDRX qui s'appelle crop. Et une fois de plus, si vous connaissez NumPy, c'est exactement la même. Et donc on va dire, tu prends X et tu prends les 8000 premières lignes. Et puis pour la validation, tu prends les 2000 dernières. Donc on coupe X et Y en deux. Ça me fait X-train, Y train, X valide, Y valide. Et on affichera les formes de tout ça pour se rassurer qu'on a bien ce qu'il faut. Donc, X train, ça va être du 8000 x 100. Y train, ça va être 8000. X valide, ça va être 2000 x 100. Et Y valide, ça va être 2000. OK ? Ça va ? Bon, voilà, on a fini le dataset. Ensuite, étape d'après. Alors d'ailleurs, si vous avez envie de copier-coller les lignes et de les passer dans Python interactivement, ça marche, on peut le faire. Si vous avez envie de l'exécuter au fur et à mesure, vous pouvez faire ça. Et donc, vous verrez que les formes sont bien ce que je viens de dire. Bon, donc ensuite, il faut que je construise mon réseau. Alors, histoire de faire simple, on va construire le même réseau que celui que je vous ai montré tout à l'heure. Donc, une couche d'entrée, une couche de sortie et une couche au milieu. Donc là, j'utilise l'API Symbol, des MixNet. Et elle est super, moi j'adore ce truc parce qu'elle est super simple à utiliser. En fait, comme vous voyez, on va chaîner, on chaîne les couches les unes après les autres. On commence par créer une couche Data, ligne 36, c'est la couche d'entrée. D'ailleurs, vous voyez que je ne donne pas sa taille. Je ne lui dis pas « Hey, il y a 100 neurones. » J'ai 100 features, je devrais lui dire « Il y a 100 neurones. » MXNet va comprendre ça tout seul après. Donc, Data, c'est ma couche d'entrée. Et puis ensuite, ligne 37, à la suite de Data, je viens brancher une couche que j'appelle FC1, donc Fully Connected One, avec 1024 neurones. OK ? Et puis à la suite de ces 1024 neurones, je viens coller une couche d'activation. Alors là, on a un symbole différent, mais sur mon slide de tout à l'heure, on ne séparait pas les neurones et l'activation. On voyait ça comme une couche. Donc ici, on a deux API, mais bon, c'est la même chose. Dans votre tête, ça ne doit pas créer de confusion. Donc j'active FC1 avec ma fonction relu. Et puis ensuite, j'ai une deuxième couche fully connected, qui est ma couche de sortie, FC2. Et je vois que le nombre de neurones, ici c'est category count, donc le nombre de neurones de FC2, c'est 10, puisque j'ai 10 catégories. D'accord ? Alors, qu'est-ce que c'est le machin softmax ? Ça, je n'ai pas expliqué. Alors, si je n'avais pas ça, si ma couche, si je m'arrêtais, si je n'avais pas la ligne 40, ce que j'aurais, en fait, dans mes neurones, dans mes 10 neurones de FC2, j'aurais les valeurs issues de l'activation. D'accord ? Donc, j'aurais les valeurs calculées par le multiply and accumulate de fc2 et c'est tout. J'aurai ça. Mais moi ce que je veux c'est des probabilités. Les probabilités, c'est simple, il faut que toutes les valeurs soient entre 0 et 1 et que leur somme fasse 1. Les 10 valeurs qu'il y a sur cette couche de sortie, il faut que je puisse les additionner à 1 et qu'il n'y en ait aucune évidemment qui soit plus grande que 1 et aucune soit négative. En fait, c'est ce que va faire cette fonction softmax. Softmax, c'est une fonction mathématique à qui vous donnez un vecteur et qui transforme ces valeurs de manière intelligente pour que leur somme fasse 1. Du coup, je peux les interpréter comme des probabilités. Mais ça, c'est vraiment un élément important. Ce n'est pas des probabilités au strict du terme. Souvenez-vous, quand vous avez fait des probas, vous dites, il y a 7 jours dans la semaine, il n'a plus 3 jours et il a fait beau 4 jours. On raisonnait avec un nombre d'événements bien défini et on calculait des probabilités et des fréquences sur des trucs bien définis. C'était vraiment des probabilités. Ici, on a envie de les voir comme des probabilités. D'accord ? Mais ce n'est pas vraiment des probabilités au sens statistique du terme. Vous comprenez ce que je veux dire ? Donc quand un réseau de neurones vous dit ce machin-là à 99% c'est un chien, ça ne veut pas vraiment dire 99%. Ça veut dire que lorsqu'on a regardé toutes les valeurs qu'il y avait sur la couche de sortie et qu'on les a transformées en probabilités, il y en a une qui sort et qui dit 99%. D'accord ? Mais ce n'est pas tout à fait la même chose que des probabilités au sens statistique du terrain. Voilà, c'est tout. Bon, et donc, et voilà, et ce que je balance en sortie, eh bien, c'est donc ces valeurs-là. Donc, dans out, je vais pouvoir lire mes 10 probabilités. OK ? Donc, je crée mon modèle à partir de cette couche de sortie, ligne 41, voilà, et là, mon modèle est prêt. OK ? Donc, vous voyez, finalement, en 4, 5 lignes de code, j'ai combiné les couches avec une API de très haut niveau, je ne me suis pas vraiment posé la question, je n'ai surtout pas connecté les neurones un par un, je ne me suis pas embêté. Donc littéralement, si je vous avais laissé un peu plus de temps que je vous donnais le dessin de mon réseau de neurones de tout à l'heure, je vous avais dit maintenant codez-le avec l'API, assez vite vous arriveriez à le faire. Parce qu'on est sur une API de vraiment haut niveau et on ne se pose pas les détails de la plomberie. On ne se pose pas la question de comment les neurones sont connectés. Ok, ils sont connectés, c'est fait. Ensuite, là mon réseau est prêt, donc maintenant il va falloir que je crée mon itérateur. L'itérateur, je vous le rappelle, c'est l'objet qui va servir les données batch par batch au réseau. Ok ? On pourrait le faire à la main, on pourrait faire une boucle for, et puis s'amuser à itérer à la main sur X et Y, enfin j'ai envie de dire pourquoi. Si on a un objet qui le fait pour nous, c'est mieux. Donc l'itérateur, il va prendre le jeu d'entraînement, les labels de training, la taille de batch, et puis il me crée un objet sur lequel je vais pouvoir itérer et qui va me servir les échantillons ici 16 par 16, d'accord, automatique. Comme ça, on ne s'emmerde pas avec la plomberie, une fois de plus. Et on pourrait vraiment itérer dessus. Ligne 47, 48, 49, 50. Si vous avez envie d'afficher tous les batchs du jeu de données, vous pouvez exécuter ça. Puis, il va vous afficher les 16 échantillons, les 16 labels, et puis le batch d'après, etc. C'est vraiment un itérateur au sens programmatique du terme. Maintenant, il n'y a plus qu'à coller les deux ensemble. C'est cette API Bind ligne 53. Là, on va prendre l'itérateur et on va l'associer au réseau qu'on vient de créer. C'est à ce moment-là qu'MixNet va dimensionner la couche d'entrée. Parce qu'à ce moment-là, il voit bien que les échantillons ont 100 features. À ce moment-là, il sait qu'il va devoir mettre 100 neurones sur la couche d'entrée. C'est un petit confort supplémentaire. Alors, on pourrait s'arrêter là. On pourrait ignorer la ligne 54 et 55. Mais on ne va pas le faire, puisqu'on aime bien comprendre les détails maintenant. Donc, souvenez-vous, au début, tous les poids du réseau sont aléatoires. Ils ne sont pas spécialement initialisés par un mix-nay. Il y a une initialisation par défaut, bon très bien. Donc on pourrait dire, ok, on fait aveuglément confiance à ça, et puis c'est très bien. Mais il se trouve qu'il y a des façons un peu plus intelligentes d'initialiser les points. Donc ça reste des façons aléatoires de le faire, c'est-à-dire on va tirer des valeurs aléatoirement dans des distributions, etc. Mais il se trouve que ces techniques-là permettent d'entraîner plus vite et d'éviter un certain nombre de difficultés. Et la méthode Xavier, qui s'appelle comme ça parce que c'est Xavier Goro qui est un chercheur français qui l'a inventée, la méthode Xavier, elle va faire ça. Elle va initialiser les poids de manière aléatoire, mais c'est un aléatoire intelligent. D'accord ? Et puis ensuite, il va falloir que je choisisse une fonction qui va optimiser les poids. Vous vous souvenez de tout à l'heure, on a mes graphes en 2D en 3D là. Donc la méthode historique pour faire ça, la méthode historique qui va ajuster les poids et vous faire descendre de la montagne, alors ça s'appelle SGD, Stochastic Gradient Descent, ça date de 1951, donc c'est pas tout à fait un perdreau de l'année, ça date même d'avant l'intelligence artificielle, c'est juste une fonction d'optimisation mathématique, donc on va garder ça, et puis on va prendre un learning rate de 0,1, qui est une valeur très typique. Vous vous souvenez de ce que j'ai dit, pas trop petit, pas trop grand. C'est un truc que vous pourrez essayer après, c'est de le changer et de voir quel impact ça a. Et ensuite, on va entraîner. « Fit », c'est ce qui va lancer l'entraînement. Et puis à la fin de l'entraînement, on va prendre le... on va créer un itérateur de validation avec le dataset de validation. Puis, on va le passer à travers le réseau qu'on a entraîné. Et puis, on va regarder la validation qu'on a obtenue. D'accord ? Ce qui est celle qui nous intéresse vraiment. D'accord ? Ok. Alors, on n'a pas vu combien d'époques on faisait. Où est-ce qu'il est ? 50. Ah oui, pardon, 50. On va entraîner pendant 50 époques. On va le baisser un petit peu parce que ça va défiler vite. Mettons 10 époques. Du coup, il fait tout le dataset et il reprend son même dataset. Oui, exactement. Quand on dit 10 époques, il va passer le dataset batch par batch une fois à travers le réseau. Après chaque batch, il fait la backpropagation identifiée, étudier SGD pour ajuster les poids, etc. Et puis une fois qu'il arrive à la pointe du dataset, plus 1 sur les époques et il recommence. Donc on va faire ça 10 fois. Donc mettons 10 époques. Et donc pour le lancer, c'est vachement compliqué, vous allez juste faire, il faut que j'aille dans le bon répertoire, vous faites Python, First example. Je suis au mauvais endroit. Python. Allez, c'est parti. On ignore tous les chiffres pour l'instant. Ah oui, je ne l'ai pas changé. Le boulet. Je l'ai changé dans le mauvais code. Ok, donc 10 époques. Allez, c'est reparti pour 10 époques. Donc on voit tout au début, on voit les formes qui s'affichent. Donc les deux premières, c'est tout le dataset, les deux suivantes, c'est le training set, les deux dernières, c'est le validation set. Ok ? Donc on voit bien nos 8000, 2000, etc. Ok ? Ça tourne ? Vous arrivez à le lancer ? Ouais ? Levez la main ceux qui arrivent à le lancer. Ouais, ok, d'accord. Allez, c'est bien. Bravo ! Vous faites du deep learning. Pour l'instant, on ne fait rien de bien intelligent, mais voilà, vous avez fait du deep learning. Vous allez rentrer à la maison ce soir, et vous direz à votre meilleur membre, moitié, chéri, ce soir, j'ai fait du deep learning. Voilà. Et il ou elle vous répondra, ouais, mais qu'est-ce qu'on mange ? L'histoire de ma vie. Bon, alors, qu'est-ce qu'on voit ? On voit les époques qui défilent. D'accord ? Donc, ce qui se passe sous le capot, c'est mon littérateur, il sert les échantillons, 16 par 16 au modèle. À la fin de chaque batch, batch propagation. On ajuste les poids, on fait les dérivés partiels, on sait qu'on a avancé un petit pas dans la bonne direction. Batch suivant, batch suivant, batch suivant, batch suivant. Quand on est arrivé à la fin de l'époque, on recommence. On voit époque 1, époque 2, époque 3, époque 4, époque 5. On voit le temps que ça prend, pas trop, parce que c'est un tout petit dataset. Et puis on voit la training accuracy. Alors, qu'est-ce qu'il y a là, la training accuracy ? Qu'est-ce qu'on peut dire ? Elle monte. Bon, elle monte, mais enfin, elle n'atteint jamais que 21%. Alors, c'est peut-être parce qu'on n'a mis que 10 époques. Hein ? Mais d'ailleurs, comment elle estime, du coup, qu'on va essayer et qu'on a entraîné à fond ? Ah ben, elle ne l'estime pas du tout, monsieur. C'est toi qui vas devoir décider qu'on t'arrête. Oui, mais du coup, voilà. Les chiffres qui sortent, là, c'est qu'en fait, là, comme je ne lui ai pas donné, là, en fait, il remesure, ça, ça doit être l'accuratie du dernier batch de l'époque. D'accord ? Le dernier batch de l'époque, il affiche l'accuratie. Donc, ça donne une idée. D'accord ? Oui, c'est des données complètement random. Donc, ça doit commencer à faire sonner l'alarme dans vos têtes. Depuis tout à l'heure, on va voir. Depuis tout à l'heure, je vous dis, on extrait des patterns automatiquement, on apprend, on apprend. Qu'est-ce qu'il peut y avoir à apprendre dans des trucs aléatoires ? Ou alors, il n'est pas général. On y va. On va mettre plus d'époque. On va faire 50 maintenant, de toute façon ça va vite. Allez, on met 50. 50 époques et on est reparti. Ça tourne ? Ouais ? Ah, bim ! Hum ! Alors, normalement, au bout de 50, enfin même au bout de 44 finalement, on atteint 100% et forcément on ne va pas plus haut. Donc là, il faut qu'on réfléchisse à ce qui vient de se passer quand même. On vient de prendre 10 000 échantillons complètement aléatoires, on les a passés à travers un réseau, bon ok, il a 1024 neurones au milieu, c'est pas négligeable. Et il arrive à les apprendre à 100%. Ce qui veut dire quoi concrètement ? Ce qui veut dire que si vous prenez le réseau que vous venez d'entraîner là, et que vous prenez n'importe lequel des éléments du training set, il va vous donner le bon label. Donc il a appris parfaitement ses 8000 échantillons. C'est ça que ça veut dire, 100%. Ce n'est pas 99, c'est 100%. D'accord ? Donc, il sait prédire parfaitement les 8000 échantillons du training set. On n'a pas passé la validation ? Alors, tout à la fin, on a passé la validation. C'est la dernière ligne qu'on voit là. Mais là, qu'est-ce qu'on voit ? On voit 9%. Donc, c'est une escroquerie mon truc en fait. Donc, aller chercher le goudron les plumes et voilà, on y va. Bon, mais non, c'est votre faute en fait. C'est la faute du code. On réfléchit, on respire. Parce qu'on est vite perdu dans les chiffres et les trucs. Il faut comprendre ce qu'on fait. Une fois de plus, l'intuition, c'est super, super important. D'accord ? Donc, tu l'as dit tout à l'heure, on a généré des données aléatoires. Ok. J'ai commencé ma présentation par dire, le deep learning, ça trouve automatiquement les fichiers. On suppose que le générateur de nombre aléatoire de Python fait bien son travail. Et par conséquent, on ne voit pas très bien quel pattern il pourrait y avoir dans ces données aléatoires. On respire. On a généré des données vraiment... parfaitement aléatoire et on essaie d'apprendre un pattern. Est-ce que ça marche ? Non. On arrive à apprendre le training set parce qu'on a une fonction mathématique avec 1024 neurones de fully connected et elle peut apprendre plein de conneries, y compris ça. Par contre, quand on prend les 2000 échantillons qu'il n'a pas vus et qu'on lui fait passer là, il ne sait rien faire. Et ce n'est pas un hasard que ce soit 9. Si on voulait être hyper précis, ça devrait être 10. Parce que vous avez des échantillons qu'il n'a jamais vus et qui sont répartis en 10 classes. Donc vous avez une chance sur 10 d'avoir bon. Puisqu'il n'y a aucun pattern là-dedans. Donc il tire, il lance une pièce, il lance un dé à 10 faces et puis... Ah ouais, je suis sûr que c'est un 3, ça. Mais de temps en temps, il a bon. 9 à 10% du temps. D'ailleurs, vous n'avez peut-être pas tous ce chiffre-là. Vous avez peut-être des chiffres... Des fois, on tombe sur 10. Donc, cet exemple débile, il a quand même quelques vertus. La première vertu, c'est qu'il vous donne le squelette d'un script à Mixnet. Ça aura toujours cette gueule-là. Alors, on charge... les données, on les trifouille, on les papouille, mais on leur fait des trucs compliqués, mais à la fin, on les met dans un ND Array. D'accord ? Ce ND Array, il nous sert à faire un itérateur. D'accord ? On construit un modèle en empilant des couches. Alors, ici, on a fait l'API symbolique, mais je vous montrerai rapidement, gluons tout à la fin. C'est la même limonade, on empile les couches, ce n'est pas très compliqué. On définit éventuellement un optimiseur, ici on a pris le GD, on définit un learning rate, on a pris 0,1 parce que je vous ai dit que c'était bien, voilà, et puis on lance, voilà, et puis on espère qu'on a bon. D'accord ? On voit qu'on a atteint 100% de training accuracy parce qu'on avait un réseau suffisamment grand pour joyeusement faire de l'overfitting sur ce jeu de données, mais ce qu'on devrait vraiment regarder, c'est la validation, c'est la précision de validation, et là, elle est dégueulasse. Elle est dégueulasse parce que c'est des données aléatoires. Et que, garbage in, garbage out. Donc, il n'y a pas de magie. Si vos données sont pourries, soit parce que vous ne les avez pas nettoyées, il y a des valeurs manquantes, il y a des incohérences, il y a des doublons, il y a mille raisons qu'elles soient pourries, soit juste parce qu'il n'y a pas de pattern dedans, donc vous n'avez pas les bons features, ce n'est pas un réseau de deep learning qui va résoudre votre problème. Donc il n'y a pas de magie. Vous comprenez bien. On a une entrée, on essaie de mapper une entrée et une sortie avec une fonction mathématique compliquée dont on découvre les paramètres itérativement. C'est ça le deep learning, pas autre chose. Avant de passer à l'exemple d'après, on va changer le learning rate, que vous voyez ce que ça peut faire. Mettez par exemple 0,01. On le divise par 100. C'est la taille du pas ou l'inverse ? Non, c'est pas... La taille du pas est plus... au learning rate. Oui, c'est ça, exactement. Donc là, on fait des passes 100 fois plus petits, c'est ça que ça veut dire. Donc, changez de learning rate et réexécuter votre code. Bon, on voit tout de suite ce qu'il se passe. On lui dit de faire des pas 100 fois plus petits. Sans surprise, il descend 100 fois plus vite de la montagne. Au bout de 50 époques, il n'a pas fait beaucoup de chemin. D'accord ? Donc trop petit, pas bien. Pas bien au début. Parce que peut-être après, c'est bien. Alors maintenant, on va faire la connerie inverse. Il ne faut pas que je dise de gros mots, je suis filmé. Ouh là là. On va mettre, allez, mettons, allez, 0,5. Ah, 0,5, il arrive encore à apprendre un peu. Comme quoi. Bon, alors attendez, on va arrêter. On va faire plus violent. On va mettre... Ah, on va mettre 10. Ben oui. Ah, ben non, mais... Voilà. Voilà. Bon. Tout. Tout à fait, c'est la fin du monde. Oui, parce que là, on a les bottes de géant et on fait des pas tellement grands qu'il ne se passe plus rien. C'est important de voir ça parce que là, évidemment, on est sur un exemple qui est assez trivial. Mais j'ai un collègue qui a un t-shirt, et je vous jure que c'est vrai, où c'est marqué « qui calme and lower the learning rate. C'est-à-dire que là, j'ai mis une valeur qui est caricaturale, mais parfois, vous pouvez commencer à 0.1. Vous commencez à 0.1 et vous voyez quand même ça. C'est-à-dire, vous voyez un modèle qui n'apprend pas. D'accord ? Donc, la première réaction, c'est diviser le learning rate par 10. D'accord ? Si vous voyez un modèle qui n'apprend pas, il y a plein de raisons pour qu'il n'apprenne pas. Mais la plus probable, c'est que le learning rate est trop grand. D'accord ? Donc, divisez-le par 10 et puis voyez si ça va mieux. Ok ? Tu n'arriveras pas forcément au même endroit. Tu vois ? Tu vois ce que je veux dire ? Voilà. C'est que si je reviens sur... Attends, où il est mon horrible truc, là ? Si je reviens sur ça, la taille du pas... Alors déjà, il y a quand même un truc qu'il faut retenir. C'est que si j'entraîne 10 fois de suite, même avec les mêmes paramètres, rien ne me dit que j'arrive au même endroit. D'accord ? Alors, c'est pour ça qu'on utilise Xavier et ces machins-là. C'est que Xavier, ça... ça nous fait démarrer, je vais mettre des énormes guillemets, au bon endroit. D'accord ? Bon. Mais, c'est vrai qu'il n'y a rien qui garantit qu'on parte du même endroit. On va partir de 10 points différents. D'accord ? Et donc, on va arriver peut-être à 10 endroits différents. Et si en plus, on fait varier le learning rate, peut-être que, c'est ce qu'on disait tout à l'heure, j'ai peut-être un learning rate qui est juste bien pour sortir de ce trou-là et me faire tomber dans l'autre. Et c'est vachement important ce truc-là parce qu'en fait, quand on commence à faire du deep learning, on cherche le modèle ultime, l'entraînement ultime et puis on se dit « Ah, ça y est, c'est bon ! » C'est bon jusqu'au coup d'après. Donc, en fait, quand on n'entraîne pas un modèle une fois, on l'entraîne 10 fois, 50 fois, 100 fois, avec des paramètres différents et généralement même à la fin, on n'en garde pas qu'un. On en garde de 5 à 10. On va garder les 10 meilleurs. Et lorsqu'on va prédire, on va prédire avec les 10 et on va faire la moyenne des prédictions. Et l'intuition derrière ça, c'est que chaque modèle risque de faire des conneries de temps en temps. Mais en faisant une moyenne sur 10 modèles et en espérant qu'ils ne font pas tous la même connerie au même moment, finalement, on annule ce truc-là. C'est ce qui s'appelle l'ensemble training. On entraîne plein de modèles, on garde les meilleurs et on prédit avec les meilleurs. Et on fait la moyenne des prédictions, ce qui, une fois de plus, réduit d'autant. S'il y en a un qui prédit absolument n'importe quoi, mais que les neuf autres sont pas mal, cette prédiction pourrie, elle est annihilée. Et il est probable que ces dix modèles, ils sont tous tombés dans des minimums différents. D'accord ? Alors, est-ce qu'il y a des questions sur celui-là ? Est-ce qu'il y a des gros doutes métaphysiques ? Ou est-ce qu'on est à peu près... Oui ? Vas-y. Oui, on t'entend, on t'entend. Non, là, on t'entendait tout à l'heure. Un, deux. Vas-y, c'est bon. Je voulais savoir s'il était possible de... combiner des méthodes d'optimisation pour éviter justement de tomber dans un minimum local ? Est-ce qu'on peut d'abord utiliser une approche globale avec un pas relativement grand pour gagner du temps et ensuite, quand on voit que la variation de valeur est faible, passer sur une approche locale avec un plus petit pas ? Super question ! Bravo, merci. C'est exactement ce qu'on fait. En fait, ici, je reviens juste sur ma ligne de code. Je vais enlever le 10 parce que la prochaine fois que je vais l'exécuter, je vais avoir l'air idiot. Encore plus idiot. Donc ici, on travaille avec un learning rate fixe. Mais en pratique, évidemment, on ne va pas faire ça. Parce que tu as exactement mille doigts sur le problème. C'est-à-dire qu'on pourrait le voir encore sur mon slide. D'accord ? Je vais peut-être le mettre un peu plus loin. Voilà. On pourrait se dire intuitivement... Imaginons qu'on commence sur la montagne. Et là, la pente, elle est raide. Donc, on peut dire, OK, c'est raide, on peut descendre. On descend vite, on y va. On descend un grand coup, on essaie d'accélérer dans la pente. Et puis après, ça s'aplatit. Et là, on pourrait se dire, c'est plus compliqué maintenant, parce que mon histoire tout à l'heure de je tâte avec le pied, si la pente est comme ça, elle marche bien la solution. Si la pente est vraiment très plate, il faut peut-être qu'on soit plus fin que ça. Et donc, effectivement, ce qu'on va faire, c'est qu'on va faire varier le learning rate au fur et à mesure. Donc généralement, ce qu'on dit toujours, c'est au début, on essaie de garder un learning rate élevé le plus longtemps possible parce que c'est ça qui nous fait descendre rapidement. D'accord ? Idem sur le... à ce slide-là. Hop. Ok ? Au début, là, on aimerait bien descendre un grand coup puis arriver en bas. Tu veux dire, il n'y a pas de doute. C'est là. On voit que la pente est comme ça, on y va. Après, on peut commencer à explorer. Il y a plusieurs techniques pour faire ça. On peut faire ce qu'on appelle du « learning rate scheduling ». On va dire que les 10 premières époques, on fait 0,1. Les 10 suivantes, on fait… et puis on divise peut-être par deux. On divise par deux toutes les 10 époques. On va faire 0,1 sur les 10 premières époques. 0,05 sur les 10 suivantes, 0,025, etc. Mais ça, ça pose la question de comment tu sais que c'est 10, 20 et 30 ? On ne sait pas. On ne sait pas, sauf si c'est un modèle qu'on a déjà entraîné 100 fois, qu'on a tracé toutes les courbes de précision et qu'on sait qu'effectivement, ça monte très vite au début, puis après ça plafonne un peu et peut-être là, il faut chercher plus plus finement donc ça c'est une solution mais c'est généralement pas la bonne solution au début et ça c'est le slide que j'ai comme quoi faut jamais sauter des slides voilà c'est le slide que j'ai sauté tout à l'heure ok donc tu l'avais vu voilà c'est bien c'est bien il faut me challenger j'adore ici en fait on voit On est sur un saddle point par ailleurs, mais on voit qu'effectivement, il y a certains optimiseurs qui vont accélérer dans la descente, et puis plus ou moins vite. Donc on voit que SGD, dans son implémentation vraiment naïve, il reste coincé sur le saddle point, parce que toutes les dérivées sont nulles, il y a un maximum dans un sens et un minimum dans l'autre sens, d'accord ? Là, on a un minimum et là, on a un maximum. Donc, ils restent coincés parce qu'ils ne peuvent pas aller ailleurs. Mais on voit que les autres, parce qu'ils sont plus malins, non seulement ils ne restent pas coincés, mais surtout, ils accélèrent dans la pente. On va aller tester ceux-là. Il y en a toute une famille qui s'appelle ADA, ça veut dire adaptative, tout simplement. Ça veut dire qu'en fait, ils vont adapter le learning rate aux conditions. Donc quand il y a de la pente, ils vont accélérer. Quand ça devient plat, ils vont le baisser. Et il y a même des optimiseurs qui vont avoir un learning rate par dimension. D'accord ? Et donc ce qui permet d'avoir, s'il y a une dimension qui est hyper pentue, on va accélérer. D'accord ? Et s'il y a une dimension, la dimension transversale qui est hyper plate, on va aller plus doucement pour explorer. D'accord ? Donc les ADA, GRAD, ADA, DELTA, il y en a qui s'appellent ADAM, enfin ADAM, pareil, ils vont faire ces trucs-là. On va les tester après. Ok ? Super question. Merci. D'autres questions sur le principe général ? Ça va ? Prêt ? Ok. Alors, on va quitter ce truc-là. On va remonter le répertoire. Et maintenant, on va aller dans MNIST. Et là, on va jouer avec un vrai dataset, même s'il est facile. Alors, MNIST, pour ceux qui ne l'auraient jamais vu, et il y en a peut-être qui ne l'ont jamais vu, c'est un dataset qui ressemble à ça. Il est facile à comprendre. Si on est arrivé à afficher la page, peut-être. C'est un dataset d'images. Décidément, voilà. Et ces images, c'est tout simplement des chiffres manuscrits de 0 à 9. Il y en a 60 000. J'espère qu'ils n'ont pas tous été écrits par le même bonhomme. J'espère que non. Sinon, le dataset n'aurait pas beaucoup d'intérêt. 60 000 digits. Et évidemment, le but du jeu, ça va être de les classer automatiquement et de deviner que telle image est un 0, que telle image est un 5, etc. C'est un dataset qui ne sert à rien. Il est bien pour apprendre, il ne résout aucun problème dans la vraie vie et vous allez voir, il est très simple à apprendre. On arrive très vite à d'excellentes précisions. Et je vous en montrerai un autre qui est compatible avec celui-là, mais qui est beaucoup plus dur. Je ménage mes effets. Alors, on y va. Donc, on va ouvrir, je ne sais plus, train model. J'étais inspiré ce jour-là. Trainmodel.pi. Ce n'est pas toujours facile. Décalage horaire, tout ça. Ah ben non, mais pas sur cette instance-là, idiot. Oui, mon truc, il est là. Oui. Alors, train, modèle, paf, voilà. Ok. Alors, qu'est-ce qui ne va pas changer ? Déjà, c'est bien, pour se rassurer, parce que là, c'est anxiogène. On a fait le premier exemple tout con, maintenant, on en fait un peu plus évolué. Alors, ce qui ne va pas changer, c'est la structure du code. On va trouver exactement la même chose. C'est super séquentiel, vous n'allez pas être perdu. Ce qui va changer, c'est qu'on va avoir un autre dataset et puis on va avoir un réseau avec un peu plus de couches. D'accord ? Alors, c'est parti. Donc ici, 50 époques, pourquoi pas ? Alors, comme MNIST est un truc qui est, c'est vraiment le dataset de tests par excellence, dans les librairies de deep learning comme MXNet ou les autres, TensorFlow, Keras, etc., on a carrément un itérateur tout en un. Celui-là, il va nous construire automatiquement les itérateurs. Il n'y a même pas besoin de lui passer les noms de fichiers, il les connaît tout seul, c'est magique. On va charger, et le dataset est déjà découpé en train et validation. Donc magnifique. Ensuite, on construit un réseau. Alors, la couche d'entrée, data. Ah mais là, on a un problème. On est un peu stoppés. Parce que tout à l'heure, on travaillait avec quoi ? On travaillait avec des échantillons qui étaient... Chaque échantillon dans mon premier exemple, c'était déjà des trucs plats. C'était des vecteurs. Chaque échantillon, c'est un vecteur de 100 valeurs aléatoires. Vous vous souvenez ? Ici, ce n'est pas ça. Moi, ici, j'ai des images. Jusqu'à preuve du contraire, c'est en deux dimensions, des images. Donc, comment est-ce qu'on fait rentrer une image en deux dimensions sur une couche, sur une input layer qui est plate ? Eh bien, on aplatie l'image. D'accord ? C'est exactement ce qu'on fait. On aplatie l'image, on transforme l'image. Donc, deux dimensions, on a un vecteur à une dimension. C'est ce que fait cette opération-là, Flatten. D'accord ? Donc, vous prenez les lignes, voilà. En gros, on prend les différentes lignes de l'image et on les met bout à bout. OK ? C'est ce que ça fait. Bon. Alors, la taille de l'image, en fait, il la connaît automatiquement. C'est vrai que je ne l'ai pas précisé. Les images, elles font 28 pixels sur 28 pixels. Voilà. Donc ça fait 784 pixels. Donc en fait, ici on va se retrouver, mais MXNet le fait automatiquement. Donc il va prendre ce ND array à deux dimensions et il va l'aplatir en une dimension. Donc ma couche d'entrée, elle va avoir 784 neurones. Et chaque pixel va rentrer dans un neurone de la couche d'entrée. Et puis derrière, c'est comme tout à l'heure, j'ai une première couche « fully connected » avec 512 neurones activés par... Alors ici, on a mis TanH. C'est pourquoi pas, on peut essayer de TanH. C'est une autre fonction d'activation, plus ancienne, on va la laisser. Donc, lignes 13 et 14, on a une première couche et son activation. Lignes 15 et 16, on a une deuxième couche avec 64 neurones et son activation. Et lignes 17 et 18, on a la couche de sortie avec 10 neurones parce qu'il y a 10 catégories et softmax parce qu'on a envie d'avoir des trucs qui ressemblent à des probas. D'accord ? Pas plus compliqué que tout à l'heure. On a juste une couche de plus. La suite, c'est vraiment la même. D'accord ? Je bind, j'utilise Xavier pour initialiser les paramètres. J'utilise SGD avec un learning rate fixe et un autre paramètre qui s'appelle le momentum. Le momentum, c'est une des méthodes d'accélération. C'est pour accélérer dans la pente. En gros, je simplifie un petit peu. C'est un paramètre qu'on peut donner à SGD en lui disant « Ok, mais vas-y quand même. Vas-y, tu peux bomber. » Et puis, après, on fit, et puis c'est tout. Et on va le sauver, ce modèle-là. Après. Ok ? Alors, on y va. Qu'est-ce que j'ai fait comme connerie ? Donc, en avant, on va exécuter ce truc-là. Je vais vérifier que j'ai le bon. ... Oui, c'est parti. Vraiment, vraiment ? Parce que j'ai tendance à les bricoler à longueur de journée. Oui, non, c'est vraiment le même. Ok, ça marche. Allez, pan ! Ah, ben zut alors ! On a oublié une étape ? Ah ben oui, il y a un petit script download mnist. Allez, on va faire un petit dédose sur yann.lecun.com. Allez, en avant. Donc, faites juste sh... shdownload.mnist. Moi, je les ai déjà 100 fois. Rendons à César ce qui appartient à César. Yann LeCun, c'est un des grands chercheurs en intelligence artificielle mondiaux. Il est français, comme son nom l'indique. Il travaille chez Facebook aujourd'hui. Et il a beaucoup contribué au deep learning. Il a inventé pas mal d'architectures de réseau. On en reparlera tout à l'heure. Et voilà. OK ? Donc, vous téléchargez le dataset et vous le relancez. OK ? C'est bon ça tourne ? Ça mouline ? Là ça va commencer à être un peu plus lent maintenant sur vos machines. Voilà. Là, je ne tourne pas sur mon PC. Je ne vous le cache pas. À 40 000 samples par seconde, je ne suis pas sur mon laptop. Mais bon, je ne paye pas mes factures AWS. Les mauvaises langues disent que c'est pour ça que je les ai rejoints. Ils n'ont peut-être pas toujours tort. Je ne suis pas sûr. Bon. Ok, donc qu'est-ce qu'on voit ? On voit comme tout à l'heure, on voit les batchs qui défilent, les époques qui défilent. Alors cette fois, comme on a fourni le littérateur de validation aussi, on voit à la fin de chaque époque, on voit la validation accuracy qui s'affiche en même temps. Donc ce qu'on veut voir, une fois de plus, on respire, on ne s'est pas embêté par les chiffres. Ce qu'on veut voir, c'est une training d'accuracy qui globalement augmente. Ça a l'air d'être le cas. On pourrait même dire qu'elle diminue un peu chez moi. J'étais à 95,38, 95,40, 42, 45, 44, 44, ah non, j'ai 54, non, non, ça continue à monter, 54, ouais, bon, voilà, il y a des petites variations, c'est pas monotone, mais bon, donc j'arrive à 95, 50, ok, donc training accuracy, ça monte, validation accuracy, ça monte, On veut voir un truc comme ça. D'accord ? On veut voir ça. Là, manifestement, on n'est quand même pas au bout de la ligne bleue. Parce qu'on est à 95 et on devrait aller plus loin. D'accord ? Mais je le sais parce que j'ai déjà joué avec. Et la ligne rouge, on est bien, mais on ne l'a pas vue. Chuté comme une brique. Donc, on se dit, bon, on est arrivé à faire 95. Alors, c'est là que ça commence à devenir intéressant. Parce qu'on se dit, maintenant, moi, je n'en. J'ai lu tous ces articles de blog sur MNIST et les mecs, ils arrivent à 99. Et comment c'est possible ? Pourquoi moi, je suis à 95 ? Là, on commence à rentrer dans le vrai sujet. Bon. Alors, allez, des suggestions. Qu'est-ce qu'on pourrait faire ? Alors, le flatten, il est probablement embêtant. On a l'intuition qu'il peut être embêtant, parce que passer d'un truc 2D à un truc 1D, on n'est pas sûr que ce soit la bonne idée. On se le garde pour plus tard. C'est une bonne remarque, on se le garde pour plus tard. Sans changer massivement cette hypothèse-là. Qu'est-ce qu'on pourrait faire ? On pourrait mettre plus de couches. Allez, on essaye ? On y va. Soyons fous. On pourrait se dire, allez, deep learning, deep. Allez, c'est parti. Donc, on pourrait se dire, allez, on va remettre une troisième couche. ... Donc, il faut la mettre avant la dernière. Il ne faut pas se tromper. Voilà. On pourrait faire ça. Je fais juste le truc. Que tout le monde ait un modèle. Alors, tatata. Donc là, ça va être... Donc, vous avez compris, les trucs, ça s'enchaîne à la queue leu leu, pour ainsi dire. Donc, il ne faut pas vous gorer sur les noms. Voilà. Voilà. On pourrait faire ça. Allez. Allez. Donc là, on a... Vous avez compris comment ça marche ? Quand vous créez une couche, elle vous retourne son nom. Et quand vous créez la suivante, il faut que vous passiez le nom de la précédente. C'est comme ça qu'on les chaîne. Donc, acte 2, acte 3, etc. Ah oui, la dernière, oui. Merci. La dernière, il faut évidemment que ce soit la dernière. Voilà. On pourrait faire ça. L'intuition étant, on a rajouté les paramètres, on a rajouté une couche avec 64, d'accord ? Donc, il y a plus de paramètres dans la fonction, donc s'il y a plus de paramètres dans la fonction, elle doit être capable d'apprendre plus de trucs. La fonction est plus compliquée, elle peut prendre des formes plus compliquées, donc pourquoi pas ? Ok ? Et là aussi, oui, je crois que j'ai... Ce nom-là, en fait, on s'en fout. Ouais, ça, on s'en fout. 1, 2, bon, voilà. On va laisser comme ça. Voilà. Ok. Bon, ben, on essaye. Alors là, ça va devenir un peu lent chez vous, mais chez moi, ça va aller. Ok. Ah, ça se casse la gueule parce que duplicate names detected. Alors, qu'est-ce que j'ai fait comme anerie ? Ah oui, il y a deux fois FC2. Ah, bien sûr. Voilà, ça c'est sûr. FC3, FC4. Voilà. Ok, allez, c'est reparti. Ouf, ça ne l'a pas rallenti beaucoup. C'est une grosse instance. C'est une grosse instance, oui. Il y a 36 coeurs, elle marche bien. Oui, voilà, je pense que chez vous, ça va être pénible. Au bout de la première époque, oui. Moi, ça m'épate à chaque fois, c'est que même au bout d'une époque, on arrive à... C'est-à-dire, une époque, on a passé le dataset qu'une fois, on a ajusté les poids, et bien on arrive déjà à 0,9 au bout d'une époque. Est-ce que les poids des CIDAP sont randoms ? Oui, ils sont randoms. Mais en... Tu vois, là, on a 50 000 échantillons. On a une taille de batch de 16... Je crois. Donc, ça fait quoi ? Ça fait 1000... 3000 coups, à peu près. On fait 3000 coups de backpropagation, par époque, à la louche. Donc, ça veut dire qu'en 3000 backpropagation, on arrive déjà... Finalement, on descend hyper vite de la montagne et on arrive déjà dans un grand plateau qu'il faut qu'on explore. Est-ce qu'on a fait beaucoup mieux, chef ? Non. Bon. On pourrait peut-être... On en a plein, on en a 50 000. Ah oui, je ne l'ai pas dit. On a 60 000 échantillons, donc on en a 6 000 de chaque. Mais c'est une bonne remarque. On pourrait se dire, peut-être qu'avec plus de data, on va généraliser mieux. Mais vous voyez, rajouter des couches, là, ça n'a rien réglé. Bon. Ça a ralenti, ça coûte plus cher. Alors, merci pour nous, mais non. Donc, alors, on va l'enlever. On va tout recasser. Voilà. Ah non, j'y fais le con. Ouais, non, non, mais attends, attends, attends, attends. On va faire vachement plus simple. Voilà. C'était une mauvaise idée. Mais c'était une bonne idée dans le sens où il faut tester des trucs. Plus de couches, niais. Dans la salle d'en face, qu'est-ce qu'on fait ? Qu'est-ce qu'on pourrait essayer ? Il n'y a pas de mauvaise idée. Il n'y a que des idées. Elles sont mauvaises à la fin, mais au début elles sont toutes neutres. Qu'est-ce qu'on pourrait essayer ? Alors, on pourrait essayer moins de couches, c'est pas bête. Pour essayer moins de couches, euh... Ouais. Alors, essayons moins de couches. Allez, on va le faire dans les deux sens. Donc, on va juste commenter ces machins-là. Alors... Ouais, c'est comme les mecs, des fois ils ont moins de neurones, ils marchent mieux. Alors, c'est ça l'arrière-pensée ? Bah non. Non mais déjà, ils en ont pas beaucoup en général. Alors, la question c'est combien ? Pourtant on dit, vous tentez une couche. Bah non, tu vois. Pas forcément. Je ne sais pas pourquoi, mais je ne suis pas optimiste. On est coincé à... Non, on fait un peu moins bien, finalement. Tu vois, on n'avance plus. Bon. On n'avance plus. On est resté coincé à 84, 6. Bon, non. Allez, on continue. Alors, on pourrait avoir des couches plus larges. Alors, 10 on sait pourquoi ? Alors, on part de 768 features. Là, l'intuition, c'est que tu pars de 768 et tu vas arriver à 10. D'accord ? Je ne sais pas si c'est démontré par quelques formes de publications que ce soit, mais il se trouve que réduire graduellement le truc n'est pas une mauvaise idée. C'est scientifique, je viens de dire. Donc, on pourrait se dire... Peut-être que le passage de 512 à 64, peut-être qu'il est trop violent. Alors, et si on essayait 128 ? C'est parti. C'est... C'est... C'est un espèce d'entonnoir dans lequel on essaie de faire passer les données. En tout cas, pour les réseaux fully connected, c'est comme ça. On constate que ça marche pas mal comme ça. On va essayer ça après. Parce que là, j'ai l'impression que... Oui, mais c'est la sortie de la... Ah oui, je vois ce que tu veux dire. Non, ce n'est pas bête. Oui, on va revenir là-dessus. Bon, c'est un peu... Oui, bof, bof. On va dire bof. Ok. Simplayer, shoot again. Alors, on sent que là, on devient un peu désespéré parce qu'on a essayé plus de couches, ce n'est pas terrible. Moins de couches, ce n'est pas terrible. Plus de neurones dans les couches, ce n'est pas terrible. Donc, mon intuition me dit que ce n'est pas forcément la structure du réseau qui est en cause. D'accord ? Bon, alors là, il faut commencer à réfléchir. On pourrait réduire le learning rate en espérant que peut-être au bout de 150 époques, il se passe quelque chose. On pourrait essayer ça. En pratique, ça ne change pas grand-chose dans ce cas-là. Je peux gagner du temps. Et effectivement, on se dit « mon Dieu, qu'est-ce qu'il reste dans cette histoire ? » Seul truc auquel on n'a pas touché, c'est la fonction d'activation. Alors oui, c'est une bonne remarque. Peut-être que les données sont pourries. C'est vrai que c'est un truc, bon ici on ne se pose pas la question parce que c'est un dataset de référence, on sait qu'il est bien, mais c'est une très bonne remarque. On pourrait se dire peut-être que ma précision plafonne parce que j'ai des doublons, parce que j'ai des... Donc peut-être qu'il faut que je refasse une passe de cleaning sur mes données. Si je n'arrive vraiment pas à avancer, soit il me faut plus de données, soit il faut que je les nettoie, tu les inspectes, tu regardes s'il manque des valeurs, etc. Si elles sont clean, peut-être qu'il t'en faut juste plus. Mais c'est vrai. Ici, on sait que ce n'est pas ça, parce que Yann LeCun a fait ce qu'il fallait sur son dataset. Bon. Alors, c'est vrai qu'on pourrait dire « tanH ». Alors, « tanH », c'est la fonction originale qui a été effectivement utilisée dans les années 90, on va dire. Mais tout à l'heure, j'ai dit « tiens, relou, là ». Manifestement, on utilise « relou » aujourd'hui. D'accord ? Alors, on va faire un truc vachement scientifique. Voilà. On va virer TanH et on va mettre Relu partout. Bam ! Ah ! Slash G. Pourcent S slash TanH slash Relu slash G. Bam ! Voilà. Ça, c'est du deep learning. OK ? Donc là, on n'a pas changé la structure, on change juste l'activation. OK ? Alors, on va quand même... C'est intéressant ce que j'ai dit tout à l'heure alors TanH elle a cette gueule là bon donc elle a une partie au milieu qui est presque complètement droite quoi bien pentue bien sympa et puis elle a deux parties complètement plates. D'accord ? Les deux extrémités sont très plates. Et ça, ça pose un petit problème. Alors, je vais vous refaire mal à la tête 30 secondes avec mes histoires de dérivés. Quand on calcule les dérivés, on va aussi calculer les dérivés des fonctions d'activation. D'accord ? La fonction d'activation, elle rentre dans le calcul. Ok ? Alors, regardons la dérivée. Dans la partie centrale de TanH, on va dire c'est presque y égale x. Donc là, la dérivée c'est 1, donc il y a de la pente. Super. S'il y a de la pente, on va pouvoir ajuster les poids. Mais aux deux extrémités, il n'y a plus de pente. Il y a deux asymptotes. Et donc, si les valeurs qui sortent là, si les valeurs qui sortent, qui sortent du multiply and accumulate sont très très positives ou très très négatives. Elles vont être activées là sur ces parties très plates. Et donc ça veut dire que quand cette valeur varie ici, quand U varie, même si je multiplie U par 10, imaginez U égale 1 million. La valeur d'activation entre U égale 1 million et U égale 10 millions, elles sont quasiment identiques. Parce que cette courbe, elle est complètement plate. Donc, je n'ai plus de pente. Donc, ça veut dire que, comme je n'ai plus de pente, quand je vais calculer les dérivés de cette fonction-là, je ne vais quasiment rien mettre à jour. Donc, si jamais, d'accord, vous comprenez pourquoi, il n'y a plus de pente. Donc, je ne peux plus avancer. Et ça veut dire que, si jamais, dans mon multiply et accumulate, je tombe dans des valeurs très très négatives ou très très positives, j'arrête de mettre à jour les poids. Si la structure de mon réseau fait qu'à un moment, il y a un bout du réseau qui pond des valeurs U égales à 100 000, je ne vais plus jamais mettre à jour les poids pour ce truc-là. D'accord ? J'ai une zone presque figée dans mon réseau. C'est ça que ça veut dire. Donc, ce n'est pas bien. Et c'est pour ça que c'est une des raisons pour lesquelles on a inventé Relu. Parce que Relu, il n'y a pas de limite, elle a toujours de la pente dans les positifs. Donc même si j'ai des valeurs hyper élevées, j'ai toujours de la pente. Donc j'arrive toujours à updater mes poids. C'est un peu théorique, ce que je raconte, mais c'est l'intuition. Alors, on y va. ... Alors ? Ça claque ! Voilà. Ça continue à monter même. Et en plus, Relu, elle est super facile à calculer. Donc, c'est une des raisons pour laquelle elle est sympathique, c'est que la fonction Relu, en fait, vous faites le max entre 0 et X. Vous avez vu. Parce que si la valeur est négative, on prend 0. Et si la valeur est positive, c'est la valeur. Donc Relu à implémenter, elle est super simple et hyper rapide. Donc elle permet même d'accélérer l'entraînement. Alors on arrive à combien ? 96 ? Ça monte encore, hein ? 96 ? On arrive à 96,50. Donc, on a gagné un gros pourcent par rapport à tout ça. D'accord ? Donc, vous voyez, ce n'est pas anecdotique, ces trucs-là. Alors, après, le pourquoi du comment, honnêtement, personne n'en sait rien. Il y a bien un mec à Stanford qui doit savoir. Mais, nous, on s'en fiche. On ne veut pas savoir. Ce qu'on veut savoir, c'est Relu marche bien. Dans de nombreux cas, on prend Relu. D'accord ? C'est tout. On est pragmatique. C'est du code. Ça marche bien comme ça, on fait comme ça. Donc c'est quand même important de comprendre ce que font ces fonctions-là pour vérifier que vous utilisez les trucs à peu près à l'état de là. Mais vous voyez que ça fait des grosses différences. Ceci dit, on reste quand même coincé à 96-42. Alors, il y a encore un truc auquel on n'a pas touché. Alors... L'optimiseur, on n'y a pas touché. Bon. Alors, on va y toucher. C'est quoi le WD ? Alors, WD, c'est Weight Decay. Attends, j'expliquerai après. C'est un autre paramètre, mais en l'occurrence, ici, je ne suis pas sûr qu'il joue grand chose. Donc, je vous ai parlé des optimiseurs magiques. Alors, on va utiliser des optimiseurs magiques. Et donc, on va dire que, allez, on va prendre AdaDelta, parce qu'il est bien. C'est celui qui accélère dans la pente et qui ajuste le learning rate, etc. Comme ça, même, ça nous embête, ça nous enlève la responsabilité de choisir un learning rate. Il va prendre une valeur par défaut, puis après, il va se débrouiller. Alors, on y va. ... Alors, il est parti de plus bas, mais bon. Il part de plus bas, mais la question, c'est est-ce qu'il va arriver ? D'où est-ce qu'il va arriver ? D'accord ? Donc, lui, il ajuste le learning rate en fonction de... Il nous reste encore du chemin à faire. Oui, je vais te montrer après. 97, 11. Bon. Et alors après, ok, vous creusez encore un peu le sujet, et puis vous vous rendez compte que... Pas de rien, merci. Et puis vous vous dites... Ah, il y a un truc qui s'appelle Adam, et puis les gens, ils ont l'air de bien s'en servir, quoi. Allez, on va dégainer celui-là, on va voir. ... Et vous voyez, ce n'est pas compliqué de les changer, ce n'est pas compliqué de les tester. Et là, bon, on va voir jusqu'où il va. Et là, il y a une nouvelle version de MXNet qui va sortir, il y a de nouveaux optimiseurs qui ont été implémentés. Vous les testez, vous gagnez 0,3% d'accuratie, mais c'est gratuit. Enfin, vous voyez ? Donc, il faut les voir comme des boîtes noires, ces trucs-là. Si vous voulez comprendre le fonctionnement mathématique de ces optimiseurs, ça fait un peu mal à la tête. Ce n'est pas inabordable, honnêtement. Mais bon, ça fait un peu mal à la tête. Ou alors, vous pouvez vous dire, ok, je lis l'article, je veux voir dans quel cas il marche bien, dans quel cas qui s'en est servi avec de mon résultat. Est-ce que ça ressemble au problème que j'essaie de résoudre ? Oui, non. Puis voilà, 97, 11, c'est à peu près pareil. D'accord ? Alors, si on voulait faire du GPU, on va le voir sur l'exemple d'après, en fait. Je l'ai dans mon code d'après. Et le paramètre WD, pour répondre tout à l'heure, c'est Weight Decay. C'est pour combattre l'overfitting. Donc, en fait, ce qu'on va faire, c'est qu'on va... C'est un mécanisme qui fait de la régularisation. Et donc, quand on va mettre à jour les poids, on va faire des mises à jour plus petites. C'est encore un autre mécanisme. Il y a le learning rate qui fait la mise à jour et il y a le weight decay qui va faire une mise à jour un peu plus petite. Ça permet, quand tu as un réseau qui apprend trop vite, on aurait pu faire l'exemple avec le dataset synthétique. Si tu as un réseau qui apprend trop vite, que tu vois vraiment la précision de training qui augmente trop et que tu veux le freiner un peu, parce que tu as envie de l'entraîner plus longtemps. C'est une façon de ralentir. Non, il ne faut pas qu'il aille trop vite. Si les deux accuracies montent très vite en parallèle, c'est bien. Mais parfois, tu as la training accuracy qui monte super vite et la validation accuracy qui monte pas vide. Donc là, tu dis, non, non, moi, je m'en fous. Je veux rendre son travail d'apprentissage plus dur. Donc, je vais le freiner, d'accord, pour pouvoir l'entraîner plus longtemps en espérant que la validation accuracy suive. Bon. Alors, on pourrait continuer à bricoler les paramètres pendant longtemps. Mais, je reviens à la remarque de notre ami, là, tout à l'heure, qui a dit, non, mais attends, on a pris des images, on les a aplaties, C'est quoi ces conneries ? C'est pas forcément la bonne chose. C'était ça l'idée. Le fait que l'image soit en 2D, c'est une information. Et toi, ce que tu fais, c'est que tu en fais un vecteur. Donc forcément, on perd de l'information en faisant ça. Intuitivement, on se dit, merde, c'est pas logique. Donc on a sûrement perdu de l'information en faisant ça. Le problème étant qu'avec les architectures de réseau que je vous ai montré pour l'instant, tout ce que je vous ai montré, c'est une input layer plate sur laquelle on vient claquer un vecteur. C'est pour ça qu'on a aplati. D'accord ? Donc, est-ce qu'on pourrait travailler avec une architecture de réseau qui saurait prendre en entrée des trucs en plusieurs dimensions ? C'est ça qu'on voudrait, en fait. D'accord ? Une couche d'entrée qui ne soit pas plate, qui soit multidimensionnelle. Ok ? C'est ça, je résume votre pensée, bien sûr. Et bien, la réponse est oui. Et donc, puisque la réponse est oui, on va reparler de M. LeCun. Et M. LeCun, en 1998, ça ne date pas d'hier, il a inventé une nouvelle architecture de réseau, ça a été le principal inventeur on va dire de cette architecture qui s'appelle les réseaux à convolution. Alors, commençons par l'intuition parce que c'est toujours commencé par l'intuition. L'intuition c'est que dans une image il y a des trucs importants et des trucs pas importants. D'accord ? Je sais qu'il est tard, mais il faut s'accrocher. Il y a de l'information intéressante et de l'information pas intéressante. Il y a des pixels qui vont m'aider, des pixels qui ne vont pas m'aider. Et il y en a plein. Et je ne veux pas aplatir, on a vu que ça a ses limites. Et donc, je veux jeter le truc qui ne sert à rien et garder les bons trucs. Donc, il va falloir que j'extraie... et c'est ça les features finalement que j'extrais automatiquement de mon image les éléments importants, donc concrètement que je garde les pixels qui contiennent le plus d'informations et que j'ignore les autres. Et ce faisant, puisque je vais jeter des pixels qui ne servent à rien, la taille de mes images elle va réduire. Sinon ça sert à quoi ce que je suis en train de faire. D'accord ? Donc, au fur et à mesure, je vais réduire la taille de mes images. Je vais faire ça plusieurs fois. Je vais les réduire, les réduire, les réduire, les réduire. Et puis, à un moment, ça sera petit. D'accord ? Et oui. Et ça sera suffisamment petit pour que je puisse l'aplatir et utiliser mon bon vieux réseau Fully Connected. Comme avant. D'accord ? Parce que je n'aurai pas besoin d'avoir un million de features sur ma couche d'entrée. Et je pourrais aplatir parce que je sais que, de toute façon, maintenant, ça ne ressemble plus du tout à l'image de départ. Et si j'ai bien extrait les features, ce qui me reste à la fin, ce n'est pas vraiment des pixels, c'est l'essence de l'image d'origine. C'est l'information la plus importante qu'il y avait dans l'image d'origine. Donc là, je peux aplatir et classifier. C'est ça l'intuition. Donc maintenant, il nous faudrait deux outils mathématiques, un pour extraire l'information et un pour réduire la taille des images. L'outil qui sert à extraire, c'est ce qu'on appelle la convolution. Alors si vous avez joué avec Photoshop ou tous ces trucs là vous l'avez déjà fait sans le savoir d'accord à tous les filtres charpene bleu à oui non mais les génant pardon pardon là je montre mon âge Snapchat ça j'ai ok voilà bon bah oui non Photoshop qui personne ne fait vous de jeu je suis né au siècle dernier faut être patient d'accord donc à chaque fois que vous faites du traitement d'image comme ça que vous voulez détecter les bord, vous voulez faire l'effet relief, etc. En fait, c'est de la convolution. Donc, comment ça marche ? Là, on a une image de départ. Et sur cette image, je vais prendre un petit filtre. D'accord ? Donc, 3 par 3. Et je vais le faire glisser. Donc, je vais le positionner en haut à gauche. Je vais appliquer l'opération sur les 9 pixels qui sont là. Merde. Voilà. Ok. Et puis après, je vais me décaler, je vais faire les 9 d'après, et puis après, je vais me décaler, etc. Et je vais glisser mon filtre, comme ça, sur toute l'image. D'accord ? C'est une petite fenêtre qui se déplace sur le truc. D'accord ? Bon. Et l'opération est donc à la fin, j'obtiens ça, dans ce cas précis. Donc, on voit que ce filtre-là, à quoi il me sert ? Il me sert manifestement à détecter le bord des objets. Ok ? La silhouette, si vous voulez. D'accord ? Ok ? Et donc, je ne sais pas ce que c'est que ce truc-là. A mon avis, c'est sorti d'un film quelconque. Je ne sais pas. Quelqu'un sait ce que c'est que cet animal ? Ça rappelle quelqu'un ? Non, je ne sais rien. Je ne sais pas. Je ne sais pas ce que c'est. A mon avis, c'est tiré d'un film. Bref. Si on savait ce que c'était que cet animal, on le reconnaîtrait aussi très bien dans l'image de droite. D'accord ? Imaginez que ce soit un chien. On va prendre l'exemple. D'accord ? Si c'était un chien à gauche, on verrait un chien à droite. On a perdu les couleurs, on a perdu le fond, mais on verrait très bien ce que c'est. On voit très bien ce que c'est que cet objet qu'on ne connaît pas. Et on a jeté plein d'informations au passage. Le ciel, je ne sais pas si c'est du sable derrière, on a tout jeté. Toute cette information-là, elle a disparu, parce qu'elle ne servait à rien. Ce que je voulais, c'était détecter les bords, donc j'ai gardé les bords. Donc c'est ça, la convolution. Ici, c'est un filtre qui détecte les bords. On pourrait avoir des filtres qui font plein d'autres choses. On pourrait avoir des filtres qui détectent les angles, qui détectent les lignes verticales, les lignes horizontales, etc. Donc voilà ce que c'est que la convolution. Maintenant, une fois qu'on a ça, notre chameau galactique, là, je sais pas ce que c'est. On se dit, bon, on a extrait des trucs. Et ce qu'on voit, c'est qu'il y a plein d'informations inutiles. Il y a encore plein de zones noires. Il y a plein de zones noires, là, par exemple. Enfin, tout ça, ça sert strictement à rien. Ça, ça sert à rien. Et même à la limite, sur cette zone-là, si on gardait juste le bout lumineux et qu'on jetait les pixels noirs, ça se passerait pas mal, quoi. Et donc ça, c'est la deuxième opération qu'on appelle le pooling. Ici, c'est ce qu'on appelle le max pooling. Pareil, on va définir une fenêtre. Ici, c'est une fenêtre de 2 par 2. On commence en haut à gauche, on prend le bloc de 2 par 2 et on garde la plus grande valeur. Ce carré de 4 pixels devient un unique pixel qui vaut 6, qui est le pixel le plus élevé. On le déplace et on recommence. Le carré vert, les 4 pixels verts, ils deviennent un unique pixel qui contient cette valeur 8, etc. Donc mécaniquement, on va réduire la taille de l'image. Et pourquoi on garde le max ? Parce que le max, si c'est des pixels cette histoire, qu'on considère Imaginez que ce soit sur 8 bits. 0, c'est noir. 255, c'est blanc. A votre avis, il faut garder le noir ou garder le blanc là-dedans ? Le blanc. Ce qu'on a détecté ici, c'est les edges, les bords, ils sont blancs. Donc c'est ça qu'on veut garder. Donc on veut garder le pixel le plus lumineux parce que c'est celui dans lequel il y a le plus d'informations. D'accord ? Donc voilà les deux opérations. On extrait les features avec la convolution et ensuite, on jette les trucs qui ne servent à rien avec le pooling. Ok ? Alors maintenant qu'on a compris ça, on a compris le net. Ce réseau s'appelle le net parce que c'est Yann LeCun. Et donc on voit qu'on commence avec une image 32 par 32 parce qu'à l'époque, pour ceux qui étaient en 98, on n'avait pas des gros ordinateurs. 32 par 32, c'est déjà bien. On applique une première convolution, ici avec des filtres 5 par 5, et plusieurs filtres. Parce que, comme je dis tout à l'heure, certains filtres vont détecter certains features. Et on voit les images convolutées, je ne sais pas si on peut dire comme ça, elles ne sont pas tout à fait identiques. Donc on n'a pas extrait les mêmes choses. D'accord ? Donc ici, Ici, on en affiche quatre. En fait, le but de l'apprentissage ici, ça va être d'apprendre les bons filtres. Donc, quand on dit automatiquement le deep learning extrait les features, en fait, ce qu'on fait quand on parle d'image, c'est que la couche de convolution va apprendre quels sont les filtres qui permettent d'extraire la bonne information des images. Est-ce qu'il y a un moyen d'aider l'apprentissage ? Si on a une idée un peu intuitive, les filtres qui vont être prouvés, ce serait un moyen de l'idée ? Alors, tu pourrais initialiser tes filtres avec des valeurs qui te paraissent les bonnes, mais en pratique, si tu entraînes sur 5 millions d'images, tu vois ? À mon avis, il faut se faire une bonne idée. Mais la question est intéressante. On va apprendre le contenu de ces filtres. Concrètement, pendant le training, je pars avec des valeurs aléatoires ici. Et en utilisant les mêmes techniques que tout à l'heure, backpropagation, optimisation, etc., on va découvrir les valeurs de filtres qui permettent d'extraire les features, qui permettent de bien classifier les images. Ça commence à faire mal à la tête. Ça se passe en même temps. Donc, c'est vrai, tu as raison. Donc, on va apprendre les filtres de convolution. Donc, après la convolution, on fait le pooling. Donc là, le pooling, il n'y a rien à apprendre. Il n'y a pas de paramètres sur le pooling. C'est libre. On réduit et c'est tout. D'accord ? Ça ne ressemble plus trop déjà à mon truc initial, mais vous voyez, on a gardé quand même les bords. On voit les formes. Donc là, on voit qu'il y a quand même des features. On recommence, on refait un deuxième coup de convolution. Alors là, ça ne ressemble plus à grand-chose. Un deuxième coup de pooling. On arrive à des toutes petites images de 5 par 5. Et à la fin, j'aplatis et j'utilise le classifiant. Et donc, on entraîne tous les paramètres en même temps. Donc, tu as raison. Les paramètres de ce réseau, c'est tous les filtres de convolution dans les deux couches, plus les poids de la couche connectée. Et on se dit, mais comment ça marche, quoi ? Comment ? Non, mais c'est vrai. Moi, je me pose toujours la question. Ça, la partie connectée, on... Ouais, tu as une question ? Partie connectée, on se dit « ouais, d'accord, entrée, sortie, machin ». Mais que ces filtres-là soient eux-mêmes appris automatiquement et que ça marche, moi, ça continue de m'émerveiller. Il y avait une question. Oui, je voulais savoir si ce sont toujours les mêmes types de filtres qui sont passés sur les images d'entrée. Parce que du coup, sur des images qui sont peu contrastées, on ne va pas pouvoir segmenter. Et du coup, est-ce qu'en conséquence, il faut, en fonction de la donnée d'entrée, évaluer le contraste ? Est-ce que les filtres vont être adaptatifs ? Alors, les filtres vont être appris pendant l'entraînement. Je veux dire que ça va être les mêmes pour tous les échantillons. Donc, c'est vrai que ça peut être un vrai problème. C'est-à-dire que si dans ton dataset, tu as 80% d'images bien, 10% complètement surexposées, 10% complètement sous-exposées, il est probable que tu aies des comportements un peu bizarres. Donc, la normalisation des images, donc là, c'est du pré-traitement, la normalisation des images, la normalisation des couleurs, la balance des blancs, enfin, tous ces trucs-là, c'est important. D'accord ? Bon. Donc ça, ça pourrait être un argument pour avoir un training set homogène. Bon, maintenant, imagine que tu construis un modèle pour une appli mobile que les gens vont utiliser, ils vont prendre en photo un animal et puis ils veulent le reconnaître automatiquement. Dans les échantillons qu'ils vont t'envoyer, il y aura du surexposé, du sous-exposé, du flou, du prix de travers, etc. Donc, si tu as un dataset aux petits oignons. Parfait. Que toutes les images, elles sont magnifiques. Elles ne sont pas surexposées, pas sous-exposées. Parfaitement cadrées. Le chien, le chat, ils sont bien au milieu de l'image. Ils sont de face, ils sourient, tout va bien. Si ça, si ton dataset est trop clean, alors tu vas avoir un entraînement qui va être bien, une validation qui va être bien. Et après, quand les utilisateurs vont t'envoyer les échantillons de la mort, tu auras une validation pourrie. Donc, le conseil, c'est d'avoir un dataset qui ressemble, en tout cas, qui inclut des échantillons qui ressemblent fortement à ce que tes gens, tes utilisateurs vont t'envoyer. Donc, il faut qu'il y ait du moche. Il faut qu'il y ait du moche, il faut qu'il y ait du pourri. Ça s'appelle adversarial training. D'accord ? Donc, il faut qu'il y ait des échantillons vraiment merdiques. Il faut même qu'il y ait à la limite presque des échantillons qui à l'œil nu ne sont pas classables. Tu vois ? Et tu dis si c'est un chat ou si c'est un chien. Tu dirais ouais peut-être. Parce que ça, ça va obliger ton process d'entraînement à travailler plus dur. Si ton dataset est trop facile et c'est le problème de MNIST, s'il est trop facile, bon bah ouais tout le monde y arrive et puis à la fin quand tu mets des vrais échantillons ça donne pas grand chose. Ok ? Bon. Alors, on va quand même... Donc, ok, ça va sur ça ? Vous avez compris ça ? Ouais ? Allez, on va exécuter ce truc-là. On va finir avec ça. Alors, ouais, j'avais dit que je vous montrais deux, trois exemples. Alors, on peut faire plein d'âneries avec ces réseaux à convolution. On peut faire ça, de la détection d'objets, de la segmentation d'objets. Tout ça, c'est des projets sur GitHub avec MXNet. De la détection de texte, de la détection de visage, de la détection de pose. C'est en temps réel, ça sera un flux vidéo. Après, il y a encore d'autres architectures. Mais on peut faire plein plein d'âneries. Je vais vous donner tout, vous pourrez tout regarder tranquillement. Alors, on reste dans MNIST et on ouvre. Allez. Donc, je crois que c'est train... Non, c'est pas 3. Comment il s'appelle ? Non, c'est train modèle V3. Voilà. Hop. Alors, toujours la même histoire. On charge MNIST. On construit le réseau en convolution. Donc là, c'est exactement le net. D'accord ? Donc on voit dans la première couche de convolution, on a 20 filtres. Donc on va apprendre à détecter 20 features. D'accord ? Lesquels ? On laisse faire le réseau. C'est assez expérimental. Tu lis l'article de recherche de LeNet. J'ai peut-être changé les valeurs. C'était peut-être 32. Mais il a jugé que 32 filtres, c'était bien. Au départ, ils sont randoms et le processus d'apprentissage va les modifier. Les filtres, c'est un filtre 5 par 5. J'ai 25 paramètres par filtre fois 20. J'ai 500 paramètres à apprendre dans cette couche-là. Ensuite, je fais du pooling. Ensuite, je recommence. Ensuite, j'ai aplati. Et puis, je classifie avec une couche à 500 neurones. D'accord ? Allez voir l'architecture canonique de LeNet. Prenez l'article et vous verrez, ça a cette tête-là. Le seul truc, c'est qu'il n'utilise pas ReLU. Lui, il utilisait Tanh au départ, parce que ReLU n'avait pas été inventé. Donc, j'ai juste modifié ça. Sinon, si on a un modèle qui sait reconnaître les chats, si on veut faire reconnaître les lapins, on peut... Garde la question pendant deux minutes. Pour répondre sur ta question de si on voulait faire du GPU, comment on ferait ? On ferait comme ça. Donc là, par défaut, on entraîne sur CPU. Si j'avais un GPU, il faudrait que je lui passe ce contexte là, MXGPU0 pour entraîner sur GPU. Et si j'avais 3 GPU sur la machine, je ferais ça. Parce que ça, c'est un des points sympas dans MXNet. Le reste, c'est identique. On bind, on initialise, on utilise Adam ici et on entraîne. Et vous voyez, glorieusement... 30 lignes de code. Et là, on est déjà sur des réseaux un peu plus sympas. Alors, c'est parti. Alors, essayez de le lancer sur votre machine, parce que ce sera intéressant de voir combien de temps ça prend. J'ai combien d'époques ? J'espère que je n'ai pas trop d'époques. Combien j'ai mis d'époques ? 50. On va mettre 25. Allez, c'est reparti. Oui, c'est intéressant de voir. Combien vous faites d'échantillons par seconde ? Sur ta machine locale ? 1 500. Donc là, je suis sur une instance qui n'a pas de GPU, mais qui a beaucoup de cœur. Et donc voilà, elle a du cœur, donc elle travaille le plus fort. Mais gardez à l'esprit, là, on travaille sur des toutes petites images. M-list, c'est tout petit. Donc quand on travaille sur des images en couleur, des images plus grandes, etc., ça devient impossible à faire sur CPU. C'est pour ça qu'il faut des GPU. D'accord ? Et l'accélération que vous aurez en GPU sur l'entraînement, c'est x100, ça peut être vite x100. Alors ? Non, Nvidia seulement. De manière générale, oui. Toutes les librairies, MXNet, TensorFlow, etc., c'est Nvidia. T'as qu'à regarder cours de bourse de Nvidia, tu vois. Ça leur réussit bien. Oui, et Bitcoin aussi. Oui. Mais je pense qu'on leur a acheté plus que les bitcoines. Je ne serais pas surpris. Je n'ai pas les chiffres. Alors, on est arrivé à combien là ? 80... On est arrivé à plus de 97. Bon, si on bricolait encore... Moi, j'ai un exemple qui arrive à 99 de... On peut dépasser largement 99. Qu'est-ce qu'il y a dans ton exemple ? Qu'est-ce que j'ai changé ? Peut-être le nombre de filtres. Je ne sais plus. Il faudrait que je regarde mes sources. Oui, c'est à peu près la même architecture, mais j'ai un peu de bricolage. D'accord ? Donc, voilà. On arrive, vous voyez, on arrive à faire beaucoup mieux. On est à 97,6. Une fois de plus, on pourrait dépasser 99 en continuant à bricoler. Là où, avec le réseau d'avant, on aurait du mal à atteindre 98. D'accord ? Alors... Juste pour finir, ce que je vous conseille de faire, c'est évidemment de continuer à bricoler sur la base de ce col là. Refaites les tests qu'on a fait tout à l'heure, rajoutez des couches, changez le nombre de filtres, changez la taille des filtres, faites-vous plaisir, etc. Et puis si vous n'y arrivez pas, vous pouvez aller pomper dans mes exemples et puis vous aurez le réseau qui fait 99%. Si vous avez marre de MNIST, il y en a un autre qui est rigolo qui s'appelle Fashion MNIST. Alors ça, je ne l'ai pas choisi pour vous mesdemoiselles et mesdames. Il est fait par Zalando que vous connaissez forcément, sans faire du sexisme. Pour les messieurs qui ne connaîtraient pas Zalando, demandez à votre copine, elle saura. Et donc c'est un dataset qui est parfaitement compatible, c'est-à-dire c'est des images 28 par 28, monochromes, mais il y a toujours 10 classes, mais au lieu d'avoir des 0 et des 1 et des 2 et des 9, il y a des t-shirts, des godasses, des sacs, etc. Et les noms des fichiers sont même identiques. Donc vous pouvez télécharger Fashion MNIST et l'utiliser exactement avec le même code que celui qu'on a utilisé, même littérateur de MXNet, comme c'est les mêmes noms de fichier, il va le charger pareil. Vous téléchargez celui-là, vous remplacez les fichiers par ceux-là, et vous réexécutez. Et vous allez voir que là, vous allez en baver. Là, vous allez avoir du mal à dépasser 80, 85, parce que c'est beaucoup plus difficile. Le pire bougé, c'est de comment faire les classifier. C'est toujours pareil. C'est beaucoup plus difficile. Donc, Fashion MNIST, c'est un bon exemple. Alors, quelques ressources pour terminer. Si vous êtes curieux des services qu'il y a sur AWS pour faire du machine learning, parce que là, finalement, le seul truc que j'ai utilisé, j'ai utilisé une instance pour faire tourner mes trucs plus vite, mais bon, vous voyez, ça marche sur votre machine, on n'a pas du tout utilisé AWS aujourd'hui. Si vous êtes curieux de quels sont les services qui existent, il y a des services de haut niveau pour faire de la reconnaissance d'images, de la synthèse vocale, il y a plein de choses. Allez voir là, il y a plein de choses à tester. Il y a le blog Machine Learning d'AWS sur lequel il y a pas mal d'articles techniques. J'ai réussi à en publier quelques-uns aussi. Le site MXNet, vous l'avez vu. Le GitHub d'MXNet. Où il y a les sources et alors Gluon dont on n'a pas parlé on n'a plus le temps mais c'est pas grave allez voir Gluon c'est une autre API donc c'est un peu différent de l'API symbolique et en particulier je vous recommande fortement la doc de Gluon c'est-à-dire que mon collègue qui a écrit ça en fait il a écrit un espèce de bouquin sur le deep learning sur le machine learning et le deep learning et donc il vous explique les algos en général. C'est quoi la convolution, comment ça marche, c'est quoi la classification, comment ça marche, etc. Après, il vous montre comment l'implémenter avec Gluon, puis il vous explique pourquoi c'est bien Gluon. Regardez les deux, et puis vous pourrez toujours me poser des questions ensuite. Ça, c'est mon blog. Mon blog sur Medium, où je poste pas mal de choses. MXNet, Machine Learning, Deep learning et puis des services AWS, etc. Mais très orienté machine learning, deep learning. Et si vous voulez, là on est allé assez vite paradoxalement ce soir parce qu'on a couvert plusieurs présentations en une. Si vous voulez tout revoir à tête reposée, en fait j'ai plein de sessions qui ont été enregistrées sur YouTube et en particulier vous verrez j'ai une playlist qui s'appelle Dev Days dans laquelle il y a trois sessions, IA et Deep Learning, qui couvrent en gros ce qu'on a vu aujourd'hui, mais on va un peu plus lentement, on rentre un peu plus dans les détails. Donc vous pourrez, si vous voulez revoir, c'est vrai qu'on aura la vidéo ici, mais si vous voulez revoir d'autres versions avec d'autres exemples, etc., et un peu plus de détails, vous pouvez aller voir aussi sur YouTube. Ok ? Alors, ce que je ferais, c'est... Il y en a un en particulier que je vous conseille, qui est bien adapté au public ce soir, à mon avis. Donc ça, c'est un de mes articles sur Medium, qui est en deux parties. C'est 10 steps to deep learning. Donc comment j'ai fait, en fait, comment moi j'ai fait, modestement, pour m'y mettre, quelles sont les ressources que j'ai utilisées, quelles sont les étapes que j'ai utilisées, et dans quel ordre, surtout. Parce que l'ordre est important, parce qu'il y a beaucoup de choses à apprendre. C'est comme toujours, si on ne suit pas un peu de méthode, on se disperse. C'est-à-dire qu'aller creuser les fonctions d'optimisation là, maintenant, ça ne sert à rien. Dans six mois, quand vous aurez bien progressé, oui, c'est intéressant. Mais d'abord, il faut prendre une librairie, que ce soit MXNet ou Keras ou une autre, puis commencer à bricoler. Après, vous allez aussi loin que vous avez envie. Si vous voulez refaire des maths et de l'algèbre à la fin il y a moyen. Donc je vous conseille ça, il y a plein de gens qui m'ont dit que ça les avait aidés à démarrer. Donc voilà et donc ce que je ferai peut-être pas ce soir mais demain c'est que je posterai mes slides sur Twitter donc vous aurez ces slides là et puis la vidéo on l'aura très prochainement. Ok ? Voilà et de manière générale si vous avez des questions par la suite, même dans un mois, c'est pas grave. Vous pouvez bien sûr vous connecter sur LinkedIn, j'essaie de répondre à mes messages mais ça s'enfile un peu. Il semblerait empiriquement que Twitter soit la meilleure façon de me joindre. Donc n'hésitez pas à me poser des questions. Si vous implémentez des trucs sympas et que vous voulez que je les partage, c'est avec plaisir. Si vous bossez sur des projets et que vous avez envie que je les partage, vous me pinguez sur Twitter je serais ravi de repartager vos projets et de vous faire un peu de pub. Voilà, merci beaucoup. Un mille merci à Télécom Paris, Valet, Allianz, tout le monde, le Conseil Général, on les aime tous, ils rendent les événements possibles. Et bien sûr, merci à vous d'être venus. J'étais vraiment très content de faire enfin un événement Deep Learning en France. J'étais très content de voir plein de jeunes filles, de dames. C'est super. Vous ne lâchez pas, d'accord ? Vous continuez parce qu'on a besoin de vous dans les équipes et on a besoin de gens qui s'y mettent. On a besoin de gens en France qui maîtrisent ces technos-là pour nous faire avancer collectivement. Dieu sait qu'on en a besoin. Merci encore mille fois de m'avoir invité. Et puis, merci à toutes et à tous. Merci beaucoup.

Tags

Deep LearningMachine LearningNeural NetworksFeature EngineeringSupervised Learning