Créer un réseau neuronal simple



Traduction de la création d'un réseau neuronal simple

Que ferons-nous? Nous allons essayer de créer un réseau neuronal simple et très petit, que nous expliquerons et vous apprendrons à distinguer quelque chose. En même temps, nous n'entrerons pas dans l'histoire et la jungle mathématique (de telles informations sont très faciles à trouver) - au lieu de cela, nous essaierons d'expliquer le problème (pas le fait qu'il sera possible) à vous et à nous-mêmes avec des dessins et du code.

Beaucoup de termes dans les réseaux de neurones sont liés à la biologie, alors commençons par le début:


Le cerveau est une chose compliquée, mais il peut également être divisé en plusieurs parties et opérations principales:



L'agent causal peut également être interne (par exemple, une image ou une idée):



Voyons maintenant les parties basiques et simplifiées du cerveau:


Le cerveau ressemble généralement à un réseau câblé.

Un neurone est la principale unité de calcul dans le cerveau, il reçoit et traite les signaux chimiques des autres neurones et, en fonction d'un certain nombre de facteurs, ne fait rien, ou génère une impulsion électrique, ou potentiel d'action, qui envoie ensuite des signaux aux neurones connectés voisins via des synapses:



Rêves, souvenirs, mouvements autorégulateurs, réflexes et tout ce que vous pensez ou faites est dû à ce processus: des millions voire des milliards de neurones travaillent à différents niveaux et créent des connexions qui créent différents sous-systèmes parallèles et représentent un réseau neuronal biologique .

Bien sûr, ce sont toutes des simplifications et des généralisations, mais grâce à elles, nous pouvons décrire un simple
réseau de neurones:



Et décrivez-le formellement à l'aide du graphique:



Quelques précisions sont nécessaires ici. Les cercles sont des neurones et les lignes sont des connexions entre eux,
et, pour ne pas compliquer à ce stade, la relation est un mouvement direct d'information de gauche à droite . Le premier neurone est actuellement actif et grisé. Nous lui avons également attribué un numéro (1 - si cela fonctionne, 0 - sinon). Les nombres entre les neurones indiquent le poids de la connexion.

Les graphiques ci-dessus montrent le moment du réseau, pour un affichage plus précis, vous devez le diviser en périodes de temps:



Pour créer votre propre réseau de neurones, vous devez comprendre comment les poids affectent les neurones et comment les neurones sont entraînés. A titre d'exemple, prenez un lapin (lapin test) et mettez-le dans les conditions d'une expérience classique.



Lorsqu'un flux d'air sûr leur est dirigé, les lapins, comme les humains, clignotent:



Ce modèle de comportement peut être représenté graphiquement:



Comme dans le diagramme précédent, ces graphiques ne montrent que le moment où le lapin ressent une respiration, et de cette façon, nous codons le coup comme une valeur logique. De plus, nous calculons si le deuxième neurone est déclenché en fonction de la valeur de poids. S'il est égal à 1, alors le neurone sensoriel est déclenché, nous clignotons; si le poids est inférieur à 1, on ne clignote pas: le deuxième neurone a une limite de 1.

Nous introduisons un élément de plus - un signal sonore sûr:



Nous pouvons modéliser l'intérêt d'un lapin comme suit:



La principale différence est que maintenant le poids est nul , nous n'avons donc pas reçu de lapin clignotant, enfin, pour le moment du moins. Apprenez maintenant au lapin à clignoter dans l'équipe, en mélangeant
irritants (signal sonore et souffle):



Il est important que ces événements se produisent à différentes périodes , dans les graphiques, cela ressemblera à ceci:



Le son lui-même ne fait rien, mais le flux d'air fait toujours cligner le lapin, et nous le montrons à travers des poids multipliés par les stimuli (rouges).

L'apprentissage d' un comportement complexe peut être exprimé de manière simpliste comme un changement progressif de poids entre les neurones connectés au fil du temps.

Pour entraîner le lapin, répétez les étapes:



Pour les trois premières tentatives, les schémas ressembleront à ceci:



Veuillez noter que le poids du stimulus sonore augmente après chaque répétition (surligné en rouge), cette valeur est maintenant arbitraire - nous avons choisi 0,30, mais le nombre peut être n'importe quoi, même négatif. Après la troisième répétition, vous ne remarquerez pas de changement dans le comportement du lapin, mais après la quatrième répétition, quelque chose de surprenant se produira - le comportement changera.



Nous avons supprimé l'effet de l'air, mais le lapin clignote toujours lorsqu'il a entendu un bip! Ce dernier comportement peut expliquer ce comportement:



Nous avons formé le lapin à répondre au son en clignotant.


Dans une véritable expérience de ce type, plus de 60 répétitions peuvent être nécessaires pour obtenir un résultat.

Maintenant, nous allons quitter le monde biologique du cerveau et des lapins et essayer d'adapter tout ce qui
appris à créer un réseau neuronal artificiel. Tout d'abord, essayons de faire une tâche simple.

Disons que nous avons une machine à quatre boutons qui distribue de la nourriture lorsque vous appuyez sur la droite
boutons (enfin, ou énergie si vous êtes un robot). La tâche consiste à savoir quel bouton donne la récompense:



Nous pouvons représenter (schématiquement) ce que fait le bouton lorsque vous cliquez dessus comme suit:



Ce problème est mieux résolu dans son intégralité, alors examinons tous les résultats possibles, y compris le bon:


Appuyez sur le 3e bouton pour obtenir votre dîner.

Pour reproduire un réseau neuronal en code, nous devons d'abord créer un modèle ou un graphe auquel le réseau peut être associé. Voici un graphique adapté à la tâche, en plus, il affiche bien son homologue biologique:



Ce réseau neuronal ne reçoit que les informations entrantes - dans ce cas, ce sera la perception du bouton sur lequel vous avez appuyé. De plus, le réseau remplace les informations entrantes par des poids et tire une conclusion basée sur l'ajout d'une couche. Cela semble un peu déroutant, mais voyons comment le bouton est présenté dans notre modèle:


Notez que tous les poids sont 0, donc le réseau neuronal, comme un nourrisson, est complètement vide, mais complètement interconnecté.

Ainsi, nous comparons l'événement externe avec la couche d'entrée du réseau neuronal et calculons la valeur à sa sortie. Elle peut coïncider ou non avec la réalité, mais pour l'instant nous l'ignorerons et commencerons à décrire la tâche de manière informatisée. Commençons par entrer des poids (nous utiliserons JavaScript):

var inputs = [0,1,0,0]; var weights = [0,0,0,0]; //       

L'étape suivante consiste à créer une fonction qui collecte les valeurs et les poids d'entrée et calcule la valeur à la sortie:

 function evaluateNeuralNetwork(inputVector, weightVector){ var result = 0; inputVector.forEach(function(inputValue, weightIndex) { layerValue = inputValue*weightVector[weightIndex]; result += layerValue; }); return (result.toFixed(2)); } //   ,  ,    —    /    

Comme prévu, si nous exécutons ce code, nous obtiendrons le même résultat que dans notre modèle ou graphique ...

 evaluateNeuralNetwork(inputs, weights); // 0.00 

Exemple en direct: Neural Net 001 .

La prochaine étape dans l'amélioration de notre réseau de neurones sera un moyen de vérifier ses propres valeurs de sortie ou de résultat comparables à la situation réelle,
codons d'abord cette réalité particulière dans une variable:



Pour détecter les incohérences (et combien), nous ajoutons une fonction d'erreur:

 Error = Reality - Neural Net Output 

Avec lui, nous pouvons évaluer les performances de notre réseau de neurones:



Mais plus important encore, qu'en est-il des situations où la réalité donne un résultat positif?



Maintenant, nous savons que notre modèle de réseau de neurones ne fonctionne pas (et nous savons combien), tant mieux! C'est génial car maintenant nous pouvons utiliser la fonction d'erreur pour contrôler notre apprentissage. Mais tout cela aura du sens si nous redéfinissons la fonction d'erreur comme suit:

 Error = <b>Desired Output</b> - Neural Net Output 

Un écart insaisissable, mais si important, montrant tacitement que nous allons
utiliser les résultats obtenus précédemment pour comparer avec les actions futures
(et pour la formation, comme nous le verrons plus loin). Il existe dans la vraie vie, plein de
répéter des schémas, de sorte qu'il peut devenir une stratégie évolutive (enfin,
la plupart des cas).

Ensuite, dans notre exemple de code, nous ajouterons une nouvelle variable:

 var input = [0,0,1,0]; var weights = [0,0,0,0]; var desiredResult = 1; 

Et une nouvelle fonctionnalité:

 function evaluateNeuralNetError(desired,actual) { return (desired — actual); } // After evaluating both the Network and the Error we would get: // "Neural Net output: 0.00 Error: 1" 

Exemple en direct: Neural Net 002 .

Pour résumer le sous-total . Nous avons commencé la tâche, réalisé son modèle simple sous la forme d'un réseau neuronal biologique, et obtenu un moyen de mesurer ses performances par rapport à la réalité ou au résultat souhaité. Nous devons maintenant trouver un moyen de corriger l'écart - un processus qui peut être considéré comme une formation pour les ordinateurs et les personnes.

Comment former un réseau neuronal?

La base de l'enseignement des réseaux de neurones biologiques et artificiels est la répétition
et les algorithmes de formation , nous allons donc travailler avec eux séparément. Commencez avec
algorithmes d'apprentissage.

Dans la nature, les algorithmes d'apprentissage sont compris comme des changements physiques ou chimiques
caractéristiques des neurones après expériences:



Une illustration spectaculaire de la façon dont deux neurones changent au fil du temps dans le code et notre modèle «algorithme d'apprentissage» signifie que nous allons simplement changer quelque chose au fil du temps pour nous faciliter la vie. Par conséquent, ajoutons une variable pour indiquer le degré de facilitation de la vie:

 var learningRate = 0.20; //   ,      :) 

Et qu'est-ce que ça va changer?

Cela va changer le poids (tout comme un lapin!), En particulier le poids de la sortie que nous voulons:



Comment coder un tel algorithme est votre choix, pour plus de simplicité j'ajoute le coefficient d'entraînement au poids, le voici sous forme de fonction:

 function learn(inputVector, weightVector) { weightVector.forEach(function(weight, index, weights) { if (inputVector[index] > 0) { weights[index] = weight + learningRate; } }); } 

Lorsqu'elle est utilisée, cette fonction d'apprentissage ajoutera simplement notre coefficient d'apprentissage au vecteur de poids du neurone actif , avant et après le cercle d'entraînement (ou répétition), les résultats seront les suivants:

 // Original weight vector: [0,0,0,0] // Neural Net output: 0.00 Error: 1 learn(input, weights); // New Weight vector: [0,0.20,0,0] // Neural Net output: 0.20 Error: 0.8 //    ,      1 ( ) — ,    ,    ,       

Exemple en direct: Neural Net 003 .

Bon, maintenant que nous allons dans la bonne direction, le dernier détail de ce puzzle sera l'introduction de répétitions .

Ce n'est pas si difficile, dans la nature, nous faisons simplement la même chose encore et encore, et dans le code, nous indiquons simplement le nombre de répétitions:

 var trials = 6; 

Et l'introduction dans notre réseau neuronal d'entraînement de la fonction du nombre de répétitions ressemblera à ceci:

 function train(trials) { for (i = 0; i < trials; i++) { neuralNetResult = evaluateNeuralNetwork(input, weights); learn(input, weights); } } 

Eh bien, notre rapport final:

 Neural Net output: 0.00 Error: 1.00 Weight Vector: [0,0,0,0] Neural Net output: 0.20 Error: 0.80 Weight Vector: [0,0,0.2,0] Neural Net output: 0.40 Error: 0.60 Weight Vector: [0,0,0.4,0] Neural Net output: 0.60 Error: 0.40 Weight Vector: [0,0,0.6,0] Neural Net output: 0.80 Error: 0.20 Weight Vector: [0,0,0.8,0] Neural Net output: 1.00 Error: 0.00 Weight Vector: [0,0,1,0] // Chicken Dinner ! 

Exemple en direct: Neural Net 004 .

Nous avons maintenant un vecteur de poids qui ne donnera qu'un seul résultat (poulet pour le dîner), si le vecteur d'entrée correspond à la réalité (en appuyant sur le troisième bouton).

Alors qu'est-ce qui est si cool qu'on vient de faire?

Dans ce cas particulier, notre réseau de neurones (après l'entraînement) peut reconnaître les données d'entrée et dire ce qui mènera au résultat souhaité (nous devons encore programmer des situations spécifiques):



De plus, c'est un modèle évolutif, un jouet et un outil pour notre formation. Nous avons pu apprendre quelque chose de nouveau sur l'apprentissage automatique, les réseaux de neurones et l'intelligence artificielle.

Attention aux utilisateurs:

  • Un mécanisme de stockage pour les échelles étudiées n'est pas fourni, donc ce réseau neuronal oubliera tout ce qu'il sait. Lors de la mise à jour ou du redémarrage du code, vous avez besoin d'au moins six tentatives réussies pour que le réseau soit pleinement formé si vous pensez qu'une personne ou une machine appuiera sur des boutons au hasard ... Cela prendra un certain temps.
  • Les réseaux biologiques pour l'apprentissage des choses importantes ont une vitesse d'apprentissage de 1, vous n'avez donc besoin que d'une seule répétition réussie.
  • Il existe un algorithme d'apprentissage très similaire aux neurones biologiques, il a un nom accrocheur: règle widroff-hoff ou formation widroff-hoff .
  • Les seuils de neurones (1 dans notre exemple) et les effets de la reconversion (avec un grand nombre de répétitions, le résultat sera supérieur à 1) ne sont pas pris en compte, mais ils sont de nature très importante et sont responsables de blocs complexes et importants de réactions comportementales. Comme des poids négatifs.

Notes et références pour plus de lecture


J'ai essayé d'éviter les mathématiques et les termes stricts, mais si vous êtes intéressé, nous avons construit un perceptron , qui est défini comme un algorithme d'apprentissage supervisé ( enseignement avec un professeur ) de classificateurs doubles - une chose difficile.

La structure biologique du cerveau n'est pas un sujet simple, en partie à cause de l'inexactitude, en partie à cause de sa complexité. Il est préférable de commencer par Neuroscience (Purves) et Cognitive Neuroscience (Gazzaniga). J'ai modifié et adapté l'exemple de lapin de Gateway to Memory (Gluck), qui est également un excellent guide pour le monde des graphes.

Une autre ressource magnifique, An Introduction to Neural Networks (Gurney), convient à tous vos besoins liés à l'IA.

Et maintenant en Python! Merci à Ilya Andschmidt pour la version Python fournie:

 inputs = [0, 1, 0, 0] weights = [0, 0, 0, 0] desired_result = 1 learning_rate = 0.2 trials = 6 def evaluate_neural_network(input_array, weight_array): result = 0 for i in range(len(input_array)): layer_value = input_array[i] * weight_array[i] result += layer_value print("evaluate_neural_network: " + str(result)) print("weights: " + str(weights)) return result def evaluate_error(desired, actual): error = desired - actual print("evaluate_error: " + str(error)) return error def learn(input_array, weight_array): print("learning...") for i in range(len(input_array)): if input_array[i] > 0: weight_array[i] += learning_rate def train(trials): for i in range(trials): neural_net_result = evaluate_neural_network(inputs, weights) learn(inputs, weights) train(trials) 

Et maintenant sur GO! Merci pour cette version de Kieran Maher.

 package main import ( "fmt" "math" ) func main() { fmt.Println("Creating inputs and weights ...") inputs := []float64{0.00, 0.00, 1.00, 0.00} weights := []float64{0.00, 0.00, 0.00, 0.00} desired := 1.00 learningRate := 0.20 trials := 6 train(trials, inputs, weights, desired, learningRate) } func train(trials int, inputs []float64, weights []float64, desired float64, learningRate float64) { for i := 1; i < trials; i++ { weights = learn(inputs, weights, learningRate) output := evaluate(inputs, weights) errorResult := evaluateError(desired, output) fmt.Print("Output: ") fmt.Print(math.Round(output*100) / 100) fmt.Print("\nError: ") fmt.Print(math.Round(errorResult*100) / 100) fmt.Print("\n\n") } } func learn(inputVector []float64, weightVector []float64, learningRate float64) []float64 { for index, inputValue := range inputVector { if inputValue > 0.00 { weightVector[index] = weightVector[index] + learningRate } } return weightVector } func evaluate(inputVector []float64, weightVector []float64) float64 { result := 0.00 for index, inputValue := range inputVector { layerValue := inputValue * weightVector[index] result = result + layerValue } return result } func evaluateError(desired float64, actual float64) float64 { return desired - actual } 

Source: https://habr.com/ru/post/fr423647/


All Articles