这个问题比代码更具概念性,所以用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处于这样的结构中,其中每个神经元是具有输入,权重和基于输入/权重计算的输出的对象,并且神经元存储在2D&#39;层中。 ; x维是图层的数组(因此,第一层是输入,第二层是隐藏等),y维是该层内部的Neuron对象的列表。 &#39;数据&#39;输入的格式为[data,correct-output]
,如[[0,1],[1]]
。
我的LEARNING_RATE也是1,隐藏的图层有2个神经元。
我觉得我的反向传播方法一定存在一些概念问题,因为我已经测试了我的代码的其他部分(比如feedForward部分),并且它工作正常。我尝试使用各种来源,但我主要依靠关于反向传播的维基百科文章以及它给我的方程式。
我知道阅读我的代码可能会让人感到困惑,尽管我试图让它尽可能简单易懂,但任何帮助都会非常感激。