I'm trying to move a tensorflow model from its original html into a react app (built with create-react-app).
My App.js looks like this:
import logo from './logo.svg';
import * as tf from "@tensorflow/tfjs";
// import { loadImageclassification } from "@tensorflow/tfjs";
import './App.css';
import * as automl from "@tensorflow/tfjs-automl";
// import model from './model.json';
// 'model.json'
function App() {
var loadFile = function(event) {
var image = document.getElementById('output');
image.src = URL.createObjectURL(event.target.files[0]);
run();
};
async function run() {
// const model = await tf.loadImageclassification('model.json');
const model = await tf.automl.loadImageclassification('model.json');
const image = document.getElementById('output');
const predictions = await model.classify(image);
//const predictions = predictions.sort(function(a, b){return a-b});
console.log(predictions);
// Show the resulting object on the page.
const pre = document.getElementById('result');
pre.textContent = JSON.stringify(predictions, null, 2);;
}
return (
<div className="App">
<div className="hero-text">
<h1>classifier</h1>
<h3>Upload a picture to see what type it is! </h3>
<p>
<input type="file" accept="image/*" name="image" id="file" onChange={loadFile} />
</p>
<div id="demobox">
<p>
<label for="file">Upload your image</label>
</p>
</div>
<p><img id="output" width="200" alt="output" /></p>
<div className="result" id="result">
</div>
</div>
</div>
);
}
export default App;
My index.html looks like this:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script src="https://unpkg.com/@tensorflow/tfjs"></script>
<script src="https://unpkg.com/@tensorflow/tfjs-automl"></script>
</body>
</html>
However, when I try to npm start the app, I get some variation of this error:
Attempted import error: 'automl' is not exported from '@tensorflow/tfjs' (imported as 'tf').
I've tried changing around my import structure, to no avail, but I assume it's something obvious and basic that I'm doing wrong, so I figured there was a good shot that someone here might see the problem within a few seconds.
Edit:
I've hacked my way through a couple of the errors I was getting, and my App.js file currently looks like this (the only difference in my index.html file is that I removed the two <script src="...unpkg..."></script>s):
import logo from './logo.svg';
import * as tf from "@tensorflow/tfjs";
// import { loadImageclassification } from "@tensorflow/tfjs";
import './App.css';
import * as automl from "@tensorflow/tfjs-automl";
import * as modelJSON from './model.json';
function App() {
var loadFile = function(event) {
var image = document.getElementById('output');
image.src = URL.createObjectURL(event.target.files[0]);
run();
};
async function run() {
console.log(modelJSON);
// const model = await tf.loadImageclassification('model.json');
const model = await automl.loadImageClassification(modelJSON);
const image = document.getElementById('output');
const predictions = await model.classify(image);
console.log(predictions);
const pre = document.getElementById('result');
pre.textContent = JSON.stringify(predictions, null, 2);
}
return (
<div className="App">
<div className="hero-text">
<h1>classifier</h1>
<h3>Upload a picture to see what type it is! </h3>
<p>
<input type="file" accept="image/*" name="image" id="file" onChange={loadFile} />
</p>
<div id="demobox">
<p>
<label htmlFor="file">Upload your image</label>
</p>
</div>
<p><img id="output" width="200" alt="output" /></p>
<div className="result" id="result">
</div>
</div>
</div>
);
}
export default App;
However, I am now getting the following error, which seems to be issuing from somewhere in the loadImageClassification method:
Unhandled Rejection (TypeError): modelUrl.lastIndexOf is not a function
And in the "view source" section of the error message is this:
24 |
25 | /** Loads and parses the dictionary. */
26 | export async function loadDictionary(modelUrl: string): Promise<string[]> {
> 27 | const lastIndexOfSlash = modelUrl.lastIndexOf('/');
28 | const prefixUrl =
29 | lastIndexOfSlash >= 0 ? modelUrl.slice(0, lastIndexOfSlash + 1) : '';
30 | const dictUrl = `${prefixUrl}dict.txt`;
I'll keep blundering around, but maybe one of you will have mercy on me.
Edit 2:
Changed my run function to this:
async function run() {
const modelUrl = "<MY_GITHUB_PAGES_URL_LINKING_TO_MODEL.JSSON>";
const model = await automl.loadImageClassification(modelUrl);
...
Based on the information that loadImageClassification uses a fetch request under the hood and so requires a remote file (which is strange, because it seemed to work fine in the static index.html original version of this same project).
However, I am now getting the following 404 for the GET request to the https://myusername.github.io/model.json page:
Edit 3:
It appears github pages won't work for that, so I am now trying it just with a localhost express server, which at present looks like this:
const modelJSON = require('./model.json');
const express = require("express");
const bodyParser = require("body-parser");
const CORS = require("cors");
const app = express();
app.use(bodyParser.json());
app.use(CORS());
let modelObj = modelJSON;
app.get("/", (req, res) => {
// console.log(modelObj);
res.send(modelObj);
});
app.listen(5000, () => {
console.log("Server listening on port 5000");
});
I can see the correct data when I navigate to localhost5000, but when I change
async function run() {
const modelUrl = "<MY_GITHUB_PAGES_URL_LINKING_TO_MODEL.JSSON>";
const model = await automl.loadImageClassification(modelUrl);
...
to
async function run() {
const modelUrl = "http://localhost:5000/";
const model = await automl.loadImageClassification(modelUrl);
I get these errors:
Edit 4:
Now I am getting these errors:
My server.js file looks like this:
So presumably the problem now has to do with the fact that loadImageClassification assumes that the ...shard__of6.bin and dict files are in the same directory as the model.json file.
Now the question is probably: how to simulate the file structure that it (i.e., loadImageClassification) is expecting with an express js server.
Fundamental confusion:
I'm just don't understand why, when loadImageClassification is in the original static html, it does not seem to require a remote url from which to fetch model.json — but then when I put it in my react app, it suddenly gives me this error: "Fetch API cannot load file:///Users///client/src/model.json. URL scheme must be 'http' or 'https' for CORS request."
from Tensorflow automl model in react




No comments:
Post a Comment