tractjs
Run ONNX and TensorFlow inference in the browser. A thin wrapper on top of tract.
Website | API Docs
Why tractjs instead of ONNX.js?
There is currently one other usable ONNX runner for the browser, ONNX.js. There are a couple of things tractjs does better:
- tractjs supports more operators. LSTMs (even bidirectional) are supported, while ONNX.js does not support any recurrent networks.
- tractjs is maintained. At the time of writing the last significant commit to ONNX.js was more than one year ago.
- tractjs is more convenient to use. It can build to a single file
tractjs.min.js
which contains the inlined WASM and WebWorker. The WASM backend of ONNX.js can not as easily be used without a build system.
There are however also some downsides to tractjs. See the FAQ.
Getting started
Without a bundler
<html>
<head>
<meta charset="utf-8" />
<script src="https://unpkg.com/tractjs/dist/tractjs.min.js"></script>
<script>
const model = new tractjs.Model("path/to/your/model");
model
.predict([new tractjs.Tensor(new Float32Array([1, 2, 3, 4]), [2, 2])])
.then((preds) => {
console.log(preds);
});
</script>
</head>
</html>
With a bundler
npm install tractjs
import * as tractjs from "tractjs";
const model = new tractjs.Model("path/to/your/model");
model
.predict([new tractjs.Tensor(new Float32Array([1, 2, 3, 4]), [2, 2])])
.then((preds) => {
console.log(preds);
});
FAQ
My model with dynamic input dimensions doesn't work. Why?
Currently, tract requires fully determined input dimensions to optimize a model. There are two options:
- Turn
optimize
off:
const model = new tractjs.Model("path/to/your/model", {
optimize: false,
});
This will however significantly impact performance.
- Set fixed input dimensions via input facts. Input facts are a way to provide additional information about input type and shape that can not be inferred via the model data:
const model = new tractjs.Model("path/to/your/model", {
inputFacts: {
0: ["float32", [1, 3, 224, 224]],
},
});
Be aware that the model will only work properly with inputs of this exact shape though.
There is ongoing work in tract to allow dynamically sized inputs.
What about size?
At the time of writing, tractjs is very large for web standards (8.5MB raw, 2.5MB gzipped). This is due to tract being quite large, and due to some overhead from inlining the WASM. But it's not as bad as it sounds. You can load tractjs lazily along your demo, where you will likely have to load significantly large weights too.
If you are working on a very size-sensitive application, get in touch and we can work on decreasing the size. There are some more optimizations to be done (e. g. an option not to inline WASM, and removing panics from the build). There is also ongoing work in tract to decrease size.
What about WebGL / WebNN support?
tractjs are bindings to the tract Rust library which was originally not intended to be run on the web. WebGL / WebNN support would be great, but would require lots of web-specific changes in tract so it is currently not under consideration.
Why do I still get some output back when passing an input with invalid shape / rank?
Currently tract does not do much error handling in regard to input dimensionality. So most of the time you will get some output back, it will just not be correct. There is ongoing work in tract to be more strict about input dimensionality.
License
Apache 2.0/MIT
All original work licensed under either of
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall
be dual licensed as above, without any additional terms or conditions.