Нейронная сеть Java XOR не работает должным образом - PullRequest
0 голосов
/ 23 февраля 2019

У меня есть нейронная сеть с 2 входными, 2 скрытыми нейронами и 1 выходным нейроном для решения проблемы xor.Я случайным образом инициализирую веса между 0 и 1, я использую скорость обучения 0.1 с sigmoid функцией активации.

Когда я тренирую только один вариант, например, 1 и 0 с целью 1,он работает нормально и дает правильное предположение.Однако, когда я пытаюсь обучить все возможные входные данные вместе, выходные данные сходятся около 0.5-0.6.

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

Вот ссылка на мой код на GitHub .

Есть идеи, как мне решить эту проблему?

1 Ответ

0 голосов
/ 25 февраля 2019

Я подозреваю, что обратное распространение не реализовано должным образом.Обзор приведен, например, в http://users.pja.edu.pl/~msyd/wyk-nai/multiLayerNN-en.pdf на отдельных страницах с 17 по 20.

Метод tuneWeigths - и delta_weights класса Output_Neuron реализованы правильно.Однако на этом шаге должен быть определен массив weightDeltaHidden (см. Комментарий в коде), который понадобится позже при настройке весов класса Hidden_Neuron.

tuneWeigths - и delta_weights -метод Hidden_Neuron -класса не реализованы должным образом.Здесь, помимо прочего, должен использоваться ранее определенный массив weightDeltaHidden.

В приведенном ниже коде я внес необходимые изменения без существенного изменения дизайна кода.Но, возможно, рефакторинг имеет смысл.

Изменения в Output_Neuron -классе:

...

private double[] weightedDeltaHidden;

...

Output_Neuron(int hiddenNeurons) {

    ...

    this.weightedDeltaHidden = new double[hiddenNeurons];
}

...

void tuneWeights(double LR, double[] hidden_output, int target) {
    double delta = (target - output) * f.dSigmoid(output);
    for (int i = 0; i < weights.length; i++) {
        weights[i] += delta_weights(i, LR, delta, hidden_output);
    }
}

double delta_weights(int i, double LR, double delta, double[] hidden_output) {
    weightedDeltaHidden[i] = delta * weights[i]; // weightedDeltaHidden is the product of delta of this output neuron and the weight of the i-th hidden neuron.
                                                 // That value is needed when the weights of the hidden neurons are tuned...
    return LR * delta * hidden_output[i];
}

...

double[] getWeightedDeltaHidden() {
    return weightedDeltaHidden;
}

Изменения в Hidden_Neuron -классе:

...

void tuneWeights(double LR, int[] inputs, double weightedDeltaHiddenTotal) {
    for (int i = 0; i < weights.length; i++) {
        weights[i] += delta_weights(LR, inputs[i], weightedDeltaHiddenTotal);
    }
}

private double delta_weights(double LR, double input, double weightedDeltaHiddenTotal) {
    double deltaOutput = f.dSigmoid(output) * weightedDeltaHiddenTotal;
    return LR * deltaOutput * input;
}

...

Изменения вNetwork -класс внутри train -метода, где происходит настройка скрытых весов:

void train(int[] inputs, int target) {

    ...

    //tune Hidden weights
    for (int i = 0; i < numOfHiddenNeurons; i++) {
        double weightedDeltaHiddenTotal = 0;
        for (int j = 0; j < numOfOutputNeurons; j++) {
            weightedDeltaHiddenTotal += output_neurons[j].getWeightedDeltaHidden()[i]; // weightedDeltaHiddenTotal is the sum of the weightedDeltaHidden over all output neurons. Each weightedDeltaHidden
        }                                                                              // is the product of delta of the j-th output neuron and the weight of the i-th hidden neuron.
        hidden_neurons[i].tuneWeights(LR, inputs, weightedDeltaHiddenTotal);
    }
}

С этими изменениями, типичный вывод для вызовов 1_000_000 train (2 скрытых нейрона) равен

Error: 1.9212e-01 in cycle 0
Error: 8.9284e-03 in cycle 100000
Error: 1.5049e-03 in cycle 200000
Error: 4.7214e-03 in cycle 300000
Error: 4.4727e-03 in cycle 400000
Error: 2.1179e-03 in cycle 500000
Error: 2.9165e-04 in cycle 600000
Error: 2.0655e-03 in cycle 700000
Error: 1.5381e-03 in cycle 800000
Error: 1.0440e-03 in cycle 900000
0 0: 0.0170
1 0: 0.9616
0 1: 0.9612
1 1: 0.0597

и для вызовов 100_000_000 train (2 скрытых нейрона)

Error: 2.4755e-01 in cycle 0
Error: 2.7771e-04 in cycle 5000000
Error: 6.8378e-06 in cycle 10000000
Error: 5.4317e-05 in cycle 15000000
Error: 6.8956e-05 in cycle 20000000
Error: 2.1072e-06 in cycle 25000000
Error: 2.6281e-05 in cycle 30000000
Error: 2.1630e-05 in cycle 35000000
Error: 1.1546e-06 in cycle 40000000
Error: 1.7690e-05 in cycle 45000000
Error: 8.6837e-07 in cycle 50000000
Error: 1.3603e-05 in cycle 55000000
Error: 1.2905e-05 in cycle 60000000
Error: 2.1657e-05 in cycle 65000000
Error: 1.1594e-05 in cycle 70000000
Error: 1.9191e-05 in cycle 75000000
Error: 1.7273e-05 in cycle 80000000
Error: 9.1364e-06 in cycle 85000000
Error: 1.5221e-05 in cycle 90000000
Error: 1.4501e-05 in cycle 95000000
0 0: 0.0008
1 0: 0.9961
0 1: 0.9961
1 1: 0.0053

Увеличение количества скрытых нейронов повышает производительность.Ниже показан типичный вывод для вызовов 1_000_000 train (4 скрытых нейрона):

Error: 1.2617e-02 in cycle 0
Error: 7.9950e-04 in cycle 100000
Error: 4.2567e-04 in cycle 200000
Error: 1.7279e-04 in cycle 300000
Error: 1.2246e-04 in cycle 400000
Error: 1.0456e-04 in cycle 500000
Error: 6.9140e-05 in cycle 600000
Error: 6.8698e-05 in cycle 700000
Error: 5.1640e-05 in cycle 800000
Error: 4.4534e-05 in cycle 900000
0 0: 0.0092
1 0: 0.9905
0 1: 0.9912
1 1: 0.0089
...