我正在尝试用 Javascript 实现一个神经网络,我的项目规范希望实现为每个节点和层提供单独的对象。我在编程神经网络方面相当陌生,在网络的反向传播训练过程中遇到了一些障碍。我似乎无法找到解释为什么反向传播算法不能为每个训练时期正确训练网络。
我遵循了一些网站上的教程,确保尽可能严格地遵循: http://galaxy.agh.edu.pl/~vlsi/AI/backp_t_en/backprop.html
这里是原始代码的链接: http://jsfiddle.net/Wkrgu/5/
这是我正在尝试做的,据我所知,这是我可以解释的正在发生的事情: 在计算每个节点/神经元的导数值和误差之后,我正在实现这个函数:
// Once all gradients are calculated, work forward and calculate
// the new weights. w = w + (lr * df/de * in)
for(i = 0; i < this._layers.length; i++) {
// For each neuron in each layer, ...
for(j = 0; j < this._layers[i]._neurons.length; j++) {
neuron = this._layers[i]._neurons[j];
// Modify the bias.
neuron.bias += this.options.learningRate * neuron.gradient;
// For each weight, ...
for(k = 0; k < neuron.weights.length; k++) {
// Modify the weight by multiplying the weight by the
// learning rate and the input of the neuron preceding.
// If no preceding layer, then use the input layer.
neuron.deltas[k] = this.options.learningRate * neuron.gradient * (this._layers[i-1] ? this._layers[i-1]._neurons[k].input : input[k]);
neuron.weights[k] += neuron.deltas[k];
neuron.weights[k] += neuron.momentum * neuron.previousDeltas[k];
}
// Set previous delta values.
neuron.previousDeltas = neuron.deltas.slice();
}
}
渐变属性定义为:
error = 0.0;
// So for every neuron in the following layer, get the
// weight corresponding to this neuron.
for(k = 0; k < this._layers[i+1]._neurons.length; k++) {
// And multiply it by that neuron's gradient
// and add it to the error calculation.
error += this._layers[i+1]._neurons[k].weights[j] * this._layers[i+1]._neurons[k].gradient;
}
// Once you have the error calculation, multiply it by
// the derivative of the activation function to get
// the gradient of this neuron.
neuron.gradient = output * (1 - output) * error;
我的猜测是我更新权重的速度太快,或者我通过将它们完全乘以错误的值来更新它们。与我在该主题上可以找到的公式相比,我觉得我已经非常彻底地遵循了它们,但我显然做错了一些事情。
当我使用这些训练数据时,我得到了这些结果:
a.train([0,0], [0]);
a.train([0,1], [1]);
a.train([1,0], [1]);
console.log(a.input([0,0])); // [ 0.9960981505402279 ]
console.log(a.input([1,0])); // [ 0.9957925569461975 ]
console.log(a.input([0,1])); // [ 0.9964499429402672 ]
console.log(a.input([1,1])); // [ 0.996278252201647 ]
更新: 这是固定代码的链接:http://jsfiddle.net/adamthorpeg/aUF4c/3/ 注意:在每个输入的误差都可以容忍之前不会进行训练,因此有时一旦达到一个理想值的可容忍误差,您仍然会得到不准确的结果。为了充分训练它,必须继续训练,直到所有错误都可以容忍为止。
最佳答案
我找到了问题的答案。答案是双重的:
首先,网络存在“灾难性遗忘”的问题。我一次在一个理想值/输入对上训练它,而不是循环遍历每一对并一次训练一个时期。
其次,行内:
neuron.deltas[k] = this.options.learningRate * neuron.gradient * (this._layers[i-1] ? this._layers[i-1]._neurons[k].input : input[k]);
我将学习率和梯度(导数计算)乘以前一个神经元的输入值,而不是前一个神经元的输出值,后者将作为权重计算的输入。因此,该行的正确代码应该是:
neuron.deltas[k] = this.options.learningRate * neuron.gradient * (this._layers[i-1] ? this._layers[i-1]._neurons[k].output : input[k]);
此资源非常宝贵:http://blog.zabarauskas.com/backpropagation-tutorial/
关于javascript - 反向传播训练卡住了,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22054877/