Проблема с нейросетью C#

Вот код:

public class NeuralNetwork
{
    public int[] Layers;
    private float[][] Neurons;
    private float[][] B;
    private float[][][] Weights;
    public float LearningRate = 0.01f;
    public NeuralNetwork(params int[] sizes)
    {
        var r = new Random();
        Layers = sizes.ToArray();
        Neurons = new float[sizes.Length][];
        B = new float[sizes.Length][];
        Weights = new float[sizes.Length - 1][][];
        for (int i = 0; i < sizes.Length; i++)
        {
            Neurons[i] = new float[sizes[i]];
            B[i] = new float[sizes[i]];
            if (i != 0)
                for (int j = 0; j < sizes[i]; j++)
                    B[i][j] = (float)(r.NextDouble() * (double)r.Next());
        }
        for (int i = 0; i < sizes.Length - 1; i++)
        {
            Weights[i] = new float[sizes[i]][];
            for (int j = 0; j < sizes[i]; j++)
            {
                Weights[i][j] = new float[sizes[i + 1]];
                for (int k = 0; k < sizes[i + 1]; k++)
                    Weights[i][j][k] = (float)(r.NextDouble() * (double)r.Next());
            }
        }
    }
    public NeuralNetwork(float learningRate, int[] layers, float[][] b, float[][][] weights)
    {
        LearningRate = learningRate;
        Layers = layers;
        B = b;
        Weights = weights;
        Neurons = new float[layers.Length][];
        for (int i = 0; i < Neurons.Length; i++)
            Neurons[i] = new float[layers[i]];
    }
    public float[] Forward(params float[] input)
    {
        if (input.Length != Neurons[0].Length) throw new ArgumentException();
        Neurons[0] = input.Select(x => 1 / (1 + MathF.Exp(-x))).ToArray();
        for (int i = 1; i < Neurons.Length; i++)
        {
            for (int j = 0; j < Neurons[i].Length; j++)
            {
                Neurons[i][j] = 0;
                for (int k = 0; k < Neurons[i - 1].Length; k++)
                    Neurons[i][j] += Neurons[i - 1][k] * Weights[i - 1][k][j];
                Neurons[i][j] = 1 / (1 + MathF.Exp(-(Neurons[i][j] + B[i][j])));
            }
        }
        return Neurons[Neurons.Length - 1].ToArray();
    }
    public void Backward(float[] input, float[] output)
    {
        float[] errors = new float[output.Length];
        float[] outputNet = Forward(input);
        for (int i = 0; i < errors.Length; i++)
            errors[i] = output[i] - outputNet[i];
        for (int i = Neurons.Length - 2; i >= 0; i--)
        {
            float[] errorsNext = new float[Neurons[i].Length];
            float[] gradient = new float[Neurons[i + 1].Length];
            float[][] deltas = new float[Neurons[i + 1].Length][];
            for (int j = 0; j < Neurons[i + 1].Length; j++)
            {
                gradient[j] = errors[j] * Neurons[i + 1][j] * (1 - Neurons[i + 1][j]) * LearningRate;
                B[i + 1][j] += gradient[j];
            }
            for (int j = 0; j < Neurons[i + 1].Length; j++)
            {
                deltas[j] = new float[Neurons[i].Length];
                for (int k = 0; k < Neurons[i].Length; k++)
                    deltas[j][k] = gradient[j] * Neurons[i][k];
            }
            for (int j = 0; j < Neurons[i].Length; j++)
            {
                for (int k = 0; k < Neurons[i + 1].Length; k++)
                    errorsNext[j] += Weights[i][j][k] * errors[k];
            }
            errors = errorsNext;
            for (int j = 0; j < Neurons[i + 1].Length; j++)
                for (int k = 0; k < Neurons[i].Length; k++)
                    Weights[i][k][j] = Weights[i][k][j] + deltas[j][k];
        }
    }
    public (float[][][], float[][], int[], float) GetNetworkData() => (Weights.ToArray(), B.ToArray(), Layers.ToArray(), LearningRate);
}

Проблема в том, что при прямом проходе все нейроны равны 1, поэтому после функции деактивации Neurons[i + 1][j] * (1 - Neurons[i + 1][j]) он возвращает 0 (такая проблема возникла в нейросети[784;16;16;10] и в нейросети[784;512;128;32;10], в нейронных сетях для решения задач XOR,NXOR и в задаче о виде ириса с нейросетью[4;5;3] такой проблемы не возникло). Использую функцию сигмойда. Как это исправить?

Для обучения нейросети использовал базу рукописных цифр MNIST датасет Вот код который читает эту базу

public static class P
{
    public static List<(float[],float[])> Read()
    {
        var images = new List<(float[], float[])>(60000);
        var a = new BinaryReader(new FileStream("train-labels.idx1-ubyte", FileMode.Open));
        var b = new BinaryReader(new FileStream("train-images.idx3-ubyte", FileMode.Open));
        var m = a.ReadInt32();
        var f = a.ReadInt32();
        b.ReadInt32();
        b.ReadInt32();
        b.ReadInt32();
        b.ReadInt32();
        for (int i = 0; i < 60000; i++)
        {
            var pixels = new float[28*28];
            for (int j = 0; j < 28; j++)
            {
                for (int k = 0; k < 28; k++)
                {
                    var v=(float)(b.ReadByte());
                    pixels[j+k*28] = v;
                }
            }
            var t=new float[10];
            t[a.ReadByte()]=1f;
            images.Add((pixels,t));
        }
        return images;
    }
}

Дополнительные медоты к нейронке

public static void Save(this NeuralNetwork Net, string name)
    {
        var NetData = Net.GetNetworkData();
        List<string> NetMemory = new List<string>() { string.Join(";", NetData.Item3), NetData.Item4.ToString() };
        foreach (var i in NetData.Item1)
            foreach (var j in i)
                NetMemory.Add(string.Join(";", j));
        foreach (var i in NetData.Item2)
            NetMemory.Add(string.Join(";", i));
        File.WriteAllLines(name + " (" + string.Join("; ", Net.Layers) + ").txt", NetMemory);
    }
    public static NeuralNetwork Load(string name)
    {
        string[] NetworkMemoryFile = File.ReadAllLines(name + ".txt");
        int[] layers = NetworkMemoryFile[0].Split(';').Select(x => int.Parse(x)).ToArray();
        float learningRate = float.Parse(NetworkMemoryFile[1]);
        float[][][] weights = new float[layers.Length - 1][][];
        int weightsI = 0;
        for (int i = 0; i < layers.Length - 1; i++)
        {
            weights[i] = new float[layers[i]][];
            for (int j = 0; j < layers[i]; j++)
                weights[i][j] = NetworkMemoryFile[2 + weightsI++].Split(";").Select(x => float.Parse(x)).ToArray();
        }
        float[][] b = new float[layers.Length][];
        int bI = 0;
        for (int i = 0; i < layers.Length; i++)
            b[i] = NetworkMemoryFile[2 + weightsI + bI++].Split(";").Select(x => float.Parse(x)).ToArray();
        return new NeuralNetwork(learningRate, layers, b, weights);
    }

А вот обучение и тестирование

public static void Main()
    {
        var data = P.Read();
        //var a=new NeuralNetwork(784,16,16,10);
        //a.Save("MNIST");
        var a = NeuralNetworkExpansion.Load("MNIST (784; 16; 16; 10)");
        for (int j = 0; j < 1; j++)
        {
            foreach (var i in data)
                a.Backward(i.Item1, i.Item2);
            a.Save("MNIST");
            Console.WriteLine(j);
        }
        foreach (var i in data.Take(100))
        {
            Console.WriteLine(string.Join("; ", a.Forward(i.Item1).Select(x => Math.Round(x, 2))));
            Console.WriteLine(string.Join("; ", i.Item2));
        }
    }

Попробовал изменить функцию на RELu и Tanh, такая же ситуация


Ответы (1 шт):

Автор решения: Дмитрий Попов

В общем и целом, я нашёл как исправить проблему: сделал так чтобы веса и смещения при создании могли быть отрицательными, а так же отредактировал данные для обучения (1 если значение пикселя больше 200, и 0 в ином случае);

→ Ссылка