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
Je suppose qu'il est à cause de la fonction sigmoïde non linéaire – Aditya
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
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