Нейронная сеть очень долго работает при увеличении размера сети

152
16 ноября 2020, 19:50

Сделал простую нейронную сеть на C#. Все работает нормально с маленьким примером, а если я создаю 10 входных нейронов да еще скрытых слоев 2. То у меня до идеального ответа пройдет эпох 700. И каждый раз разное значение.

Я пытался изменять гиперпараметры, но безуспешно.

Пожалуйста посмотрите мой код и подскажите что я сделал не так.

И если не сложно может кто нибудь объяснить где у меня ошибка в поиске ошибки нейронной сети. Я все вроде делал по статье, но не получается.

P.s вообще идея была что на вход подается 9 значений (это 0 или 1 в зависимости от того закрашена клетка или нет). И если в поле 3 на 3 палка вертикальная, то нейронная сеть говорит что палка вертикальная ну или горизонтальная.

Вот ссылка на статью: https://m.habr.com/ru/post/312450/

А вот сам код:

static Random r;
static void Main(string[] args)
{
    //Входные данные
    double[,] inputData = new double[,]
    {
        {1,0,0,1,0,0,1,0,0},
        {1,1,1,0,0,0,0,0,0},
        {0,1,0,0,1,0,0,1,0},
        {0,0,0,1,1,1,0,0,0},
        {0,0,1,0,0,1,0,0,1},
        {0,0,0,0,0,0,1,1,1}
    };
    /*inputData = new double[,]
    {
        {0,1,1}, {0,0,1},{1,0,1},{0,0,0},{1,0,0},{0,1,0},{1,1,0},{1,1,1}
    };*/
    //Идеальные значения
    double[] outputData = new double[] { 1, 0, 1, 0, 1, 0 };
    //outputData = new double[] { 1, 1, 0, 0, 0, 0, 0, 1 };
    //Значение момента
    double a = 0.8;
    //Скорость обучения
    double E = 0.8;
    //Все нейроны
    double[][,] allNeurons = new double[][,]
    {
        new double[10,1], new double[6,2], new double[4,2], new double[1,2]
        //new double[4, 1], new double[1, 2]
    };
    //Все веса
    double[][,,] allWeights = new double[][,,]
    {
        new double[10,5,2], new double[6,3,2], new double[4,1,2]
        //new double[4,1,2]
    };
    r = new Random();
    //Инициализация весов в промежутке от -0.5 до 0.5 случайным образом
    for (int i = 0; i < allWeights.GetLength(0); i++)
        for (int j = 0; j < allWeights[i].GetLength(0); j++)
            for (int k = 0; k < allWeights[i].GetLength(1); k++)
                allWeights[i][j, k, 0] = r.NextDouble() - 0.5;
    double error = 0;
    for (int epoch = 0; epoch < 1000; epoch++)
    {
        Console.ForegroundColor = ConsoleColor.Red;
        Console.WriteLine(epoch);
        Console.ResetColor();
        for (int stepTrain = 0; stepTrain < inputData.GetLength(0); stepTrain++)
        {
            //Инициализация входных нейронов
            for (int i = 0; i < allNeurons[0].GetLength(0) - 1; i++)
                allNeurons[0][i, 0] = inputData[stepTrain, i];
            //Инициализация нейронов смещения
            for (int i = 0; i < allNeurons.GetLength(0) - 1; i++)
                allNeurons[i][allNeurons[i].GetLength(0) - 1, 0] = 1;
            //Прямое прохождение по всем слоям
            for (int i = 1; i < allNeurons.GetLength(0); i++)
            {
                int lastLayer = 1;
                if (i == allNeurons.GetLength(0) - 1)
                    lastLayer = 0;
                for (int k = 0; k < allNeurons[i].GetLength(0) - lastLayer; k++)
                {
                    for (int j = 0; j < allNeurons[i - 1].GetLength(0); j++)
                        allNeurons[i][k, 0] += allWeights[i - 1][j, k, 0] * allNeurons[i - 1][j, 0];
                    allNeurons[i][k, 0] = Sigmoid(allNeurons[i][k, 0]);
                }
            }
            //Нахождение ошибки у выходных нейронов
            int index = allNeurons.GetLength(0) - 1;
            for (int i = 0; i < allNeurons[index].GetLength(0); i++)
                allNeurons[index][i, 1] = FixOutError(outputData, allNeurons[index][i, 0], stepTrain);
            //Нахождение ошибок для скрытых нейронов
            for (int i = allNeurons.GetLength(0) - 2; i >= 1; i--)
            {
                int lastLayer = 1;
                if (i + 1 == allNeurons.GetLength(0) - 1)
                    lastLayer = 0;
                for (int j = 0; j < allNeurons[i].GetLength(0); j++)
                {
                    for (int k = 0; k < allNeurons[i + 1].GetLength(0) - lastLayer; k++)
                        allNeurons[i][j, 1] += allWeights[i][j, k, 0] * allNeurons[i + 1][k, 1];
                    allNeurons[i][j, 1] = allNeurons[i][j, 1] * (1 - allNeurons[i][j, 0]) * allNeurons[i][j, 0];
                }
            }
            //Корректировка весов
            for (int i = 1; i < allNeurons.GetLength(0); i++)
            {
                int lastLayer = 1;
                if (i == allNeurons.GetLength(0) - 1)
                    lastLayer = 0;
                for (int k = 0; k < allNeurons[i - 1].GetLength(0); k++)
                    for (int j = 0; j < allNeurons[i].GetLength(0) - lastLayer; j++)
                    {
                        allWeights[i - 1][k, j, 1] = E * allNeurons[i - 1][k, 0] * allNeurons[i][j, 1] + a * allWeights[i - 1][k, j, 1];
                        allWeights[i - 1][k, j, 0] += allWeights[i - 1][k, j, 1];
                    }
            }
            error += Math.Pow(Math.Atan(outputData[stepTrain] - allNeurons[3][0, 1]), 2);
            Console.WriteLine(allNeurons[3][0, 0]);
        }
        Console.ForegroundColor = ConsoleColor.Green;
        Console.WriteLine(error / outputData.Length);
        error = 0;
        Console.ResetColor();
        //Thread.Sleep(300);
    }
    Console.ReadKey();
}
static double FixOutError(double[] outputData, double outputValue, int index) => (outputData[index] - outputValue) * (1 - outputValue) * outputValue;
static double Sigmoid(double outputData) => 1 / (1 + Math.Exp(-(outputData)));

Дополнение:

Я изменил поиск ошибки тоесть строку

error += Math.Pow(Math.Atan(outputData[stepTrain] - allNeurons[3][0, 1]), 2);

на строку

error += Math.Abs(outputData[stepTrain] - allNeurons[3][0, 0]);

И в конце эпохи я просто делю error на количество элементов в массиве идеальных значений.

И заметил что первые эпох 200 значение error стоит 0.6 примерно и почти не изменяется. После 200 эпох ошибка начинает спадать до 0.04 и дальше медленно уменьшается.

Как исправить это ошибку когда 200 эпох error почти не изменяется.

Дополнение:

Я изменил случайную генерацию весов с -0.5 до 0.5 на с -1 до 0 и нейронная сеть начала обучаться за 100 эпох а не за 700 или 1400 как было.

Но не знаю правильно ли я сделал

Answer 1

В общем посидев и поигравшись с нейронной сетью.

1) Изменил количество скрытых слоев до 1 слоя в котором 5 нейронов (1 нейрон смещения)

2) Оставил генерацию весов -0.5 до 0.5 Особо роли не сыграло. Только в начале, эпох 8-10 нейронка немного тупит. (Хотя бы не 200 эпох как раньше)

3) Если останавливать обучение на error <= 0.05 то это займет эпох 80 (минимальное которое я получил) если нужно более точнее ответы (хотя они и так уже достаточно точны) то при error <= 0.02 нейронка будет учиться 400 эпох. Потому что примерно на 0.3-0.4 ошибка очень медленно спадает.

4) Гиперпараметры изменил так:

Значение момента (a) = 0.9

Скорость обучения (E) ставил на 1, но решил поставить на 0.9 просто где то слышал что лучше не ставить гиперпараметры на 1 (особенно значение момента).

В итоге с 800-1400 эпох обучения я снизил до 80-400 (зависит от четкости ответа который вам нужен).

Исправьте пожалуйста если я где-то допустил ошибку.

Просто нейронными сетями занимаю неделю всего.

READ ALSO
Реализация двойного прыжка

Реализация двойного прыжка

Собственно в названии и заключается проблемаКод следующий:

100
Как отобразить картинку из byte[] во вьюшке в img

Как отобразить картинку из byte[] во вьюшке в img

Как отображать картинки(массив байтов) в вьюшке(<img>)?

132
В чём проблемы с функцией SalesTax

В чём проблемы с функцией SalesTax

Начал читать C# 7 иNET Core

133
Wpf и горячие клавишы

Wpf и горячие клавишы

Да, я знаю как использовать хоткеи (XAML):

131