Load Tensorflow js model from local file system in javascript - javascript

I have converted a keras model to tensorflow json format and saved it locally in my computer. I am trying to load that json model in a javascript code using the below command
model = await tf.loadModel('web_model')
But the model is not getting loaded.
Is there a way to load tensorflow json model from local file system?

I know you're trying to load your model in a browser but if anybody lands here that's trying to do it in Node, here's how:
const tf = require("#tensorflow/tfjs");
const tfn = require("#tensorflow/tfjs-node");
const handler = tfn.io.fileSystem("./path/to/your/model.json");
const model = await tf.loadLayersModel(handler);

LoadModel uses fetch under the hood. And fetch cannot access the local files directly. It is meant to be used to get files served by a server. More on this here.
To load a local file with the browser, there is two approaches, asking the user to upload the file with
<input type="file"/>
Or serving the file by a server.
In these two scenarios, tf.js provides way to load the model.
Load the model by asking the user to upload the file
html
<input type="file" id="upload-json"/>
<input type="file" id="upload-weights"/>
js
const uploadJSONInput = document.getElementById('upload-json');
const uploadWeightsInput = document.getElementById('upload-weights');
const model = await tfl.loadModel(tf.io.browserFiles(
[uploadJSONInput.files[0], uploadWeightsInput.files[0]]));
Serving the local files using a server
To do so, one can use the following npm module http-server to serve the directory containing both the weight and the model. It can be installed with the following command:
npm install http-server -g
Inside the directory, one can run the following command to launch the server:
http-server -c1 --cors .
Now the model can be loaded:
// load model in js script
(async () => {
...
const model = await tf.loadFrozenModel('http://localhost:8080/model.pb', 'http://localhost:8080/weights.json')
})()

const tf = require('#tensorflow/tfjs');
const tfnode = require('#tensorflow/tfjs-node');
async function loadModel(){
const handler = tfnode.io.fileSystem('tfjs_model/model.json');
const model = await tf.loadLayersModel(handler);
console.log("Model loaded")
}
loadModel();
This worked for me in node. Thanks to jafaircl.

If you're using React with create-react-app, you can keep your saved model files in your public folder.
For example, say you want to use the blazeface model. You would
Download the .tar.gz model from that web page.
Unpack the model into your app's public directory. So now you have the files from the .tar.gz file in a public subdir:
%YOUR_APP%/public/blazeface_1_default_1/model.json
%YOUR_APP%/public/blazeface_1_default_1/group1-shard1of1.bin
Load the model in your React app using
tf.loadGraphModel(process.env.PUBLIC_URL + 'blazeface_1_default_1/model.json'

You could try:
const model = await tf.models.modelFromJSON(myModelJSON)
Here it is in the tensorflow.org docs

Check out our documentation for loading models: https://js.tensorflow.org/api/latest/#Models-Loading
You can use tf.loadModel takes a string which is a URL to your model definition which needs to get served over HTTP. This means you need to start an http-server to serve those files (it will not allow you to make a request to your filesystem because of CORS).
This package can do that for you: npmjs.com/package/http-server

You could use insecure chrome instance:
C:\Program Files (x86)\Google\Chrome\Application>chrome.exe --disable-web-security --disable-gpu --user-data-dir=C:/Temp
Than you could add this script to redefine fetch function
async function fetch(url) {
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest
xhr.onload = function() {
resolve(new Response(xhr.responseText, {status: 200}))
}
xhr.onerror = function() {
reject(new TypeError('Local request failed'))
}
xhr.open('GET', url)
xhr.send(null)
})
}
After that be shure that you use the right model loader
my comment about loader issue
BUT your weights will be incorrect - as I understand there are some encoding problems.

If you are trying to load it in server side, use #tensorflow/tfjs-node instead of #tensorflow/tfjs and update to 0.2.1 or higher version to resolve this issue.

I am using React js for loading model (for image classification and more machine learning stuff)
Tensorflow.js do not support an Api to read a previously model trained
const file= new Blob()
file.src=modelJSON
const files= new Blob()
files.src=modelWeights
console.log(files)
const model= await tf.loadLayersModel(tf.io.browserFiles([file, files]));
[![enter image description here][1]][1]
You be able to create an APi in Express.js for servering your model (model.json and weigths.bin) if you use a web app (for a tensorflow.lite you could use a opencv.readTensorflowmodel(model.pb, weight.pbtxt)
References: How to load tensorflow-js weights from express using tf.loadLayersModel()?
const classifierModel = await tf.loadLayersModel(
"https://rp5u7.sse.codesandbox.io/api/pokeml/classify"
);
const im = new Image()
im.src =imagenSample//'../../../../../Models/ShapesClassification/Samples/images (2).png';
const abc= this.preprocessImage(im);
const preds = await classifierModel.predict(abc)//.argMax(-1);
console.log('<Response>',preds,'Principal',preds.shape[0],'DATA',preds.dataSync())
const responde=[...preds.dataSync()]
console.log('Maxmimo Valor',Math.max.apply(Math, responde.map(function(o) { return o; })))
let indiceMax = this.indexOfMax(responde)
console.log(indiceMax)
console.log('<<<LABEL>>>',this.labelsReturn(indiceMax))

If you are using Django, you should:
create a directory static in your app and put your model there.
load that static directory to the template where you want to use your model:
var modelPath = "{% static 'sampleModel.json' %}">
Don't forget to also load tensorflow.js library:
<script src="https://cdn.jsdelivr.net/npm/#tensorflow/tfjs"></script>
Now you can load your model:
<script>model = await tf.loadGraphModel(modelPath)</script>

i found a solution that it works. You can replace the url with a localhost url on xampp, for example (directory = model) http://localhost/model/model.json and after that you have to disable your browser CORS policy. For me i found a chrome extention and removed cors for my specific tab and it worked.
Thank me later!!

Related

Electron doesn't add json file to application

This is my first electron/node application, I m trying to use a json file as a datastore. so I created a simple one index.json under the app folder next to index.js|css|html
I installed a npm package jsonfile that is loading just fine
When I try to load my json file the EOF is rised claiming that there is no json file, and I can see that using the DevTools source tab that my json file is not there ( not loaded )
I tried force reload from electron app menu.
Here is my files code that is reading my json
const jsonfile = require('jsonfile')
const file = '/index.json';
var json;
jsonfile.readFile(file)
.then(obj => json = obj)
.catch(error => console.error(error))
------------ Edit
correcting the path name to index.json or ./index.json rises the same issue
You can use the native fs (filesystem) module.
let path = "index.json"
const fs = require('fs');
const json = JSON.parse(fs.readFileSync(path));
Thanks for your support
For me the issue was more about file system handling than electron.
All I did is to chmod my project folder to assure that I will be able to read and write into the index.json datastore
sudo chmod -R 777 /opt/workspaces/electron/myElectronPrpjectFolder
Then for a better path resolution I used the basic idea used in electron archtype, It more error safe
const path = require('path')
const file = path.join(__dirname,'index.json');
var json;
var html = "";// The returned object.
$(document).ready(function () {
jsonfile.readFile(file)
.then(obj => {
json = JSON.parse(JSON.stringify(obj));
console.log(JSON.stringify(json))
parseIssues(json.children);
document.getElementById('a').innerHTML = html;
})
.catch(error => console.error(error))
});
You can see that I m using JQuery in this snippet but it also works without JQuery.
in resume, better path resolve policy with granted priveleges on folder.
Thanks

Unable to load python trained model in tensorflow.js

I am getting the following errors when I am trying to load a Model, which I trained in Python, when I use the loadModel() function tensorflow.js:
Failed to load resource: net::ERR_NAME_NOT_RESOLVED
Uncaught (in promise) TypeError: Failed to fetch
Below is the predict.js file
console.log ("hello");
let model;
(async function () {
model = await tf.loadModel("http://keras_model/model.json");
$(".progress-bar").hide();
console.log("it works");
})();
The directory structure:
main
-dataset (contains images for training the model)
-training_scripts (python scripts to train the model)
-user_interface
--server.js (server made using node.js(and express))
--static (this folder contains the trained keras model)
--index.html (html file to be served)
--predict.js
--keras_model(this folder contains the model.json file)
Any help will be appreciated!!
If you want to load local files in tfjs you need to use the file type file:/// and for this to work you need the node extension of tfjs. You can load it by installing and requiring node-fetch into your program.
You can also use the fileSystem handler exposed in tfjs-node like this:
const tf = require("#tensorflow/tfjs");
const tfn = require("#tensorflow/tfjs-node");
const handler = tfn.io.fileSystem("./path/to/your/model.json");
const model = await tf.loadModel(handler);

loadFrozenModel does not work with local files

need help with async/await.
currently studying https://github.com/tensorflow/tfjs-converter.
and I'm stumped at this part of the code (loading my python converted saved js model for use in the browser):
import * as tf from '#tensorflow/tfjs';
import {loadFrozenModel} from '#tensorflow/tfjs-converter';
/*1st model loader*/
const MODEL_URL = './model/web_model.pb';
const WEIGHTS_URL = '.model/weights_manifest.json';
const model = await loadFrozenModel(MODEL_URL, WEIGHTS_URL);
/*2nd model execution in browser*/
const cat = document.getElementById('cat');
model.execute({input: tf.fromPixels(cat)});
I noticed it's using es6 (import/export) and es2017 (async/await) so I've used babel with babel-preset-env, babel-polyfill and babel-plugin-transform-runtime. I've used webpack but switched over to Parcel as my bundler (as suggested by the tensorflow.js devs). In both bundlers I keep getting the error that the await should be wrapped in an async function so I wrapped the first part of the code in an async function hoping to get a Promise.
async function loadMod(){
const MODEL_URL = './model/web_model.pb';
const WEIGHTS_URL = '.model/weights_manifest.json';
const model = await loadFrozenModel(MODEL_URL, WEIGHTS_URL);
}
loadMod();
now both builders say that the 'await is a reserved word'. vscode eslinter says that loadMod(); has a Promise void. (so the promise failed or got rejected?)
I'm trying to reference the javascript model files using a relative path or is this wrong? I have to 'serve' the ML model from the cloud? It can't be from a relative local path?
Any suggestions would be much appreciated. Thanks!
tf.loadFrozenModel uses fetch under the hood. Fetch is used to get a file served by a server and cannot be used with local files unless those are served by a server. See this answer for more.
For loadFrozenModel to work with local files, those files needs to be served by a server. One can use http-server to serve the model topology and its weights.
// install the http-server module
npm install http-server -g
// cd to the repository containing the files
// launch the server to serve static files of model topology and weights
http-server -c1 --cors .
// load model in js script
(async () => {
...
const model = await tf.loadFrozenModel('http://localhost:8080/tensorflowjs_model.pb', 'http://localhost:8080/weights_manifest.json')
})()
You try to use this function
tf.loadFrozenModel(MODEL_FILE_URL, WEIGHT_MANIFEST_FILE_URL)
And your code has a syntax error. If you use the key words 'await', you must define one async function, such as below:
async function run () {
/*1st model loader*/
MODEL_URL = './model/web_model.pb';
const WEIGHTS_URL = '.model/weights_manifest.json';
const model = await loadFrozenModel(MODEL_URL, WEIGHTS_URL);
/*2nd model execution in browser*/
const cat = document.getElementById('cat');
model.execute({input: tf.fromPixels(cat)});
}
run();

How to change URLs inside a client-side JS at build?

I have a JS file that gets served by a Node.Js server to a web browser.
When running in Dev I want the client-side JS to send data to the localhost so can I log the payload to my local node.js server.
But when we deploy to production I of course want the client-side JS file to send data from the browser to my Production URL.
Right now I've been manually modifying the URL in the JS file that gets served, toggling between localhost and the public URL before I do my Gulp build but I know that is not the right way, and prone to the "whoops I forgot" issue.
What is the correct approach? Or best practice? Is there some gulp package I should be using?
In case you haven't solved this by now you can use gulp-replace. For example, say you have a build task that reads from /src, minifies your JavaScript and outputs it to /dist. You can pipe your JavaScript source to replace() (first argument is the development URL, second argument is your production URL):
var gulp = require('gulp');
var path = require('path');
var jsmin = require('gulp-jsmin');
var replace = require('gulp-replace');
var SOURCE = 'src';
var BUILD = 'dist';
var URL = 'http://www.whatever.com/api';
gulp.task('build', function () {
return gulp.src(path.join(SOURCE, '**/*.js'))
.pipe(jsmin())
.pipe(replace('http://localhost:3000/api', URL))
.pipe(gulp.dest(BUILD))
});
If you have a file ./src/script.js that does a simple jQuery AJAX request, see the before and after effect below.
Before
$.get('http://localhost:3000/api', function (data) {
console.log(data);
});
After (ignoring minification)
$.get('http://www.whatever.com/api', function (data) {
console.log(data);
});

Remote File Upload Protractor test

I am writing tests in protractor which a JS based framework and selenium test stack for running tests. I am facing an issue where I have to test file upload.
Problem I am having is File I am trying to upload is in the test package whereas selenium node is a separate server so it will not get the file.
I tried using file descriptor although the file name is set contents don’t get uploaded.
Below is the code snippet that I have.
var remote = require('selenium-webdriver/remote');
browser.setFileDetector(new remote.FileDetector());
var absolutePath = path.resolve(__dirname, "../specs/data/baseProducts.csv");
$('input[type="file"]').sendKeys(absolutePath);
Do you have any inputs for the same?
Or do you know anyone who has written file upload tests in JS using selenium?
Your help will be much appreciated
First of all, for the file upload to work with remote selenium servers, you need the latest protractor (currently, 3.0.0) (which would have the latest selenium-webdriver nodejs package as a dependency).
Then, these two lines are crucial to be able to send files over the wire to the selenium node:
var remote = require('selenium-webdriver/remote');
browser.setFileDetector(new remote.FileDetector());
And, now you should be able to upload files as if you are running tests locally.
Complete working test (tested on BrowserStack, works for me perfectly):
var path = require('path'),
remote = require('selenium-webdriver/remote');
describe("File upload test", function () {
beforeEach(function () {
browser.setFileDetector(new remote.FileDetector());
browser.get("https://angular-file-upload.appspot.com/");
});
it("should upload an image", function () {
var input = element(by.model("picFile")),
uploadedThumbnail = $("img[ngf-src=picFile]");
// no image displayed
expect(uploadedThumbnail.isDisplayed()).toBe(true);
// assuming you have "test.jpg" right near the spec itself
input.sendKeys(path.resolve(__dirname, "test.jpg"));
// there is a little uploaded image displayed
expect(uploadedThumbnail.isDisplayed()).toBe(true);
});
});
Also see relevant issues:
setFileDectector unable to set remote file detector
Protractor file uploads - Support remote uploads with webdriver setFileDetector & LocalFileDetector
Thanks to #alecxe for his answer!
I just had this situation, trying to upload some files to BrowserStack. In my case I'm using Cucumber - Protractor - NodeJs - BrowserStack. This code is already tested, working in local env and BorwserStack.
let path = require('path');
let remote = require('selenium-webdriver/remote');
this.When(/^I upload a file$/, () => {
browser.setFileDetector(new remote.FileDetector());
var fileToUpload = '../image_with_title.jpg';
var absolutePath = path.join(__dirname, fileToUpload);
page.fileupload.sendKeys(absolutePath);
});
The magic line is:
let remote = require('selenium-webdriver/remote');
This solution worked for me.
The below two lines of code did the trick.
var remote = require('selenium-webdriver/remote');
browser.setFileDetector(new remote.FileDetector());
I am able to upload the file remote server.

Categories