Code viewer for World: Character recognition neur...


 
var showMatrix=!1;


//  basic idea is to activate the functions like relu,leaky_relu etc

class ActivationFunction
{
    constructor(t,e,i=!1)
    {
        this.func=t;
        this.dfunc=e;
        this.use_X_values=i;
        
    }
    
}

//building the activation functions

let sigmoid=new ActivationFunction(t=>1/(1+Math.exp(-t)),t=>t*(1-t));
let tanh=new ActivationFunction(t=>Math.tanh(t),t=>1-t*t);
let arctan=new ActivationFunction(t=>Math.atan(t),t=>1/(t*t+1),use_X_values=!0);
let softsign=new ActivationFunction(t=>t/(1+Math.abs(t)),t=>1/Math.pow(Math.abs(t)+1,2),use_X_values=!0);
let relu=new ActivationFunction(t=>t<0?0:t,t=>t<0?0:1,use_X_values=!0);
let leaky_relu=new ActivationFunction(t=>t<0?0.01*t:t,t=>t<0?0.01:1,use_X_values=!0);
let softplus=new ActivationFunction(t=>Math.log(1+Math.exp(t)),t=>1/(1+Math.exp(-t)),use_X_values=!0);
let gaussian=new ActivationFunction(t=>Math.exp(t*t*-1),t=>-2*t*Math.exp(t*t*-1),use_X_values=!0);

var Softmax = function(ar) { ar.map( x => Math.exp(x) / (ar.map( y => Math.exp(y))).reduce( (a,b) => a+b)) };
//Machine Learning Model that will recognize the characters
class NeuralNet

{
    constructor(t,e,i)
    {
        if(t instanceof NeuralNet)
        {
            let e=t;
            this.input_nodes=e.input_nodes;
            this.hidden_nodes=e.hidden_nodes;
            this.output_nodes=e.output_nodes;
            this.weights_ih=e.weights_ih.copy();
            this.weights_ho=e.weights_ho.copy();
            this.bias_h=e.bias_h.copy();
            this.bias_o=e.bias_o.copy();
            
        }
        else 
        this.input_nodes=t;
        this.hidden_nodes=e;
        this.output_nodes=i;
        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,5);
        this.bias_o=new Matrix(this.output_nodes,5);
        this.bias_h.randomize();
        this.bias_o.randomize();
        this.setLearningRate(0.1);
        this.setActivationFunction();
        
    }
    //predition process
    predict(t)
    {
        let e=Matrix.fromArray(t),i=Matrix.multiply(this.weights_ih,e);
        i.add(this.bias_h),i.map(this.activation_function.func);
        let s=Matrix.multiply(this.weights_ho,i);
        return s.add(this.bias_o),s.map(this.activation_function.func),s.toArray();
        
    }
    
    //setting the learning rate 
    setLearningRate(t)
    {
        this.learning_rate=t;
        
    }
    
    setActivationFunction(t=tanh)
    {
        this.activation_function=t;
        
    }
    
    train(t,e)
    {
        let i=Matrix.fromArray(t), s=Matrix.multiply(this.weights_ih,i);
        s.add(this.bias_h) , s.map(this.activation_function.func);
        
        let o=Matrix.multiply(this.weights_ho,s);
        o.add(this.bias_o) , o.map(this.activation_function.func);
        
        let a=Matrix.fromArray(e), n=Matrix.subtract(a,o),
        r=Matrix.map(o,this.activation_function.dfunc);
        r.multiply(n), r.multiply(this.learning_rate);
        
        let l=Matrix.transpose(s), h=Matrix.multiply(r,l);
        this.weights_ho.add(h) , this.bias_o.add(r);
        
        let d=Matrix.transpose(this.weights_ho), c=Matrix.multiply(d,n), u=Matrix.map(s,this.activation_function.dfunc);
        u.multiply(c) , u.multiply(this.learning_rate);
        
        let g=Matrix.transpose(i), m=Matrix.multiply(u,g);
        
        this.weights_ih.add(m),
        this.bias_h.add(u);
        
    }
    
    serialize()
    {
        return JSON.stringify(this);
        
    }
    
    static deserialize(t)
    {
        "string"==typeof t&&(t=JSON.parse(t));
        let e=new NeuralNet(t.input_nodes,t.hidden_nodes,t.output_nodes);
        return e.weights_ih=Matrix.deserialize(t.weights_ih),
        e.weights_ho=Matrix.deserialize(t.weights_ho),
        e.bias_h=Matrix.deserialize(t.bias_h),
        e.bias_o=Matrix.deserialize(t.bias_o),
        e.learning_rate=t.learning_rate,
        e;
        
    }
    copy()
    {
        return new NeuralNet(this);
        
    }
    mutate(t)
    {
        this.weights_ih.map(t),
        this.weights_ho.map(t),
        this.bias_h.map(t),
        this.bias_o.map(t);
        
    }
    
}

//Multilayer Neural Network
class NeuralNetMulti
{
    constructor(t,e)
    {
        this.nodes=t,
        this.lr=e||0.01,
        this.activation=NeuralNetMulti.rhlu,
        this.dactivation=NeuralNetMulti.drhlu,
        this.weights=[],
        this.biases=[];
        
        for(let t=0;t<this.nodes.length-1;t++)
        this.weights.push(new Matrix(this.nodes[t+1],this.nodes[t]).randomize());
        
        for(let t=1;t<this.nodes.length;t++)
        this.biases.push(new Matrix(this.nodes[t],1).randomize());
        
    }
    static dtanh(t)
    {
        return 1/pow(Math.cosh(t),2);
        
    }
    static sigmoid(t)
    {
        return 1/(1+Math.exp(-t));
        
    }
    
    static dsigmoid(t)
    {
        return t*(1-t);
        
    }
    
    static rhlu(t)
    {
        return t<0?0:t;
        
    }
    
    static drhlu(t)
    {
        return t<0?0:1;
        
    }
    
    predict(t)
    {
        let e=Matrix.fromArray(t);
        for(let t=0;t<this.weights.length;t++)
        (e=Matrix.multiply(this.weights[t],e)).add(this.biases[t]),
        e.map(this.activation);
        
        return e.toArray();
        
    }
    train(t,e)
    {
        let i=Matrix.fromArray(e),
        s=Matrix.fromArray(this.predict(t)),
        o=[],
        a=Matrix.fromArray(t);
        
        for(let t=0;t<this.weights.length;t++)
        o.push(a),
        
        (a=Matrix.multiply(this.weights[t],a)).add(this.biases[t]),
        a.map(this.activation);
        
        let n=Matrix.subtract(i,s),
        r=Matrix.map(s,this.dactivation);
        r.multiply(n),
        r.multiply(this.lr);
        
        for(let t=o.length-1;t>=0;t--)
        {
            let e=Matrix.multiply(r,Matrix.transpose(o[t]));
            this.weights[t].add(e),
            this.biases[t].add(r),
            n=Matrix.multiply(Matrix.transpose(this.weights[t]),n),
            (r=Matrix.map(o[t],this.dactivation)).multiply(n),
            r.multiply(this.lr);
            
        }
        
    }
    
    getModel()
    
    {
        let t=this,
        e={nodes:t.nodes,lr:t.lr,activation:t.activation,dactivation:t.dactivation,weights:[],biases:[]};
        
        for(let i of t.weights)
        {
            let t={rows:i.rows,cols:i.cols,data:[]};
            for(let e of i.data)
            {
                let i=[];
                for(let t of e)i.push(t);
                t.data.push(i);
                
            }
            e.weights.push(t);
            
        }
        
        for(let i of t.biases)
        {
            let t={rows:i.rows,cols:i.cols,data:i.data};
            e.biases.push(t);
            
        }
        return e;
        
    }
    
    static formModel(t)
    {
        let e=new NeuralNetMulti(t.nodes,t.lr);
        e.nodes=t.nodes,
        e.lr=t.lr,
        e.activation=t.activation,
        e.dactivation=t.dactivation;
        
        for(let i=0;i<e.weights.length;i++)
        {
            e.weights[i].rows=t.weights[i].rows,
            e.weights[i].cols=t.weights[i].cols;
            
            for(let s=0;s<t.weights[i].rows;s++)
            for(let o=0;o<t.weights[i].cols;o++)
            e.weights[i].data[s][o]=t.weights[i].data[s][o];
            e.weights[i].rows=t.weights[i].rows;
            
        }
        return e;
        
    }
    
    copy()
    {
        let t=this.getModel();
        return NeuralNetMulti.formModel(t);
        
    }
    mutate(t)
    {
        for(let e of this.weights)e.map(t);
        for(let e of this.biases)e.map(t);
        
    }
    
    merge(t,e=0.5)
    {
        let i=1-e,s=e;
        for(let e=0;e<this.nodes.length;e++)
        if(this.nodes[e]!=t.nodes[e])
        return void console.error("Neural Networks can not be merged");
        
        this.lr=this.lr*i+t.lr*s;
        
        for(let e=0;e<this.weights.length;e++)
        for(let o=0;o<this.weights[e].rows;o++)
        for(let a=0;a<this.weights[e].cols;a++)
        
        this.weights[e].data[o][a]=this.weights[e].data[o][a]*i+t.weights[e].data[o][a]*s;
        
        for(let e=0;e<this.biases.length;e++)
        
        for(let o=0;o<this.biases[e].rows;o++)
        
        for(let a=0;a<this.biases[e].cols;a++)
        
        this.biases[e].data[o][a]=this.biases[e].data[o][a]*i+t.biases[e].data[o][a]*s;
        
        return this;
        
    }
    
    setActivation(t,e)
    {
        this.activation=t,
        this.dactivation=e;
        
    }
    
    setLearningRate(t)
    {
        this.lr=t;
        
    }
    
}


    const optFunction = async ({ optimizer, epochs }, { xs, ys }) => {

      // Create a simple sequential model.
      const model = tf.sequential();

      // add a dense layer to the model and compile
      model.add(tf.layers.dense({ units: 1, inputShape: [1] }));
      model.compile({
        loss: 'meanSquaredError',
        optimizer,
      });

      // train model using defined data
      const h = await model.fit(xs, ys, {epochs});

      //printint out each optimizer and its loss
      console.log(optimizer, h.history.loss[h.history.loss.length - 1]);
      return { loss: h.history.loss[h.history.loss.length - 1], status: hpjs.STATUS_OK } ;
    };

    async function hyperTFJS(){

      // Generating some data for training (y = 2x - 1) in tf tensors and defining its shape
      const xs = tf.tensor2d([-1, 0, 1, 2, 3, 4], [6, 1]);
      const ys = tf.tensor2d([-3, -1, 1, 3, 5, 7], [6, 1]);

      // defining a search space we want to optimize. Using hpjs parameters here
      const space = { 
        optimizer: hpjs.choice(['sgd', 'adagrad', 'adam', 'adamax', 'rmsprop']),
        epochs: hpjs.quniform(50, 200, 50),
      };

      // finding the optimal hyperparameters using hpjs.fmin. Here, 6 is the # of times the optimization function will be called (which can be changed)
      const trials = await hpjs.fmin(
        optFunction, space, hpjs.search.randomSearch, 6,
        { rng: new hpjs.RandomState(654321), xs, ys }
      );

      const opt = trials.argmin;

      //printing out data
      console.log('trials', trials);
      console.log('best optimizer:', opt.optimizer);
      console.log('best epochs:', opt.epochs);
    }
    
const PIXELS=28,PIXELSSQUARED=PIXELS*PIXELS,NOTRAIN=6e4,NOTEST=1e4,noinput=PIXELSSQUARED,nohidden=24,nooutput=10,learningrate=0.1;

let do_training=!0;

const TRAINPERSTEP=30,TESTPERSTEP=5,ZOOMFACTOR=7,ZOOMPIXELS=ZOOMFACTOR*PIXELS,canvaswidth=2*ZOOMPIXELS+120,canvasheight=3*ZOOMPIXELS+102,doodlewidth=PIXELS,DOODLE_THICK=15,DOODLE_BLUR=3;
let mnist,nn,canvas,dst,src,hierarchy,contours,img,diffX,diffY,M,doodle,demo,hidden_no_slider,learning_rate_slider,cvOutput=[],trainrun=1,train_index=0,testrun=1,test_index=0,total_tests=0,total_correct=0,doodle_exists=!1,demo_exists=!1,mousedrag=!1;
var train_inputs,test_inputs,demo_inputs,doodle_inputs,thehtml;

function randomWeight()
{
    return AB.randomFloatAtoB(-0.5,0.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(0,51,0),
    (doodle=createGraphics(ZOOMPIXELS,ZOOMPIXELS)).pixelDensity(2),
    wipeDoodle(),
    strokeWeight(3),
    stroke(255,0,0),
    rect(0,0,ZOOMPIXELS,ZOOMPIXELS),
    textSize(13),
    textAlign(CENTER),
    text("DOODLE AREA",ZOOMPIXELS/2,ZOOMPIXELS/2.2),
    rect(0,ZOOMPIXELS+50,ZOOMPIXELS,ZOOMPIXELS),
    rect(0,canvasheight-ZOOMPIXELS-2,ZOOMPIXELS,ZOOMPIXELS),
    textSize(13),
    textAlign(CENTER),
    text(" DEMO AREA ",100,canvasheight-ZOOMPIXELS/1.8),
    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 NeuralNet(noinput,nohidden,nooutput)).setLearningRate(learningrate),loadData()})})})})}
    
    function loadData()
    {
        loadMNIST(function(t)
        {
            mnist=t,console.log("All data loaded into mnist object:"),
            console.log(mnist),
            AB.removeLoading();
            
        }
        );
        
    }
    
    function getImage(t)
    {
        
        let e=createImage(PIXELS,PIXELS);
        e.loadPixels();
        
        for(let i=0;i<PIXELSSQUARED;i++)
        {
            let s=t[i],o=4*i;
            e.pixels[o+0]=s,
            e.pixels[o+1]=s,
            e.pixels[o+2]=s,
            e.pixels[o+3]=255;
            
        }
        
        return e.updatePixels(),
        e;
        
    }
    
    function getInputs(t)
    {
        let e=[];
        for(let i=0;i<PIXELSSQUARED;i++)
        {
            let s=t[i];
            e[i]=s/255;
            
        }
        return e;
        
    }
    
    function trainit(t)
    {
        let e=mnist.train_images[train_index],
        i=mnist.train_labels[train_index];
        
        if(t)
        {
            var s=getImage(e);
            image(s,0,ZOOMPIXELS+50,ZOOMPIXELS,ZOOMPIXELS),
            image(s,ZOOMPIXELS+50,ZOOMPIXELS+50,PIXELS,PIXELS);
            
        }
        
        let o=getInputs(e),a=[0,0,0,0,0,0,0,0,0,0];
        a[i]=1,
        train_inputs=o,
        nn.train(o,a),
        thehtml=" trainrun: "+trainrun+"<br> no: "+train_index,
        AB.msg(thehtml,4),
        ++train_index==NOTRAIN&&(train_index=0,console.log("finished trainrun: "+trainrun),trainrun++);
        
    }
    
    function testit()
    {
        let t=mnist.test_images[test_index],
        e=mnist.test_labels[test_index],
        i=getInputs(t);test_inputs=i;
        let s=findMax(nn.predict(i));
        total_tests++,
        s==e&&total_correct++;
        
        let o=total_correct/total_tests*100;
        thehtml=" testrun: "+testrun+"<br> no: "+total_tests+" <br>  correct: "+total_correct+"<br>  score: "+greenspan+o.toFixed(2)+"</span>",
        AB.msg(thehtml,6),
        ++test_index==NOTEST&&(console.log("finished testrun: "+testrun+" score: "+o.toFixed(2)),testrun++,test_index=0,total_tests=0,total_correct=0);
        
    }
    
    function find123(t)
    {
        let e=0,i=0,s=0,o=0,a=0,n=0;
        for(let r=0;r<t.length;r++)
        t[r]>s?(e=r,s=t[r]):t[r]>o?(i=r,o=t[r]):t[r]>n&&(a=r,n=t[r]);
        return[e,i,a];
        
    }
    function findMax(t)
    {
        let e=0,i=0;
        for(let s=0;s<t.length;s++)
        t[s]>i&&(e=s,i=t[s]);
        
        return e;
        
    }
    
    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 t=ZOOMPIXELS-2;
                mouseX<t&&mouseY<t&&pmouseX<t&&pmouseY<t&&(mousedrag=!0,doodle_exists=!0,doodle.stroke("cream"),strokeJoin(BEVEL),doodle.strokeWeight(DOODLE_THICK),doodle.line(mouseX,mouseY,pmouseX,pmouseY));
                
            }
            else if(mousedrag)
            {
                mousedrag=!1,
                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 t=contours.get(0),
                e=cv.moments(t,0);
                
                M=e.m00;
                  let i=Math.round(e.m10/e.m00*100)/100,s=Math.round(e.m01/e.m00*100)/100,o=PIXELS/2,a=PIXELS/2;
                  diffX=Math.round(o-i),
                  diffY=Math.round(a-s);
                  
                  let n=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,n,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=!0;
        var t=AB.randomIntAtoB(0,NOTEST-1);
        demo=mnist.test_images[t];
        var e=mnist.test_labels[t];
        thehtml="Test image no: "+t+"<br>Classification: "+e+"<br>",AB.msg(thehtml,8);
        
    }
    
    function drawDemo()
    {
        var t=getImage(demo);
        image(t,0,canvasheight-ZOOMPIXELS,ZOOMPIXELS,ZOOMPIXELS),
        image(t,ZOOMPIXELS+50,canvasheight-ZOOMPIXELS,PIXELS,PIXELS);
        
    }
    function guessDemo()
    {
        let t=getInputs(demo);
        demo_inputs=t;
        let e=findMax(nn.predict(t));
        thehtml=" We classify it as: "+greenspan+e+"</span>",AB.msg(thehtml,9);
        
    }
    function drawDoodle()
    {
        let t=doodle.get();
        image(t,0,0,ZOOMPIXELS,ZOOMPIXELS),image(t,ZOOMPIXELS+50,0,PIXELS,PIXELS);
        
    }
    
    let lastT=0;
    
    function guessDoodle()
    {
        (img=doodle.get()).resize(PIXELS,PIXELS),
        img.loadPixels();
        
        let t=[];
        for(let e=0;e<PIXELSSQUARED;e++)
        t[e]=img.pixels[4*e]/255;
        
        let e=Array.from(t);
        for(let t=0;t<e.length;t++)
        e[t]=cvOutput[t];
        t=Array.from(e);
        
        for(let e=0;e<t.length;e++)
        t[e]=-255*t[e];
        doodle_inputs=t;
        
        let i=find123(nn.predict(t));
        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=!1,doodle.background("black");
        
    }
    
    function showInputs(t)
    {
        var e="";
        for(let i=0;i<t.length;i++)
        {
            i%PIXELS===0&&(e+="\n"),
            e=e+" "+t[i].toFixed(2);
            
        }
        console.log(e);
        
    }