in Intelligence artificielle Machine Learning Javascript data science technologie ~ read.
Créer un réseau de neurones en Javascript en 30 lignes de codes

Créer un réseau de neurones en Javascript en 30 lignes de codes

Cet article est une traduction de celui écrit par Per Harald Borgen, co-fondateur de Scrimba, publié sur freecadecamp.org.

Je ne suis pas du tout expert dans ce domaine que je découvre à peine. Amateur de Javascript, je trouve cette introduction aux réseaux de neurones très accessibles.

Bonne lecture.


Illustration en bandeau : image étrange générée par le réseau de neurones Google Dream

Dans cet article je vais vous montrer comment créer et entraîner un réseau de neurones en utilisant Synaptic.js. Cette bibliothèque permet de faire du Deep Learning dans le navigateur en Node.js.

Nous allons créer le réseau de neurones le plus simple qui soit : celui-ci nous permettra de résoudre l'équation OU exclusif (XOR).

Mais avant de rentrer dans les entrailles du code, commençons par aborder quelques notions de base des réseaux de neurones.

Neurones et synapses

La brique de base d'un réseau de neurones c'est... le neurone.

Un neurone c'est un peu comme une fonction mathématique. Il prend quelques données d'entrées, et il retourne un résultat.

Il y a une grande variété de neurones différents. Notre réseau va utiliser des neurones formels à fonction sigmoïde, lesquels vont prendre des nombres en entrées et retourner une valeur comprise entre 0 et 1.

Le cercle ci-dessous représente un neurone formel. Son entrée est 5, et il retourne 1. Les flèches sont des synapses, elles connectent le neurone à d'autres couches du réseau.

Neurone sigmoid

D'où vient ce chiffre 5 en rouge ? C'est la somme des trois synapses connectées au neurone comme l'indiquent les trois flèches sur la gauche. Décomposons cela.

Tout à gauche nous trouvons deux valeurs plus une troisième valeur de seuil. Nous trouvons les chiffres 1 et 0 en vert. Et la valeur de seuil est le -2 de couleur marron.

Pour commencer, les deux valeurs d'entrée en vert sont multipliées aux coefficients de poids en bleu 7 et 3 qui leurs sont associés.

Ensuite nous les ajoutons à la valeur de biais, ce qui nous donne le chiffre 5 en rouge. Celui-ci constitue l'entrée à proprement parlée du neurone artificiel.

Calcul réalisé en entrée du neurone

Comme c'est une fonction de sigmoïde qui est associée à ce neurone, celle-ci écrase toute valeur d'entrée à quelque chose entre 0 et 1, notre sortie ici se trouve compressée à 1.

En associant ensemble des neurones de ce type, vous réalisez ainsi un réseau de neurones. La propagation se fait dans le sens des entrées vers les sorties, via des neurones connectés entre eux par des synapses. Comme sur l'image ci-dessous :

Couches de neurones

L'objectif d'un réseau de neurones, c'est de s’entraîner pour pouvoir généraliser, comme reconnaître les chiffres d'une écriture manuscrite ou bien reconnaître les spams dans une boîte email. Et pour un réseau de neurones, savoir bien généraliser se résume à avoir les bonnes valeurs de poids et de seuils sur les synapses du réseau. Comme sur les chiffres en bleu et marron dans notre exemple du dessus.

Pour entraîner le réseau, on l'expose à des séries de données d'entrées, comme des chiffres écrits à la main par exemple, et on attend de ce réseau qu'il prédise le bon résultat final.

Après chaque prédiction, on calcule à quel point la réponse est erronée, puis on ajuste les valeurs de poids et de seuils de sorte à obtenir une meilleure réponse du réseau sur une nouvelle itération de prédiction. Ce procédé d'apprentissage s'appelle la rétropropagation du gradient. Faites cela un bon millier de fois et votre réseau va vite devenir bon pour généraliser.

Le fonctionnement de la rétropropagation du gradient est hors du champs de ce didacticiel, mais je vous recommande les trois meilleures ressources que j'ai pu trouver permettant de le comprendre:

Le code

Après cette brève et basique introduction, entrons dans le code. La première chose qu'il nous faut faire, c'est de créer les couches du réseau. Cela se fait simplement avec la fonction new Layer() de Synaptic. Le nombre précisé en paramètre indique la quantité de neurones que la couche doit contenir.

Si vous êtes un peu perdu sur ce qu'est une couche, visionnez ce screencast.

const { Layer, Network } = window.synaptic;

var inputLayer = new Layer(2);  
var hiddenLayer = new Layer(3);  
var outputLayer = new Layer(1);  

Ensuite, nous allons connecter ces couches entre elles et instancier le réseau, comme ceci :

inputLayer.project(hiddenLayer);  
hiddenLayer.project(outputLayer);

var myNetwork = new Network({  
 input: inputLayer,
 hidden: [hiddenLayer],
 output: outputLayer
});

Nous obtenons un réseau 2–3–1, que l'on peut représenter comme ceci :

Réseau 2-3-1

Le moment est venu d'entraîner notre réseau :

// train the network - learn XOR

var learningRate = .3;

for (var i = 0; i < 20000; i++) {  
  // 0,0 => 0
  myNetwork.activate([0,0]);
  myNetwork.propagate(learningRate, [0]);

  // 0,1 => 1
  myNetwork.activate([0,1]);
  myNetwork.propagate(learningRate, [1]);

  // 1,0 => 1
  myNetwork.activate([1,0]);
  myNetwork.propagate(learningRate, [1]);

  // 1,1 => 0
  myNetwork.activate([1,1]);
  myNetwork.propagate(learningRate, [0]);
}

Dans ce code nous réalisons 20 000 itérations sur le réseau. A chaque itération nous propageons quatre fois d'avant en arrière les quatre couples d'entrées possibles pour ce réseau : [0,0] [0,1] [1,0] [1,1] .

Nous commençons avec myNetwork.activate([0,0]) , dans lequel [0,0] représente le couple de données entré dans le réseau. Il s'agit de la propagation en avant, également appelée activation du réseau. Après chaque propagation en avant il nous faut réaliser une rétropropagation. Dans celle-ci le réseau actualise ses valeurs de poids et de seuils.

La rétropropagation est réalisée avec cette ligne de code : myNetwork.propagate(learningRate, [0]), dans celle-ci learningRate est une constante qui précise au réseau de combien il devrait ajuster les poids à chaque itération. Le second paramètre 0 représente la bonne valeur de sortie compte tenu des valeurs d'entrée [0,0].

Le réseau compare alors ses propres prédictions avec le résultat théorique attendu. C'est ce qui lui permet de déduire à quel point sa prédiction était bonne ou mauvaise.

Il se sert de cette comparaison pour ajuster ses valeurs de poids et de seuils, de sorte que sa prochaine prédiction soit plus juste.

Après avoir suivi ce cycle 20 000 fois, nous pouvons vérifier si notre réseau a bien appris en lui soumettant les quatres couples d'entrées possibles :

console.log(myNetwork.activate([0,0]));  
-> [0.015020775950893527]

console.log(myNetwork.activate([0,1]));  
->[0.9815816381088985]

console.log(myNetwork.activate([1,0]));  
-> [0.9871822457132193]

console.log(myNetwork.activate([1,1]));  
-> [0.012950087641929467]

Si nous réalisons un arrondi à l'entier le plus proche, nous obtenons les bonnes réponses à l'équation du OU exclusif. Hourra!

C'est aussi simple que cela. Même si nous avons à peine effleuré le sujet des réseaux de neurones, vous devriez en savoir suffisamment pour commencer à jouer avec Synaptic, et continuer d'apprendre par vous-même. Leur wiki comprend de nombreux exemples et de bons didacticiels.

Pour finir, n'hésitez pas à partager vos connaissances en créant un screencast Scrimba ou bien en rédigeant un article lorsque vous apprenez quelque chose de nouveau ! :-)

comments powered by Disqus