我有一个神经网络,其中有2个输入,2个隐藏的神经元和1个输出神经元,可以解决xor
问题。我在0和1之间随机初始化权重,并使用0.1
和激活功能sigmoid
来学习。
当我只训练一个选项(例如1和0,目标为1)时,它可以正常工作并给出适当的猜测。但是,当我尝试一起训练所有可能的输入时,输出会在0.5-0.6
附近收敛。
我尝试过更改学习率,权重的初始化范围和网络训练的次数,但是对最终输出没有影响。
这是我在GitHub上的代码的链接。
关于如何解决此问题的任何想法?
答案 0 :(得分:1)
我怀疑反向传播未正确实施。概述在例如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