这个问题比代码更具概念性,因此用JS编写的这个问题应该无关紧要 .
所以我正在尝试创建一个神经网络,我正在通过尝试训练它来做一个简单的任务来测试它 - 一个OR门(或者,实际上,只是任何逻辑门) . 为了简单起见,我没有使用任何批次使用Gradient Descent(批处理对于此任务来说似乎是不必要的,而且我所拥有的代码越少,调试就越容易) .
但是,经过多次迭代后,输出总是收敛到输出的平均值 . 例如,给定此训练集:
[0,0] = 0
[0,1] = 1
[1,0] = 1
[1,1] = 0
无论输入如何,输出总是收敛于0.5左右 . 如果训练集是:
[0,0] = 0,
[0,1] = 1,
[1,0] = 1,
[1,1] = 1
输出总是收敛到0.75左右 - 所有训练输出的平均值 . 对于所有输出组合,这似乎都是正确的 .
似乎这种情况正在发生,因为无论何时给出输出为0的东西,它都会改变权重以接近它,并且每当给出输出为1的东西时,它会改变权重以接近它,这意味着加班时间会在平均值附近收敛 .
这是反向传播代码(用Javascript编写):
this.backpropigate = function(data){
//Sets the inputs
for(var i = 0; i < this.layers[0].length; i ++){
if(i < data[0].length){
this.layers[0][i].output = data[0][i];
}
else{
this.layers[0][i].output = 0;
}
}
this.feedForward(); //Rerun through the NN with the new set outputs
for(var i = this.layers.length-1; i >= 1; i --){
for(var j = 0; j < this.layers[i].length; j ++){
var ref = this.layers[i][j];
//Calculate the gradients for each Neuron
if(i == this.layers.length-1){ //Output layer neurons
var error = ref.output - data[1][j]; //Error
ref.gradient = error * ref.output * (1 - ref.output);
}
else{ //Hidden layer neurons
var gradSum = 0; //Find sum from the next layer
for(var m = 0; m < this.layers[i+1].length; m ++){
var ref2 = this.layers[i+1][m];
gradSum += (ref2.gradient * ref2.weights[j]);
}
ref.gradient = gradSum * ref.output * (1-ref.output);
}
//Update each of the weights based off of the gradient
for(var m = 0; m < ref.weights.length; m ++){
//Find the corresponding neuron in the previous layer
var ref2 = this.layers[i-1][m];
ref.weights[m] -= LEARNING_RATE*ref2.output*ref.gradient;
}
}
}
this.feedForward();
};
这里,NN处于这样的结构中,其中每个神经元是具有输入,权重和基于输入/权重计算的输出的对象,并且神经元存储在其中x维是层的2D 'layers'阵列中(所以,第一层是输入,第二层是隐藏等,而y维是该层内部的神经元对象的列表 . 输入的'data'以 [data,correct-output]
的形式给出,就像 [[0,1],[1]]
一样 .
我的LEARNING_RATE也是1,我的隐藏层有2个神经元 .
我觉得我的反向传播方法一定存在一些概念问题,因为我已经测试了我的代码的其他部分(比如feedForward部分),它运行正常 . 我尝试使用各种来源,虽然我主要依靠关于反向传播的维基百科文章以及它给我的方程式 .
.
.
我知道阅读我的代码可能会让人感到困惑,尽管我尽量让它变得简单易懂,但任何帮助都会非常感激 .