Skip to content

Commit

Permalink
new neuroevolution regression path example
Browse files Browse the repository at this point in the history
  • Loading branch information
shiffman committed Apr 16, 2020
1 parent ecf09a1 commit 8d74aa0
Show file tree
Hide file tree
Showing 4 changed files with 234 additions and 0 deletions.
16 changes: 16 additions & 0 deletions examples/p5js/NeuralNetwork/NeuroEvolution_Path/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>

<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.10.2/p5.min.js"></script>
<script src="http:https://localhost:8080/ml5.js" type="text/javascript"></script>
<meta charset="utf-8" />
</head>

<body>
<script src="population.js"></script>
<script src="particle.js"></script>
<script src="sketch.js"></script>
</body>

</html>
67 changes: 67 additions & 0 deletions examples/p5js/NeuralNetwork/NeuroEvolution_Path/particle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// The Nature of Code
// Daniel Shiffman
// http:https://natureofcode.com

class Particle {
constructor(brain) {
// All of our physics stuff
this.position = createVector(width/2, height/2);
this.acceleration = createVector();
this.velocity = createVector();
// Fitness and DNA
this.fitness = 0;
// Bird can be created with an existing neural network
if (brain) {
this.brain = brain;
} else {
// Create a new neural network
const options = {
inputs: 2,
outputs: 2,
task: 'regression',
noTraining: true
}
this.brain = ml5.neuralNetwork(options);
this.brain.mutate(1);
}
}

// fitness = one divided by distance squared
calcFitness() {
let d = p5.Vector.dist(this.position, target);
this.fitness = pow(1 / d, 2);
return this.fitness;
}

applyForce(force) {
this.acceleration.add(force);
}

// Run in relation to all the obstacles
// If I'm stuck, don't bother updating or checking for intersection
think() {
let inputs = [];
inputs[0] = this.position.x / width;
inputs[1] = this.position.y / height;
let outputs = this.brain.predictSync(inputs);
this.velocity = p5.Vector.fromAngle(outputs[0].value * TWO_PI);
this.velocity.mult(outputs[1].value * 5);

// let force = p5.Vector.fromAngle(angle);
// force.mult(mag);
// this.applyForce(force);
}


update() {
this.velocity.add(this.acceleration);
this.position.add(this.velocity);
this.acceleration.mult(0);
}

show() {
stroke(255);
fill(255, 150);
ellipse(this.position.x, this.position.y, 8);
}
}
72 changes: 72 additions & 0 deletions examples/p5js/NeuralNetwork/NeuroEvolution_Path/population.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// The Nature of Code
// Daniel Shiffman
// http:https://natureofcode.com


// A class to describe a population of particles

class Population {
constructor(total) {
this.population = [];
this.generations = 0; // Number of generations
for (let i = 0; i < total; i++) {
this.population[i] = new Particle();
}
}

update() {
for (let p of this.population) {
p.think();
p.update();
}
}

show() {
for (let p of this.population) {
p.show();
}
}

reproduce() {
let brainA = this.pickOne();
let brainB = this.pickOne();
let childBrain = brainA.crossover(brainB);
// 1% mutation rate
childBrain.mutate(0.01);
return new Particle(childBrain);
}

// Pick one parent probability according to normalized fitness
pickOne() {
let index = 0;
let r = random(1);
while (r > 0) {
r = r - this.population[index].fitness;
index++;
}
index--;
return this.population[index].brain;
}

// Normalize all fitness values
calculateFitness() {
let sum = 0;
for (let p of this.population) {
sum += p.calcFitness();
}
for (let p of this.population) {
p.fitness = p.fitness / sum;
}
}

// Making the next generation
reproduction() {
let nextPopulation = [];
// Refill the population with children from the mating pool
for (let i = 0; i < this.population.length; i++) {
nextPopulation[i] = this.reproduce();
}
this.population = nextPopulation;
this.generations++;
}
}
79 changes: 79 additions & 0 deletions examples/p5js/NeuralNetwork/NeuroEvolution_Path/sketch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// The Nature of Code
// Daniel Shiffman
// http:https://natureofcode.com


// How long should each generation live
let lifetime;
let lifeCounter;

// Population
let population;

// Target position
let target;

// Interface
let info;
let slider;

function setup() {
let canvas = createCanvas(600, 600);

// Move the target if you click on the canvas
canvas.mousePressed(function() {
target.x = mouseX;
target.y = mouseY;
});

// Improve performance for many small neural networks
ml5.tf.setBackend('cpu');

// The number of cycles we will allow a generation to live
lifetime = 200;
lifeCounter = 0;


// Arbitrary starting target
target = createVector(20, height / 2);

// Create a population N Particles
population = new Population(100);

// Interface
info = createP("");
// Slider for speeding up simulation
slider = createSlider(1, 50, 1);

}

function draw() {

// Update the population
for (let n = 0; n < slider.value(); n++) {
if (lifeCounter < lifetime) {
population.update();
lifeCounter++;
// Otherwise a new generation
} else {
lifeCounter = 0;
// Next generation
population.calculateFitness();
population.reproduction();
}

}

// Draw target
background(0);
fill(100, 255, 100);
stroke(255);
rectMode(CENTER);
rect(target.x, target.y, 24, 24);

// Show population
population.show();

// Display some info
info.html(`Generation # ${population.generations}<br>Cycles left: ${(lifetime - lifeCounter)}`);
}

0 comments on commit 8d74aa0

Please sign in to comment.