JavaScript中的神经网络学习不当

我尝试将这里找到的神经网络重写为JavaScript。我的JavaScript代码如下所示。

function NeuralFactor(weight) {    var self = this;    this.weight = weight;    this.delta =  0;}function Sigmoid(value) {    return 1 / (1 + Math.exp(-value));}function Neuron(isInput) {    var self = this;    this.pulse = function() {        self.output = 0;        self.input.forEach(function(item) {            self.output += item.signal.output * item.factor.weight;        });        self.output += self.bias.weight;        self.output = Sigmoid(self.output);    };    this.bias = new NeuralFactor(isInput ? 0 : Math.random());    this.error = 0;    this.input = [];    this.output = 0;    this.findInput = function(signal) {        var input = self.input.filter(function(input) {            return signal == input.signal;        })[0];        return input;    };}function NeuralLayer() {    var self = this;    this.pulse = function() {        self.neurons.forEach(function(neuron) {            neuron.pulse();        });    };    this.neurons = [];    this.train = function(learningRate) {        self.neurons.forEach(function(neuron) {            neuron.bias.weight += neuron.bias.delta * learningRate;            neuron.bias.delta = 0;            neuron.input.forEach(function(input) {                input.factor.weight += input.factor.delta * learningRate;                input.factor.delta = 0;            })        })    }}function NeuralNet(inputCount, hiddenCount, outputCount) {    var self = this;    this.inputLayer = new NeuralLayer();    this.hiddenLayer = new NeuralLayer();    this.outputLayer = new NeuralLayer();    this.learningRate = 0.5;    for(var i = 0; i < inputCount; i++)        self.inputLayer.neurons.push(new Neuron(true));    for(var i = 0; i < hiddenCount; i++)        self.hiddenLayer.neurons.push(new Neuron());    for(var i = 0; i < outputCount; i++)        self.outputLayer.neurons.push(new Neuron());    for (var i = 0; i < hiddenCount; i++)        for (var j = 0; j < inputCount; j++)            self.hiddenLayer.neurons[i].input.push({                signal: self.inputLayer.neurons[j],                factor: new NeuralFactor(Math.random())            });    for (var i = 0; i < outputCount; i++)        for (var j = 0; j < hiddenCount; j++)            self.outputLayer.neurons[i].input.push({                signal: self.hiddenLayer.neurons[j],                factor: new NeuralFactor(Math.random())            });    this.pulse = function() {        self.hiddenLayer.pulse();        self.outputLayer.pulse();    };    this.backPropagation = function(desiredResults) {        for(var i = 0; i < self.outputLayer.neurons.length; i++) {            var outputNeuron = self.outputLayer.neurons[i];            var output = outputNeuron.output;            outputNeuron.error = (desiredResults[i] - output) * output * (1.0 - output);        }        for(var i = 0; i < self.hiddenLayer.neurons.length; i++) {            var hiddenNeuron = self.hiddenLayer.neurons[i];            var error = 0;            for(var j = 0; j < self.outputLayer.neurons.length; j++) {                var outputNeuron = self.outputLayer.neurons[j];                error += outputNeuron.error * outputNeuron.findInput(hiddenNeuron).factor.weight * hiddenNeuron.output * (1.0 - hiddenNeuron.output);            }            hiddenNeuron.error = error;        }        for(var j = 0; j < self.outputLayer.neurons.length; j++) {            var outputNeuron = self.outputLayer.neurons[j];            for(var i = 0; i < self.hiddenLayer.neurons.length; i++) {                var hiddenNeuron = self.hiddenLayer.neurons[i];                outputNeuron.findInput(hiddenNeuron).factor.delta += outputNeuron.error * hiddenNeuron.output;            }            outputNeuron.bias.delta += outputNeuron.error * outputNeuron.bias.weight;        }        for(var j = 0; j < self.hiddenLayer.neurons.length; j++) {            var hiddenNeuron = self.hiddenLayer.neurons[j];            for(var i = 0; i < self.inputLayer.neurons.length; i++) {                var inputNeuron = self.inputLayer.neurons[i];                hiddenNeuron.findInput(inputNeuron).factor.delta += hiddenNeuron.error * inputNeuron.output;            }            hiddenNeuron.bias.delta += hiddenNeuron.error * hiddenNeuron.bias.weight;        }    };    this.train = function(input, desiredResults) {        for(var i = 0; i < self.inputLayer.neurons.length; i++) {            var neuron = self.inputLayer.neurons[i];            neuron.output = input[i];        }        self.pulse();        self.backPropagation(desiredResults);        self.hiddenLayer.train(self.learningRate);        self.outputLayer.train(self.learningRate);    };}

现在我正在尝试让它学习如何解决XOR问题。我的训练方法如下:

var net = new NeuralNet(2,2,1);var testInputs = [[0,0], [0,1], [1,0], [1,1]];var testOutputs = [[1],[0],[0],[1]];for (var i = 0; i < 1000; i++)    for(var j = 0; j < 4; j++)        net.train(testInputs[j], testOutputs[j]);function UseNet(a, b) {    net.inputLayer.neurons[0].output = a;    net.inputLayer.neurons[1].output = b;    net.pulse();    return net.outputLayer.neurons[0].output;}

问题是无论我使用什么参数,得到的所有结果都接近0.5且相当随机。例如:

UseNet(0,0) => 0.5107701166677714UseNet(0,1) => 0.4801498747476413UseNet(1,0) => 0.5142463167153447UseNet(1,1) => 0.4881829364416052

我的代码可能有什么问题?


回答:

这个网络对于解决XOR问题来说足够大,我看不出有什么明显的错误,所以我怀疑它陷入了局部最小值。

尝试将训练集遍历10,000次而不是1000次,这样它有更好的机会摆脱任何局部最小值并收敛。你还可以通过增加隐藏神经元的数量、调整学习率η或添加动量来大大提高收敛速度。要实现后者,尝试使用以下作为你的训练函数:

this.train = function(learningRate) {    var momentum = 0 /* 某个值,可能是相当小的。 */;    self.neurons.forEach(function(neuron) {        neuron.bias.weight += neuron.bias.delta * learningRate;        neuron.bias.delta = 0;        neuron.input.forEach(function(input) {            input.factor.weight += (input.factor.delta * learningRate) + (input.factor.weight * momentum);            input.factor.delta = 0;        })    })}

我通过将学习率调整为1.5(相当高)和动量调整为0.000001(相当小)取得了不错的效果。

(顺便问一下,你有没有尝试用不同的种子运行.NET实现?它也可能需要相当长的时间才能收敛!)

Related Posts

L1-L2正则化的不同系数

我想对网络的权重同时应用L1和L2正则化。然而,我找不…

使用scikit-learn的无监督方法将列表分类成不同组别,有没有办法?

我有一系列实例,每个实例都有一份列表,代表它所遵循的不…

f1_score metric in lightgbm

我想使用自定义指标f1_score来训练一个lgb模型…

通过相关系数矩阵进行特征选择

我在测试不同的算法时,如逻辑回归、高斯朴素贝叶斯、随机…

可以将机器学习库用于流式输入和输出吗?

已关闭。此问题需要更加聚焦。目前不接受回答。 想要改进…

在TensorFlow中,queue.dequeue_up_to()方法的用途是什么?

我对这个方法感到非常困惑,特别是当我发现这个令人费解的…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注