Skip to content

Instantly share code, notes, and snippets.

@GuilhermeRossato
Created February 29, 2020 21:34
Show Gist options
  • Save GuilhermeRossato/dcc28716fa4700d24b7ac862d36e5dde to your computer and use it in GitHub Desktop.
Save GuilhermeRossato/dcc28716fa4700d24b7ac862d36e5dde to your computer and use it in GitHub Desktop.
Simple Artificial Network with Javascript
var sigmoid_lookup_size = 128;
var sigmoid_lookup = (new Float32Array(sigmoid_lookup_size+1)).map((a,i) => 1/(1+Math.exp(-(i-(sigmoid_lookup_size/2))/(sigmoid_lookup_size/32))));
function real_sigmoid(x) {
return 1 / (1 + Math.exp(-x));
}
function cached_sigmoid(x) {
if (x < -16) {
return -16;
} else if (x >= 16) {
return 16;
}
const position = x * (sigmoid_lookup_size/32) + sigmoid_lookup_size / 2;
const i = position|0;
if (i+1 > sigmoid_lookup_size) {
return 1;
} else if (i < 0) {
return 0;
}
const diff = position - i;
return sigmoid_lookup[i] * (1 - diff) + sigmoid_lookup[i+1] * diff;
}
class NeuralNetwork {
constructor(inputs, hidden_layers, hidden, outputs) {
if (inputs < 1 || hidden_layers < 0 || outputs < 1) {
throw new Error("Invalid parameters");
}
const hidden_weights = hidden_layers <= 0 ? 0 : (inputs+1) * hidden + (hidden_layers-1) * (hidden+1) * hidden;
const output_weights = (hidden_layers ? (hidden+1) : (inputs+1)) * outputs;
const total_weights = (hidden_weights + output_weights);
const total_neurons = (inputs + hidden * hidden_layers + outputs);
let size = 4 + 2 + (total_weights + total_neurons + total_neurons - inputs);
size -= outputs;
const data = this.data = new Float32Array(size);
data[0] = this.inputs = inputs;
data[1] = this.hidden_layers = hidden_layers;
data[2] = this.hidden = hidden;
data[3] = this.outputs = outputs;
data[4] = this.total_weights = total_weights;
data[5] = this.total_neurons = total_neurons;
this.weight = 6;
this.output = this.weight + total_weights;
this.delta = this.output + total_neurons;
this.random = Math.random;
this.randomize();
this.sigmoid = cached_sigmoid;
}
randomize() {
for (let i = 0; i < this.total_weights; i++) {
this.data[this.weight + i] = this.random() - 0.5;
}
}
act_output(sum) {
return this.sigmoid(sum);
}
run(inputs) {
if (inputs.length !== this.inputs) {
throw new Error("Input doest not match, expected "+this.inputs+", got "+inputs.length);
}
let w = this.weight;
let o = this.output + this.inputs;
let i = this.output;
let h, j, k;
const result = new Float32Array(this.outputs);
// Treat first layer the same way we treat other layers for consistency
for (h = 0; h < inputs.length; h++) {
this.data[this.output + h] = inputs[h];
}
// Simple case where there are no hidden layers
if (!this.hidden_layers) {
for (j = 0; j < this.outputs; j++) {
let sum = this.data[w] * -1.0;
w++;
for (k = 0; k < this.inputs; k++) {
sum += this.data[w] * this.data[i + k];
w++;
}
result[j] = this.act_output(sum);
this.data[o] = this.act_output(sum);
o++;
}
return result;
}
/* Figure input layer */
for (j = 0; j < this.hidden; j++) {
let sum = this.data[w] * -1.0;
w++;
for (k = 0; k < this.inputs; k++) {
sum += this.data[w] * this.data[i + k];
w++;
}
this.data[o] = this.act_output(sum);
o++;
}
i += this.inputs;
/* Calculate hidden layers. */
for (h = 1; h < this.hidden_layers; h++) {
for (j = 0; j < this.hidden; j++) {
let sum = this.data[w] * -1.0;
w++;
for (k = 0; k < this.hidden; k++) {
sum += this.data[w] * this.data[i + k];
w++;
}
this.data[o] = this.sigmoid(sum);
o++;
}
i += this.hidden;
}
let ret = o;
/* Calculate output layer. */
for (j = 0; j < this.outputs; j++) {
let sum = this.data[w] * -1.0;
w++;
for (k = 0; k < this.hidden; k++) {
sum += this.data[w] * this.data[i + k];
w++;
}
result[j] = this.data[o] = this.sigmoid(sum);
o++;
}
/* Sanity check that we used all weights and wrote all outputs. */
if (w - this.weight != this.total_weights) {
console.log("Failed test 1");
}
if (o - this.output != this.total_neurons) {
console.log("Failed test 2", o, this.output, this.total_neurons);
}
return result;
}
}
const ann = new NeuralNetwork(3, 1, 1, 1);
console.log(ann.total_weights, "weights");
const input = [1, 1, 1];
console.log("generated", ann.run(input)[0]);
const w0 = ann.data[ann.weight + 0];
const w1 = ann.data[ann.weight + 1];
const w2 = ann.data[ann.weight + 2];
const w3 = ann.data[ann.weight + 3];
const w4 = ann.data[ann.weight + 4];
const w5 = ann.data[ann.weight + 5];
const hiddenLayer = 1 - cached_sigmoid(w0 - input[0] * w1 - input[1] * w2 - input[2] * w3);
const outputLayer = 1 - cached_sigmoid(w4 - hiddenLayer * w5);
console.log("calculated", outputLayer);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment