Model converter

Simplify, optimize, and inspect ONNX models with onnxsim and onnx-optimizer, compiled to WebAssembly. Everything runs locally in your browser — models are never uploaded.

versionsloading…

Parse a text graph

Paste an ONNX model or graph in the textual representation — the form onnx.parser.parse_graph / parse_model accept. It is parsed into a model by the WebAssembly module (a bare graph is wrapped into a model with a default-domain opset import) and shown in the Before Netron pane. Local function definitions (<domain: "..."> name (...) => (...) {...} blocks after the graph) are parsed too, and the wrapped model gains an opset import for each function's domain so it validates. With convert after parsing on, it is also run straight through the currently selected convert mode below (Simplify / Optimize / Inline functions, or a single debug pass).

Convert a model

⏳ Loading WebAssembly runtime… the file picker is disabled until it is ready.
Fetches the model straight from the Hugging Face Hub in your browser (nothing is uploaded), then runs it through the same Simplify / Optimize path as an uploaded file. Bare names default to the onnxmodelzoo org; any owner/repo or direct .onnx URL works too. Picking a model (or entering a repo id / URL) shows its download size first, so you can see how big it is before fetching. When a repo holds more than one .onnx, the largest is auto-detected; use the file selector to convert a different one.
Shareable link: the input model and options can be set from the URL — e.g. ?model=onnxmodelzoo/resnet18d_Opset18 or ?model=https://…/foo.onnx&optimizer=optimize&cf=0. It loads and converts automatically (add &autoload=0 to only prefill). Keys: model (hf/url), graph (an ONNX text graph to parse), optimizer (a.k.a. mode/processor; the convert mode — simplify/optimize/optimize_fixed/inline/infer_shapes/data_propagation/fold_constant), constant_fold/cf, shape_inference/si, inline_functions/inline, tensor_size_threshold/tst, target_opset/opset, autorun/autoinfer (auto-run inference after each conversion), backend (prefills the backend-test URL). Setting an input updates this URL so it stays shareable (uploads excepted).
Builds a link that reproduces the current input and all the conversion options below (processor, constant fold, shape inference, tensor size threshold, target opset) and copies it to your clipboard. Uploaded local files have no URL, so share a Hugging Face model / URL, a backend test case, or a pasted text graph.
Downloads via @huggingface/hub, reconstructing the file from content-addressed chunks and caching them in IndexedDB so repeated / overlapping loads reuse them. On by default; falls back to a direct download automatically if the Xet path isn't available (e.g. a non-Xet repo or a CORS block).
The in-browser Xet client (XetBlob) fetches a file serially, so parallel shards reads it in that many concurrent byte-range slices to saturate your link — this is what makes Xet fast enough to be the default (~10 or fewer is usually best; 1 disables sharding). Xet also gives chunk dedup / cache reuse across repeated or overlapping loads.
Fetches model.onnx and the test data (test_data_set_N/ of input_*.pb / output_*.pb) from GitHub, runs the model through onnxruntime-web with the test inputs, and checks each output against the expected tensor within tolerance. Pick a preset above or paste a GitHub tree / raw.githubusercontent.com URL; listing uses GitHub's public (rate-limited) API. With convert the model on, the fetched model is also run through the selected convert mode below (and shown in the Netron panes).

Convert mode & options


single pass (debug):







Visualize with Netron (before / after)

Renders the model graph with a self-hosted Netron: the original model on the left and the simplified/optimized result on the right, so you can compare them side by side. Nothing is uploaded — the model bytes are posted straight into the embedded Netron in your browser, so there is no model-size limit. Use export SVG to save the rendered graph as an SVG image.

Netron is driven here purely as an embeddable model-preview component over a postMessage protocol; that idea and protocol are being discussed upstream in lutzroeder/netron#1591.

Before
After

Dynamic dimensions (dim_param)

Lists the model's symbolic axis names (ONNX dim_params) on its graph inputs and outputs — before and after simplify/optimize — so you can see how the conversion changed the dynamic axes: a batch / sequence axis kept symbolic, or a symbolic dimension folded to a fixed size. Read straight from the model bytes in your browser (nothing is uploaded); symbolic axes are shown highlighted.

Try it: load Xenova/all-MiniLM-L6-v2 (a ~21 MB quantized MiniLM sentence-transformer) — its inputs and output carry the named dynamic axes batch_size and sequence_length, so they show up here on both the before and after sides. Most image models (e.g. the onnxmodelzoo ResNets in the dropdown) are fully static and list no dim_params.

Console outputs:

Download log saves the console output above as a .log file. Report an issue opens a pre-filled GitHub issue with the selected options, browser info, and the tail of the console output. Please also attach your model (and the downloaded log) so the problem can be reproduced.

onnxsim profiling

Profiling is on by default (“profile simplification” above): convert a model with Simplify and the fixed-point transforms (shape inference, onnx-optimizer, constant folding) — with ONNX Runtime's own per-operator constant-folding spans merged in — render below as a flame graph. Download the JSON, or click Embed in Perfetto to open the full Perfetto timeline inline on this page.

Run inference (onnxruntime-web)

Runs a model for a few iterations to check it executes, using dummy inputs generated from the model's input shapes. The model picker chooses what to run: compare (before vs after conversion) — the default — runs both the original upload and the converted result on the same deterministic input and reports how far their outputs diverge (max |Δ|) plus the speed difference, so you can confirm the simplify/optimize step preserved the model's numerics and see how much faster it got. You can also run just the converted result or the original upload on their own. The batch control sizes the model's dynamic batch (first) axis; it has no effect on inputs whose first dimension is fixed. The warmup control runs that many untimed passes before the timed iterations, so one-time costs (kernel/program compilation, buffer allocation) don't add noise to the reported latency; set it to 0 to time every run. WebGPU falls back to WebAssembly when unavailable. Tick auto-run after each conversion to run this panel automatically whenever a conversion finishes (with the options selected here), instead of clicking Run inference each time.

The execution-provider picker also offers WebNN (GPU / NPU / CPU), which runs the model through the browser's own ML stack. WebNN is experimental and ships behind a flag (Chrome/Edge: chrome://flags/#web-machine-learning-neural-network), with the broadest support on Windows — the WebNN status line below the controls reports whether it is usable in your browser, and any WebNN run falls back to WebAssembly when the chosen device or an operator is unsupported.

If the model carries onnxsim's MAC/FLOP metrics in its metadata_props (onnxsim PR #527, e.g. annotated via onnxsim.model_info.annotate_metadata), they are shown below with the achieved throughput (GFLOP/s = model FLOPs ÷ average latency). With annotate model info on (the default), the converter bakes these metrics into both the converted result and the original upload, so you can run each and compare their MACs alongside the measured inference speed.

WebNN status: probing…

With profiling on (default), the run captures an onnxruntime-web trace: on WebGPU, one span per GPU kernel invocation; on WASM (or as a fallback), one span per session.run iteration. It renders below in the same viewer, with an Embed in Perfetto button to open the full timeline inline.