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...
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.
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)
(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.