burn-onnx
Library Listed
Import and export ONNX models with the Burn framework
- Downloads
- 14,530
- Dependents
- 23
- Stars
- 141
- Forks
- 45
- Contributors
- 81
- Commits
- 751
- Latest release
- 0.22.0 ·
About
Turn ONNX models into native Rust code for the Burn deep learning framework.
Docs | Burn Book | Supported Operators | Examples | Discord
burn-onnx reads an ONNX model exported from PyTorch, TensorFlow, JAX, or anything else that speaks
ONNX, and writes it out as plain Burn code: a Model struct with a typed forward method, plus a
weights file. There is no ONNX runtime to ship. The result compiles with the rest of your crate and
runs on every Burn backend, from a browser tab or a microcontroller to a CUDA GPU.
Read the full README
- Readable output. The generated
.rsfile is ordinary Burn code you can read, step through in a debugger, and edit. - Any backend, any target. CPU, CUDA, Metal, Vulkan, WebGPU, WebAssembly, and
no_stdembedded. - Every opset. Each supported operator handles ONNX opsets 1 through 24, including the attribute to input migrations and changed defaults along the way.
- Optimized at import. Constant folding, shape propagation, common subexpression elimination, dead code removal, and attention fusion run before code generation.
- Built for big models. Large graphs are split into submodules so the generated code stays compilable, which takes graphs as large as the 28,000-node Stable Diffusion XL UNet.
- Extensible. Operators outside the supported set, including vendor domains like
com.microsoft, can be implemented with your own Rust instead of blocking the import. - Trainable. The imported model is a regular Burn
Module, so you can fine-tune it. - Export too. Experimental support for the reverse direction: save a Burn module as an ONNX file.
Quick Start
Add the dependencies to Cargo.toml. The generated code loads its weights through burn-store, so
your crate needs it as well, and burn needs a backend feature (flex is the portable CPU
backend):
[dependencies]
burn = { version = "0.22", features = ["flex"] }
burn-store = "0.22"
[build-dependencies]
burn-onnx = "0.22"
Convert the model in build.rs:
use burn_onnx::ModelGen;
fn main() {
ModelGen::new()
.input("src/model/my_model.onnx")
.out_dir("model/")
.run_from_script();
}
Include the generated code, for example from src/model/mod.rs:
pub mod my_model {
include!(concat!(env!("OUT_DIR"), "/model/my_model.rs"));
}
Then run it:
use burn::tensor::{Device, Tensor};
use crate::model::my_model::Model;
fn main() {
let device = Device::default();
let model = Model::default(); // loads the weights written by build.rs
let input = Tensor::<4>::zeros([1, 3, 224, 224], &device);
let output = model.forward(input);
println!("{output}");
}
The Burn Book chapter walks through the same steps in more detail, and onnx-inference is a complete project that classifies MNIST digits.
What gets generated
For each .onnx input, ModelGen writes a .rs file and a .bpk (Burnpack) weights file. Here
is the forward method generated for the MNIST model in the example above:
pub fn forward(&self, input_1: Tensor<4>) -> Tensor<2> {
let conv2d1_out1 = self.conv2d1.forward(input_1);
let relu1_out1 = burn::tensor::activation::relu(conv2d1_out1);
let conv2d2_out1 = self.conv2d2.forward(relu1_out1);
let relu2_out1 = burn::tensor::activation::relu(conv2d2_out1);
// ...
let linear2_out1 = self.linear2.forward(relu4_out1);
let batchnormalization2_out1 = self.batchnormalization2.forward(linear2_out1);
let logsoftmax1_out1 = log_softmax(batchnormalization2_out1, 1);
logsoftmax1_out1
}
Layers with weights become Burn modules (Conv2d, Linear, BatchNorm, ...) and everything else
becomes direct tensor operations. Pass .development(true) to ModelGen to also dump the parsed
ONNX graph next to the code, which helps when debugging an import.
Loading weights
ModelGen::load_strategy decides how the model finds its weights at runtime:
LoadStrategy | Generated constructors | Good for |
|---|---|---|
File (default) | default(), from_file(path, &device), from_bytes(..) | desktop and server apps |
Embedded | default(), from_embedded(&device), from_bytes(..) | single-binary deploys, embedded |
Bytes | from_bytes(bytes, &device) | WebAssembly, custom loaders |
None | none | managing weights yourself |
With File, Model::default() reads the .bpk from the path it was written to at generation time:
an absolute path inside OUT_DIR from a build script, or the out_dir exactly as given to
onnx2burn or run_from_cli, which a relative path resolves against the working directory at
runtime. That is convenient during development; for a binary you distribute, ship the .bpk and
call Model::from_file(path, &device), or switch to Embedded. Avoid Model::new(&device) on its
own: it builds the structure without loading any weights.
Command Line
onnx2burn runs the conversion outside a build script. It is useful for reading the generated code,
or for checking in generated code that you intend to edit by hand:
cargo install burn-onnx
onnx2burn my_model.onnx ./generated
Flags: --embed-states (embed weights in the code), --no-simplify, --no-partition, and
--no-development (skip the debug dumps the CLI writes by default).
Custom Operators
Operators outside the
supported set do not have
to block an import: vendor domains such as com.microsoft, ops from a framework's custom export, and
op types not implemented yet. Register a hook and supply the Rust yourself:
// build.rs
ModelGen::new()
.input("src/model/my_model.onnx")
.out_dir("model/")
.register_custom_op(FftReal) // handles my_domain::FftReal
.register_op_override(MyMatMul) // replaces the generated code for every MatMul
.run_from_script();
CustomOpsupplies type inference and code generation for one ONNX(op_type, domain). It can read the node's attributes and constant inputs.OpOverridereplaces the generated code for a built-in operator, to route it to a fused, quantized, or hardware-specific kernel of your own. Type inference still comes from the built-in.
Everything a hook needs is re-exported from burn_onnx::ext, so you never depend on onnx-ir or
match proc-macro2/quote versions by hand.
Not sure which operators a model needs? Build with no hooks registered. The import fails with a list of every unsupported operator, its domain, and how many nodes use it:
Failed to parse ONNX file 'src/model/custom_model.onnx': model contains 2 custom op(s) with no
covering inference hook:
- example.custom::ChannelScale used by 1 node(s)
- example.custom::ScaleBias used by 1 node(s)
Register hooks via ModelGen::register_custom_op.
The custom-op-hooks example is a working walkthrough, and the Development Guide has the full reference.
Exporting to ONNX (experimental)
The export feature goes the other way. OnnxExporter runs a module's forward pass once on a
capture device, records the operations, and writes an ONNX model with the weights embedded:
[dependencies]
burn-onnx = { version = "0.22", features = ["export"] }
use burn_onnx::export::OnnxExporter;
let sample = Tensor::<4>::zeros([1, 3, 224, 224], &device);
OnnxExporter::new()
.export(&model, sample, MyModel::forward)?
.save("my_model.onnx")?;
export fixes every dimension to the sample's shape. export_dynamic takes a second sample and an
InputSpec per input to mark axes such as the batch size as symbolic. The exporter targets opset 18
and currently covers the operations typical of convolutional and fully connected networks
(ResNet-18 exports and passes the ONNX checker); anything it cannot lower yet is reported as
ExportError::UnsupportedOperation. See the
export module docs for details.
How It Works
model.onnx
│
▼
onnx-ir parse protobuf ─▶ typed IR nodes ─▶ type & shape inference ─▶ simplification
│
▼
burn-onnx Burn code generation ─▶ partition large graphs into submodules
│
├─▶ model.rs Model struct + forward(), formatted Rust
└─▶ model.bpk weights in Burnpack format
onnx-ir is a standalone ONNX
parser that knows nothing about Burn: it turns the protobuf into a typed graph, parses each
operator's attributes into a typed config, infers types and static shapes, and simplifies the
graph. burn-onnx then maps each node
to Burn code. The Development Guide
covers each phase in detail.
Crates
| Crate | Description |
|---|---|
burn-onnx | Code generator, onnx2burn CLI, and ONNX exporter |
onnx-ir | Framework-independent ONNX parser and intermediate representation |
onnx-ir-derive | Derive macros used by onnx-ir |
Examples
| Example | Description |
|---|---|
| onnx-inference | MNIST classifier: the smallest complete import |
| image-classification-web | SqueezeNet in the browser with WebAssembly and WebGPU |
| raspberry-pi-pico | no_std inference on a microcontroller, weights embedded |
| custom-op-hooks | Custom operators and built-in operator overrides |
Testing and Compatibility
- Real-world models. 27 models are imported, compiled, and compared against ONNX Runtime outputs, covering image classification, detection, depth estimation, language models, speech, text-to-speech, and diffusion: ResNet, YOLO, CLIP, BERT variants, Qwen, SmolLM, Kokoro, Silero VAD, Depth Pro, Stable Diffusion XL, and more.
- The official ONNX test suite. 1,185 of the 1,765 upstream ONNX backend node tests pass end to end on every CI run, with the status of the rest tracked in a checked-in expectations file.
- Opset compliance. Every supported operator is tested at every opset version it exists in, 461 operator-version combinations in all.
- Operator tests. Hundreds of integration tests built from PyTorch- or NumPy-generated models, with expected outputs from the ONNX reference evaluator.
Troubleshooting
- Unsupported operator. The error lists each missing operator. Check the supported operators, then either implement it as a custom op or open an issue.
- Generated code does not compile. Make sure
burn,burn-store, andburn-onnxare the same version. Find the generated file undertarget/<profile>/build/<your-crate>-*/out/and read it, or generate it withonnx2burnto inspect it directly. Please report it, with the model if you can. - Wrong outputs. Confirm the model was loaded with
default(),from_file,from_embedded, orfrom_bytes, notnew. Then compare against ONNX Runtime with the same input. - Very old models. Opsets 1 through 24 are supported, but upgrading an old model with
onnx_opset_upgrade.py(uv run --script onnx_opset_upgrade.py) to opset 16 also runs ONNX shape inference, which can help with models that carry little shape information.
Contributing
Contributions are welcome. Please read the Contributing Guidelines before opening a PR, and the Development Guide for the architecture and a step-by-step walkthrough of adding an operator. For questions and discussion, join us on Discord.
License
Licensed under either of Apache License, Version 2.0 or MIT license at your option.
Compatibility
- Runs on
- GPU support unknown
What shows it
- no dependency or feature matches a backend row
- Native code
- None found
- No native code found
- Python bindings
- No Python binding crate found
- License
- Apache-2.0 OR MIT
Compare with similar projects
Order: strongest tier first, then most downloads, then name, with unmeasured values last. A library counts downloads over 30 days. An app counts binary downloads per release. An app with none counts its crate downloads over 30 days. ML Rust runs this catalogue, so its closest project always gets a row.
| Project | Downloads | Dependents | Stars | Latest release | Runs on (GPU) | Native code | License |
|---|---|---|---|---|---|---|---|
|
Import and export ONNX models with the Burn framework |
14,530 downloads over 30 days | 23 | 141 | 0.22.0 | GPU support unknown | No native code found | Apache-2.0 OR MIT |
|
onnx-extractor Listed
Minimal ONNX model loader for extracting weights, tensors, operations, and graph structure |
3,975 downloads over 30 days | 4 | 6 | 0.5.2 | GPU support unknown | No native code found | MIT |
|
gguf Listed
GGUF file parser |
2,472 downloads over 30 days | 4 | 25 | 0.1.8 | GPU support unknown | No native code found | MIT |
|
onnx-rs Listed
Zero-dependency ONNX model parser in Rust |
453 downloads over 30 days | 5 | 6 | 0.1.3 | GPU support unknown | No native code found | MIT |
|
One backbone, many specialists. CMF is a self-describing, memory-mappable single-file format and a dependency-free runtime for quantized LLMs — zero-copy execution on CPU or GPU (Vulkan · Metal · DX12) that overlays task-specialized skills onto one shared model, with no per-model duplication. |
24 binary downloads per release | Not applicable | 52 | Not measured | Not measured | Apache-2.0 | |
|
Model conversion and quantization with no Python: reads SafeTensors, GGUF, TCF and PyTorch state dicts, writes SafeTensors, GGUF and TCF, and quantizes to Q2_K through Q8_0 and IQ4 formats, including Q4_K_M mixes. GPTQ, AWQ, NF4, FP8, EXL2 and ONNX input are not implemented. Python bindings |
23 downloads over 30 days | Not applicable | 0 | 0.2.1 | GPU support unknown | No native code found | Apache-2.0 |
All projects in Datasets and model formatsAll projects in Run and serve models
Why ListedNo archive, New or Featured rule places it, so it is Listed.
What it lacks for Featured
- It has 6 active dependents and 6 new dependents in 365 days. Featured needs 11 active dependents or 9 new dependents in 365 days. The repository route reads 141 stars, 45 forks and 81 contributors. It needs 4,539 stars, 434 forks and 79 contributors together.
What else the check found
- The last activity is on 7 Nov 2026, 2 days ago. The rules expect an update within 365 days. Dormancy rule
Exact rules: Listed, Featured library. The check on applied thresholds version 9.
Every rule outcome, as the check records it
expected-interval: version 0.22.0 base 140, raised to the 365-day floor: E = 365 daysdormancy: last activity 2026-11-07, 2 days ago, E = 365: activefeatured: not featured: active_users 6 < 11 and new_adopters 6 < 9 and repository route stars 141 (needs 4539), forks 45 (needs 434), contributors 81 (needs 79)listed: listed: no archive, new or featured rule applies
Crates4 crates
- burn-onnx Primary
- burn-import
- onnx-ir
- onnx-ir-derive
Measurements and sources
Each signal row shows the raw value, its source and the fetch date. The Sources list gathers every distinct source on this page. Movement needs more history.
Sources6 sources
- Description: the crates.io description
- crates.io database dump, fetched
- RustSec advisory database, fetched
- GitHub repository, fetched
- crates.io package, fetched
- GitHub contributors, fetched
Adoption6 active dependents, 6 new dependents in 365 days1 not measured
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| Active dependents | 6 | crates.io database dump | Yes | |
| New dependents (365 days) | 6 | crates.io database dump | Yes | |
| Peak active dependents | 5.5 | crates.io database dump | Yes | |
| Active dependents as a share of the peak | 1 | crates.io database dump | Yes | |
| Binary downloads per release | Not measured | Yes |
MaintenanceLatest human commit: 2 days ago3 not measured
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| Latest human commit | 2026-11-07 | GitHub repository | Yes | |
| Latest release | 2026-10-29 | crates.io database dump | Yes | |
| First release | 2023-05-06 | crates.io database dump | Yes | |
| Latest version | 0.22.0 | crates.io database dump | Yes | |
| Days the oldest outside issue waits for a reply | 0 | GitHub repository | Yes | |
| Maintainer replies over 365 days | 25 | GitHub repository | Yes | |
| Repository archived | false | GitHub repository | Yes | |
| Repository gone | false | GitHub repository | Yes | |
| Release commit or manifest in the repo | true | crates.io package | Yes | |
| Published docs | true | crates.io database dump | Yes | |
| Latest release fails cargo check | Not measured | Yes | ||
| Build check date | Not measured | Yes | ||
| Build check toolchain | Not measured | Yes |
SecurityUnpatched vulnerabilities: none
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| Unpatched vulnerabilities past the grace window | none | RustSec advisory database | Yes | |
| RustSec unmaintained advisory | none | RustSec advisory database | Yes | |
| Deprecation notice | none | crates.io database dump | Yes | |
| Deprecated requirement | none | crates.io database dump | Yes |
Distribution10 releases, 14,530 downloads over 30 days5 not measured
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| Releases | 10 | crates.io database dump | Yes | |
| Downloads over 30 days | 14530 | crates.io database dump | Yes | |
| Binary downloads over the last 3 releases | Not measured | Yes | ||
| Homebrew installs on request over 365 days | Not measured | Yes | ||
| Repology repository families | Not measured | Yes | ||
| Docker pull growth over 90 days | Not measured | Yes | ||
| Docker pulls at the growth baseline | Not measured | Yes | ||
| Every version a prerelease | false | crates.io database dump | Yes | |
| Every version 0.0.x | false | crates.io database dump | Yes | |
| Every version yanked | false | crates.io database dump | Yes | |
| Crate deleted from crates.io | false | crates.io database dump | Yes |
Repository141 stars, 45 forks, 81 contributors, 751 commits. Stars alone never qualify a project.
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| GitHub stars | 141 | GitHub repository | Yes — one part of the repository route | |
| GitHub forks | 45 | GitHub repository | Yes — one part of the repository route | |
| Contributors with a GitHub account | 81 | GitHub contributors | Yes — one part of the repository route | |
| Commits on the default branch | 751 | GitHub repository | No | |
| Repository's main crate left out of the entry | none | crates.io database dump | Yes |
Facts that never count
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| License | Apache-2.0 OR MIT | crates.io database dump | No | |
| Runs on, from listed crates and their direct dependencies | GPU support unknown | crates.io database dump | No | |
| What shows each backend | no dependency or feature matches a backend row | crates.io database dump | No | |
| Native code, from listed crates and their dependencies | No native code found | crates.io database dump | No | |
| Python bindings, from direct dependencies of listed crates | No Python binding crate found | crates.io database dump | No | |
| Crates that depend on a listed crate directly | 23 | crates.io database dump | No |
Corrections and review history
No correction applies to this entry.
Judgments
A judgment enters only through an approved issue and a merged pull request.
No judgment applies to this entry.