Code viewer for World: New World 2222222

// Cloned by atharva joshi on 4 Dec 2021 from World "New World" by atharva joshi 
// Please leave this clone trail here.
 
//---- normal P5 code -------------------------------------------------------
$.getScript("/uploads/atharva/prepareData.js")

//$.getScript ( "https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.2.0/p5.min.js")
$.getScript("https://unpkg.com/ml5@0.7.1/dist/ml5.min.js")
$.getScript("https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@0.11.7")




thehtml = '<h1>Doodle Classifier</h1> '
AB.msg(thehtml, 1);

thehtml = '<h2>Click the Train button to train the Model, then the Test button to pass it a test image.</h2> '
AB.msg(thehtml, 2);

thehtml = '<button class="train" id="train">train</button>';
AB.msg(thehtml, 4);

// 3 Training header
thehtml = '<span class="alert alert-primary" id="training-alert" role="alert">Training...</span>';
AB.msg(thehtml, 7);
thehtml = '<span class="alert1 alert-primary" id="Accuray-alert" role="alert"></span>';
AB.msg(thehtml, 8);
//   thehtml = '<textarea class="testpercentage"></textarea>'
//   AB.msg ( thehtml, 7 );

thehtml = '<h2>Draw a Train, Rainbow or Cat and click the Guess button.</h2> '
AB.msg(thehtml, 9);

// 5 Testing header
thehtml = '<button class="guess" id="guess">guess</button>';
AB.msg(thehtml, 10);
thehtml = '<button class="btn btn-success" id="generate">Generate</button>';
AB.msg(thehtml, 12);

// 7 Demo header 
thehtml = '<button class="clear" id="clear">clear</button>';
AB.msg(thehtml, 14);


thehtml = '<span id="output" class="alert alert-success" role="alert">๐ŸŽ‰๐ŸŽ‰Draw a cat/flower/bird and Guess๐ŸŽ‰๐ŸŽ‰</span>';
AB.msg(thehtml, 17);
AB.newDiv('canvas')

let dataObjectsArray = [];

// Contains the arrays of preloaded data
let dataPreload = [];
let temp_training_data;
let temp_training_labels;

// Model
let model;
let nn;
// Tensors
xs = {};
ys = {};
testing_xs = {};
testing_ys = {};

const numberOfEachDoodle = 1000;
const data_proportion = 0.8;

function preload() {
    console.log("Preloading data");
    let filename;
    for (let i = 0; i < doodleLabelList.length; i++) {
        filename = doodleLabelList[i].toLowerCase();
        dataPreload[i] = loadBytes("/uploads/atharva/" + filename + ".bin");
    }
    console.log(dataPreload);
    console.log("Done");
}

// Setup function of p5.js (called after preload)
async function setup() {
    let canvas = createCanvas(280, 280);
    canvas.parent("canvas");
    background(0);
    initializeData();
    console.log("Creating training tensors");

    let rTensors = prepareData(training_data, training_labels);
     temp_training_data = training_data;
     temp_training_labels = training_labels;

    xs = rTensors[0];
    ys = rTensors[1];
    console.log("Done");
    console.log("Creating testing tensors");
    // TODO: Something less cancerous
    rTensors = prepareData(testing_data, testing_labels);
    testing_xs = rTensors[0];
    testing_ys = rTensors[1];
    // Log progress
    console.log("Done");
    // Log progress
    console.log("Creating model");
    // Let's build the model
    model = buildModel();
    // Log progress
    console.log("Done");

    let trainButton = select("#train");
    let trainingAlert = document.getElementById("training-alert");
    trainingAlert.style.display = "none";
    let accurayalert = document.getElementById("Accuray-alert");
    accurayalert.style.display = "none";

    trainButton.mousePressed(
        // Log progress
        () => {
            trainingAlert.style.display = "inline";
            accurayalert.style.display = "inline";

            console.log("Training model");

            // Let's train the model (this .then(() => thingy is an application of the
            // new ES6 functionnality combined with the js promises).
            train(trainingAlert, accurayalert).then(async () => {
                // Log progress
                console.log("Done");
                trainingAlert.style.display = "none";
                trainingAlert.className = "btn btn-disabled";

                // const saveResult = await model.save("indexeddb://my-model");
            });
        }
    );

    // const model =  await tf.loadModel('indexeddb://my-model');

    let guessButton = select("#guess");

    guessButton.mousePressed(function() {
        let inputs = [];
        let inputImage = [];
        let img = get();
        img.resize(28, 28);
        img.loadPixels();
        // Convert black in white drawings to white in black drawings(training doodles are white on black)
        for (let i = 0; i < dataLength; i++) {
            let alpha = img.pixels[i * 4];
            // normalize the pixels
            inputs[i] = alpha / 255.0;
        }
        // We need to create a 2D array with this pixel because the model has been
        // trained with 2D tensors.
        inputImage[0] = inputs;

        // convert array to tensor
        let tensorToPredict = tf.tensor2d(inputImage);
        console.log(tensorToPredict);
        //  predict the doodle
        let guess = model.predict(tensorToPredict);
        let argMax = guess.argMax(1);
        let classifiedLabel = argMax.dataSync()[0];

        let classifiedDoodleLabel = doodleLabelList[classifiedLabel];
        const output = select("#output");
        output.html(classifiedDoodleLabel + "!!!");
        console.log("Guessed: " + classifiedDoodleLabel);
    });

    let clearButton = select("#clear");
    clearButton.mousePressed(function() {
        background(0);
        const output = select("#output");
        output.html("");
    });

    //////////////Genrating a Random image from dataset that is cat,flower,bird
    let generateButton = select("#generate");

    generateButton.mousePressed(function() {
        background(0);
        const output = select("#output");
        output.html("");
        let randomIndex = floor(
            random(
                numberOfEachDoodle * doodleLabelList.length * (1 - data_proportion)
            )
        );
        let offset = randomIndex * dataLength;
        let doodlePixels = testing_xs
            .dataSync()
            .subarray(offset, offset + dataLength);
        let otherOffset = randomIndex * doodleLabelList.length;
        let labelsResult = testing_ys
            .dataSync()
            .subarray(otherOffset, otherOffset + doodleLabelList.length);
        let doodleIndex;
        for (let i = 0; i < labelsResult.length; i++) {
            if (labelsResult[i] === 1) {
                doodleIndex = i;
            }
        }
        console.log(doodleLabelList[doodleIndex]);
        let img = createImage(28, 28);
        img.loadPixels();
        for (let i = 0; i < dataLength; i++) {
            let val = doodlePixels[i] * 255;
            img.pixels[i * 4 + 0] = val;
            img.pixels[i * 4 + 1] = val;
            img.pixels[i * 4 + 2] = val;
            img.pixels[i * 4 + 3] = 255;
        }
        img.updatePixels();
        img.resize(280, 280);
        image(img, 0, 0);
    });
}

function draw() {
    strokeWeight(12);
    stroke(255);
    if (mouseIsPressed) {
        line(pmouseX, pmouseY, mouseX, mouseY);
    }
}


//////////////////////////////////////  dataobject
class DataObject {
    constructor(label) {
        this.label = label;
        this.totalData = [];
        this.trainingData = [];
        this.testingData = [];
        this.trainingLabels = [];
        this.testingLabels = [];
        this.data_proportion = 0.8;
        this.numberOfEachDoodle = 1000;
        this.bytesArrayLength = 784;
        this.numberOfDoodles = 1000;
    }

    get trainingData() {
        return this._trainingData;
    }
    get testingData() {
        return this._testingData;
    }
    get trainingLabels() {
        return this._trainingLabels;
    }
    get testingLabels() {
        return this._testingLabels;
    }

    set trainingData(data) {
        this._trainingData = data;
    }

    set testingData(data) {
        this._testingData = data;
    }

    set trainingLabels(data) {
        this._trainingLabels = data;
    }

    set testingLabels(data) {
        this._testingLabels = data;
    }

    loadBytesData() {
        let index = doodleLabelList.indexOf(this.label);
        let bytesObject = dataPreload[index];
        // bytesObject.bytes is the actual bytes array
        this.totalData = bytesObject.bytes;
    }

    splitData() {
        console.log(this.numberOfDoodles);
        for (let i = 0; i < this.numberOfDoodles; i++) {
            // keeping track of index
            let offset = i * this.bytesArrayLength;

            // threshold for test/train data split
            let threshold = floor(this.data_proportion * this.numberOfDoodles);
            if (i < threshold) {
                // 1 - 800
                this.trainingData[i] = this.totalData.subarray(
                    offset,
                    offset + this.bytesArrayLength
                );
                this.trainingLabels[i] = this.label;
            } else {
                // 1 - 200
                this.testingData[i - threshold] = this.totalData.subarray(
                    offset,
                    offset + this.bytesArrayLength
                );
                this.testingLabels[i - threshold] = this.label;
            }
        }
    }
}




//////// training and testing
function buildModel() {
    
    
    const options = {
    
    task: 'imageClassification', // or 'regression'
    inputs: [128,128,4,255], // r, g, b
    debug: true
        }

 nn = ml5.neuralNetwork(options)
    ;
    
    
    
    for (j=0; j<temp_training_data ;j++){
    let offset = j * dataLength;
        let doodlePixels = temp_training_data
            .dataSync()
            .subarray(offset, offset + dataLength);
        let otherOffset = randomIndex * doodleLabelList.length;
        let labelsResult = temp_training_labels
            .dataSync()
            .subarray(otherOffset, otherOffset + doodleLabelList.length);
        let doodleIndex;
        for (let i = 0; i < labelsResult.length; i++) {
            if (labelsResult[i] === 1) {
                doodleIndex = i;
            }
        }
        console.log(doodleLabelList[doodleIndex]);
        let img = createImage(28, 28);
        img.loadPixels();
        for (let i = 0; i < dataLength; i++) {
            let val = doodlePixels[i] * 255;
            img.pixels[i * 4 + 0] = val;
            img.pixels[i * 4 + 1] = val;
            img.pixels[i * 4 + 2] = val;
            img.pixels[i * 4 + 3] = 255;
        }
        img.updatePixels();
        img.resize(280, 280);
    
  
    nn.addData({image : img } , {labels : labelsResult})
    }

    nn.normalizeData();
    /*let tempModel = tf.sequential();
    
    

    const hiddenLayer1_Units = 256;
    const hiddenLayers_Activation = "sigmoid";
    const hiddenLayer4_Units = 512;
    const hiddenLayer4 = tf.layers.dense({
        units: hiddenLayer4_Units,
        activation: hiddenLayers_Activation,
    });

    const hiddenLayer1 = tf.layers.dense({
        units: hiddenLayer1_Units,
        inputShape: dataLength,
        activation: hiddenLayers_Activation,
    });

    const hiddenLayer2_Units = 128;
    const hiddenLayer2 = tf.layers.dense({
        units: hiddenLayer2_Units,
        activation: hiddenLayers_Activation,
    });

    const hiddenLayer3_Units = 64;
    const hiddenLayer3 = tf.layers.dense({
        units: hiddenLayer3_Units,
        activation: hiddenLayers_Activation,
    });


    /*
    
    //output layer
    const outputLayer_Activation = "softmax";
    const output = tf.layers.dense({
        units: doodleLabelList.length,
        activation: outputLayer_Activation,
    });

    tempModel.add(hiddenLayer1);
    tempModel.add(hiddenLayer2);
    tempModel.add(hiddenLayer3);
    tempModel.add(output);

    const model_LearningRate = 0.5;
    const model_Optimizer = tf.train.adagrad(model_LearningRate);
    const model_Loss =  "meanSquaredError";
    tempModel.compile({
        optimizer: model_Optimizer,
        loss: model_Loss,
        metrics: ["accuracy"],
        debug: true
    });
    //tempModel.compile(optimizer=tf.train.adagrad(model_LearningRate), loss=tf.keras.losses.CategoricalCrossentropy(), metrics = ["accuracy"]);*/
    return nn;
}


async function train(alert, alert1) {
    /*const training_DoShuffle = true;
    const training_ValidationSplit = 0.2;
    const training_BatchSize = 16;
    const training_NumEpochs = 50;
    await model.fit(xs, ys, {
        shuffle: training_DoShuffle,
        validationSplit: training_ValidationSplit,
        batchSize: training_BatchSize,
        epochs: training_NumEpochs,
        callbacks: {
            onEpochEnd: (epochs, logs) => {
                console.log("Epoch: " + (epochs + 1));
                console.log("Loss: " + logs.loss);
                console.log("Accuracy: " + logs.acc.toFixed(2));
                alert.innerHTML = `Training ${epochs * 2}% done...`;
                alert1.innerHTML = `Accuracy: ${100 * logs.acc.toFixed(2)}`;

            },
        },
    });*/
    nn.train({epochs : 50}, function (){ alert.innerHTML = `Training ${epochs * 2}% done...`;
                alert1.innerHTML = `Accuracy: ${100 * logs.acc.toFixed(2)}` })
}