{"cells":[{"cell_type":"code","metadata":{"id":"1215b33d681","hideRun":false},"source":["import {NeuroModule, nm, BinLayer, Linear} from '/web/oda/apps/neuronet/genius/neuro-module/neuro-module.js';\nimport {tensor} from '/web/oda/apps/neuronet/genius/torus/torus.js';"],"outputs":[]},{"cell_type":"code","metadata":{"id":"110ebbffa46","hideRun":false},"source":["MNIST = class MNIST  extends NeuroModule{\n    constructor(dim = 28) {\n        super(arguments);\n    }\n    \n    __init__(){\n        this.layer1 = new Linear(this.dim*this.dim,this.dim*this.dim/2,true)\n        this.layer2 = new Linear(this.dim*this.dim/2,10,true)\n    }\n    \n    forward(x){\n        x=tensor.from(x)\n        x = this.layer1(x)\n        x = x.sigm()\n        x = this.layer2(x)\n        x = x.sigm()\n        return x\n    }\n}\n"],"outputs":[]},{"cell_type":"code","metadata":{"id":"10bdb2bf168","hideRun":false},"source":["// model = await this.contextItem.owner.getFile('mnist/model.json');\n// out_size = 10\n//  if(model){\n//     //  model = await model.load();\n//      mnist = new MNIST(model);\n//  }\n//  else\nmnist = new MNIST();\n//loss.back();\n//this.contextItem.$owner.saveFile(mnist.toJSON(), 'mnist/model.json')\nprint(mnist)"],"outputs":[{"data":{"text/plain":"{\n    \"$\": \"MNIST\",\n    \"dim\": 28,\n    \"prototype\": {}\n}"}}]},{"cell_type":"code","metadata":{"id":"5df214bef8","hideRun":false},"source":["datasetRaw = await ODA.loadJSON('/web/oda/apps/neuronet/mnist/mnist.json');\n\ngetTrain = (dataset = datasetRaw, batch=5, test_size=0.2) => {\n    let [result, res] = [{inputs:[],targets:[]},[]] \n\n    let suBatch = Array(10).fill(0).map((_,i)=>i) //.sort(()=>Math.random() - 0.5)\n    suBatch.forEach(n=>{\n        let target  = Array(10).fill(0);\n        target[n] = 1\n        for (let j=0; j<batch; j++) {\n            let br = Math.floor(dataset[n].length * (1-test_size))\n            let k = Math.floor(Math.random() * br)\n            res.push([dataset[n][k].flat(),target])\n        }\n    })\n        \n    res.sort(()=>Math.random() - 0.5)\n    res.forEach ( ([inp,tar]) => {result.inputs.push(inp); result.targets.push(tar)} )\n    return result\n}\n\n// print(datasetRaw[0][0].flat())"],"outputs":[{"data":{"text/plain":"{}"}}]},{"cell_type":"code","metadata":{"id":"1123b3d3bb","hideRun":false},"source":["// dat = mnist.getTrain(datasetRaw , 1)\n// print(`getTrain возвращает { inputs (${dat.inputs.length} по ${dat.inputs[0].length}) ,targets (${dat.targets.length} по ${dat.targets[0].length}) }.`)\n\n// let loss='',rez=''\n\n// // print(dat.inputs[0])\n\n// for (let i=0; i<dat.inputs.length; i++) {\n//     // print (i)\n//     rez = mnist.forward(dat.inputs[i])\n//     loss = rez.crossEntropy (dat.targets[i]);\n//     loss.back();\n// }\n// print (loss)"],"outputs":[]},{"cell_type":"code","metadata":{"id":"7b7e86475","hideRun":false},"source":["// dat = mnist.getTrain(datasetRaw , 1)\n// print(`getTrain возвращает { inputs (${dat.inputs.length} по ${dat.inputs[0].length}) ,targets (${dat.targets.length} по ${dat.targets[0].length}) }.`)\n\n// let loss='',rez=''\n\n// // print(dat.inputs[0])\n\n// for (let i=0; i<dat.inputs.length; i++) {\n//     // print (i)\n//     rez = mnist.forward(dat.inputs[i])\n//     loss = rez.crossEntropy (dat.targets[i]);\n//     loss.back();\n// }\n// print (loss)"],"outputs":[]},{"cell_type":"code","metadata":{"id":"54704f176","hideRun":false,"autoRun":true},"source":["ODA({is: 'oda-mnist', imports: '@oda/button', template: /*html*/ `\n    <style>\n        :host {max-width:1000px; margin:auto; display:grid; grid-template-columns:1fr 1fr; grid-template-areas: 'input output' 'loss loss'; }\n        .block {border: 1px solid #4d85cf; padding:10px; margin:10px;}\n        .box { margin:10px}\n        .block h3 {margin:0 10px;}\n        oda-button {border: 1px solid #4d85cf; margin:10px;}}\n    </style>\n    <div class='block' style='grid-area:input;'>\n        <h3>input:</h3>\n        <svg class='box' width=\"281\" height=\"281\" xmlns='http://www.w3.org/2000/svg' viewBox='0 0 281 281'>\n            <rect x=\"0\" y=\"0\" width=\"281\" height=\"281\" fill='#4d85cf'/>\n            <rect ~for='rects' :x=\"$for.item?.x\" :y=\"$for.item?.y\" width=\"9\" height=\"9\" :fill='$for.item?.v?\"#070637\":\"#a9caff\"'/>            \n        </svg>\n    </div>\n    <div class='block' style='grid-area:output;'>\n        <h3>output:</h3>\n        <svg class='box' width=\"281\" height=\"281\" xmlns='http://www.w3.org/2000/svg' viewBox='0 0 281 281'>\n            <rect x=\"0\" y=\"0\" width=\"281\" height=\"281\" fill='#a9caff'/>\n            <g ~for='result' :transform=\"'translate(0,'+ ($for.index * 28) +')'\">\n                <rect x=\"2\" y=\"2\" :width=\"276*$for.item\" height=\"24\" :fill='maxIndex===$for.index? \"#ff00ff55\" : \"#4d85cf55\"'/>\n                <text x=\"265\" y=\"16\" font-size='16' dominant-baseline=\"middle\" fill=\"#070637\">{{$for.index}}</text>\n                <text x=\"5\" y=\"16\" font-size='16' dominant-baseline=\"middle\" fill=\"#070637\">{{($for.item*100).toFixed(2)}} %</text>\n            </g>\n            <text x=\"150\" y=\"160\" font-size='200' dominant-baseline=\"middle\" text-anchor=\"middle\" fill=\"#070637\">{{maxIndex}}</text>                \n        </svg>\n    </div>\n    <div class='block' style='grid-area:loss;'>\n        <h3>loss:</h3>\n        <svg class='box' :width :height xmlns='http://www.w3.org/2000/svg' :viewBox=\"'0 0 ' + width + ' ' + height\">\n            <rect x=\"0\" y=\"0\" :width :height fill='#a9caff'/>\n            <path :d='pathD' fill=\"none\" stroke=\"#070637\" stroke-width=\"2\"/>\n        </svg>\n    </div>\n    <oda-button :label='go?\"pause\":\"play\"' :icon='go?\"av:pause\":\"av:play-arrow\"' @tap=\"_go()\"></oda-button> \n    `,\n    get rects() {\n        return this.input.map((v,i)=> {\n            let [x,y] = [i%28, ~~(i/28)].map(a=>a*10+1)\n            return {x,y,v}\n        } )\n    },\n    get maxIndex() { return this.result.reduce((a,b,i,c)=>c[a]>b?a:i,0) },\n\n    get pathD(){\n        if (this.pointsL.length<2) return ''\n        let padding = Math.min(this.width,this.height)/10\n        let [w,h] = [this.width,this.height].map(x=>x-padding*2)\n        let dx = w/(this.pointsL.length-1)\n        let [min,max] = [Math.min(...this.pointsL),Math.max(...this.pointsL)]\n        let points = this.pointsL.map((v,i)=>[i*dx+padding,h-(v-min)/(max-min)*h+padding])\n        let rez = 'M ' + points[0].join(' ') + ' '\n        if (this.bezier) rez+=  'Q ' + points[0].join(' ') + ', ' + points[1].join(' ') + ' ' \n        else  rez += 'L ' + points[1].join(' ') + ' '\n        points.slice(2).forEach(e => rez += (this.bezier?'T ':'L ') + e.join(' ') + ' ' )\n        return rez\n    },\n\n    get pointsL() {\n        let [lL,lP] = [this.loss.length,this.maxPoint]\n        if (lL<lP) return this.loss\n        let newP = Array(lP-1).fill(0).map((_,i)=>{\n            let idx = Math.floor(i*(lL/(lP-1)))\n            let dL = Math.floor(lL/(lP-1))+1\n            return this.loss.slice(idx,idx+dL).reduce((a,c)=>a+c)/dL\n        })\n        newP.push(this.loss[lL-1])\n        return newP\n    },\n\n    go:false,\n    _go(){\n        this.go = !this.go\n        this.steps()\n    },\n\n    width:281*2+10*6+2,\n    height:281,\n    maxPoint:100,\n\n    input: {\n        $def: new Array(28*28).fill(0)\n    },\n    result:{\n        $def: new Array(10).fill(0.1)\n    },\n    loss:{\n        $def:[]//new Array(20000).fill(0).map(_=> Math.random()*5-2)\n    },\n\n    mnist: new MNIST(),\n    getTrain:getTrain,\n\n    step() {\n        let dat = this.getTrain(undefined, 1)\n        let loss, rez;\n        for (let i=0; i<dat.inputs.length; i++) {\n            rez = this.mnist(dat.inputs[i])\n            loss = rez.crossEntropy (dat.targets[i]);\n            this.loss.push(loss.data[0])\n            loss.back();\n            if (i===0) {\n                this.input = dat.inputs[i]\n                this.result = rez.data\n            }\n            // console.log(loss.data[0])\n        }\n    },\n    steps(){\n        if (this.go) setTimeout(() => {\n            this.step()\n            this.steps()\n        }, 0)            \n    }\n\n})\n"],"outputs":[]},{"cell_type":"html","metadata":{"id":"189f97824ef"},"source":["<oda-mnist></oda-mnist>"]},{"cell_type":"code","metadata":{"id":"f7b1365c51","hideRun":false},"source":["layer1 = nm.linear(10, 10);\nlayer2 = nm.linear(10, 10);\nprint(`layer1 (${layer1.dim_in} x ${layer1.dim_out}), layer2 (${layer2.dim_in} x ${layer2.dim_out})`)\n\n// layer3 = new BinLayer(input.length, target.length);"],"outputs":[{"data":{"text/plain":"layer1 (undefined x undefined), layer2 (undefined x undefined)"}}]},{"cell_type":"code","metadata":{"id":"12d005b792f","hideRun":false},"source":["// print(tensor.LEARNING_RATE)\ntensor.LEARNING_RATE = 0.3;\n// print(tensor.LEARNING_RATE)\nloss = 0\nfor (let i=0; i<10; i++) {\n    input = Array(10).fill(0)\n    input[Math.floor(Math.random()*10)]=1\n    // print(input.join(''))\n    \n    result = layer1(input);\n    // print('layer1', result);\n    result = result.sigm();\n    // print('sigm1', result);\n    result = layer2(result);\n    // print('layer2', result.data);\n    result = result.sigm();\n    \n    result = result.softmax();\n    \n    \n    \n    let res = ''\n    result.data.forEach(x=> res += (' ' + x.toFixed(1)) )\n    // print(res)\n\n    print(` input = ${input.join('   ')} \\n result=${res} \\n max=    ${softmax(result.data).join('   ')}` )\n    // print('sigm2',, ,  ;\n    \n    loss = result.crossEntropy (input);\n    // print('loss', loss.data[0]);\n    loss.back();\n}\nprint('loss', loss.data[0]);\n\n\nprint([...result.data])\n\n\n// i = 0 "],"outputs":[{"data":{"text/plain":"ReferenceError:\nsoftmax is not defined\n(27:54)"}}]},{"cell_type":"code","metadata":{"id":"120f8586aca","hideRun":false},"source":["\n// if (i<dat.targets.length) {\n//     res = mnist(dat.inputs[i])\n//     loss = res.MSE(dat.targets[i])\n//     print(`subStep= ${i} target=${dat.targets[i].join('')} res=${res.data} `)\n//     print('loss',loss.data[0])\n//     loss.back()\n//     i += 1\n// }\n \n\n\n// loss = res.MSE(target)\n\n// print(mnist.layer1.WEIGHTS.data.toString())\n// res1 = mnist(input)\n// loss1 = res.MSE(target)\n// print(res1.data)\n// print(loss1.data)\n// res2 = mnist(input)\n// loss2 = res.MSE(target)\n// print(res2.data)\n// print(loss2.data)"],"outputs":[]},{"cell_type":"code","metadata":{"id":"5a7d878b1b","hideRun":false},"source":["function binarize (grad_i) {\r\n    let p = Math.max(0,Math.min(1,(grad_i+1)/2)) // σ(x) = hard sigmoid\r\n    return p>Math.random() // +1 with probability p = σ(x), -1 otherwise.\r\n}\r\n\r\nlet grad = -0.7\r\nprint (`σ(x) = ${Math.max(0,Math.min(1,(grad+1)/2))} = ${Math.max(0,Math.min(1,(grad+1)/2))*100} % ` )\r\n\r\nlet n = 1000\r\nlet rezz = Array(n).fill(grad).map(g => binarize(g)).reduce((akk,b) => { b? akk.true++:akk.false++; return akk },{true:0,false:0} )\r\n\r\nprint(`true: ${rezz.true}, (${rezz.true/n*100} %) `)"],"outputs":[{"data":{"text/plain":"σ(x) = 0.15000000000000002 = 15.000000000000002 % "}},{"data":{"text/plain":"true: 159, (15.9 %) "}}]},{"cell_type":"code","metadata":{"id":"14213e4b005","hideRun":false},"source":["v = Array(15).fill(0).map(a =>  (Math.random()>0.5)?0:1  ) // [0,1,1,1,0]\r\nmul = v.filter(b=>b).reduce((akk,b) => akk*(-1), 1 )>0\r\nprint (mul)\r\nresult = 'return (' + v.map((_,i)=>{\r\n                    return '(v['+i+'] - 1)';\r\n            }).filter(l=>l).join(` + `) + ')&1;\\n';\r\nprint(result)\r\nconst fn = new Function('v',result);\r\nprint(fn(v))\r\n// print(`in= ${v.join('')}  mul =`fn(v))"],"outputs":[{"data":{"text/plain":"true"}},{"data":{"text/plain":"return ((v[0] - 1) + (v[1] - 1) + (v[2] - 1) + (v[3] - 1) + (v[4] - 1) + (v[5] - 1) + (v[6] - 1) + (v[7] - 1) + (v[8] - 1) + (v[9] - 1) + (v[10] - 1) + (v[11] - 1) + (v[12] - 1) + (v[13] - 1) + (v[14] - 1))&1;\n"}},{"data":{"text/plain":"1"}}]},{"cell_type":"code","metadata":{"id":"91775068b6","hideRun":false},"source":["    // print(`input= ${input.join('')} result = ${result.data.map(x=>(Math.round(x*10)/10))} ` )\n    \nprint(`-1- ${Array(5).fill(0).map(y=>Math.random()).map(x=>(Math.round(x*10)/10))}) -1-`)\n\nh = Array(5).fill(0).map(y=>Math.random())\nprint(`-2- ${h.map(x=>(Math.round(x*10)/10))}) -2-`)\n"],"outputs":[{"data":{"text/plain":"-1- 0.8,0.9,0.6,0.7,1) -1-"}},{"data":{"text/plain":"-2- 0.8,0.7,0.2,0.5,0.3) -2-"}}]},{"cell_type":"code","metadata":{"id":"13884c43847","hideRun":false},"source":["// let softmax = (output) => {\n//     let maximum = output.reduce(function(p,c) { return p>c ? p : c; });\n//     let nominators = output.map(function(e) { return Math.exp(e - maximum); });\n//     let denominator = nominators.reduce(function (p, c) { return p + c; });\n//     let softmax = nominators.map(function(e) { return e / denominator; });\n//     let maxIndex = 0;\n//     softmax.reduce(function(p,c,i){if(p<c) {maxIndex=i; return c;} else return p;});\n//     let result = [];\n//     for (var i=0; i<output.length; i++) (i==maxIndex)? result.push(1) : result.push(0)\n//     return result;\n// }\n\n// let tt = Object.values({\n//     \"0\": 0.09848282486200333,\n//     \"1\": 0.12310634553432465,\n//     \"2\": 0.09121625870466232,\n//     \"3\": 0.12418807297945023,\n//     \"4\": 0.11233071237802505,\n//     \"5\": 0.09030517935752869,\n//     \"6\": 0.08965815603733063,\n//     \"7\": 0.0996328815817833,\n//     \"8\": 0.08942568302154541,\n//     \"9\": 0.081653892993927\n// })\n// print(softmax([1,3,8]))\n\nlet softmax = (output) => {\n    let exps = output.map(x=>Math.exp(x))\n    let sum = exps.reduce((akk,v)=>akk+v)\n    return exps.map(e=>e/sum)\n}\nprint(softmax([1,3,8]))\n\nx = tensor.from([1,3,8])\n\nprint(x.softmax())"],"outputs":[{"data":{"text/plain":"[\n    0.0009049591825877395,\n    0.006686794167383233,\n    0.992408246650029\n]"}},{"data":{"text/plain":"{\n    \"$\": \"tensor\",\n    \"shape\": \"3\",\n    \"dType\": \"Float32Array\",\n    \"data\": \"0.0009049591608345509 0.006686794105917215 0.992408275604248\"\n}"}}]},{"cell_type":"code","metadata":{"id":"15a0ed373ae","hideRun":false},"source":["xor = [\n  { input: [0, 0], output: [0]},\n  { input: [0, 1], output: [1]},\n  { input: [1, 0], output: [1]},\n  { input: [1, 1], output: [1]}];\n  \nlayer_xor = nm.linear(2, 1, true);\ntensor.LEARNING_RATE = 0.3;\nloss = 0"],"outputs":[]},{"cell_type":"code","metadata":{"id":"6fd7cadaff","hideRun":false},"source":["\nloss = 0\nfor (let i=0; i<1000; i++) {\n    let x = xor[Math.floor(Math.random()*4)]\n    \n    // print (tensor.from(x.input) ) \n\n    result = layer_xor(tensor.from(x.input));\n\n    // print(` input = ${x.input.join(',')}  result= ${result.data[0].toFixed(2)} ` )\n    // print('sigm2',, ,  ;\n    \n    loss = result.MSE(x.output);\n    // print('loss', loss.data[0]);\n    loss.back();\n}\nprint('loss', loss.data[0]);"],"outputs":[{"data":{"text/plain":"loss\n0.1590086966753006"}}]},{"cell_type":"code","metadata":{"id":"82ab1f8db2","hideRun":false},"source":["\nloss = 0\nfor (let i=0; i<1000; i++) {\n    let x = xor[Math.floor(Math.random()*4)]\n    \n    // print (tensor.from(x.input) ) \n\n    result = layer_xor(tensor.from(x.input));\n\n    // print(` input = ${x.input.join(',')}  result= ${result.data[0].toFixed(2)} ` )\n    // print('sigm2',, ,  ;\n    \n    loss = result.MSE(x.output);\n    // print('loss', loss.data[0]);\n    loss.back();\n}\nprint('loss', loss.data[0]);"],"outputs":[{"data":{"text/plain":" input = 0,0  result= 0.29 "}},{"data":{"text/plain":" input = 0,1  result= 0.96 "}},{"data":{"text/plain":" input = 1,0  result= 0.84 "}},{"data":{"text/plain":" input = 1,1  result= 1.51 "}}]}],"metadata":{},"nbformat":4,"nbformat_minor":2}