0

J'essaie donc de mettre en œuvre un réseau de neurones de rétropropagation dans C#. Et j'ai rencontré un hoquet. Lors de la formation du réseau, toutes les sorties sont soit 0,49 ??? ... 0,51 ??? ...Quelqu'un peut-il me dire ce qui ne va pas avec cette implémentation de propagation en retour?

Voilà ma classe réseau

namespace BackPropNetwork 
{ 
public class Network 
{ 
    public double[][] Values { get; set; } 
    public double[][] Deltas { get; set; } 
    public double[][][] Weights { get; set; } 
    public Network(params int[] size) 
    { 
     Values = new double[size.Length][]; 
     Weights = new double[size.Length][][]; 
     Deltas = new double[size.Length][]; 
     Random r = new Random(); 
     for(int i = 0; i < size.Length; i++) 
     { 
      Values[i] = new double[size[i]]; 
      Weights[i] = new double[size[i]][]; 
      Deltas[i] = new double[size[i]]; 
      if (i != size.Length - 1) { 
       for (int j = 0; j < size[i]; j++) 
       { 
        Weights[i][j] = new double[size[i + 1]]; 
        for(int k= 0; k < size[i + 1]; k++) 
        { 
         Weights[i][j][k] = r.NextDouble() ; 
        } 
       } 
      } 
     } 
    } 
    public double[] FeedThrough (double[] input) 
    { 
     if(input.Length!= Values[0].Length) 
     { 
      throw new InvalidOperationException(); 
     } 
     Values[0] = input; 
     for(int i = 0; i < Values.Length-1; i++) 
     { 
      for(int j = 0; j < Values[i + 1].Length; j++) 
      { 
       Values[i + 1][j] = Sigmoid(GetPassValue(i, j),false); 
      } 
     } 
     return Values[Values.Length - 1]; 
    } 
    double GetPassValue(int layer,int neuron) 
    { 
     double sum = 0; 
     for(int i = 0; i < Values[layer].Length; i++) 
     { 
      sum += Values[layer][i] * Weights[layer][i][neuron]; 
     } 
     return sum; 
    } 
    public double Sigmoid(double d, bool dir) 
    { 
     if (dir) 
     { 
      return d * (1 - d); 
     }else 
     { 
      return 1/(1 + Math.Exp(d)); 
     } 
    } 
    public void CorrectError(double[] error) 
    { 
     for(int i = Values.Length - 1; i >= 0; i--) 
     { 

      if (i !=Values.Length - 1) 
      { 
       error = new double[Values[i].Length]; 
       for(int j = 0; j < Values[i].Length; j++) 
       { 
        error[j] = 0; 
        for(int k = 0; k < Values[i + 1].Length; k++) 
        { 
         error[j] += Weights[i][j][k] * Deltas[i + 1][k]; 
        } 
       }  
      } 

      for(int j = 0; j < Values[i].Length; j++) 
      { 
       Deltas[i][j] = error[j] * Sigmoid(Values[i][j],true); 
      } 

     } 

    } 
    public void ApplyCorrection(double rate) 
    { 
     for(int i = 0; i < Values.Length-1; i++) 
     { 
      for(int j = 0; j < Values[i].Length; j++) 
      { 
       for(int k = 0; k < Values[i + 1].Length; k++) 
       { 
        Weights[i][j][k] = rate * Deltas[i + 1][k] * Values[i][j]; 
       } 
      } 
     } 
    } 
} 

}

et est ici ma classe de testeur :

namespace BackPropagationTest 
{ 
class Program 
{ 
    static void Main(string[] args) 
    { 
     Network n = new Network(3, 5, 5, 1); 
     double[][] input = new double[][] { new double[] { 1, 0, 1 }, new double[] { 1, 1, 1 }, new double[] { 0, 0, 0 }, new double[] {0, 1, 0 } }; 
     double[][] output = new double[][] { new double[] { 0 },new double[] { 1 }, new double[] { 0 }, new double[] { 0 } }; 
     for (int i = 0; i < 10; i++) 
     { 
      for(int j = 0; j < input.Length; j++) 
      { 
       var x = n.FeedThrough(input[j]); 
       double[] error = new double[output[0].Length]; 
       for(int k= 0; k < x.Length; k++) 
       { 
        error[k] = output[j][k] - x[k]; 
       } 
       n.CorrectError(error); 
       n.ApplyCorrection(0.01); 
       for(int k = 0; k < x.Length; k++) 
       { 
        Console.Write($"Expected: {output[j][k]} Got: {x[k]} "); 
       } 
       Console.WriteLine(); 


      } 
      Console.WriteLine(); 

     } 
    } 
} 

}

et voici ma sortie:

Expected: 0 Got: 0.270673949003643 
Expected: 1 Got: 0.500116517554687 
Expected: 0 Got: 0.499609458404919 
Expected: 0 Got: 0.50039031963377 

Expected: 0 Got: 0.500390929619276 
Expected: 1 Got: 0.500390929999612 
Expected: 0 Got: 0.499609680732027 
Expected: 0 Got: 0.500390319841144 

Expected: 0 Got: 0.50039092961941 
Expected: 1 Got: 0.500390929999612 
Expected: 0 Got: 0.499609680732027 
Expected: 0 Got: 0.500390319841144 

Expected: 0 Got: 0.50039092961941 
Expected: 1 Got: 0.500390929999612 
Expected: 0 Got: 0.499609680732027 
Expected: 0 Got: 0.500390319841144 

Et ça continue comme ça pour toujours.

Edit 1:

J'ai fait un changement dans la fonction ApplyCorrection() où j'ai remplacé

Weights[i][j][k] = rate * Deltas[i + 1][k] * Values[i][j]; 

avec `

Weights[i][j][k] += rate * Deltas[i + 1][k] * Values[i][j]; 

et maintenant les poids semblent mettre à jour. mais je doute encore de la justesse de cette mise en œuvre. A.k.a encore besoin d'aide :)

Edit 2:

Je ne sommateur l'erreur totale de la couche de sortie backpropagating plutôt toutes les erreurs d'échantillonnage individuellement. Maintenant, je suis, mais les sorties sont très confus:

Et j'ai également changé la paire de sortie de (0,1) à (-1, 1) dans les tentatives de rendre les valeurs d'erreur calculées plus grandes. Ce est après 1000000 à un taux époques d'apprentissage de 0,1:

Expected: -1 Got: 0.999998429209274 Expected: 1 Got: 0.999997843901661 Expected: -1 Got: 0.687098308461306 Expected: -1 Got: 0.788960893508226 Expected: -1 Got: 0.999998429209274 Expected: -1 Got: 0.863022549216158 Expected: -1 Got: 0.788960893508226 Expected: -1 Got: 0.999998474717769

+0

Je suppose qu'il est à cause de la fonction sigmoïde non linéaire – Aditya

+0

En fait, je si ce pourrait être parce que je suis mise en poids dans la fonction ApplyCorrection. où il est Poids [i] [j] [k] = taux * Deltas [i + 1] [k] * Valeurs [i] [j]; Je pense que cela devrait être Poids [i] [j] [k] + = taux * Deltas [i + 1] [k] * Valeurs [i] [j]; – Paso

+0

Cela a semblé faire changer les sorties, et a fait apprendre au réseau. mais je ne suis toujours pas sûr de la justesse de ma mise en œuvre. – Paso

Répondre

0

Essayez de jouer avec quelque chose comme ci-dessous et vérifiez l'erreur diminue ou toujours le même.

public double Sigmoid(double d, bool dir) 
{ 
    if (dir) 
    { 
     return d * (1 - d); 
    }else 
    { 
     if (d < -45.0) return 0.0; 
     else if (d > 45.0) return 1.0; 
     else return 1.0/(1.0 + Math.Exp(-d)); 
    } 
} 
+0

Si c'est vrai, il renvoie la dérivée. Et non je ne le suis pas. mais merci quand même – Paso

+0

Ok, je l'ai essayé et ce qui se passe, c'est que les poids arrêtent de changer – Paso

+0

Oh, ça n'a jamais marché. Merci beaucoup! – Paso