├── .gitignore ├── README.md ├── demos ├── character_recognition.js └── xor.js ├── lib ├── math.js └── neural.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Neural Network 2 | 3 | A simple Neural Network implementation. 4 | 5 | A project of [The Great Code Club](http://www.greatcodeclub.com/). 6 | 7 | ## Installation 8 | 9 | You need: 10 | 11 | - A recent version of [node](http://nodejs.org/). 12 | 13 | ## Usage 14 | 15 | See files in demos/ 16 | 17 | $ node demos/character_recognition.js 18 | 19 | ## License 20 | 21 | Copyright 2014 Coded Inc. 22 | marc@codedinc.com 23 | 24 | You are free to modify and distribute this however you want. Except for teaching purposes. 25 | -------------------------------------------------------------------------------- /demos/character_recognition.js: -------------------------------------------------------------------------------- 1 | var neural = require('../lib/neural') 2 | var network = new neural.Network() 3 | 4 | network.addLayer(10, 20) // Hidden layer, 10 neurons, 20 inputs 5 | network.addLayer(2) // Output layer, 2 neurons 6 | 7 | // Our character "images". Imagine `1`s as black pixels. 8 | var zero = [ 9 | 0, 1, 1, 0, 10 | 1, 0, 0, 1, 11 | 1, 0, 0, 1, 12 | 1, 0, 0, 1, 13 | 0, 1, 1, 0 14 | ] 15 | 16 | var one = [ 17 | 0, 0, 1, 0, 18 | 0, 0, 1, 0, 19 | 0, 0, 1, 0, 20 | 0, 0, 1, 0, 21 | 0, 0, 1, 0 22 | ] 23 | 24 | var two = [ 25 | 0, 1, 1, 0, 26 | 1, 0, 0, 1, 27 | 0, 0, 1, 0, 28 | 0, 1, 0, 0, 29 | 1, 1, 1, 1 30 | ] 31 | 32 | var three = [ 33 | 1, 1, 1, 1, 34 | 0, 0, 0, 1, 35 | 0, 1, 1, 1, 36 | 0, 0, 0, 1, 37 | 1, 1, 1, 1 38 | ] 39 | 40 | network.train([ 41 | // Training examples 42 | // inputs outputs 43 | [ zero, [0, 0] ], 44 | [ one, [0, 1] ], 45 | [ two, [1, 0] ], 46 | [ three, [1, 1] ], 47 | ]) 48 | 49 | 50 | // Querying the network 51 | var outputs = network.process([ 52 | 1, 1, 1, 1, 53 | 1, 0, 0, 1, 54 | 1, 0, 0, 1, 55 | 1, 0, 0, 1, 56 | 1, 1, 1, 0 57 | ]) 58 | // outputs === [~0, ~0] 59 | 60 | // Convert the output to binary (base 2) and then to decimal (base 10). 61 | var binary = outputs.map(function(v) { return Math.round(v) }).join("") 62 | var decimal = parseInt(binary, 2) 63 | 64 | console.log("Recognized", decimal, outputs) 65 | -------------------------------------------------------------------------------- /demos/xor.js: -------------------------------------------------------------------------------- 1 | var NeuralNetwork = require('../lib/neural').Network 2 | var network = new NeuralNetwork() 3 | 4 | // Layers 5 | network.addLayer(5, 2) // Hidden layer: 5 neurons, 2 inputs each (# inputs = # inputs to process) 6 | network.addLayer(4) // Hidden layer: 4 neurons 7 | network.addLayer(1) // Output layer: 1 neuron, outputting the result 8 | 9 | // network.trainingIterations = 500000 10 | 11 | network.train([ 12 | // Training examples 13 | // inputs outputs 14 | [ [0, 0], [0] ], 15 | [ [0, 1], [1] ], 16 | [ [1, 0], [1] ], 17 | [ [1, 1], [0] ] 18 | ]) 19 | 20 | // Querying the network 21 | var output = network.process([1, 0]) // => [1] 22 | console.log("1 XOR 0 =", Math.round(output), output) 23 | 24 | var output = network.process([0, 0]) // => [0] 25 | console.log("0 XOR 0 =", Math.round(output), output) 26 | 27 | var output = network.process([1, 1]) // => [0] 28 | console.log("1 XOR 1 =", Math.round(output), output) 29 | -------------------------------------------------------------------------------- /lib/math.js: -------------------------------------------------------------------------------- 1 | exports.rand = function rand() { 2 | return Math.random() * 0.4 - 0.2 // Random weight between -0.2 and 0.2 3 | } 4 | 5 | // Mean squared error 6 | exports.mse = function mse(errors) { 7 | var sum = errors.reduce(function(sum, i) { return sum + i * i }, 0) 8 | return sum / errors.length 9 | } 10 | 11 | exports.sum = function sum(array) { 12 | return array.reduce(function(sum, i) { return sum + i }, 0) 13 | } 14 | 15 | exports.sigmoid = function sigmoid(x) { 16 | return 1 / (1 + Math.pow(Math.E, -x)) 17 | } -------------------------------------------------------------------------------- /lib/neural.js: -------------------------------------------------------------------------------- 1 | var math = require('./math') 2 | 3 | function Neuron(numInputs) { 4 | this.weights = new Array(numInputs) 5 | this.bias = math.rand() 6 | 7 | for (var i = 0; i < this.weights.length; i++) { 8 | this.weights[i] = math.rand() 9 | } 10 | } 11 | 12 | Neuron.prototype.process = function(inputs) { 13 | this.lastInputs = inputs 14 | 15 | var sum = 0 16 | for (var i = 0; i < inputs.length; i++) { 17 | sum += inputs[i] * this.weights[i] 18 | } 19 | sum += this.bias 20 | 21 | return this.lastOutput = math.sigmoid(sum) 22 | } 23 | 24 | 25 | function Layer(numNeurons, numInputs) { 26 | this.neurons = new Array(numNeurons) 27 | 28 | for (var i = 0; i < this.neurons.length; i++) { 29 | this.neurons[i] = new Neuron(numInputs) 30 | } 31 | } 32 | 33 | Layer.prototype.process = function(inputs) { 34 | return this.neurons.map(function(neuron) { 35 | return neuron.process(inputs) 36 | }) 37 | } 38 | 39 | 40 | function Network() { 41 | this.layers = [] 42 | } 43 | exports.Network = Network 44 | 45 | Network.prototype.process = function(inputs) { 46 | var outputs 47 | this.layers.forEach(function(layer) { 48 | outputs = layer.process(inputs) 49 | inputs = outputs 50 | }) 51 | return outputs 52 | } 53 | 54 | Network.prototype.addLayer = function(numNeurons, numInputs) { 55 | if (numInputs == null) { 56 | var previousLayer = this.layers[this.layers.length - 1] 57 | numInputs = previousLayer.neurons.length 58 | } 59 | 60 | var layer = new Layer(numNeurons, numInputs) 61 | this.layers.push(layer) 62 | } 63 | 64 | // Stop training when mean squared error of all output neurons reach this threshold 65 | Network.prototype.errorThreshold = 0.00001 66 | 67 | // Number of iterations on each training 68 | Network.prototype.trainingIterations = 500000 69 | 70 | // Rate at which the network learns in each iteration 71 | Network.prototype.learningRate = 0.3 72 | 73 | Network.prototype.train = function(examples) { 74 | var outputLayer = this.layers[this.layers.length - 1] 75 | 76 | for (var it = 0; it < this.trainingIterations; it++) { 77 | 78 | for (var e = 0; e < examples.length; e++) { 79 | var inputs = examples[e][0] 80 | var targets = examples[e][1] 81 | 82 | var outputs = this.process(inputs) 83 | 84 | for (var i = 0; i < outputLayer.neurons.length; i++) { 85 | var neuron = outputLayer.neurons[i] 86 | 87 | neuron.error = targets[i] - outputs[i] 88 | 89 | // Keep track of the error of each examples to determine when to stop training. 90 | neuron.errors = neuron.errors || [] 91 | neuron.errors[e] = neuron.error 92 | 93 | neuron.delta = neuron.lastOutput * (1 - neuron.lastOutput) * neuron.error 94 | } 95 | 96 | for (var l = this.layers.length - 2; l >= 0; l--) { 97 | for (var j = 0; j < this.layers[l].neurons.length; j++) { 98 | var neuronJ = this.layers[l].neurons[j] 99 | 100 | neuronJ.error = math.sum(this.layers[l + 1].neurons. 101 | map(function(n) { return n.weights[j] * n.delta })) 102 | neuronJ.delta = neuronJ.lastOutput * (1 - neuronJ.lastOutput) * neuronJ.error 103 | 104 | for (var i = 0; i < this.layers[l + 1].neurons.length; i++) { 105 | var neuronI = this.layers[l + 1].neurons[i] 106 | 107 | for (var w = 0; w < neuronI.weights.length; w++) { 108 | neuronI.weights[w] += this.learningRate * neuronI.lastInputs[w] * neuronI.delta 109 | } 110 | neuronI.bias += this.learningRate * neuronI.delta 111 | } 112 | } 113 | } 114 | } 115 | 116 | // Compute the mean squared error for all examples. 117 | var error = math.mse(outputLayer.neurons. 118 | reduce(function(errors, n) { return errors.concat(n.errors) }, [])) 119 | 120 | if (it % 10000 === 0) { 121 | console.log({ iteration: it, mse: error }) 122 | } 123 | 124 | if (error <= this.errorThreshold) { 125 | return 126 | } 127 | 128 | } 129 | 130 | } 131 | 132 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "neural", 3 | "version": "0.0.1", 4 | "description": "A simple Neural Network", 5 | "main": "lib/neural.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/greatcodeclub/neural.git" 9 | }, 10 | "keywords": [ 11 | "ai", 12 | "neural-network" 13 | ], 14 | "author": "Marc-Andre Cournoyer", 15 | "bugs": { 16 | "url": "https://github.com/greatcodeclub/neural/issues" 17 | } 18 | } 19 | --------------------------------------------------------------------------------