TL;DR:
- ONNX Runtime is a hardware-agnostic inference engine supported by Microsoft, Intel, NVIDIA, Qualcomm, and ARM — it runs on virtually any edge hardware
- Exporting your PyTorch or TensorFlow model to ONNX format takes minutes; the same .onnx file then deploys to CPU, GPU, or NPU targets with the right execution provider
- Execution providers are the key abstraction: CUDA for NVIDIA, TensorRT for Jetson, OpenVINO for Intel, XNNPACK for ARM — swap the EP, keep the model
One of the persistent headaches of edge AI deployment is the hardware fragmentation problem. You train your model in PyTorch, then discover your target hardware is an Intel NUC, a Jetson Orin, an STM32 microcontroller, and a Qualcomm Snapdragon gateway — each with its own preferred framework, SDK, and toolchain. Maintaining separate deployment paths for each target is expensive and error-prone.
ONNX Runtime solves this at the inference layer. ONNX (Open Neural Network Exchange) is an open standard for representing ML models; ONNX Runtime is Microsoft’s high-performance inference engine for that standard. Together they give you a train-once, deploy-anywhere path that works across a wider range of hardware than any framework-native solution.
The Model Export Step
The starting point is converting your trained model to ONNX format. For PyTorch:
import torch
import torch.onnx
model = YourModel()
model.load_state_dict(torch.load("model.pth"))
model.eval()
dummy_input = torch.randn(1, 3, 224, 224) # match your input shape
torch.onnx.export(
model,
dummy_input,
"model.onnx",
opset_version=17,
input_names=["input"],
output_names=["output"],
dynamic_axes={"input": {0: "batch_size"}}
)
For TensorFlow/Keras, the tf2onnx library handles the conversion:
pip install tf2onnx
python -m tf2onnx.convert --saved-model ./saved_model --output model.onnx --opset 17
The resulting .onnx file is what you deploy to all targets. No retraining, no framework-specific serialisation — the same file runs everywhere.
Execution Providers: How Hardware Acceleration Works
ONNX Runtime uses an “execution provider” (EP) abstraction to route operations to the appropriate hardware backend. You specify the EP at runtime; the model stays the same.
| Hardware target | Execution provider | Use case |
|---|---|---|
| x86/ARM CPU (generic) | CPUExecutionProvider | Baseline, works everywhere |
| NVIDIA GPU | CUDAExecutionProvider | Jetson, desktop GPUs |
| NVIDIA Jetson optimised | TensorRTExecutionProvider | High-performance Jetson deployment |
| Intel CPU/GPU/VPU | OpenVINOExecutionProvider | Intel NUC, Movidius, Core Ultra NPU |
| ARM Cortex-A NPU | QNNExecutionProvider | Qualcomm devices |
| ARM CPU (optimised) | XNNPACKExecutionProvider | Raspberry Pi, ARM SBCs |
| DirectML (Windows) | DmlExecutionProvider | Windows edge devices |
A session with CPU fallback to CUDA looks like this:
import onnxruntime as ort
providers = ["CUDAExecutionProvider", "CPUExecutionProvider"]
session = ort.InferenceSession("model.onnx", providers=providers)
input_name = session.get_inputs()[0].name
result = session.run(None, {input_name: preprocessed_input})
Swap CUDAExecutionProvider for OpenVINOExecutionProvider when deploying to Intel hardware. The rest of your inference code is identical.
Optimising for Edge Targets
Raw ONNX models are often not optimal for constrained hardware. Two tools help:
Model optimisation with ort.transformers.optimizer or onnxoptimizer:
python -m onnxruntime.tools.optimizer_cli --input model.onnx --output model_opt.onnx --model_type bert
Quantisation for size and speed:
from onnxruntime.quantization import quantize_dynamic, QuantType
quantize_dynamic(
"model.onnx",
"model_quantized.onnx",
weight_type=QuantType.QInt8
)
Dynamic INT8 quantisation typically cuts model size by 3–4x and speeds up CPU inference by 2–4x with minimal accuracy loss for most vision and NLP tasks. For Cortex-M deployment, ONNX Runtime for Microcontrollers (ONNX-MLIR compiled to C) enables this at the firmware level.
Deploying to Constrained Hardware
For standard Linux-based edge devices (Raspberry Pi 4/5, NVIDIA Jetson, Intel NUC), ONNX Runtime installs as a Python or C++ library via pip or the official packages.
For microcontrollers and deeply embedded targets, the options are:
- ONNX Runtime for Microcontrollers — subset of ORT targeting Cortex-M class devices
- onnx2c — converts ONNX models to pure C code, suitable for bare-metal deployment
- ONNX-MLIR — MLIR-based compilation targeting a range of embedded architectures
- Qualcomm QNN SDK — for Snapdragon-based IoT hardware with Hexagon NPU access
For Jetson Orin specifically, the TensorRT execution provider gives significantly better throughput than CUDA alone. TensorRT performs layer fusion, precision calibration, and kernel tuning at model-load time — accept the longer first-load time in exchange for substantially faster inference.
A Practical 2026 Deployment Checklist
- Export with opset 17 or higher — earlier opsets lack operators for newer model architectures
- Validate the exported model immediately:
onnx.checker.check_model("model.onnx") - Run onnxsim (ONNX Simplifier) to remove redundant nodes before deployment
- Benchmark on target hardware with
ort.perf_testbefore committing to a production deployment — performance varies significantly by device and EP - Set inter_op_num_threads and intra_op_num_threads explicitly for CPU targets; the defaults often underutilise available cores on multi-core edge devices
- Profile with ORT’s built-in profiler to find bottleneck ops before optimising
Where ONNX Runtime Doesn’t Fit
ONNX Runtime is an inference engine, not a training framework. If your edge use case requires on-device training or fine-tuning (federated learning, personalisation), look at tinyML frameworks like TensorFlow Lite Micro or framework-native options.
Some very new model architectures lag in ONNX opset support — if you’re using cutting-edge ops, check compatibility against the opset version your target ONNX Runtime release supports before committing to the export path.
For models that need to run on dedicated AI accelerators with proprietary toolchains (certain Hailo, NXP, or MediaTek NPUs), the vendor SDK may be a more direct path than ONNX Runtime, even if it means maintaining parallel deployment code.
For everything else — which covers the vast majority of computer vision, NLP, and tabular inference use cases at the edge — ONNX Runtime is the most practical cross-platform deployment option available in 2026.