有人能告诉我这个反向传播实现有什么问题吗

Can someone tell me what is wrong with this back propagation implementation

所以我正在尝试在 C# 中实现反向传播神经网络。我遇到了一个小问题。训练网络时,所有输出要么是 0.49???... 要么是 0.51???...

这是我的网络 class

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];
                }
            }
        }
    }
}

}

这是我的测试仪 class:

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();

        }
    }
}

}

这是我的输出:

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

就这样一直持续下去。

编辑 1:

我在替换

的 ApplyCorrection() 函数中进行了更改
 Weights[i][j][k] = rate * Deltas[i + 1][k] * Values[i][j];

与`

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

现在权重似乎更新了。但我仍然质疑这个实现的正确性。 A.k.a 仍然需要帮助:)

编辑 2:

我没有对输出层的总误差求和,而是单独反向传播每个样本误差。现在我是,但输出非常混乱:

并且我还将输出对从 (0,1) 更改为 (-1, 1) 以尝试使计算出的误差值更大。 这是在学习率为 0.1 的 1000000 个纪元之后:

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

尝试像下面这样玩,检查错误是否正在减少或仍然相同。

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));
    }
}