{"id":10707,"date":"2016-06-14T17:19:33","date_gmt":"2016-06-14T15:19:33","guid":{"rendered":"https:\/\/www.etalab.gouv.fr\/?p=10707"},"modified":"2019-06-18T10:34:22","modified_gmt":"2019-06-18T08:34:22","slug":"un-reseau-de-neurones-pour-opensolarmap-23","status":"publish","type":"post","link":"https:\/\/preprod.etalab.gouv.fr\/un-reseau-de-neurones-pour-opensolarmap-23","title":{"rendered":"Un r\u00e9seau de neurones pour OpenSolarMap (2\/3)"},"content":{"rendered":"\n
Apr\u00e8s avoir essay\u00e9 un algorithme tr\u00e8s simple, puis un ou plusieurs\nalgorithmes classiques, il est parfois (mais pas toujours) n\u00e9cessaire\nde mettre en place un algorithme sp\u00e9cialis\u00e9 dans le probl\u00e8me \u00e0\nr\u00e9soudre. Les r\u00e9seaux de neurones sont une cat\u00e9gorie\u00e9d\u2019algorithmes qui\nont fait leurs preuves de mani\u00e8re spectaculaire dans le domaine du\ntraitement d\u2019images.<\/strong><\/p>\n\n\n\n Au del\u00e0 de l\u2019effet de mode dont ils b\u00e9n\u00e9ficient, les r\u00e9seaux de\nneurones constituent bel et bien une avanc\u00e9e majeure en traitement\nd\u2019images et dans bien d\u2019autres domaines. Ce champ de recherche\nrepr\u00e9sente une proportion importante des articles parues dans les\nrevues de r\u00e9f\u00e9rence en machine learning : NIPS<\/a> et ICML<\/a>. Le domaine\njouit \u00e9galement d\u2019une pleine reconnaissance acad\u00e9mique comme\nl\u2019illustre la chaire annuelle de l\u2019INRIA au Coll\u00e8ge de France en \u00ab Informatique\net sciences num\u00e9riques \u00bb<\/a> consacr\u00e9e par Yann LeCun aux r\u00e9seaux\nneuronaux. Cette chaire, cours et s\u00e9minaires inclus, constitue\nd\u2019ailleurs une excellente introduction aux techniques des r\u00e9seaux\nneuronaux, parmi les multiples ressources disponibles librement sur\nInternet.<\/p>\n\n\n\n Les r\u00e9seaux de neurones sont \u00e9tudi\u00e9s depuis les ann\u00e9es 50 avec\nl\u2019invention du perceptron<\/a>. Mais\nceux qui bouleversent la communaut\u00e9 du machine learning depuis 2011 se\nd\u00e9nomment plus pr\u00e9cis\u00e9ment \u00ab r\u00e9seaux de neurones profonds \u00e0\nconvolution \u00bb (\u00ab deep convolutional neural networks \u00bb, abr\u00e9g\u00e9 parfois\nen CNN pour Convolutional Neural Networks ou encore ConvNets) :neurone<\/strong> : M\u00eame s’il y a une lointaine analogie\nentre les neurones biologiques et les neurones informatiques, ils\nconstituent deux domaines d’\u00e9tude \u00e0 ne pas confondre. Un neurone\ninformatique prend en entr\u00e9e plusieurs valeurs num\u00e9riques et\napplique une fonction \u00e0 ces entr\u00e9es. Le r\u00e9sultat num\u00e9rique de cette\nfonction constitue l’unique sortie du neurone. Le neurone Rectified\nLinear Unit<\/a>\u00e9(ReLU)\u00e9est majoritairement employ\u00e9 : chaque entr\u00e9e\nest\u00e9multipli\u00e9e par un coefficient (ou poids) puis cette somme est\nrenvoy\u00e9e si elle est positive, z\u00e9ro est renvoy\u00e9 sinon. \n<\/p>\n\n\n\n \nFigure 1 : neurone de type ReLU \u00e0 3 entr\u00e9es.\n\n\n\n<\/li> \n\n r\u00e9seau<\/strong> : Les\nneurones sont dispos\u00e9s en un r\u00e9seau qui prend la forme de plusieurs\ncouches successives. La premi\u00e8re couche prend en entr\u00e9e les valeurs de\nl’image (ou d’un autre type d’entr\u00e9e comme du texte ou du son). Les\nsorties de la premi\u00e8re couche constituent les entr\u00e9es de la deuxi\u00e8me\ncouche, etc. Les sorties de la derni\u00e8re couche sont les sorties du\nr\u00e9seau, mais les valeurs num\u00e9riques qui transitent entre les couches\nsont cach\u00e9es \u00e0 l’utilisateur. De l\u00e0 vient en partie leur r\u00e9putation\nd’\u00eatre des \u00ab bo\u00eetes noires \u00bb. \n\n<\/a><\/p>\n\n\n\n \nFigure 2 : r\u00e9seau de neurones \u00e0 3 couches\n\n<\/li> \n\n convolution\n<\/strong>(paragraphe technique \u00e0 lire en seconde lecture)<\/em> :\nLes r\u00e9seaux\n\u00e0 convolution<\/a> op\u00e8rent g\u00e9n\u00e9ralement sur des images. La premi\u00e8re\ncouche de neurones est de la m\u00eame forme que l’image en entr\u00e9e. La\nsortie de cette premi\u00e8re couche, comme toutes les sorties\ninterm\u00e9diaires, forment des images. Au sein d’une couche de neurones,\nles param\u00e8tres de chaque neurones sont choisis de telle sorte que la\ncouche applique un filtrage lin\u00e9aire puis une rectification. Un\nfiltrage lin\u00e9aire est la convolution entre une image d’entr\u00e9e et un\nfiltre lin\u00e9aire. Un filtre lin\u00e9aire, dans le cas du traitement\nd’images, se repr\u00e9sente come une petite image, typiquement de taille 3\npar 3 pixels ou 5 par 5. Les r\u00e9seaux \u00e0 convolution ont l’avantage de\ntirer partie de la structure g\u00e9om\u00e9trique de l’image d’entr\u00e9e. De plus,\nchaque couche de neurones est param\u00e9tr\u00e9e par un filtre lin\u00e9aire qui\nest beaucoup plus simple \u00e0 apprendre que dans le cas g\u00e9n\u00e9ral. Par\nexemple, pour une image d’entr\u00e9e de 224 par 224 pixel en noir et\nblanc, une couche de neurones de la m\u00eame taille est compos\u00e9 de 224×224\nneurones et si chaque neurone est connect\u00e9 \u00e0 chaque pixel d’entr\u00e9e, il\ny a 222×224 param\u00e8tres par neurones. Cela fait un total de\n224x224x224x224 = 2.517.630.976 param\u00e8tres pour cette seule couche. Il\nfaudrait donc des milliards d’images pour faire apprendre correctement\nun tel r\u00e9seau. En comparaison, param\u00e9trer la couche de neurones par un\nfiltre de 3×3 pixels ne requiert d’apprendre que 9 valeurs\nnum\u00e9riques. Concr\u00e8tement, cela revient \u00e0 mettre la majorit\u00e9 des poids\ndes neurones \u00e0 z\u00e9ro, et \u00e0 partager tous les poids restants entre les\nneurones de la couche. Dans un r\u00e9seau \u00e0 convolution, des \u00e9tapes de\nr\u00e9duction de la taille de l’image s’intercalent entre les couches de\nneurones. Pour le r\u00e9seau LeNet 5, deux \u00e9tapes de r\u00e9duction, appel\u00e9es\n\u00ab subsampling \u00bb alternent avec les deux \u00e9tapes de convolution. Les\nderni\u00e8res couchent perdent la structure g\u00e9om\u00e9trique en d\u00e9pliant\nl’image sur une dimension, mais le nombre de param\u00e8tres \u00e0 apprendre\nest raisonnable du fait de la petite taille des images. Enfin, il\nfaut pr\u00e9ciser que, de la m\u00eame mani\u00e8re qu’une image d’entr\u00e9e peut\ncontenir plusieurs canaux de couleur (rouge, vert et bleu par\nexemple), les images interm\u00e9diaires se composent de plusieurs\ncanaux. Dans le cas de LeNet 5, les images interm\u00e9diaires se composent\nde 6 puis de 16 canaux. Au fil de l’apprentissage du r\u00e9seau, chaque\ncanal va se sp\u00e9cialiser dans la reconnaissance d’une forme g\u00e9om\u00e9trique\nparticuli\u00e8re.\n\n profond<\/strong> : Les\nr\u00e9seaux de neurones traditionnels, \u00e9tudi\u00e9s dans les ann\u00e9es 70,\nutilisaient entre 1 et 3 couches de neurones. On parle de r\u00e9seaux\nprofonds pour parler des architectures avec un nombre \u00e9lev\u00e9s de\ncouches qui peut d\u00e9passer la centaine ! Les couches proches de l’image\nd’entr\u00e9e se sp\u00e9cialisent dans la d\u00e9tection de features g\u00e9om\u00e9triques\ntr\u00e8s simples (des coins, des lignes) alors les couches finales\nd\u00e9tectent des features abstraites qui d\u00e9pendent de l’usage du r\u00e9seau\n(des lettres pour un r\u00e9seau de reconnaissance d’\u00e9criture, des objets,\ndes esp\u00e8ces d’animaux). <\/ul>\n\n\n<\/p>\n\n\n\n \nFgure 3 : r\u00e9seau de neurones LeNet 5\n<\/p>\n\n\n\n Comme tous les algorithmes dits\nsupervis\u00e9s, les r\u00e9seaux de neurones sont \u00ab appris \u00bb sur un \u00e9chantillon\nde donn\u00e9es d’exemples labellis\u00e9s. La m\u00e9thode d’apprentissage utilis\u00e9e,\nnomm\u00e9e backpropagation<\/a>,\nva modifier petit \u00e0 petit les param\u00e8tres de chaque couche pour\naugmenter la qualit\u00e9 des pr\u00e9dictions jusqu’\u00e0 atteindre une situation\n(localement) optimale. Une fois la phase d’apprentissage termin\u00e9e, le\nr\u00e9seau\u00e9est capable de faire des pr\u00e9dictions sur de nouvelles images.\n<\/p>\n\n\n\n Les r\u00e9seaux de neurones pr\u00e9sentent des\nperformances spectaculaires et inattendues. Une des enjeux th\u00e9orique\nactuel est de comprendre ces performances et de les confirmer par des\ngaranties th\u00e9oriques. C’est par exemple l’objet des recherches\nactuelle de St\u00e9phane Mallat qui travaille sur la m\u00e9thode de\nscattering<\/a>, apparent\u00e9e aux r\u00e9seaux de neurones. <\/p>\n\n\n\n \nLes librairies de deep-learning ne manquent pas<\/a>. La\ndifficult\u00e9 est de choisir l’outil qui r\u00e9pond le mieux aux besoins du\nprojet. Pour r\u00e9pondre aux besoins d’OpenSolarMap, l’outil id\u00e9al\ndevra :\n<\/p>\n\n\n\n Parmi d’autres solutions qui auraient\nsatisfait ces crit\u00e8res, j’ai choisi Keras<\/a>\u00e9sur les recommandations d’un\nconfr\u00e8re data-scientist. Je n’ai pas eu \u00e0 regretter ce choix, mais si\nKeras n’avait pas convenu, j’aurais sans doute test\u00e9 les outils Caffe<\/a>, Lasagne<\/a>\u00e9ou le tr\u00e8s\npopulaire Torch<\/a>\u00e9m\u00eame s’il est \u00e9crit en\nlua<\/a>. <\/p>\n\n\n\n Concevoir un r\u00e9seau de neurones est\nune t\u00e8che compliqu\u00e9e qui n\u00e9cessite une exp\u00e9rience approfondie. En\nrevanche, utiliser une r\u00e9seau de neurones d\u00e9j\u00e0 pr\u00eat est beaucoup plus\nsimple et rapide \u00e0 mettre en \u00e9uvre. Le \u00ab transfer learning \u00bb une\ntechnique standard expliqu\u00e9e dans ces\u00e9notes<\/a>\u00e9du cours de vision\nCS231n de Standford<\/a>. <\/p>\n\n\n\n Il y a d\u00e9j\u00e0 de nombreux r\u00e9seaux\npr\u00e9-entra\u00een\u00e9s disponibles. Le projet Model-Zoo<\/a> de\nl’universit\u00e9 de Berkeley est une liste de ces r\u00e9seaux qui est d’un\ngrand usage pour faire ce choix. Les r\u00e9seaux list\u00e9s par Model-Zoo sont\npropos\u00e9s en Caffe, mais la plupart des mod\u00e8les sont directement\nutilisables avec d’autres librairies. J’ai choisi arbitrairement le\nc\u00e9l\u00e8bre r\u00e9seau \u00e0 16\ncouches VGG16<\/a>\u00e9du Visual\nGeometry Group<\/a> de l’universit\u00e9 d’Oxford utilis\u00e9 lors de la\ncompetition\u00e9ILSVRC de\n2014<\/a> (ImageNet 2014). Il s’agit d’un r\u00e9seau g\u00e9n\u00e9raliste. D’autres\nr\u00e9seaux auraient pu convenir aussi bien et peut-\u00eatre m\u00eame mieux. Ce\nr\u00e9seau est directement utilisable avec Keras en utilisant le GitHub\nGist suivant : https:\/\/gist.github.com\/baraldilorenzo\/07d7802847aaad0a35d3<\/a>\n<\/p>\n\n\n\n La premi\u00e8re ligne d\u00e9finit un mod\u00e8le\ns\u00e9quentiel. D’autre architectures plus compliqu\u00e9es existent, mais le\nr\u00e9seau VGG16 est un empilement de couches dont chaque couche prend en\nentr\u00e9e le r\u00e9sultat de la couche pr\u00e9c\u00e9dente. Les lignes <\/p>\n\n\n\n d\u00e9finissent des couches de neurones\nReLU avec une taille de filtre de 3 par 3 pixels et un nombre de\ncanaux de 34, 128, 256 ou 512. Les lignes <\/p>\n\n\n\n d\u00e9finissent les \u00e9tapes de r\u00e9duction\nde la taille de l’image le long du r\u00e9seau. La m\u00e9thode Max Pooling est\nutilis\u00e9e et chaque \u00e9tape divise par 2 la taille. Les lignes <\/p>\n\n\n\n sont un d\u00e9tail d’impl\u00e9mentation. Pour\ncompenser la taille du filtre de 3 pixels, une bordure de 1 pixel est\najout\u00e9 \u00e0 l’image d’entr\u00e9e avant chaque convolution pour que la sortie\nde la convolution soit de m\u00eame taille. Enfin, le dernier bloc d\u00e9finit\n3 couches de neurones fully-connected. <\/p>\n\n\n\n La taille d’entr\u00e9e sp\u00e9cifi\u00e9e est 224\npar 224 pixels (par 3 canaux). Chaque couple Zero Padding \/\nConvolution ne modifie pas la taille (\u00e9ventuellement le nombre de\ncanaux) et chaque Max Pooling divise la taille par 2 (sans modifier le\nnombre de canaux). On peut en d\u00e9duire que l’op\u00e9ration Flatten prend en\nentr\u00e9e une image de 7 par 7 pixels avec 512 canaux et renvoie un\nvecteur de taille 25.088. Les deux couches suivantes comptent 4096\nneurones puis la derni\u00e8re en compte 1000, qui correspondent aux 1000\nclasses \u00e0 pr\u00e9dire pour la comp\u00e9tition ImageNet<\/a>. <\/p>\n\n\n\n Le r\u00e9seau a \u00e9t\u00e9 entra\u00een\u00e9 pour classer\nune image parmi 1000 classes de la comp\u00e9tition ImageNet et non pas\npour distinguer l’orientation des toitures. Mais une propri\u00e9t\u00e9 des\nr\u00e9seaux de neurones est qu’il sont \u00e9galement tr\u00e8s efficaces pour\ns’adapter \u00e0 des probl\u00e8mes voisins. Seules les derni\u00e8res couches sont\nsp\u00e9cialis\u00e9es dans la t\u00e8che \u00e0 accomplir tandis que les premi\u00e8res\ncouches r\u00e9solvent des probl\u00e8mes de d\u00e9tection tr\u00e8s g\u00e9n\u00e9raux. Le\ntransfert learning utilise cet avantage pour utiliser tr\u00e8s rapidement\nun r\u00e9seau pour une nouvelle t\u00e8che. La m\u00e9thode la plus simple, sans\nfine-tuning, a \u00e9t\u00e9 utilis\u00e9e pour OpenSolarMap. <\/p>\n\n\n\n Le r\u00e9seau VGG16 prend en entr\u00e9e des\nimages de taille 224 par 224, or les images de toits ont une taille\nmoyenne de 95 par 93 pixels (voir figure 4). On a le choix d’agrandir\nles images avant d’appliquer le r\u00e9seau, ou de changer la taille\nd’entr\u00e9e du r\u00e9seau vers une valeur plus proche de la taille\nmoyenne. La premi\u00e8re approche fournirait des images majoritairement\nfloues au r\u00e9seau, c’est pourquoi j’ai choisi la seconde approche. La\ntaille de 96 par 96 est id\u00e9ale, car apr\u00e8s les 5 \u00e9tapes de r\u00e9duction,\nla taille de l’image interm\u00e9diaire tombe \u00ab juste \u00bb sur 3 par 3 pixels.\n<\/p>\n\n\n\n \nLa ligne 2 du gist est remplac\u00e9e par :\n<\/p>\n\n\n\n \nFigure 4 : r\u00e9partition des images de toits par taille (x, y)\n<\/p>\n\n\n\n Les derni\u00e8res couches sont\nsp\u00e9cifiques au concours ImagetNet et ne sont pas d’utilit\u00e9 ici. Ils\nsont donc retir\u00e9s et le dernier bloc est remplac\u00e9 par <\/p>\n\n\n\n Le choix d’enlever 3 couches est\narbitraire. La seule contrainte \u00e0 respecter est de conserver un nombre\nde features raisonnables, inf\u00e9rieur \u00e0 10.000. Avec ce choix, on compte\nalors 3 x 3 x 512 = 4608 featutres en sortie du r\u00e9seau. Ce n’est pas\nune pr\u00e9diction de la classe, mais ces features peuvent \u00eatre utilis\u00e9es\npar un classifieur comme une r\u00e9gression lin\u00e9aire. <\/p>\n\n\n\n Les 4608 features calcul\u00e9es par le\nr\u00e9seau alimentent un mod\u00e8le de r\u00e9gression logistique, r\u00e9gularis\u00e9 cette\nfois. Le param\u00e8tre de r\u00e9gularisation varie et le taux d’erreur (figure\n5) affiche une classique courbe en U du dilemme\nbiais-variance<\/a>. C’est la valeur qui donne le meilleur r\u00e9sultat qui\nest retenue. La force de la r\u00e9gularisation est un hyperparam\u00e8tre, donc\nil est indispensable de calculer la performance sur un \u00e9chantillon de\nvalidation. Le taux d’erreur sur cet \u00e9chantillon est de 7%. <\/p>\n\n\n\n \nFigure 5 : taux d’erreur en fonction de la force de la r\u00e9gularisation\n<\/p>\n\n\n\n Ce taux d’erreur est bien moins bon\nque ce qu’il serait possible d’obtenir avec des m\u00e9thodes\n\u00ab state-of-the-art \u00bb. Tout d’abord, il faudrait tester d’autres\nr\u00e9seaux que le VGG16, essayer diff\u00e9rents choix de couches \u00e0 enlever\nvoire faire du fine-tuning… Ici, il s’agissait surtout de d\u00e9montrer\nqu’il est possible d’arriver tr\u00e8s rapidement \u00e0 des r\u00e9sultats\nsatisfaisants, en utilisant un r\u00e9seau, une librairie et du code d\u00e9j\u00e0\npr\u00eats \u00e0 l’emploi.<\/p>\n","protected":false},"excerpt":{"rendered":" Apr\u00e8s avoir essay\u00e9 un algorithme tr\u00e8s simple, puis un ou plusieurs algorithmes classiques, il est parfois (mais pas toujours) n\u00e9cessaire de mettre en place un algorithme sp\u00e9cialis\u00e9 dans le probl\u00e8me \u00e0 r\u00e9soudre. Les r\u00e9seaux de neurones sont une cat\u00e9gorie\u00e9d\u2019algorithmes qui ont fait leurs preuves de mani\u00e8re spectaculaire dans le domaine du traitement d\u2019images. Introduction Au …<\/p>\nIntroduction<\/h1>\n\n\n\n
<\/a><\/figure>\n\n\n\n
<\/a><\/figure>\n\n\n\n
\nLibrairie, r\u00e9seau et code utilis\u00e9s\n<\/h1>\n\n\n\n
\nLibrairie de deep-learning\n<\/h2>\n\n\n\n
\nR\u00e9seau de neurones VGG16\n<\/h2>\n\n\n\n
model = Sequential()\nmodel.add(ZeroPadding2D((1,1),input_shape=(3,224,224)))\nmodel.add(Convolution2D(64, 3, 3, activation='relu'))\nmodel.add(ZeroPadding2D((1,1)))\nmodel.add(Convolution2D(64, 3, 3, activation='relu'))\nmodel.add(MaxPooling2D((2,2), strides=(2,2)))\n\nmodel.add(ZeroPadding2D((1,1)))\nmodel.add(Convolution2D(128, 3, 3, activation='relu'))\nmodel.add(ZeroPadding2D((1,1)))\nmodel.add(Convolution2D(128, 3, 3, activation='relu'))\nmodel.add(MaxPooling2D((2,2), strides=(2,2)))\n\nmodel.add(ZeroPadding2D((1,1)))\nmodel.add(Convolution2D(256, 3, 3, activation='relu'))\nmodel.add(ZeroPadding2D((1,1)))\nmodel.add(Convolution2D(256, 3, 3, activation='relu'))\nmodel.add(ZeroPadding2D((1,1)))\nmodel.add(Convolution2D(256, 3, 3, activation='relu'))\nmodel.add(MaxPooling2D((2,2), strides=(2,2)))\n\nmodel.add(ZeroPadding2D((1,1)))\nmodel.add(Convolution2D(512, 3, 3, activation='relu'))\nmodel.add(ZeroPadding2D((1,1)))\nmodel.add(Convolution2D(512, 3, 3, activation='relu'))\nmodel.add(ZeroPadding2D((1,1)))\nmodel.add(Convolution2D(512, 3, 3, activation='relu'))\nmodel.add(MaxPooling2D((2,2), strides=(2,2)))\n\nmodel.add(ZeroPadding2D((1,1)))\nmodel.add(Convolution2D(512, 3, 3, activation='relu'))\nmodel.add(ZeroPadding2D((1,1)))\nmodel.add(Convolution2D(512, 3, 3, activation='relu'))\nmodel.add(ZeroPadding2D((1,1)))\nmodel.add(Convolution2D(512, 3, 3, activation='relu'))\nmodel.add(MaxPooling2D((2,2), strides=(2,2)))\n\nmodel.add(Flatten())\nmodel.add(Dense(4096, activation='relu'))\nmodel.add(Dropout(0.5))\nmodel.add(Dense(4096, activation='relu'))\nmodel.add(Dropout(0.5))\nmodel.add(Dense(1000, activation='softmax'))\n<\/pre>\n\n\n\n
model.add(Convolution2D(xxx, 3, 3, activation='relu'))\n<\/pre>\n\n\n\n
model.add(MaxPooling2D((2,2), strides=(2,2)))\n<\/pre>\n\n\n\n
model.add(ZeroPadding2D((1,1)))\n<\/pre>\n\n\n\n
\nModification du r\u00e9seau\n<\/h1>\n\n\n\n
\nChangement de la taille d’entr\u00e9e\n<\/h2>\n\n\n\n
model.add(ZeroPadding2D((1,1),input_shape=(3,96,96)))\n<\/pre>\n\n\n\n
<\/a><\/figure>\n\n\n\n
\nTransfer learning\n<\/h2>\n\n\n\n
model.add(Flatten())\n<\/pre>\n\n\n\n
\nR\u00e9sultats\n<\/h1>\n\n\n\n
<\/a><\/figure>\n\n\n\n