Алгоритм обратного распространения нейронной сети застревает при обучении XOR PAttern

Обзор

Итак, я пытаюсь понять механику нейронных сетей. Я все еще не совсем понимаю математику, стоящую за этим, но я думаю, что понимаю, как это реализовать. В настоящее время у меня есть нейронная сеть, которая может изучать шаблоны обучения И, ИЛИ и ИЛИ. Однако я не могу заставить его реализовать шаблон XOR. Моя нейронная сеть с прямой связью состоит из 2 входов, 3 скрытых и 1 выход. Веса и смещения случайным образом устанавливаются между -0,5 и 0.5 , а выходы генерируются с помощью сигмоидальной функции активации

Алгоритм

Пока что я предполагаю, что допустил ошибку в своем алгоритме обучения, который описан ниже:

  1. Для каждого нейрона в выходном слое укажите значение ошибки , которое является желаемым выходом - фактическим выходом - , перейдите к шагу 3
  2. Для каждого нейрона в скрытом или входном слое (рабочий назад) предоставляют значение ошибки , которое представляет собой сумму всех весов прямого соединения * errorGradient нейрона на другом конце соединения - переходите к шагу 3
  3. Для каждого нейрона, используя предоставленное значение ошибки , сгенерируйте градиент ошибки , который равен выход * (1-выход) * ошибка . - перейти к шагу 4
  4. Для каждого нейрона отрегулируйте смещение, чтобы оно равнялось текущему смещению + LEARNING_RATE * errorGradient . Затем настройте вес каждого обратного соединения так, чтобы он равнялся текущему весу + LEARNING_RATE * выходу нейрона на другом конце соединения * errorGradient этого нейрона

Я тренирую свою нейронную сеть в режиме онлайн, поэтому это выполняется после каждой обучающей выборки.

Код

Это основной код, который запускает нейронную сеть:

private void simulate(double maximumError) {

    int errorRepeatCount = 0;
    double prevError = 0;

    double error; // summed squares of errors
    int trialCount = 0;

    do {

        error = 0;

        // loop through each training set
        for(int index = 0; index < Parameters.INPUT_TRAINING_SET.length; index++) {

            double[] currentInput = Parameters.INPUT_TRAINING_SET[index];
            double[] expectedOutput = Parameters.OUTPUT_TRAINING_SET[index];
            double[] output = getOutput(currentInput);

            train(expectedOutput);

            // Subtracts the expected and actual outputs, gets the average of those outputs, and then squares it.
            error += Math.pow(getAverage(subtractArray(output, expectedOutput)), 2); 



        }

    } while(error > maximumError);

Теперь функция train () :

public void train(double[] expected) {

    layers.outputLayer().calculateErrors(expected);

    for(int i = Parameters.NUM_HIDDEN_LAYERS; i >= 0; i--) {
        layers.allLayers[i].calculateErrors();
    }

}

Функция выходного слоя calculateErrors () :

public void calculateErrors(double[] expectedOutput) {

    for(int i = 0; i < numNeurons; i++) {

        Neuron neuron = neurons[i];
        double error = expectedOutput[i] - neuron.getOutput();
        neuron.train(error);

    }

}

Нормальный (скрытый и входной) слой calculateErrors () функция:

public void calculateErrors() {

    for(int i = 0; i < neurons.length; i++) {

        Neuron neuron = neurons[i];

        double error = 0;

        for(Connection connection : neuron.forwardConnections) {

            error += connection.output.errorGradient * connection.weight;

        }

        neuron.train(error);

    }

}

Полный класс нейрона:

package neuralNet.layers.neurons;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import neuralNet.Parameters;
import neuralNet.layers.NeuronLayer;

public class Neuron {

private double output, bias;
public List<Connection> forwardConnections = new ArrayList<Connection>(); // Forward = layer closer to input -> layer closer to output
public List<Connection> backwardConnections = new ArrayList<Connection>(); // Backward = layer closer to output -> layer closer to input

public double errorGradient;
public Neuron() {

    Random random = new Random();
    bias = random.nextDouble() - 0.5;

}

public void addConnections(NeuronLayer prevLayer) {

    // This is true for input layers. They create their connections differently. (See InputLayer class)
    if(prevLayer == null) return;

    for(Neuron neuron : prevLayer.neurons) {

        Connection.createConnection(neuron, this);

    }

}

public void calcOutput() {

    output = bias;

    for(Connection connection : backwardConnections) {

        connection.input.calcOutput();
        output += connection.input.getOutput() * connection.weight;

    }

    output = sigmoid(output);

}

private double sigmoid(double output) {
    return 1 / (1 + Math.exp(-1*output));
}

public double getOutput() {
    return output;
}

public void train(double error) {

    this.errorGradient = output * (1-output) * error;

    bias += Parameters.LEARNING_RATE * errorGradient;

    for(Connection connection : backwardConnections) {

        // for clarification: connection.input refers to a neuron that outputs to this neuron
        connection.weight += Parameters.LEARNING_RATE * connection.input.getOutput() * errorGradient;

    }

}

}

Результаты

Когда я тренируюсь для И, ИЛИ или ИЛИ, сеть может обычно сходятся в течение примерно 1000 эпох, однако, когда я тренируюсь с XOR, выходы становятся фиксированными и никогда не сходятся. Итак, что я делаю не так? Есть идеи?

Править

Следуя совету других, я начал заново и реализовал свою нейронную сеть без классов ... и она работает. Я все еще не уверен, где моя проблема в приведенном выше коде, но она где-то там.

12
задан williamg 23 February 2012 в 19:51
поделиться