done
commit
1a5e352c09
@ -0,0 +1,162 @@
|
|||||||
|
class NeuralNetwork
|
||||||
|
{
|
||||||
|
constructor(numInputs, numOutputs, numHiddenLayers, numNeuronsPerHiddenLayer)
|
||||||
|
{
|
||||||
|
|
||||||
|
this.numInputs = numInputs;
|
||||||
|
this.numOutputs = numOutputs;
|
||||||
|
this.numHiddenLayers = numHiddenLayers;
|
||||||
|
this.numNeuronsPerHiddenLayer = numNeuronsPerHiddenLayer;
|
||||||
|
|
||||||
|
this.bias = 0.0;
|
||||||
|
this.activationResponse = 1.0;
|
||||||
|
this.neuronLayers = [];
|
||||||
|
|
||||||
|
this.createNetwork();
|
||||||
|
}
|
||||||
|
|
||||||
|
createNetwork()
|
||||||
|
{
|
||||||
|
|
||||||
|
//create the layers of the network
|
||||||
|
if (this.numHiddenLayers > 0)
|
||||||
|
{
|
||||||
|
//create first hidden layer
|
||||||
|
var firstHiddenLayer = new NeuronLayer(this.numNeuronsPerHiddenLayer, this.numInputs);
|
||||||
|
this.neuronLayers.push(firstHiddenLayer);
|
||||||
|
|
||||||
|
for (var i=0; i<this.numHiddenLayers-1; ++i)
|
||||||
|
{
|
||||||
|
var newHiddenLayer = new NeuronLayer(this.numNeuronsPerHiddenLayer, this.numNeuronsPerHiddenLayer);
|
||||||
|
this.neuronLayers.push(newHiddenLayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
//create output layer
|
||||||
|
var outputLayer = new NeuronLayer(this.numOutputs, this.numNeuronsPerHiddenLayer);
|
||||||
|
this.neuronLayers.push(outputLayer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//create output layer
|
||||||
|
var outputLayer = new NeuronLayer(this.numOutputs, this.numInputs);
|
||||||
|
this.neuronLayers.push(outputLayer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update(inputs)
|
||||||
|
{
|
||||||
|
|
||||||
|
var outputs = [];
|
||||||
|
|
||||||
|
var cWeight = 0;
|
||||||
|
|
||||||
|
// If the number of inputs supplied is incorrect...
|
||||||
|
if (inputs.length!=this.numInputs)
|
||||||
|
{
|
||||||
|
return outputs; // Return empty outputs
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop through all layers
|
||||||
|
var inputLayer = true;
|
||||||
|
for (var i=0; i < this.numHiddenLayers + 1; ++i)
|
||||||
|
{
|
||||||
|
var neuronLayer = this.neuronLayers[i];
|
||||||
|
|
||||||
|
if (!inputLayer)
|
||||||
|
{
|
||||||
|
inputs = [];
|
||||||
|
inputs = inputs.concat(outputs);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
inputLayer = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
outputs = [];
|
||||||
|
|
||||||
|
cWeight = 0;
|
||||||
|
|
||||||
|
// For each neuron sum the (inputs * corresponding weights).
|
||||||
|
// Throw the total at our sigmoid function to get the output.
|
||||||
|
for (var j=0; j < neuronLayer.neurons.length; ++j)
|
||||||
|
{
|
||||||
|
var neuron = neuronLayer.neurons[j];
|
||||||
|
|
||||||
|
var totalInput = 0;
|
||||||
|
|
||||||
|
// For each weight...
|
||||||
|
for (var k=0; k < neuron.numInputs ; ++k) // -1 ???
|
||||||
|
{
|
||||||
|
// Multiply it with the input.
|
||||||
|
totalInput += neuron.weights[k] *
|
||||||
|
inputs[cWeight];
|
||||||
|
console.log("cweight "+cWeight);
|
||||||
|
console.log("neuron weight "+neuron.weights[k]);
|
||||||
|
console.log("input: "+inputs[cWeight]);
|
||||||
|
console.log("total input "+totalInput);
|
||||||
|
|
||||||
|
|
||||||
|
cWeight++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add in the bias (final weight)
|
||||||
|
// totalInput += neuron.weights[neuron.weights.length-1] * this.bias;
|
||||||
|
|
||||||
|
// We can store the outputs from each layer as we generate them.
|
||||||
|
// The combined activation is first filtered through the sigmoid function
|
||||||
|
outputs.push(this.sigmoid(totalInput, this.activationResponse));
|
||||||
|
|
||||||
|
cWeight = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return outputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
sigmoid(totalInput, activationResponse)
|
||||||
|
{
|
||||||
|
return ( 1 / ( 1 + Math.exp(-totalInput / activationResponse)));
|
||||||
|
}
|
||||||
|
|
||||||
|
getWeights()
|
||||||
|
{
|
||||||
|
var weights = [];
|
||||||
|
|
||||||
|
//for each layer
|
||||||
|
for (var i=0; i<this.numHiddenLayers + 1; ++i)
|
||||||
|
{
|
||||||
|
|
||||||
|
//for each neuron
|
||||||
|
for (var j=0; j<this.neuronLayers[i].neurons.length; ++j)
|
||||||
|
{
|
||||||
|
//for each weight
|
||||||
|
for (var k=0; k<this.neuronLayers[i].neurons[j].numInputs; ++k)
|
||||||
|
{
|
||||||
|
weights.push(this.neuronLayers[i].neurons[j].weights[k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return weights;
|
||||||
|
}
|
||||||
|
|
||||||
|
setWeights(weights)
|
||||||
|
{
|
||||||
|
var cWeight = 0;
|
||||||
|
|
||||||
|
//for each layer
|
||||||
|
for (var i=0; i<this.numHiddenLayers + 1; ++i)
|
||||||
|
{
|
||||||
|
|
||||||
|
//for each neuron
|
||||||
|
for (var j=0; j<this.neuronLayers[i].neurons.length; ++j)
|
||||||
|
{
|
||||||
|
//for each weight
|
||||||
|
for (var k=0; k<this.neuronLayers[i].neurons[j].numInputs; ++k)
|
||||||
|
{
|
||||||
|
this.neuronLayers[i].neurons[j].weights[k] = weights[cWeight++];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
class Neuron
|
||||||
|
{
|
||||||
|
constructor(numInputs)
|
||||||
|
{
|
||||||
|
this.weights = [];
|
||||||
|
this.numInputs = numInputs;
|
||||||
|
|
||||||
|
for (var i=0; i<numInputs+1; ++i)
|
||||||
|
{
|
||||||
|
var newWeight = -1 + (Math.random()*2);
|
||||||
|
//var newWeight = 1;
|
||||||
|
this.weights.push(newWeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
class NeuronLayer
|
||||||
|
{
|
||||||
|
constructor(numNeuronsPerHiddenLayer, numInputs)
|
||||||
|
{
|
||||||
|
this.neurons = [];
|
||||||
|
|
||||||
|
for (var i = 0; i < numNeuronsPerHiddenLayer; ++i)
|
||||||
|
{
|
||||||
|
var newNeuron = new Neuron(numInputs);
|
||||||
|
|
||||||
|
this.neurons.push(newNeuron);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,225 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<script src="NeuralNetwork.js"></script>
|
||||||
|
<script src="Neuron.js"></script>
|
||||||
|
<script src="NeuronLayer.js"></script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
body{
|
||||||
|
padding:0;
|
||||||
|
margin:0;
|
||||||
|
overflow:hidden;
|
||||||
|
font-family:Helvetica;
|
||||||
|
font-size:10px;
|
||||||
|
}
|
||||||
|
input{
|
||||||
|
padding:0;
|
||||||
|
}
|
||||||
|
p{
|
||||||
|
padding:0;
|
||||||
|
margin:0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#input{
|
||||||
|
position:absolute;
|
||||||
|
top:100px;
|
||||||
|
left:10px;
|
||||||
|
}
|
||||||
|
#first_layer{
|
||||||
|
position:absolute;
|
||||||
|
top: 100px;
|
||||||
|
left: 200px;
|
||||||
|
}
|
||||||
|
#second_layer{
|
||||||
|
position:absolute;
|
||||||
|
top: 100px;
|
||||||
|
left: 400px;
|
||||||
|
}
|
||||||
|
#output{
|
||||||
|
position:absolute;
|
||||||
|
top: 100px;
|
||||||
|
left: 600px;
|
||||||
|
}
|
||||||
|
#network_container{
|
||||||
|
position:absolute;
|
||||||
|
top: 100px;
|
||||||
|
left: 600px;
|
||||||
|
margin-left:-400px;
|
||||||
|
margin-top:-250px;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<canvas id="myCanvas" width="100%" height="100%"></canvas>
|
||||||
|
<div id="network_container">
|
||||||
|
<div id="input">
|
||||||
|
|
||||||
|
|
||||||
|
<input type="range" min="0" max="100" value="1" class="i0" id="i0">
|
||||||
|
<p id="i0_output"></p>
|
||||||
|
<input type="range" min="0" max="100" value="10" class="i1" id="i1">
|
||||||
|
<p id="i1_output"></p>
|
||||||
|
</div>
|
||||||
|
<div id = "first_layer">
|
||||||
|
<input type="range" min="-400" max="400" value="10" class="w0" id="w0">
|
||||||
|
<p id="w0_output"></p>
|
||||||
|
<input type="range" min="-400" max="400" value="10" class="w1" id="w1">
|
||||||
|
<p id="w1_output"></p><br><br>
|
||||||
|
<input type="range" min="-400" max="400" value="10" class="w2" id="w2">
|
||||||
|
<p id="w2_output"></p>
|
||||||
|
<input type="range" min="-400" max="400" value="10" class="w3" id="w3">
|
||||||
|
<p id="w3_output"></p><br><br>
|
||||||
|
<input type="range" min="-400" max="400" value="10" class="w4" id="w4">
|
||||||
|
<p id="w4_output"></p>
|
||||||
|
<input type="range" min="-400" max="400" value="10" class="w5" id="w5">
|
||||||
|
<p id="w5_output"></p>
|
||||||
|
</div>
|
||||||
|
<div id = "second_layer">
|
||||||
|
<input type="range" min="-400" max="400" value="10" class="w6" id="w6">
|
||||||
|
<p id="w6_output"></p>
|
||||||
|
<input type="range" min="-400" max="400" value="10" class="w7" id="w7">
|
||||||
|
<p id="w7_output"></p>
|
||||||
|
<input type="range" min="-400" max="400" value="10" class="w8" id="w8">
|
||||||
|
<p id="w8_output"></p><br><br>
|
||||||
|
<input type="range" min="-400" max="400" value="10" class="w9" id="w9">
|
||||||
|
<p id="w9_output"></p>
|
||||||
|
<input type="range" min="-400" max="400" value="10" class="w10" id="w10">
|
||||||
|
<p id="w10_output"></p>
|
||||||
|
<input type="range" min="-400" max="400" value="10" class="w11" id="w11">
|
||||||
|
<p id="w11_output"></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="output">
|
||||||
|
<input id="clickMe" type="button" value="update network" onclick="update();" />
|
||||||
|
<input id="random" type="button" value="random network" onclick="random();" />
|
||||||
|
|
||||||
|
<p id="network_output"></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
var numInputs = 2;
|
||||||
|
var numOutputs = 2;
|
||||||
|
var numHiddenLayers = 1;
|
||||||
|
var numNeuronsPerHiddenLayer = 3;
|
||||||
|
|
||||||
|
var slider = [];
|
||||||
|
var output = [];
|
||||||
|
|
||||||
|
var neuralNetwork = new NeuralNetwork(numInputs, numOutputs, numHiddenLayers, numNeuronsPerHiddenLayer);
|
||||||
|
|
||||||
|
|
||||||
|
var input0 = document.getElementById("i0")
|
||||||
|
var input_display0 = document.getElementById("i0_output")
|
||||||
|
input_display0.innerHTML = input0.value/100;
|
||||||
|
input0.oninput = function() {
|
||||||
|
input_display0.innerHTML = this.value/100;
|
||||||
|
}
|
||||||
|
var input1 = document.getElementById("i1")
|
||||||
|
var input_display1 = document.getElementById("i1_output")
|
||||||
|
input_display1.innerHTML = input1.value/100;
|
||||||
|
input1.oninput = function() {
|
||||||
|
input_display1.innerHTML = this.value/100;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//slider
|
||||||
|
for (var i = 0; i<12; i++){
|
||||||
|
slider.push(document.getElementById("w"+i));
|
||||||
|
output.push(document.getElementById("w"+i+"_output"));
|
||||||
|
output[i].innerHTML = slider[i].value/100;
|
||||||
|
slider[i].oninput = function() {
|
||||||
|
output[slider.indexOf(this)].innerHTML = this.value/100;
|
||||||
|
|
||||||
|
updateCanvas()
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('mousemove', function(e) {
|
||||||
|
console.log("move")
|
||||||
|
var x = e.clientX / window.innerWidth;
|
||||||
|
var y = e.clientY / window.innerHeight;
|
||||||
|
input0.value=x*100;
|
||||||
|
input1.value=y*100;
|
||||||
|
input_display0.innerHTML = x;
|
||||||
|
input_display1.innerHTML = y;
|
||||||
|
update([x,y])
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
//CANVAS STUFF
|
||||||
|
var c = document.getElementById("myCanvas");
|
||||||
|
var ctx = c.getContext("2d");
|
||||||
|
ctx.canvas.width = window.innerWidth;
|
||||||
|
ctx.canvas.height = window.innerHeight;
|
||||||
|
var stepsize = 50;
|
||||||
|
for(var x = 0; x < window.innerWidth; x = x+stepsize){
|
||||||
|
for(var y = 0; y < window.innerHeight; y = y+stepsize){
|
||||||
|
var outputs = neuralNetwork.update([x/window.innerWidth,y/window.innerHeight]);
|
||||||
|
ctx.fillStyle = 'hsl(' + 360 * outputs[0] + ', 50%,'+outputs[1]*100 +'%)';
|
||||||
|
//ctx.fillStyle= "rgb(255,20,255);"
|
||||||
|
console.log(outputs[1]*255)
|
||||||
|
ctx.fillRect(x,y,stepsize,stepsize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function updateCanvas(){
|
||||||
|
|
||||||
|
var stepsize = 50;
|
||||||
|
for(var x = 0; x < window.innerWidth; x = x+stepsize){
|
||||||
|
for(var y = 0; y < window.innerHeight; y = y+stepsize){
|
||||||
|
var outputs = neuralNetwork.update([x/window.innerWidth,y/window.innerHeight]);
|
||||||
|
ctx.fillStyle = 'hsl(' + 360 * outputs[0] + ', 90%,'+outputs[1]*100+'%)';
|
||||||
|
//ctx.fillStyle= "rgb(255,20,255);"
|
||||||
|
console.log(outputs[1]*255)
|
||||||
|
ctx.fillRect(x,y,stepsize,stepsize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function update(inputs){
|
||||||
|
|
||||||
|
|
||||||
|
var weights = neuralNetwork.getWeights();
|
||||||
|
var newWeights = [];
|
||||||
|
for (var i=0; i < weights.length; i++) {
|
||||||
|
newWeights.push(slider[i].value/100);
|
||||||
|
//newWeights.push(1);
|
||||||
|
}
|
||||||
|
neuralNetwork.setWeights(newWeights);
|
||||||
|
|
||||||
|
|
||||||
|
//var inputs = [input0.value/100, input1.value/100];
|
||||||
|
var outputs = neuralNetwork.update(inputs);
|
||||||
|
// console.log(neuralNetwork.getWeights());
|
||||||
|
var output_display = document.getElementById("network_output")
|
||||||
|
output_display.innerHTML = "<br> "+outputs[0] + "<br><br> "+outputs [1];
|
||||||
|
|
||||||
|
document.getElementById('network_container').style.left=outputs[0]*window.innerWidth;
|
||||||
|
document.getElementById('network_container').style.top=outputs[1]*window.innerHeight;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
random()
|
||||||
|
function random(inputs){
|
||||||
|
|
||||||
|
for (var i = 0; i<slider.length; i++){
|
||||||
|
|
||||||
|
slider[i].value = Math.random()*800-400;
|
||||||
|
output[slider.indexOf(slider[i])].innerHTML = slider[i].value/100;
|
||||||
|
}
|
||||||
|
updateCanvas();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue