简体   繁体   中英

Javascript neural network not converging

I've been trying to evolve a neural network that prints values converging to one, using a genetic algorithm.

I've tried debugging the code but don't know what I've messed up.

I'm using fitness to chose the best "brains" and then cross them over (reproduce).

At the moment it is only trying to evolve "brains" that return the number. the fitness is a function of the difference between returned number and original number.

"use strict";



function sigmoid(x) {

    return 1 / (1 + Math.E ** -x);

}



function random(min, max) {

    return (max - min) * Math.random() + min

}



function toss() {

    return random(-1, 1)

}



function Brain(inputs, hiddens, outputs) {

    this.structure = [...arguments];

    if (this.structure.length < 3) throw "Invalid layer count";

    this.layers = [];

    this.layers[this.structure.length - 1] = {

        nodes: []

    };

    for (var i = this.structure.length - 1; i--;) this.layers[i] = {

        bias: toss(),

        nodes: []

    };

    for (var i = 1; i < this.structure.length; i++) {

        var nodes = this.layers[i].nodes;;

        for (var j = this.structure[i]; j--;) {

            var node = nodes[j] = {

                weights: []

            };

            for (var k = this.structure[i - 1]; k--;) node.weights[k] = toss();

        }

    };

}



Brain.prototype.compute = function() {

    if (arguments[0] !== this.structure[0]) throw "Invalid input count";

    for (var i = arguments.length; i--;) this.layers[0].nodes[i] = {

        value: arguments[i]

    };

    for (var i = 1; i < this.layers.length - 1; i++) {

        var layer = this.layers[i];

        var feeder = this.layers[i - 1];

        for (var j = layer.nodes.length; j--;) {

            var node = layer.nodes[j];

            var dot = 0;

            for (var k = node.weights.length; k--;) dot += node.weights[k] * feeder.nodes[k].value;

            node.value = sigmoid(dot + feeder.bias);

        }

    }

    var result = [];

    var layer = this.layers[this.layers.length - 1];

    var feeder = this.layers[this.layers.length - 2];

    for (var j = layer.nodes.length; j--;) {

        var node = layer.nodes[j];

        var dot = 0;

        for (var k = node.weights.length; k--;) dot += node.weights[k] * feeder.nodes[k].value;

        result[j] = sigmoid(dot + feeder.bias);

    }

    return result;

}

Brain.prototype.cross = function() {

    var newBrain = new Brain(...this.structure);

    var brains = [this, ...arguments];

    for (var i = 1; i < newBrain.layers.length; i++) {

        var layer = newBrain.layers[i];

        for (var j = layer.nodes.length; j--;) {

            var node = layer.nodes[j];

            for (var k = node.weights.length; k--;) node.weights[k] = mutate() ||

                brains[Math.floor(Math.random() * brains.length)]

                .layers[i].nodes[j].weights[k];

        }

    }

    for (var i = newBrain.layers.length - 1; i--;) newBrain.layers[i].bias = mutate() ||

        brains[Math.floor(Math.random() * brains.length)]

        .layers[i].bias;

    return newBrain;

}



function mutate(key, nodes) {

    if (Math.random() > 0.05) return toss();

}



var brain = new Brain(1, 5, 1);

var newBrain = new Brain(1, 5, 1)

var result = brain.compute(1);

var cross = brain.cross(newBrain);



var brains = [];

for (var node = 45; node--;) brains.push({

    brain: new Brain(1, 5, 4, 3, 2, 1)

});

for (var count = 1000000; count--;) {

    brains.push({

        brain: new Brain(1, 5, 4, 3, 2, 1)

    });

    for (var node = brains.length; node--;) {

        var brain = brains[node];

        var number = 1;

        var target = number;

        brain.fitness = 1 / Math.abs(number - brain.brain.compute(number));

    }

    brains.sort((a, b) => a.fitness < b.fitness);

    if (count % 10000 === 0) console.log(brains.length, brains[0].fitness);



    var newBrains = [];

    for (var node = 10; node--;)

        for (var j = node; j--;) newBrains.push({

            brain: brains[node].brain.cross(brains[j].brain)

        });

    brains = newBrains;

}

console.log(brains);

What will I need to improve/change?

Here is the console log:

46 1.468903884218341

46 1.1881817088540865

46 4.899728181582378

46 1.5494097713447523

46 2.4958253537304644

46 2.4091648830940953

46 1.4000955420478967

46 1.7560836401632383

46 3.3419380735652897

46 2.8290305398668245

46 2.951901023302089

46 2.9400525658126675

46 2.6769575714598948

46 1.55835425177616

As you can see, the fitness seems to be random

Some advice...

  1. Neural networks usually take an input which should somehow be related to the output. I couldn't find any inputs for the network? If you can't come up with any good ideas just use the XOR problem and try to solve it.

  2. When checking if your population is becoming better over time don't look at all brains of each generation. Remember, you are intentionally creating some randomized networks which may or may not be good at your task. Try printing the Top result of each generation and maybe the average score. In a working genetic algorithm both values should become better over time. (altough the top score is way more significant & important)

  3. (Not directly adressing your issue) Don't use javascript. You could probably transscribe your current code to java/c#/c++. These languages execute way faster than JS.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM