Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tf.loadModel Fails to load keras model #924

Closed
YajJackson opened this issue Nov 20, 2018 · 28 comments
Closed

tf.loadModel Fails to load keras model #924

YajJackson opened this issue Nov 20, 2018 · 28 comments
Assignees
Labels
type:support user support questions

Comments

@YajJackson
Copy link

To get help from the community, check out our Google group.

TensorFlow.js version

0.13.5

Browser version

Version 70.0.3538.110 (Official Build) (64-bit)

Describe the problem or feature request

I can't load a keras model created by tfjs.converters.save_keras_model

Code to reproduce the bug / link to feature request

Used this to create model.json

import keras
import tensorflowjs as tfjs
mobilenet = keras.applications.mobilenet.MobileNet()
tfjs.converters.save_keras_model(mobilenet, './tfjs-models/MOBILENET')

Attempt to load model here

const model = await tf.loadModel(`./tfjs-models/MOBILENET/model.json`);

result:

Uncaught (in promise) RangeError: byte length of Float32Array should be a multiple of 4
    at new Float32Array (<anonymous>)
    at o (io_utils.ts:116)
    at Object.decodeWeights (io_utils.ts:79)
    at models.ts:287
    at index.ts:68
    at Object.next (index.ts:68)
    at o (index.ts:68)

Any help would be greatly appreciated.

@caisq
Copy link
Contributor

caisq commented Nov 20, 2018

Can you open the browser's devtools and check the status of the responses to the weight requests. Those should show up as names such as "group1-shard1of2", etc. Make sure that the response status is 200 OK and that the content of the response is correct. We've seen various kinds of HTTP servers having trouble serving binary weight files like those correctly.

@YajJackson
Copy link
Author

@caisq I'm serving these files locally, and see that rather than 200, each file has a 304 'Not Modified' status. network responses

@caisq
Copy link
Contributor

caisq commented Nov 20, 2018

What kind of HTTP server are you using, @YajJackson ?

@YajJackson
Copy link
Author

I've been using parceljs.

@YajJackson
Copy link
Author

YajJackson commented Nov 20, 2018

Is there anyway for me to test that the binaries are served properly besides tf.loadModel() failing?

@dsmilkov
Copy link
Contributor

dsmilkov commented Nov 20, 2018

Couple of things:

  • Can you share with us the model.json? In particular search for "group1-shard1ofX" and see if you can access that file directly from the browser.

  • On our side, we will improve the error message shown to the user when calling loadModel():

    • inspect the http response code and if it's not 200 OK, let the user know the response code
    • inspect the http encoding and make sure it's octet-stream / binary
    • print out the actual url that we tried to access (the url obtained by merging the base path of model.json and the "paths" field)
    • print the relevant sub-section of model.json that was used to make this request.

@YajJackson
Copy link
Author

YajJackson commented Nov 20, 2018

@dsmilkov I can access the files directly from the browser. After clearing my cache, the 304s returned to 200 OK, so looks like we're good there. Turns out that the group1-shardxofy responses had Content-Type: text/html; charset=UTF-8.

headers

@caisq
Copy link
Contributor

caisq commented Nov 20, 2018

+1 to Daniel's point that we should throw a more informative error message when the response code isn't 200 OK.

@YajJackson
Copy link
Author

@caisq I think 304 would also be acceptable.

@YajJackson
Copy link
Author

YajJackson commented Nov 20, 2018

Good news! after switching from serving my files with parcel to webpack-dev-server, the content-type header was updated appropriately to application/octet-stream. I'm no longer receiving the previous error, however, it now appears to be silently failing.

Consider this snippet:

let model;
const loadModel = async m => {
  $("#loading-spinner").show();
  model = await tf.loadModel(`/assets/tfjs-models/${m}/model.json`);
  console.log(model);
  $("#loading-spinner").hide();
};

*where m is 'MOBILENET'
Previously, tf.loadModel() would fail with the error I provided initially. Now, it seems that it's endlessly loading, without ever timing out. What could be the cause of this?

@YajJackson
Copy link
Author

YajJackson commented Nov 20, 2018

I can't say exactly what solved the issue I just mentioned, but after the following steps I was able to get that snippet to work properly:

  1. I changed tf.loadModel() to target 'https://storage.googleapis.com/tfjs-models/tfjs/iris_v1/model.json' (from example 4 in the loadModel docs)
  2. Cleared browser cache
  3. Loaded site, and observed that the example model loaded successfully.
  4. Switched back to tf.loadModel(`/assets/tfjs-models/${m}/model.json`);
  5. Loaded site, observed successful MOBILENET model load.

¯_(ツ)_/¯

@JWSunny
Copy link

JWSunny commented Jan 14, 2019

@YajJackson hello, when i use the tfjs loadfrozenmodel,i have the same problem: RangeError: byte length of Float32Array should be a multiple of 4, the statue is 200 and i alse use the parceljs, but also have the mistake, can you have any other suggestions? thanks

@JWSunny
Copy link

JWSunny commented Jan 14, 2019

@YajJackson
image

@caisq
Copy link
Contributor

caisq commented Jan 14, 2019 via email

@JWSunny
Copy link

JWSunny commented Jan 16, 2019

@YajJackson @caisq hello,i have similar problem,but the group* file is 1.4k,because of the parcel Can't serve static resources with no filename extension( parcel-bundler/parcel#1098 ),how can you success load the group* files? can you provide some suggestions, thanks.

@caisq
Copy link
Contributor

caisq commented Jan 16, 2019 via email

@JWSunny
Copy link

JWSunny commented Jan 16, 2019

@caisq i rename the group* file as group*.bin and modify the key of "path" in the json, but failed, because the parcel use the require("weightsManifest.json") and return the file path is weightsManifest.(hash value).json, so the new path of group*.bin is group*.(hash value).bin。
image

@caisq
Copy link
Contributor

caisq commented Jan 16, 2019 via email

@JWSunny
Copy link

JWSunny commented Jan 16, 2019

@caisq thanks,i'll try it.

@JWSunny
Copy link

JWSunny commented Jan 17, 2019

@caisq thanks for your suggestions, i solved the problem successfully,yesterday.

@vpanichkin
Copy link

vpanichkin commented Jan 29, 2019

Try to collect the solution in step-by-step tutorial:

  1. Install parcel-plugin-static-files
  2. Create static folder in your project folder
  3. Locate you model, weights and chunks there
  4. Add to your chunks (beginning with group1-shard) extension .bin
  5. Change file weights_manifest.json : find key "paths" and add extension .bin to all items in array
  6. Alter MODEL_URL and WEIGHTS_URL in your script respectively and parcel will serve files for you: http://localhost:1234/tensorflowjs_model.pb
    http://localhost:1234/weights_manifest.json
  7. Restart parcel

After that, the issue should disappear!

@mrmartin
Copy link

mrmartin commented Feb 3, 2019

Same problem. What worked for me was

  1. adding .bin extension to group1-shard*of*
  2. changing the .json file to reflect this

@dsmilkov dsmilkov assigned pyu10055 and unassigned caisq Feb 4, 2019
@dsmilkov
Copy link
Contributor

dsmilkov commented Feb 4, 2019

If you've experienced problems loading models in the latest release, we are working on a fix: #1188.

It's related to the problem that we are strict about the Content-Type header produced by the http server - we expect application/json for model.json and octet-stream for weights.

We are going to revert the content type check.

@mrmartin
Copy link

mrmartin commented Feb 5, 2019

#1188 will be helpful, but I don't think it's the root of the problem.

At least for me, the weights are an octet-stream even when it was failing.
The error was:
Expected content type application/octet-stream but got null.

and here's the file, with Content-Type:
tmp

Could it be that the issue is with misreading file type instead?

@dsmilkov
Copy link
Contributor

dsmilkov commented Feb 5, 2019

Hi all,

The fix just went in: tensorflow/tfjs-core#1532 and will be available in 0.15.1, which we'll release in 2 days.

@dsmilkov dsmilkov closed this as completed Feb 5, 2019
@adrienZ
Copy link

adrienZ commented Mar 11, 2019

Same problem. What worked for me was

  1. adding .bin extension to group1-shardof
  2. changing the .json file to reflect this

Worked like a charm for me thanks @mrmartin

@yingshaoxo
Copy link

Try to collect the solution in step-by-step tutorial:

  1. Install parcel-plugin-static-files
  2. Create static folder in your project folder
  3. Locate you model, weights and chunks there
  4. Add to your chunks (beginning with group1-shard) extension .bin
  5. Change file weights_manifest.json : find key "paths" and add extension .bin to all items in array
  6. Alter MODEL_URL and WEIGHTS_URL in your script respectively and parcel will serve files for you: http://localhost:1234/tensorflowjs_model.pb
    http://localhost:1234/weights_manifest.json
  7. Restart parcel

After that, the issue should disappear!

It just too complex for using!

elwin013/parcel-plugin-static-files-copy#37

parcel-bundler/parcel#1098

@theairbend3r
Copy link

I have a similar error - RangeError: attempting to construct out-of-bounds TypedArray on ArrayBuffer

I'm using express.js to send the json+bin files to react so that I can run inference in the browser itself.

Here's the relevant Express.js code. The json+bin files are all in the same folder.

app.use(
  "/api/pokeml/classify",
  express.static(path.join(__dirname, "classifier_models/original/model.json"))
)

Here's how I'm loading this in React -

  useEffect(() => {
    async function fetchModel() {
      // const mobileNetModel = await mobilenet.load()
      // const classifierModel = await axios.get("api/pokeml/classify")
      const classifierModel = await tf.loadLayersModel(
        "http://localhost:3001/api/pokeml/classify"
      )
      setModel(classifierModel)
    }
    fetchModel()
  }, [])

The model.json file loads correctly but the shards do not -
Screenshot from 2020-06-23 10-57-47

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type:support user support questions
Projects
None yet
Development

No branches or pull requests