What?
We are going to build an image classifier with MobileNet in TensorFlow js from scratch (installing python included)Why?
I wanted to learn how to use a pre-trained model in javascript.How?
Installing Python and TensorFlow
Follow this https://www.tensorflow.org/install/install_windows for windows installation.
- Download python 3.5 or 3.6. Version 3.7 will NOT work out as of July 2018. It doesn't download tensorflow js (henceforth referred to as tfjs)
- Run pip3 install --upgrade tensorflow (for CPU only)
Or pip3 install --upgrade tensorflow-gpu (for GPU)
Convert MobileNet model to tfjs model
- Get the MobileNet model from here.
- This model is in tensorflow and needs to be converted to a tfjs model. Refer https://github.com/tensorflow/tfjs-converter
tensorflowjs_converter \ --input_format=tf_frozen_model \ --output_node_names='MobilenetV1/Predictions/Reshape_1' \ --saved_model_tags=serve \ F:/image/image- classifier/mobilenet_v1_1.0_224/mobilenet_v1_1.0_224_frozen.pb \ F:/image/image-classifier/modelv1
Load the frozen model
I use GitHub as a fast and dirty way to host static files. Upload your model to a GitHub repository and use the raw path in your code.
const MODEL_URL =
"https://raw.githubusercontent.com/shivangidas/image-
classifier/master/modelv1/tensorflowjs_model.pb";
const WEIGHTS_URL =
"https://raw.githubusercontent.com/shivangidas/image-
classifier/master/modelv1/weights_manifest.json";
let model;
(async () => {
model = await tf.loadFrozenModel(MODEL_URL, WEIGHTS_URL);
})();
Get ImageNet classes
ImageNet Dataset has 1000 classes. You can read more here.
let IMAGENET_CLASSES = [];
$.getJSON(
"https://raw.githubusercontent.com/shivangidas/image-
classifier/master/mobilenet/imagenet_classes.json",
function(data) {
$.each(data, function(key, val) {
IMAGENET_CLASSES.push(val);
});
}
);
Make Predictions
- We get the image from the image tag. Refer full code for image selection part.
let imageData = document.getElementById("imageSrc"); - Make tensor from the image using tfjs inbuilt function fromPixels()
Resize the tensor to 224x224 and make the datatype float.
The MobileNet version we are using (MobileNet_v1_1.0_224) takes an input of size [batchSize,224,224, 3] let pixels = tf.fromPixels(imageData) .resizeNearestNeighbor([224, 224]) .toFloat();- Normalize tensors to values between -1 and 1. Add a dimension as we have just one image to predict, no batch.
let offset = tf.scalar(128);
pixels = pixels.sub(offset).div(offset).expandDims();
- Call predict on the tensor
const output = await model.predict(pixels);
- We get probabilities of 1000 classes.
Sort and map to the classes we imported at the beginning.
Here we are showing the top ten classes.const predictions = Array.from(output.dataSync()) .map(function(p, i) { return { probabilty: p, classname: IMAGENET_CLASSES[i] }; }) .sort((a, b) => b.probabilty - a.probabilty) .slice(0, 10);console.log(predictions);
Putting it together:
let offset = tf.scalar(128);
let imageData = document.getElementById("imageSrc");
let pixels = tf.fromPixels(imageData)
.resizeNearestNeighbor([224, 224])
.toFloat();
pixels = pixels.sub(offset).div(offset).expandDims();
const output = await model.predict(pixels);
const predictions = Array.from(output.dataSync())
.map(function(p, i) {
return {
probabilty: p,
classname: IMAGENET_CLASSES[i]
};
})
.sort((a, b) => b.probabilty - a.probabilty)
.slice(0, 10);
console.log(predictions);
That's it!
Well not really. We are making 7 extra tensors that we need to dispose to prevent a memory leak. That means the tensors created will persist in GPU and take up space. I went to great lengths to dispose of them individually but if you come up with a better solution (maybe using tidy), do let me know.
References
All the links above
No comments:
Post a Comment