How Does ONNX Runtime Execute a Model Across Hardware?
ONNX Runtime loads an .onnx model into an in-memory computation graph inside its C++ InferenceSession, runs provider-independent Basic graph optimizations (constant folding, redundant node elimination, and basic fusions), and then partitions the graph across registered Execution Providers in priority order using GetCapability(). On the CPU and CUDA providers it applies Extended graph optimizations (such as Attention and LayerNorm fusion) before running C++ kernels or CUDA / cuDNN / cuBLAS kernels; with the TensorRT provider, supported subgraphs are compiled into an NVIDIA TensorRT engine while unsupported operators fall back to CUDA or the CPU.
Showing the CUDA execution provider: 10 stages, 9 steps.
Your program
Runtime
Framework core
Model file
Kernel
Compiler
Hardware
Fallback for some operations
The selected path, step by step
Your application passes model path to ONNX model (.onnx): Your application passes the .onnx model file (or bytes) and the priority-ordered execution provider list when creating an InferenceSession.
ONNX model (.onnx) loaded into InferenceSession: InferenceSession parses the ONNX protobuf graph, operator nodes, and initializers into ONNX Runtime's in-memory Graph representation.
InferenceSession runs level-1 passes in Basic graph passes: Before partitioning the graph across providers, ONNX Runtime applies Basic graph optimizations such as constant folding, dead-node elimination, and Conv+Add fusion.
Basic graph passes handed to GetCapability split: The simplified graph is passed to ONNX Runtime's graph partitioner to assign nodes or subgraphs to registered execution providers.
GetCapability split fuses CPU/CUDA nodes in Extended & layout opt: For nodes assigned to the CPU or CUDA execution providers, ONNX Runtime runs Extended graph optimizations (complex node fusions) and CPU layout optimizations.
Extended & layout opt dispatches GPU nodes to CUDA EP (cuDNN/CUDA): Nodes claimed by CUDAExecutionProvider (including fused Attention, LayerNorm, and BiasGelu nodes) run through the CUDA execution provider.
GetCapability split unclaimed ops fall back to CPU EP kernels: Any operator node not supported by the GPU execution providers is assigned to the built-in CPUExecutionProvider.
CUDA EP (cuDNN/CUDA) launches CUDA/cuDNN kernels on NVIDIA GPU: The CUDA execution provider launches CUDA, cuDNN, and cuBLAS kernels on the NVIDIA GPU.
CPU EP kernels runs on CPU: The CPU execution provider runs its C++ kernels on the host CPU.
Why graph optimizations happen in two stages
ONNX Runtime splits graph transformations into levels that run before and after hardware partitioning. Basic graph optimizations—constant folding, dead-node elimination, and simple operator fusions like Conv+Add—are semantics-preserving rewrites that run before partitioning, so every execution provider benefits from them.
Extended graph optimizations (such as multi-node Attention, LayerNorm, and Bias+GELU fusions) and NCHWc layout transformations run after GetCapability() partitioning, because they emit fused operator nodes implemented specifically by the CPU, CUDA, or ROCm execution providers.
How GetCapability() partitions a model with fallbacks
Unlike a single-backend engine, an ONNX Runtime session takes a priority-ordered list of execution providers—for example, TensorrtExecutionProvider, then CUDAExecutionProvider, then CPUExecutionProvider. ONNX Runtime queries each provider's GetCapability() interface in order to claim subgraphs or individual nodes.
Any operator that a higher-priority accelerator provider cannot run is automatically assigned to the next provider in the list, with the built-in CPU execution provider acting as the final fallback.
Every stage
Your application
application
Your Python, C++, C#, C, Java, or Node.js code that configures an ONNX Runtime session with a priority-ordered list of execution providers.
A serialized ONNX computation graph containing standard operators, tensor types, and constant weight initializers exported from PyTorch, TensorFlow, or scikit-learn.
ONNX provides an open source format for AI models, both deep learning and traditional ML. It defines an extensible computation graph model, as well as definitions of built-in operators and standard data types.
supporting models from deep learning frameworks such as PyTorch and TensorFlow/Keras as well as classical machine learning libraries such as scikit-learn, LightGBM, XGBoost, etc.
ONNX Runtime's C++ session engine. When initialized, it parses the model into an in-memory graph, runs graph optimizations, and coordinates execution providers.
ONNX Runtime is compatible with different hardware, drivers, and operating systems, and provides optimal performance by leveraging hardware accelerators where applicable alongside graph optimizations and transforms.
Level-1 semantics-preserving graph rewrites—constant folding, redundant node elimination, and Conv/Add/BatchNorm fusions—applied before partitioning.
These are semantics-preserving graph rewrites which remove redundant nodes and redundant computation. They run before graph partitioning and thus apply to all the execution providers.
ONNX Runtime works with the execution provider(s) using the GetCapability() interface to allocate specific nodes or sub-graphs for execution by the EP library in supported hardware.
Post-partitioning complex operator fusions (Attention, LayerNormalization, SkipLayerNorm, BiasGelu on CPU/CUDA) and NCHWc data layout transforms on CPU.
These optimizations include complex node fusions. They are run after graph partitioning and are only applied to the nodes assigned to the CPU or CUDA or ROCm execution provider.
Compiles supported ONNX subgraphs into optimized NVIDIA TensorRT engines for the target GPU.
The TensorRT execution provider in the ONNX Runtime makes use of NVIDIA’s TensorRT Deep Learning inferencing engine to accelerate ONNX model in their family of GPUs.
For example ['CUDAExecutionProvider', 'CPUExecutionProvider'] means execute a node using CUDAExecutionProvider if capable, otherwise execute using CPUExecutionProvider.
The host CPU executing the CPU execution provider's C++ kernels.
This architecture abstracts out the details of the hardware specific libraries that are essential to optimize the execution of deep neural networks across hardware platforms like CPU, GPU, FPGA or specialized NPUs.
Before partitioning the graph across providers, ONNX Runtime applies Basic graph optimizations such as constant folding, dead-node elimination, and Conv+Add fusion.
For nodes assigned to the CPU or CUDA execution providers, ONNX Runtime runs Extended graph optimizations (complex node fusions) and CPU layout optimizations.
Documented inference paths for an ONNX (.onnx) model in ONNX Runtime using three execution providers: the default CPU provider, the NVIDIA CUDA provider, and the NVIDIA TensorRT provider. Other execution providers (CoreML, DirectML, OpenVINO, QNN, ROCm, WebGPU) and ONNX Runtime Training are out of scope. ONNX Runtime uses the same GetCapability() partitioning architecture for more than a dozen other execution providers, including CoreML, DirectML, OpenVINO, and WebGPU.
How this page is checked
Every stage and step above quotes the source that supports it. The quotes were checked against the ONNX specification README and the ONNX Runtime documentation (Execution Providers, Graph Optimizations, CUDA Execution Provider, TensorRT Execution Provider) on 2026-11-11. The data is a versioned JSON file under the same CC BY 4.0 license as the dataset. Found something wrong or out of date? Open an issue with the better source.