Skip to content

Commit

Permalink
further example cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
shiffman authored and bomanimc committed Nov 4, 2020
1 parent e0d9dce commit 6ebea59
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 102 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,89 +5,63 @@

/* ===
ml5 Example
Image classification using MobileNet and p5.js
Classification with Convolutional Neural Network
This example uses a callback pattern to create the classifier
=== */
let nn;
let cnn;

function setup() {

createCanvas(200, 200);
const options = {
inputs: [16, 16, 3],
task: 'imageClassification',
inputs: [2, 2, 4],
debug: true
}
nn = ml5.neuralNetwork(options);

debug: true,
};
cnn = ml5.neuralNetwork(options);
addData();
nn.train({
epochs: 20,
batchSize: 2
}, finishedTraining)

cnn.train({ epochs: 50 }, finishedTraining);
}

function finishedTraining() {
nn.classify([
0, 0, 255, 255, 0, 0, 255, 255,
0, 0, 255, 255, 0, 0, 255, 255
], gotResults)

const r = random(255);
const g = random(255);
const b = random(255);
background(r, g, b);
const newPixels = [];
for (let i = 0; i < 256; i += 1) {
newPixels.push(r, g, b);
}
cnn.classify({ pixels: newPixels }, gotResults);
}

function gotResults(err, result) {
function gotResults(err, results) {
if (err) {
console.error(err)
console.error(err);
}
console.log(result)
console.log(results);
const percent = 100 * results[0].confidence;
createP(`${results[0].label} ${nf(percent, 2, 1)}%`);
}

function addData() {
const myData = [{
label: "red-square",
value: [
255, 0, 0, 255, 255, 0, 0, 255,
255, 0, 0, 255, 255, 0, 0, 255
]
},
{
label: "green-square",
value: [
0, 255, 0, 255, 0, 255, 0, 255,
0, 255, 0, 255, 0, 255, 0, 255
]
},
{
label: "blue-square",
value: [
0, 0, 255, 255, 0, 0, 255, 255,
0, 0, 255, 255, 0, 0, 255, 255
]
const redPixels = [];
for (let i = 0; i < 256; i += 1) {
redPixels.push(random(255), 0, 0);
}

]

// method 1: adding data as objects
for(let i = 0; i < myData.length; i += 1){
const item = myData[i];
const xInputObj = {
pixelArray: item.value
}

const yInputObj = {
label: item.label
}
nn.addData(xInputObj, yInputObj)
const bluePixels = [];
for (let i = 0; i < 256; i += 1) {
bluePixels.push(0, 0, random(255));
}


// method 2:adding data as arrays with
const labelsOptions = {
inputLabels: ['pixelArray'],
outputLabels: ['label']
}
for(let i = 0; i < myData.length; i += 1){
const item = myData[i];
nn.addData([item.value], [item.label], labelsOptions)
const greenPixels = [];
for (let i = 0; i < 256; i += 1) {
greenPixels.push(0, random(255), 0);
}
}

cnn.addData({ pixels: redPixels }, { label: 'red' });
cnn.addData({ pixels: bluePixels }, { label: 'blue' });
cnn.addData({ pixels: greenPixels }, { label: 'green' });

cnn.normalizeData();
}
55 changes: 27 additions & 28 deletions src/NeuralNetwork/NeuralNetwork.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as tf from "@tensorflow/tfjs";
import * as tf from '@tensorflow/tfjs';
import axios from 'axios';
import callCallback from "../utils/callcallback";
import { saveBlob } from "../utils/io";
import { randomGaussian } from "../utils/random";
import callCallback from '../utils/callcallback';
import { saveBlob } from '../utils/io';
import { randomGaussian } from '../utils/random';

class NeuralNetwork {
constructor() {
Expand Down Expand Up @@ -42,9 +42,9 @@ class NeuralNetwork {
* uses switch/case for potential future where different formats are supported
* @param {*} _type
*/
createModel(_type = "sequential") {
createModel(_type = 'sequential') {
switch (_type.toLowerCase()) {
case "sequential":
case 'sequential':
this.model = tf.sequential();
return this.model;
default:
Expand Down Expand Up @@ -184,17 +184,17 @@ class NeuralNetwork {
let modelName;
let callback;

if (typeof nameOrCb === "function") {
modelName = "model";
if (typeof nameOrCb === 'function') {
modelName = 'model';
callback = nameOrCb;
} else if (typeof nameOrCb === "string") {
} else if (typeof nameOrCb === 'string') {
modelName = nameOrCb;

if (typeof cb === "function") {
if (typeof cb === 'function') {
callback = cb;
}
} else {
modelName = "model";
modelName = 'model';
}

this.model.save(
Expand All @@ -209,8 +209,8 @@ class NeuralNetwork {
],
};

await saveBlob(data.weightData, `${modelName}.weights.bin`, "application/octet-stream");
await saveBlob(JSON.stringify(this.weightsManifest), `${modelName}.json`, "text/plain");
await saveBlob(data.weightData, `${modelName}.weights.bin`, 'application/octet-stream');
await saveBlob(JSON.stringify(this.weightsManifest), `${modelName}.json`, 'text/plain');
if (callback) {
callback();
}
Expand All @@ -227,37 +227,36 @@ class NeuralNetwork {
if (filesOrPath instanceof FileList) {
const files = await Promise.all(
Array.from(filesOrPath).map(async file => {
if (file.name.includes(".json") && !file.name.includes("_meta")) {
return { name: "model", file };
} else if (file.name.includes(".json") && file.name.includes("_meta.json")) {
if (file.name.includes('.json') && !file.name.includes('_meta')) {
return { name: 'model', file };
} else if (file.name.includes('.json') && file.name.includes('_meta.json')) {
const modelMetadata = await file.text();
return { name: "metadata", file: modelMetadata };
} else if (file.name.includes(".bin")) {
return { name: "weights", file };
return { name: 'metadata', file: modelMetadata };
} else if (file.name.includes('.bin')) {
return { name: 'weights', file };
}
return { name: null, file: null };
}),
);

const model = files.find(item => item.name === "model").file;
const weights = files.find(item => item.name === "weights").file;
const model = files.find(item => item.name === 'model').file;
const weights = files.find(item => item.name === 'weights').file;

// load the model
this.model = await tf.loadLayersModel(tf.io.browserFiles([model, weights]));
} else if (filesOrPath instanceof Object) {

// load the modelJson
const modelJsonResult = await axios.get(filesOrPath.model, {responseType:'text'});
const modelJsonResult = await axios.get(filesOrPath.model, { responseType: 'text' });
const modelJson = JSON.stringify(modelJsonResult.data);
// TODO: browser File() API won't be available in node env
const modelJsonFile = new File([modelJson], "model.json", { type: "application/json" });
const modelJsonFile = new File([modelJson], 'model.json', { type: 'application/json' });

// load the weights
const weightsBlobResult = await axios.get(filesOrPath.weights, {responseType:'blob'});
const weightsBlobResult = await axios.get(filesOrPath.weights, { responseType: 'blob' });
const weightsBlob = weightsBlobResult.data;
// TODO: browser File() API won't be available in node env
const weightsBlobFile = new File([weightsBlob], "model.weights.bin", {
type: "application/macbinary",
const weightsBlobFile = new File([weightsBlob], 'model.weights.bin', {
type: 'application/macbinary',
});

this.model = await tf.loadLayersModel(tf.io.browserFiles([modelJsonFile, weightsBlobFile]));
Expand Down
20 changes: 10 additions & 10 deletions src/NeuralNetwork/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ const DEFAULTS = {
debug: false,
learningRate: 0.2,
hiddenUnits: 16,
noTraining: false
noTraining: false,
};
class DiyNeuralNetwork {
constructor(options, cb) {
this.callback = cb;

// Is there a better way to handle a different
// Is there a better way to handle a different
// default learning rate for image classification tasks?
if (options.task === 'imageClassification') {
DEFAULTS.learningRate = 0.02;
Expand Down Expand Up @@ -107,7 +107,7 @@ class DiyNeuralNetwork {
*/
init(callback) {
// check if the a static model should be built based on the inputs and output properties
if(this.options.noTraining === true){
if (this.options.noTraining === true) {
this.createLayersNoTraining();
}

Expand All @@ -125,15 +125,15 @@ class DiyNeuralNetwork {
* createLayersNoTraining
*/
createLayersNoTraining() {
// Create sample data based on options
// Create sample data based on options
const { inputs, outputs, task } = this.options;
if (task === 'classification') {
for (let i = 0; i < outputs.length; i += 1) {
const inputSample = new Array(inputs).fill(0);
this.addData(inputSample, [outputs[i]]);
}
} else {
const inputSample = new Array(inputs).fill(0);
const inputSample = new Array(inputs).fill(0);
const outputSample = new Array(outputs).fill(0);
this.addData(inputSample, outputSample);
}
Expand All @@ -150,7 +150,7 @@ class DiyNeuralNetwork {
return tf.tidy(() => {
const weights = this.neuralNetwork.model.getWeights();
const weightCopies = [];
for (let i = 0; i < weights.length; i+=1) {
for (let i = 0; i < weights.length; i += 1) {
weightCopies[i] = weights[i].clone();
}
nnCopy.neuralNetwork.model.setWeights(weightCopies);
Expand Down Expand Up @@ -1036,8 +1036,6 @@ class DiyNeuralNetwork {
return unformattedResults;
}



/**
* classify
* @param {*} _input
Expand Down Expand Up @@ -1195,15 +1193,17 @@ class DiyNeuralNetwork {
* mutate the weights of a model
* @param {*} rate
* @param {*} mutateFunction
*/
*/

mutate(rate, mutateFunction) {
this.neuralNetwork.mutate(rate, mutateFunction);
}

/**
* create a new neural network with crossover
* @param {*} other
*/
*/

crossover(other) {
const nnCopy = this.copy();
nnCopy.neuralNetwork.crossover(other.neuralNetwork);
Expand Down

0 comments on commit 6ebea59

Please sign in to comment.