Javascript 中的神经网络无法正确学习

Posted

技术标签:

【中文标题】Javascript 中的神经网络无法正确学习【英文标题】:Neural network in Javascript not learning properly 【发布时间】:2014-04-24 21:30:05 【问题描述】:

我尝试将找到的神经网络 here 重写为 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.5107701166677714
UseNet(0,1) => 0.4801498747476413
UseNet(1,0) => 0.5142463167153447
UseNet(1,1) => 0.4881829364416052

我的代码有什么问题?

【问题讨论】:

离题:您可以在原型中定义大多数方法,而不是在每个实例中。 一定要通读***.com/questions/13998970/… 真的令人印象深刻!嗨,我真的很想看到这个在行动。您是否将其托管在具有功能示例代码和某种界面(可以是斯巴达式)的某个地方我不知道如何触发它开始学习以及如何转储输出以查看结果?...令人着迷的东西. 【参考方案1】:

该系统使用模糊逻辑。正如文章中所说,不要使用整数,而是使用文章建议的“接近”实数——试试

UseNet(0.1,0.1) => 
UseNet(0.1,0.9) => 
UseNet(0.9,0.1) => 
UseNet(0.9,0.9) => 

对于结果,任何高于 0.5 的都是 1,低于 0 是 0

【讨论】:

你是对的,这是一个错误,需要修复,但仍然没有完全帮助,结果也不正确。【参考方案2】:

这个网络足够大,可以解决 XOR 问题,我看不到任何明显的错误,所以我怀疑它陷入了局部最小值。

尝试遍历训练集 10,000 次而不是 1000 次;这使它有更好的机会突破任何最小值并收敛。您还可以通过增加隐藏神经元的数量、调整 η(学习率)或增加动量来大大提高收敛性。要实现后者,请尝试将其用作您的训练函数:

this.train = function(learningRate) 
    var momentum = 0 /* Some value, probably fairly small. */;
    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 实现?它也可能需要 相当 一段时间才能收敛!)

【讨论】:

你是对的,它只是关于参数的优化。学习率越高,效果越好。【参考方案3】:

嗯嗯

尝试代替:

var testInputs = [[0,0], [0,1], [1,0], [1,1]];
var testOutputs = [[1],[0],[0],[1]];

这个:

var testInputs = [[0.05,0.05], [0.05,0.95], [0.95,0.05], [0.95,0.95]];
var testOutputs = [[1],[0],[0],[1]];

var testInputs = [[0,0], [0,1], [1,0], [1,1]];
var testOutputs = [[0.95],[0.05],[0.05],[0.95]];

【讨论】:

你是对的,这是一个错误,需要修复,但仍然没有完全帮助,结果也不正确。

以上是关于Javascript 中的神经网络无法正确学习的主要内容,如果未能解决你的问题,请参考以下文章

AI开发者指南丨如何正确理解神经网络和深度学习?

人工智能深度学习神经网络在双色球彩票中的应用研究

机器学习神经网络实现异或(XOR)

神经网络中啥是交叉验证,为啥要进行交叉验证?

使用JavaScript实现机器学习和神经学网络

TensorFlow 卷积神经网络--卷积层