-
Notifications
You must be signed in to change notification settings - Fork 213
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
WebAssembly support #269
Comments
Hey, thanks for your interest in tract! I have never touched wasm myself, but I'll be glad to help in any way I can. Sorry I have broken the support so recently, I think we can use conditional compilation to deal with the memory maps. I have no objection putting a WASM build under CI. Feel free to send me one or two pointers, I'll try to do this over the week-end. We are also in dire need of a release, but I keep postponing it because I want to wrap up the command line refactoring. Depending on how big the JS wrapper is, and how much coupling it will have with the API, we could consider inclusion in the main repo, and cover it with the same CI. As for WebGL, it would be interesting to see if we can plug it in tract-linalg. I agree it is a separate issue. I think we should also consider tract-tensorflow (which really should be similar to tract-onnx), but I'm perfectly happy to start with just tract-onnx. Also, I think @Geal did some work on this very same area just a few months ago. I'm very enthusiastic about this! I can't wait to see a static page browser-side demo with mobilenet and a webcam! Or any kind of voice demo of course. |
Awesome! I'm excited to start working on this. No worries about breaking support for WASM, it's actually remarkable that WASM was supported until so recently without explicitly trying to do so :) Plugging WebGL into tract-linalg sounds interesting. I'm not familiar enough with both of these to judge whether that would be possible. But if so, it'd be fantastic. However it shouldn't be a top priority for initial browser support. Regarding CI: The first and most important step is just building the relevant crates for WebAssembly i. e.
Tests will likely be more difficult to run since WASM inherently does not have access to the file system via I'm also curious to see how tract in the browser compares to the WASM backend of ONNX.js and TFJS, maybe that'd open up some opportunities for performance improvement. |
Also, I have a few ideas about how much we need to expose (been thinking about doing a FFI interface for a while). I don't think you can realistically do it with load + predict, but here is a possible subset that will cover simple stateless workflows, like image categorisation. It's really what transpires from https://github.com/snipsco/tract/blob/master/examples/tensorflow-mobilenet-v2/src/main.rs . Onnx works exactly the same way. So if I'm trying to simplify this, this is where I think we can get: 1/ We can collapse for simple cases the framework instatiation with model loading.
could become 2/ Unfortunately we can not really skip the size hinting part. We have to do it after loading and before optimising. It's a bit of a pain, but we can try to cover only the simplest cases for a start, maybe assuming everything is f32, that there is only one input, and that the output can be found automatically. The only missing bit would be then input shape, so a simple array of int would work. We can do a full TensorFact binding in the future if we need it. 3/ we can collapse into_optimized() with the SimplePlan::new() . A simple convenience model 4/ predict boils down to calling SimplePlan::run. We could eventually collapse 1,2,3 in a single function call that would be the
I like the idea, if it is practical, to try and keep a consistent API between various interface. It does not mean I want to bind everything from tract-core to JS, but if there are high-level shortcuts we want in a JS interface, I can't see why we should not have them at tract-core level. So I'm all ears about what you find out :) You mentioned LSTM and conv 1D, so I suspect you're after some real time voice or something... For that, we will need to expose the SimpleState too. And depending on the model, we may also need to expose the magic "S" streaming dimension and the pulse API (which I still think of as experimental : it does work but it is not nice to use). |
Thanks for the additional info!
That makes a lot of sense. I considered the tract API to be fixed in my initial message. If we can add higher-level functions to the tract core, it wouldn't only make the interfaces consistent but also make working with tract from Rust much nicer. Ideally, in my opinion, that would be just Actually I've been rewriting an NLP project (https://github.com/bminixhofer/nnsplit) where I previously had parallel implementations of the model in TF and PyTorch - the model became more complex and I didn't want to keep writing everything twice. I'm not at all familiar with voice applications.
From the brief description I read in your readme streaming does sound very cool and useful for your audio applications. It is not something I need right now. To get started I'd propose the following:
What do you think about this? |
Sounds good to me. It's good that you don't need streaming, it makes the exercise much more incremental. Let's see what come out of the POC, and we'll take it from there. |
I'm done with a proof of concept which runs Squeezenet in the browser! Check out https://bminixhofer.github.io/tract-js/demos/dist/ (similar to https://microsoft.github.io/onnxjs-demo/#/squeezenet). The JS code is here. ProblemsI ran into a couple of problems, none however on the tract side:
Binding StructureWriting the bindings themselves went very smoothly though and I didn't encounter any bigger problems. The bindings currently expose a The The See the code here. It is just ~ 100 LOC. Limitations
Takeaways
new tractjs.Model("model.onnx", {
"facts": {
0: ["float32", [1, 224, 224, 3]]
},
"optimize": true
// ...
}) while for Rust, some sort of builder pattern would be a good fit for a higher-level API as you mentioned.
Next stepsI'm going to work on a small demo which allows the user to upload a If you wouldn't mind, it'd be great if we could discuss the higher-level API (and tract and ONNX in general) some time via a call or IRC if you have time. You can send me an email at bminixhofer@gmail.com. |
I've made nice progress with the bindings at https://github.com/bminixhofer/tractjs.
It was hard to get all the moving pieces to work together (Typescript + web workers + WASM) but it works nicely now. I'd have a couple of questions @kali we should address before releasing the library:
|
Nicely done, thanks for taking the time to do tf! Not that I am verse enough in 2020 web stuff to judge :) Questions:
|
Thanks! In that case it is fine to leave It's good to know that you are considering binary size. I am happy with a "there is ongoing work in tract to reduce size" disclaimer in tractjs and leaving it at that for now. For my application larger size is not a deal breaker since it will be lazy loaded anyway and it's just a demo. But I'd imagine that some potential users need smaller size. You're right, the bindings are very light and should break well in case of changes. I'm just not 100% confident in the correctness of the current implementation (especially options). I guess the best way is to have a couple of tests using different options and some different models from the tract CI. Regarding a non-browser example: Browser have built-in WASM support. To run WASM outside of a browser you need a runtime such as wasmtime or wasmer. And then, currently, you need quite a bit of glue code to interact with WASM and to make a neat API. So in short, non-browser usages of wasm are quite different to what I've done and should probably be a different project altogether. Hopefully that gets easier (and aligns more) in the future :) |
Do you still feel like migrating this as a sub-dir inside the main project ? we can probalby leave it out of the locked-step release process, but having whatever tests we come with in the same CI would make sense. |
I'd argue tractjs is fitting because it is JS bindings for tract. tract-wasm would be fitting if it was not bound to the browser (i. e. used a WASM runtime like wasmer). I'm not sure about migrating it into this repo to be honest. The same CI would definitely be better, and it is not a lot of code, but:
So I think the negatives outweigh the positives at the moment. That said, I started working on tests. I have one more question: tract works with TF 1.x |
Ok. Let's leave it on your side then. tract-tf works with TF 1.x "frozen" model format, and without versions compatibility really established. The SavedModel is what actually makes TF 2 so difficult to handle. There is a small collections of models that CI runs (see .travis/native.sh) which are hosted on public urls... |
Just added the benchmarks to https://bminixhofer.github.io/tractjs/. Looks very good for tract! Especially LSTMs are much faster than in TFJS, even than the WebGL backend. The WASM backends of TFJS and ONNX.js are missing though, I'l see if I can add them. |
There was some more work left to do with:
so aside of some minor changes doc updates I have to do tractjs is ready for release 🎉 One remaining question is whether I should wait for #300 to be merged. It's not a must but it would be very nice. I am not in a hurry, but I'm not sure how much work is left for that. Thoughts? Or any other objections to releasing tractjs? |
I would like to merge the branch containing the fix for #300 (among other things) tomorrow, so... |
Ok, great! |
done ! |
tractjs is officially released! 🎉 We can close this. |
Great! I just notice the last entry in the FAQ. About invalid shapes and ranks not being caught early or not at all ? Does it still happen ? Because I thought I had done what was required. |
Oh to be honest I haven't checked in a while. I thought it didn't change. |
change is here... 5847c17#diff-c89b37e22115a5dc0b72425de44d246f Did not make an entry for it in the changelog, as I consider it a safety fix, but it is kinda breaking actually (as it makes tract less lenient). |
Hi!
At the moment, there is no easy way to reliably run ONNX models in the browser. ONNX.js exists but is apparently unmaintained and lacks support for important operations like
Conv1d
andLSTM
.The alternative is Tensorflow.js which does not directly support ONNX so a model would have to be converted from ONNX to TF, then to a TFJS model, which does also not work at the moment (see onnx/onnx-tensorflow#490).
So there is a bit of a gap in the ecosystem there.
That gap could be filled by compiling tract to WASM, and exposing a higher-level API (i. e.
load
andpredict
functions) to Javascript. WebGL support would of course be missing but that is out of scope.I did some prototyping today, and got the latest release (
tract-onnx = "0.6.3"
) to work in the browser without any changes. So I think a JS wrapper would not be too hard to make.I'll start working on this in the next couple of days. Depending on how it goes and if there is interest on your side, this could be merged back into tract at a later point.
It would be great if you could officially support compiling to WASM, and add WASM to the CI (e. g. the current master branch does not compile to WASM because of the memory maps from 99c622a).
Thanks, and please let me know what you think!
The text was updated successfully, but these errors were encountered: