Pour l'apprentissage en profondeur populaire maintenant, il est nécessaire de maintenir l'esprit d'apprentissage - les programmeurs, en particulier les architectes, doivent toujours être préoccupés par les technologies de base et les algorithmes clés, et si nécessaire, vous devez l'écrire et le maîtriser. Ne vous souciez pas du moment de l'utiliser - que ce soit pour l'utiliser est un problème politique ou s'il faut l'écrire est un problème technique, tout comme les soldats ne se soucient pas de se battre ou non, mais de la façon de gagner.
Comment les programmeurs apprennent l'apprentissage automatique
Pour les programmeurs, l'apprentissage automatique a un certain seuil (ce seuil est également sa principale compétitivité). Je crois que beaucoup de gens auront des maux de tête pour des papiers anglais remplis de formules mathématiques lors de l'apprentissage de l'apprentissage automatique, et peuvent même abandonner. Mais en fait, le programme d'implémentation de l'algorithme d'apprentissage automatique n'est pas difficile à écrire. Ce qui suit est l'algorithme de réseau neuronal multicouche inversé (BP) implémenté par 70 lignes de code, c'est-à-dire l'apprentissage en profondeur. En fait, ce ne sont pas seulement les réseaux de neurones, mais la plupart des algorithmes d'apprentissage automatique tels que la régression logistique, l'arbre de décision C45 / ID3, la forêt aléatoire, le bayésien, le filtrage collaboratif, l'informatique graphique, le kmeans, le pageank, etc. peuvent être mis en œuvre dans 100 rangées de programmes autonomes (considérez-le plus tard).
La véritable difficulté de l'apprentissage automatique réside dans la raison pour laquelle il calcule comme ceci, quel est le principe mathématique derrière lui et comment déduire la formule. La plupart des informations sur Internet introduisent cette partie des connaissances théoriques, mais vous indiquent rarement comment le processus de calcul et la mise en œuvre du programme de l'algorithme sont. Pour les programmeurs, ce que vous devez faire est uniquement des applications d'ingénierie et ne prouve pas une nouvelle méthode de calcul mathématique. En fait, la plupart des ingénieurs d'apprentissage automatique utilisent des packages open source ou des logiciels d'outils écrits par d'autres pour saisir les données et ajuster les coefficients de calcul pour former les résultats et implémenter rarement le processus d'algorithme par eux-mêmes. Cependant, il est toujours très important de maîtriser le processus de calcul de chaque algorithme, afin que vous puissiez comprendre quels changements l'algorithme a fait les données et quel effet l'algorithme est pour réaliser.
Cet article se concentre sur la mise en œuvre d'une seule machine des réseaux de neurones inversés. En ce qui concerne la parallélisation multi-machine des réseaux de neurones, Fourinone fournit un cadre informatique parallèle très flexible et complet. Nous n'avons qu'à comprendre la mise en œuvre d'un programme autonome pour concevoir et concevoir une solution de parallélisation distribuée. Si nous ne comprenons pas le processus de calcul de l'algorithme, toutes les idées ne pourront pas être étendues. De plus, il existe également un réseau neuronal convolutionnel, qui est principalement une idée de réduction de la dimensionnalité, utilisé pour le traitement d'image, qui n'est pas dans le cadre de cet article.
Description du processus du réseau neuronal:
Tout d'abord, il est important d'être clair que le réseau neuronal effectue des tâches de prédiction. Je crois que vous vous souvenez de la méthode des moindres carrés que vous avez apprise au lycée. Nous pouvons l'utiliser pour faire une analogie moins rigoureuse mais plus intuitive:
Tout d'abord, nous voulons obtenir les marqueurs d'un ensemble de données et d'un ensemble de données (dans la méthode des moindres carrés, nous obtenons également un ensemble de valeurs de x et y)
L'algorithme correspond à un paramètre de fonction qui peut exprimer cet ensemble de données en fonction de cet ensemble de données et des marques correspondantes (c'est-à-dire la formule qui calcule A et B dans la méthode des moindres carrés, mais cette formule ne peut pas être obtenue directement dans le réseau neuronal)
Nous obtenons la fonction ajustée (c'est-à-dire la ligne ajustée y ^ = ax + b dans la méthode des moindres carrés)
Ensuite, après avoir apporté de nouvelles données, la valeur prédite correspondante y ^ peut être générée (dans la méthode des moindres carrés, il s'agit d'apporter y ^ = ax + b pour obtenir le y ^ prédit, tout comme l'algorithme de réseau neuronal, mais la fonction obtenue est beaucoup plus complexe que la méthode des moindres carrés).
Le processus de calcul des réseaux de neurones
La structure du réseau neuronal est représentée dans la figure ci-dessous. Le plus à gauche est la couche d'entrée, la plus à droite est la couche de sortie et le milieu est plusieurs couches cachées. Chaque nœud neural de la couche cachée et de la couche de sortie est accumulée en multipliant le nœud de couche précédent par son poids. Le cercle marqué "+1" est le terme d'interception b. Pour chaque nœud à l'extérieur de la couche d'entrée: y = w0 * x0 + w1 * x1 +… + wn * xn + b, nous pouvons savoir que le réseau neuronal équivaut à une structure de régression logistique multicouche.
Le processus de calcul de l'algorithme: la couche d'entrée démarre, calcule de gauche à droite et va de l'avant la couche par couche jusqu'à ce que la couche de sortie produit le résultat. S'il y a une différence entre la valeur du résultat et la valeur cible, calculez de droite à gauche, calculez l'erreur de chaque couche de nœud par couche et ajustez tous les poids de chaque nœud. Après avoir atteint la couche d'entrée à l'envers, calculez-le à nouveau vers l'avant et itérez les étapes ci-dessus jusqu'à ce que tous les paramètres de poids convergent vers une valeur raisonnable. Étant donné que les programmes informatiques résolvent les paramètres d'équation et les méthodes mathématiques sont différentes, ils sélectionnent généralement les paramètres au hasard, puis ajustent constamment les paramètres pour réduire l'erreur jusqu'à ce que la valeur correcte soit approchée, la plupart des machines l'apprentissage est constamment une formation itérative. Examinons de plus près la mise en œuvre de ce processus à partir du programme.
Implémentation du programme d'algorithme du réseau neuronal
La mise en œuvre du programme d'algorithme des réseaux de neurones est divisée en trois processus: initialisation, résultats de calcul de transfert et modification inverse des poids.
1. Processus d'initialisation
Puisqu'il s'agit d'un réseau neuronal de couche N, nous utilisons une couche de tableau bidimensionnelle pour enregistrer la valeur du nœud. La première dimension est le nombre de couches, la deuxième dimension est la position de nœud de la couche et la valeur du tableau est la valeur du nœud; De même, la valeur d'erreur de nœud Layerrr est également enregistrée de la même manière. Utilisez le tableau tridimensionnel couche_onde pour enregistrer les poids de chaque nœud. La première dimension est le nombre de couches, la deuxième dimension est la position de nœud de la couche, la troisième dimension est la position du nœud de couche inférieure, la valeur du tableau est la valeur de poids d'un nœud atteignant une couche inférieure et la valeur initiale est un nombre aléatoire entre 0-1. Afin d'optimiser la vitesse de convergence, le réglage du poids de la méthode de momentum est utilisé ici. Il est nécessaire d'enregistrer le dernier montant de réglage du poids et d'utiliser le tableau tridimensionnel Layer_Weight_delta pour enregistrer. Traitement des termes d'interception: le programme définit la valeur de l'interception à 1, de sorte qu'il n'a besoin que de calculer son poids.
2. Calculez les résultats vers l'avant
La fonction S 1 / (1 + math.exp (-z)) est utilisée pour unifier la valeur de chaque nœud entre 0-1, puis calculer la couche par couche jusqu'à la couche de sortie. Pour la couche de sortie, il n'est en fait pas nécessaire d'utiliser la fonction S. Nous considérons le résultat de sortie comme une valeur de probabilité entre 0 et 1, de sorte que la fonction S est également utilisée, ce qui est également propice à l'uniformité du programme.
3. Modifiez réversé le poids
Comment calculer les erreurs dans les réseaux de neurones utilisent généralement la fonction d'erreur carrée E, comme suit:
C'est-à-dire que les carrés des erreurs de plusieurs termes de sortie et des valeurs cibles correspondants sont accumulés et divisés par 2. En fait, il s'agit de la fonction d'erreur de la régression logistique. Quant à savoir pourquoi cette fonction est utilisée pour calculer l'erreur, quelle est la rationalité mathématique et comment elle est obtenue, je suggère que les programmeurs ne veulent pas être des mathématiciens, alors n'allez pas en profondeur. Ce que nous devons faire maintenant, c'est comment prendre la valeur minimale de l'erreur de cette fonction E et la dériver. S'il y a certaines bases de mathématiques dérivées, vous pouvez essayer de déduire comment obtenir la formule suivante à partir des poids dérivés de la fonction E:
Peu importe si nous ne pouvons pas le déduire. Nous avons juste besoin d'utiliser la formule de résultat. Dans notre programme, nous utilisons coucherr pour enregistrer l'erreur minimisée après la dérivation du poids d'E, puis ajustez le poids en fonction de l'erreur minimisée.
Notez que la méthode Momentum est utilisée ici pour prendre en compte l'expérience de l'ajustement précédent pour éviter de tomber dans la valeur minimale locale. Le K ci-dessous représente le nombre d'itérations, le MOBP est le terme d'élan, et le taux est l'étape d'apprentissage:
Δw (k + 1) = mobp * Δw (k) + rate * err * couche
Il existe également de nombreuses formules utilisées ci-dessous, et la différence en effet n'est pas trop grande:
Δw (k + 1) = mobp * Δw (k) + (1-MOBP) Taux * ERR * Couche
Afin d'améliorer les performances, notez que la mise en œuvre du programme consiste à calculer l'erreur et à ajuster le poids pendant un certain temps. Tout d'abord, positionnez la position sur la seconde à la dernière couche (c'est-à-dire la dernière couche cachée), puis ajustez la couche de poids en couche inverse. Ajustez le poids de la couche L en fonction de l'erreur calculée par la couche L + 1 et calculez l'erreur de la couche L et calculez le poids la prochaine fois qu'il se déroule pour calculer le poids jusqu'à la fin de la première couche (couche d'entrée).
résumé
Pendant l'ensemble du processus de calcul, la valeur du nœud change chaque fois qu'elle est calculée et n'a pas besoin d'être enregistrée. Les paramètres de poids et les paramètres d'erreur doivent être enregistrés et doivent fournir un support pour la prochaine itération. Par conséquent, si nous concevons une solution de calcul parallèle multi-machine distribuée, nous pouvons comprendre pourquoi il existe un concept de serveur de paramètres dans d'autres cadres.
Implémentation complète du programme du réseau de neurones multicouches
Le programme d'implémentation suivant BPDEEP.java peut être utilisé directement, et il est également facile de le modifier dans toute autre implémentation de langue telle que C, C #, Python, etc., car ce sont toutes des instructions de base utilisées et aucune autre bibliothèque Java (sauf les fonctions aléatoires).
Importer java.util.random; classe publique bpdeep {public double [] [] couche; // nœuds de réseau neuronal public double [] [] coucher; // nœud neural nœud error public double [] [] [] couche_onde; // nœud neural ponde taux; // coefficient d'apprentissage public bpdeep (int [] Layernum, double taux, double mobp) {this.mobp = mobp; this.rate = rate; couche = nouveau double [Layernum.Length] []; coucherr = nouveau double [Layernum.length] []; couche_onde = nouveau double [Layernum.length] [] []; couche_ondel_delta = new double [Layernum.Length] [] []; Aléatoire aléatoire = nouveau aléatoire (); for (int l = 0; l <Layernum.length; l ++) {couche [l] = new Double [Layernum [l]]; coucherr [l] = nouveau double [Layernum [l]]; if (l + 1 <Layernum.Length) {couche_onde [l] = new double [Layernum [l] +1] [Layernum [l + 1]]; couche_ondel_delta [l] = nouveau double [Layernum [l] +1] [Layernum [l + 1]]; pour (int j = 0; j <Layernum [l] +1; j ++) pour (int i = 0; i <Layernum [l + 1]; i ++) couche_onde [l] [j] [i] = random.nextDouble (); // Random Initization Weight}}} // calculer la couche de sortie par la couche Double [] ComputeOut (double [] in) {pour (int (int (inty l = 1; l <couche.length; l ++) {for (int j = 0; j <couche [l] .length; j ++) {double z = couche_onde [l-1] [couche [l-1] .length] [j]; for (int i = 0; i <couche [l-1] .length; i ++) {couche [l-1] [i] = l == 1? In [i]: couche [l-1] [i]; z + = couche_onde [l-1] [i] [j] * couche [l-1] [i]; } calque [l] [j] = 1 / (1 + math.exp (-z)); }} return couche [couche.length-1]; } // Calculez réversement la couche d'erreur par calque et modifiez le poids de mise à jour du poids public (double [] TAR) {int l = couche.length-1; pour (int j = 0; j <coucherr [l] .length; j ++) coucherr [l] [j] = couche [l] [j] * (1-couche [l] [j]) * (Tar [j] -layer [l] [j]); while (l -> 0) {for (int j = 0; j <coucherr [l] .length; j ++) {double z = 0,0; for (int i = 0; i <coucherr [l + 1] .length; i ++) {z = z + l> 0? coucherr [l + 1] [i] * couche_onde [l] [j] [i]: 0; couche_ondel_delta [l] [j] [i] = mobp * couche_onde if (j == coucherr [l] .length-1) {couche_onder Lower_weight [l] [J + 1] [i] + = couche_onde calculout (in); Mise à jour (TAR); }}Un exemple d'utilisation de réseaux de neurones
Enfin, trouvons un exemple simple pour voir les effets magiques des réseaux de neurones. Afin de faciliter l'observation de la distribution des données, nous choisissons des données de coordonnées bidimensionnelles. Il y a 4 données ci-dessous. Le bloc représente le type de données est 1, et le triangle représente le type de données est 0. Vous pouvez voir que les données appartenant au type de bloc sont (1, 2) et (2, 1), et les données appartenant au type de triangle sont (1, 1), (2, 2). Maintenant, le problème est que nous devons diviser les 4 données en 1 et 0 dans le plan, et l'utiliser pour prédire le type de nouvelles données.
Nous pouvons utiliser l'algorithme de régression logistique pour résoudre le problème de classification ci-dessus, mais la régression logistique obtient une ligne droite linéaire en tant que ligne de division. Vous pouvez voir que peu importe comment la ligne rouge ci-dessus est placée, un échantillon est toujours divisé à tort en différents types. Par conséquent, pour les données ci-dessus, une seule ligne droite ne peut pas diviser correctement leur classification. Si nous utilisons l'algorithme de réseau neuronal, nous pouvons obtenir l'effet de classification de la figure ci-dessous, ce qui équivaut à trouver l'union de plusieurs lignes droites pour diviser l'espace, ce qui est plus précis.
Voici le code source de ce programme de test bpdeeptest.java:
Importer java.util.arrays; classe publique bpdeeptest {public static void main (String [] args) {// initialiser la configuration de base du réseau neuronal // Le premier paramètre est un tableau entier, représentant le nombre de couches du réseau neuronal et le nombre de nœuds par couche. Par exemple, {3, 10, 10, 10, 10, 2} signifie que la couche d'entrée est de 3 nœuds, la couche de sortie est de 2 nœuds et qu'il y a 4 couches cachées au milieu et 10 nœuds par couche // Le deuxième paramètre est la taille de l'étape d'apprentissage, et le troisième paramètre est le coefficient de moment BPDEEP BP = New Bpdeep (New Int [] {2, 10, 2}, 0,15, 0,8); // Définit les données d'échantillons, correspondant aux 4 données de coordonnées à deux dimensions Double [] [] Data = new Double [] [] {{1,2}, {2,2}, {1,1}, {2,1}}; // Définissez les données cibles, correspondant à la classification de 4 données de coordonnées Double [] [] Target = new Double [] [] {{1,0}, {0,1}, {0,1}, {1,0}}; // formation itérative 5000 fois pour (int n = 0; n <5000; n ++) pour (int i = 0; i <data.length; i ++) bp.train (data [i], cible [i]); // Vérifiez les exemples de données basées sur les résultats de formation pour (int j = 0; j <data.length; j ++) {double [] result = bp.computeout (data [j]); System.out.println (arrays.toString (data [j]) + ":" + arrays.tostring (résultat)); } // Prédire la classification d'une nouvelle donnée basée sur les résultats de formation double [] x = nouveau double [] {3,1}; Double [] result = bp.computeout (x); System.out.println (arrays.toString (x) + ":" + arrays.tostring (résultat)); }} résumé
Le programme de test ci-dessus montre que les réseaux de neurones ont des effets de classification magique. En fait, les réseaux de neurones ont certains avantages, mais ce ne sont pas des algorithmes universels proches du cerveau humain. Plusieurs fois, cela peut nous décevoir. Nous devons également utiliser de nombreuses données de divers scénarios pour observer ses effets. Nous pouvons modifier la couche cachée à 1 couche en couches N et ajuster le nombre de nœuds, itérations, taille d'apprentissage et coefficients de quantité de mouvement par couche pour obtenir un résultat optimisé. Cependant, dans de nombreux cas, l'effet de la couche cachée de la couche N n'est pas significativement amélioré que celui de la couche 1. Au lieu de cela, le calcul est plus complexe et prend du temps. Notre compréhension des réseaux de neurones nécessite plus de pratique et d'expérience.
Ce qui précède est tout le contenu partagé dans cet article sur la mise en œuvre d'algorithmes de réseau de neurones profonds avec 70 lignes de code Java. J'espère que ce sera utile à tout le monde. S'il y a des lacunes, veuillez laisser un message pour le signaler.