var showMatrix = false;
class ActivationFunction {
constructor(func, errorFunc, i = false) {
this.func = func;
this.dfunc = errorFunc;
this.use_X_values = i;
}
}
let sigmoid = new ActivationFunction((value) => {
return 1 / (1 + Math.exp(-value));
}, (i) => {
return i * (1 - i);
});
let tanh = new ActivationFunction((val) => {
return Math.tanh(val);
}, (rayY) => {
return 1 - rayY * rayY;
});
let arctan = new ActivationFunction((lowEnd) => {
return Math.atan(lowEnd);
}, (rayY) => {
return 1 / (rayY * rayY + 1);
}, use_X_values = true);
let softsign = new ActivationFunction((mercatorX) => {
return mercatorX / (1 + Math.abs(mercatorX));
}, (mercatorX) => {
return 1 / Math.pow(Math.abs(mercatorX) + 1, 2);
}, use_X_values = true);
let relu = new ActivationFunction((delta) => {
return delta < 0 ? 0 : delta;
}, (canCreateDiscussions) => {
return canCreateDiscussions < 0 ? 0 : 1;
}, use_X_values = true);
let leaky_relu = new ActivationFunction((t) => {
return t < 0 ? .01 * t : t;
}, (canCreateDiscussions) => {
return canCreateDiscussions < 0 ? .01 : 1;
}, use_X_values = true);
let softplus = new ActivationFunction((prop_log_scale) => {
return Math.log(1 + Math.exp(prop_log_scale));
}, (value) => {
return 1 / (1 + Math.exp(-value));
}, use_X_values = true);
let gaussian = new ActivationFunction((rayY) => {
return Math.exp(rayY * rayY * -1);
}, (rayY) => {
return -2 * rayY * Math.exp(rayY * rayY * -1);
}, use_X_values = true);
class NeuralNetwork {
constructor(inputs, outputs, propOuts) {
if (inputs instanceof NeuralNetwork) {
let that = inputs;
this.input_nodes = that.input_nodes;
this.hidden_nodes = that.hidden_nodes;
this.output_nodes = that.output_nodes;
this.weights_ih = that.weights_ih.copy();
this.weights_ho = that.weights_ho.copy();
this.bias_h = that.bias_h.copy();
this.bias_o = that.bias_o.copy();
} else {
this.input_nodes = inputs;
this.hidden_nodes = outputs;
this.output_nodes = propOuts;
this.weights_ih = new Matrix(this.hidden_nodes, this.input_nodes);
this.weights_ho = new Matrix(this.output_nodes, this.hidden_nodes);
this.weights_ih.randomize();
this.weights_ho.randomize();
this.bias_h = new Matrix(this.hidden_nodes, 1);
this.bias_o = new Matrix(this.output_nodes, 1);
this.bias_h.randomize();
this.bias_o.randomize();
}
this.setLearningRate();
this.setActivationFunction();
}
predict(inputs) {
let i = Matrix.fromArray(inputs);
let matrix = Matrix.multiply(this.weights_ih, i);
matrix.add(this.bias_h);
matrix.map(this.activation_function.func);
let self = Matrix.multiply(this.weights_ho, matrix);
return self.add(this.bias_o), self.map(this.activation_function.func), self.toArray();
}
setLearningRate(t = .1) {
this.learning_rate = t;
}
setActivationFunction(t = sigmoid) {
this.activation_function = t;
}
train(inputs, outputs) {
let n = Matrix.fromArray(inputs);
let matrix = Matrix.multiply(this.weights_ih, n);
matrix.add(this.bias_h);
matrix.map(this.activation_function.func);
let r = Matrix.multiply(this.weights_ho, matrix);
r.add(this.bias_o);
r.map(this.activation_function.func);
let targets = Matrix.fromArray(outputs);
let m = Matrix.subtract(targets, r);
let A = Matrix.map(r, this.activation_function.dfunc);
A.multiply(m);
A.multiply(this.learning_rate);
let i = Matrix.transpose(matrix);
let entrytwo = Matrix.multiply(A, i);
this.weights_ho.add(entrytwo);
this.bias_o.add(A);
let lambda = Matrix.transpose(this.weights_ho);
let theta = Matrix.multiply(lambda, m);
let X = Matrix.map(matrix, this.activation_function.dfunc);
X.multiply(theta);
X.multiply(this.learning_rate);
let delta = Matrix.transpose(n);
let filtersSwitchs = Matrix.multiply(X, delta);
this.weights_ih.add(filtersSwitchs);
this.bias_h.add(X);
}
serialize() {
return JSON.stringify(this);
}
static deserialize(json) {
if ("string" == typeof json) {
json = JSON.parse(json);
}
let opts = new NeuralNetwork(json.input_nodes, json.hidden_nodes, json.output_nodes);
return opts.weights_ih = Matrix.deserialize(json.weights_ih), opts.weights_ho = Matrix.deserialize(json.weights_ho), opts.bias_h = Matrix.deserialize(json.bias_h), opts.bias_o = Matrix.deserialize(json.bias_o), opts.learning_rate = json.learning_rate, opts;
}
copy() {
return new NeuralNetwork(this);
}
mutate(target) {
this.weights_ih.map(target);
this.weights_ho.map(target);
this.bias_h.map(target);
this.bias_o.map(target);
}
}
class NeuralNetworkMulti {
constructor(nodes, bitmap) {
this.nodes = nodes;
this.lr = bitmap || .01;
this.activation = NeuralNetworkMulti.rhlu;
this.dactivation = NeuralNetworkMulti.drhlu;
this.weights = [];
this.biases = [];
for (let i = 0; i < this.nodes.length - 1; i++) {
this.weights.push((new Matrix(this.nodes[i + 1], this.nodes[i])).randomize());
}
for (let i = 1; i < this.nodes.length; i++) {
this.biases.push((new Matrix(this.nodes[i], 1)).randomize());
}
}
static dtanh(x) {
return 1 / pow(Math.cosh(x), 2);
}
static sigmoid(x) {
return 1 / (1 + Math.exp(-x));
}
static dsigmoid(i) {
return i * (1 - i);
}
static rhlu(delta) {
return delta < 0 ? 0 : delta;
}
static drhlu(canCreateDiscussions) {
return canCreateDiscussions < 0 ? 0 : 1;
}
predict(items) {
let matrix = Matrix.fromArray(items);
for (let i = 0; i < this.weights.length; i++) {
(matrix = Matrix.multiply(this.weights[i], matrix)).add(this.biases[i]);
matrix.map(this.activation);
}
return matrix.toArray();
}
train(inputs_array, targets_array) {
let targets = Matrix.fromArray(targets_array);
let outputs = Matrix.fromArray(this.predict(inputs_array));
let keys = [];
let m = Matrix.fromArray(inputs_array);
for (let i = 0; i < this.weights.length; i++) {
keys.push(m);
(m = Matrix.multiply(this.weights[i], m)).add(this.biases[i]);
m.map(this.activation);
}
let v = Matrix.subtract(targets, outputs);
let r = Matrix.map(outputs, this.dactivation);
r.multiply(v);
r.multiply(this.lr);
for (let i = keys.length - 1; i >= 0; i--) {
let entrytwo = Matrix.multiply(r, Matrix.transpose(keys[i]));
this.weights[i].add(entrytwo);
this.biases[i].add(r);
v = Matrix.multiply(Matrix.transpose(this.weights[i]), v);
(r = Matrix.map(keys[i], this.dactivation)).multiply(v);
r.multiply(this.lr);
}
}
getModel() {
let self = this;
let net = {
nodes : self.nodes,
lr : self.lr,
activation : self.activation,
dactivation : self.dactivation,
weights : [],
biases : []
};
for (let size of self.weights) {
let t = {
rows : size.rows,
cols : size.cols,
data : []
};
for (let state of size.data) {
let i = [];
for (let t of state) {
i.push(t);
}
t.data.push(i);
}
net.weights.push(t);
}
for (let data of self.biases) {
let falseySection = {
rows : data.rows,
cols : data.cols,
data : data.data
};
net.biases.push(falseySection);
}
return net;
}
static formModel(result) {
let self = new NeuralNetworkMulti(result.nodes, result.lr);
self.nodes = result.nodes;
self.lr = result.lr;
self.activation = result.activation;
self.dactivation = result.dactivation;
for (let i = 0; i < self.weights.length; i++) {
self.weights[i].rows = result.weights[i].rows;
self.weights[i].cols = result.weights[i].cols;
for (let y = 0; y < result.weights[i].rows; y++) {
for (let j = 0; j < result.weights[i].cols; j++) {
self.weights[i].data[y][j] = result.weights[i].data[y][j];
}
}
self.weights[i].rows = result.weights[i].rows;
}
return self;
}
copy() {
let artistTrack = this.getModel();
return NeuralNetworkMulti.formModel(artistTrack);
}
mutate(val) {
for (let jq_results of this.weights) {
jq_results.map(val);
}
for (let jq_results of this.biases) {
jq_results.map(val);
}
}
merge(matrix, e = .5) {
let step = 1 - e;
let dx = e;
for (let i = 0; i < this.nodes.length; i++) {
if (this.nodes[i] != matrix.nodes[i]) {
return void console.error("Neural Networks can not be merged");
}
}
this.lr = this.lr * step + matrix.lr * dx;
for (let i = 0; i < this.weights.length; i++) {
for (let y = 0; y < this.weights[i].rows; y++) {
for (let j = 0; j < this.weights[i].cols; j++) {
this.weights[i].data[y][j] = this.weights[i].data[y][j] * step + matrix.weights[i].data[y][j] * dx;
}
}
}
for (let i = 0; i < this.biases.length; i++) {
for (let y = 0; y < this.biases[i].rows; y++) {
for (let j = 0; j < this.biases[i].cols; j++) {
this.biases[i].data[y][j] = this.biases[i].data[y][j] * step + matrix.biases[i].data[y][j] * dx;
}
}
}
return this;
}
setActivation(value, opt_pass) {
this.activation = value;
this.dactivation = opt_pass;
}
setLearningRate(learningRate) {
this.lr = learningRate;
}
}
const PIXELS = 28;
const PIXELSSQUARED = PIXELS * PIXELS;
const NOTRAIN = 6E4;
const NOTEST = 1E4;
const noinput = PIXELSSQUARED;
const nohidden = 24;
const nooutput = 10;
const learningrate = .1;
let do_training = true;
const TRAINPERSTEP = 30;
const TESTPERSTEP = 5;
const ZOOMFACTOR = 7;
const ZOOMPIXELS = ZOOMFACTOR * PIXELS;
const canvaswidth = 2 * ZOOMPIXELS + 120;
const canvasheight = 3 * ZOOMPIXELS + 102;
const doodlewidth = PIXELS;
const DOODLE_THICK = 15;
const DOODLE_BLUR = 3;
let mnist;
let nn;
let canvas;
let dst;
let src;
let hierarchy;
let contours;
let img;
let diffX;
let diffY;
let M;
let doodle;
let demo;
let hidden_no_slider;
let learning_rate_slider;
let cvOutput = [];
let trainrun = 1;
let train_index = 0;
let testrun = 1;
let test_index = 0;
let total_tests = 0;
let total_correct = 0;
let doodle_exists = false;
let demo_exists = false;
let mousedrag = false;
var train_inputs;
var test_inputs;
var demo_inputs;
var doodle_inputs;
var thehtml;
function randomWeight() {
return AB.randomFloatAtoB(-.5, .5);
}
$("#runheaderbox").css({
"max-height" : "95vh"
}), thehtml = "<hr> <h1> 1. Doodle </h1> Top row: Doodle (left) and shrunk (right). <br> Draw your doodle in top LHS. <button onclick='wipeDoodle();' class='normbutton' >Clear doodle</button> <br> ", AB.msg(thehtml, 1), thehtml = "<hr> <h1> 2. Training </h1> Middle row: Training image magnified (left) and original (right). <br> <button onclick='do_training = false;' class='normbutton' >Stop training</button> <br> ", AB.msg(thehtml, 3), thehtml = "<h3> Hidden tests </h3> ", AB.msg(thehtml, 5),
thehtml = "<hr> <h1> 3. Demo </h1> Bottom row: Test image magnified (left) and original (right). <br> The network is <i>not</i> trained on any of these images. <br> <button onclick='makeDemo();' class='normbutton' >Demo test image</button> <br> ", AB.msg(thehtml, 7);
const greenspan = "<span style='font-weight:bold; font-size:x-large; color:darkgreen'> ";
function setup() {
(canvas = createCanvas(canvaswidth, canvasheight)).position(10, 20);
canvas.background(51, 51, 51);
(doodle = createGraphics(ZOOMPIXELS, ZOOMPIXELS)).pixelDensity(1);
wipeDoodle();
strokeWeight(3);
stroke(255, 0, 0);
rect(0, 0, ZOOMPIXELS, ZOOMPIXELS);
textSize(20);
textAlign(CENTER);
text("DOODLE AREA", ZOOMPIXELS / 2, ZOOMPIXELS / 2.2);
rect(0, ZOOMPIXELS + 50, ZOOMPIXELS, ZOOMPIXELS);
rect(0, canvasheight - ZOOMPIXELS - 2, ZOOMPIXELS, ZOOMPIXELS);
textSize(16);
textAlign(CENTER);
text(" DEMO AREA ", 100, canvasheight - ZOOMPIXELS / 1.8);
rect(ZOOMPIXELS + 20, ZOOMPIXELS + 100, ZOOMPIXELS + 90, ZOOMPIXELS + 100);
text("HIDDEN_NO SLIDER ", ZOOMPIXELS + 120, ZOOMPIXELS + 130);
(hidden_no_slider = createSlider(10, 300, nohidden)).position(ZOOMPIXELS + 100, ZOOMPIXELS + 180);
text("LEARNING_RATE SLIDER ", ZOOMPIXELS + 120, ZOOMPIXELS + 230);
(learning_rate_slider = createSlider(.01, .2, learningrate)).position(ZOOMPIXELS + 100, ZOOMPIXELS + 280);
AB.loadingScreen();
$.getScript("/uploads/finally/opencv.js", function() {
$.getScript("/uploads/codingtrain/matrix.js", function() {
$.getScript("/uploads/finally/nn.js", function() {
$.getScript("/uploads/codingtrain/mnist.js", function() {
console.log("All JS loaded");
(nn = new NeuralNetwork(noinput, nohidden, nooutput)).setLearningRate(learningrate);
loadData();
});
});
});
});
}
function loadData() {
loadMNIST(function(canCreateDiscussions) {
mnist = canCreateDiscussions;
console.log("All data loaded into mnist object:");
console.log(mnist);
AB.removeLoading();
});
}
function getImage(id) {
let img = createImage(PIXELS, PIXELS);
img.loadPixels();
for (let i = 0; i < PIXELSSQUARED; i++) {
let s = id[i];
let index = 4 * i;
img.pixels[index + 0] = s;
img.pixels[index + 1] = s;
img.pixels[index + 2] = s;
img.pixels[index + 3] = 255;
}
return img.updatePixels(), img;
}
function getInputs(id) {
let dash = [];
for (let i = 0; i < PIXELSSQUARED; i++) {
let val = id[i];
dash[i] = val / 255;
}
return dash;
}
function trainit(canCreateDiscussions) {
let id = mnist.train_images[train_index];
let geneSymbol = mnist.train_labels[train_index];
if (canCreateDiscussions) {
var img = getImage(id);
image(img, 0, ZOOMPIXELS + 50, ZOOMPIXELS, ZOOMPIXELS);
image(img, ZOOMPIXELS + 50, ZOOMPIXELS + 50, PIXELS, PIXELS);
}
let data = getInputs(id);
let sample = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
sample[geneSymbol] = 1;
train_inputs = data;
nn.train(data, sample);
thehtml = " trainrun: " + trainrun + "<br> no: " + train_index;
AB.msg(thehtml, 4);
if (++train_index == NOTRAIN) {
train_index = 0;
console.log("finished trainrun: " + trainrun);
trainrun++;
}
}
function testit() {
let id = mnist.test_images[test_index];
let e = mnist.test_labels[test_index];
let sample = getInputs(id);
test_inputs = sample;
let place = findMax(nn.predict(sample));
total_tests++;
if (place == e) {
total_correct++;
}
let e_total = total_correct / total_tests * 100;
thehtml = " testrun: " + testrun + "<br> no: " + total_tests + " <br> correct: " + total_correct + "<br> score: " + greenspan + e_total.toFixed(2) + "</span>";
AB.msg(thehtml, 6);
if (++test_index == NOTEST) {
console.log("finished testrun: " + testrun + " score: " + e_total.toFixed(2));
testrun++;
test_index = 0;
total_tests = 0;
total_correct = 0;
}
}
function find123(p) {
let lastWhiteSpace = 0;
let firstNonzero = 0;
let xmax = 0;
let ymax = 0;
let bestcode = 0;
let maxv = 0;
for (let i = 0; i < p.length; i++) {
if (p[i] > xmax) {
lastWhiteSpace = i;
xmax = p[i];
} else {
if (p[i] > ymax) {
firstNonzero = i;
ymax = p[i];
} else {
if (p[i] > maxv) {
bestcode = i;
maxv = p[i];
}
}
}
}
return [lastWhiteSpace, firstNonzero, bestcode];
}
function findMax(array) {
let maxI = 0;
let maxValue = 0;
for (let i = 0; i < array.length; i++) {
if (array[i] > maxValue) {
maxI = i;
maxValue = array[i];
}
}
return maxI;
}
function draw() {
if (void 0 !== mnist) {
if (strokeWeight(3), stroke(255, 0, 0), rect(0, 0, ZOOMPIXELS, ZOOMPIXELS), textSize(20), textAlign(CENTER), text("DOODLE AREA", ZOOMPIXELS / 2, ZOOMPIXELS / 2.2), do_training) {
for (let t = 0; t < TRAINPERSTEP; t++) {
trainit(0 === t);
}
for (let t = 0; t < TESTPERSTEP; t++) {
testit();
}
}
if (demo_exists && (drawDemo(), guessDemo()), doodle_exists && (drawDoodle(), guessDoodle()), mouseIsPressed) {
var left = ZOOMPIXELS - 2;
if (mouseX < left && mouseY < left && pmouseX < left && pmouseY < left) {
mousedrag = true;
doodle_exists = true;
doodle.stroke("cream");
strokeJoin(BEVEL);
doodle.strokeWeight(DOODLE_THICK);
doodle.line(mouseX, mouseY, pmouseX, pmouseY);
}
} else {
if (mousedrag) {
mousedrag = false;
console.log("Doodle detected");
(img = doodle.get()).resize(PIXELS, PIXELS);
img.loadPixels();
imagedata = img.imageData;
src = cv.matFromImageData(imagedata);
dst = cv.Mat.zeros(src.cols, src.rows, cv.CV_8UC3);
cv.cvtColor(src, src, cv.COLOR_RGBA2GRAY, 0);
cv.threshold(src, src, 120, 255, cv.THRESH_BINARY);
contours = new cv.MatVector;
hierarchy = new cv.Mat;
cv.findContours(src, contours, hierarchy, cv.RETR_CCOMP, cv.CHAIN_APPROX_SIMPLE);
let newColIndexD = contours.get(0);
let moments = cv.moments(newColIndexD, 0);
M = moments.m00;
let _lastleft = Math.round(moments.m10 / moments.m00 * 100) / 100;
let _lasttop = Math.round(moments.m01 / moments.m00 * 100) / 100;
let bbcx = PIXELS / 2;
let bbcy = PIXELS / 2;
diffX = Math.round(bbcx - _lastleft);
diffY = Math.round(bbcy - _lasttop);
let dt = cv.matFromArray(2, 3, cv.CV_64FC1, [1, 0, diffX, 0, 1, diffY]);
return dsize = new cv.Size(src.rows, src.cols), cv.warpAffine(src, dst, dt, dsize, cv.INTER_LINEAR, cv.BORDER_CONSTANT, new cv.Scalar), cvOutput = getInputs(dst.data8S), image(img, ZOOMPIXELS + 120 + diffX * ZOOMFACTOR, 0 + diffY * ZOOMFACTOR, ZOOMPIXELS, ZOOMPIXELS), cvOutput;
}
}
}
}
function makeDemo() {
demo_exists = true;
var i = AB.randomIntAtoB(0, NOTEST - 1);
demo = mnist.test_images[i];
var beforeTab = mnist.test_labels[i];
thehtml = "Test image no: " + i + "<br>Classification: " + beforeTab + "<br>";
AB.msg(thehtml, 8);
}
function drawDemo() {
var sal = getImage(demo);
image(sal, 0, canvasheight - ZOOMPIXELS, ZOOMPIXELS, ZOOMPIXELS);
image(sal, ZOOMPIXELS + 50, canvasheight - ZOOMPIXELS, PIXELS, PIXELS);
}
function guessDemo() {
let sample = getInputs(demo);
demo_inputs = sample;
let e = findMax(nn.predict(sample));
thehtml = " We classify it as: " + greenspan + e + "</span>";
AB.msg(thehtml, 9);
}
function drawDoodle() {
let sal = doodle.get();
image(sal, 0, 0, ZOOMPIXELS, ZOOMPIXELS);
image(sal, ZOOMPIXELS + 50, 0, PIXELS, PIXELS);
}
let lastT = 0;
function guessDoodle() {
(img = doodle.get()).resize(PIXELS, PIXELS);
img.loadPixels();
let inputs = [];
for (let i = 0; i < PIXELSSQUARED; i++) {
inputs[i] = img.pixels[4 * i] / 255;
}
let input = Array.from(inputs);
for (let i = 0; i < input.length; i++) {
input[i] = cvOutput[i];
}
inputs = Array.from(input);
for (let i = 0; i < inputs.length; i++) {
inputs[i] = -255 * inputs[i];
}
doodle_inputs = inputs;
let i = find123(nn.predict(inputs));
thehtml = " We classify it as: " + greenspan + i[0] + "</span> <br> No.2 guess is: " + greenspan + i[1] + "</span> <br>No.3 guess is: " + greenspan + i[2] + "</span>";
AB.msg(thehtml, 2);
AB.msg(thehtml, 2);
}
function wipeDoodle() {
doodle_exists = false;
doodle.background("black");
}
function showInputs(groups) {
var stderr = "";
for (let i = 0; i < groups.length; i++) {
if (i % PIXELS == 0) {
stderr = stderr + "\n";
}
stderr = stderr + " " + groups[i].toFixed(2);
}
console.log(stderr);
};