§ ONNX Runtime for Engineers
9 lessons · every lesson has a Colab notebook

Execution providers

Nine lessons on running trained models with ONNX Runtime. Each lesson links to a Colab notebook for hands-on practice. The core exercises use a CPU; GPU work is optional.

Before you begin

You should be comfortable with Python functions and arrays. Inference means using a trained model to calculate an answer. A graph describes the operations used in that calculation. An operator is one kind of operation, such as addition or matrix multiplication.

Read the plain-language introduction, try its question, then open the notebook. Keep your measured results separate from the illustrative simulations on this page.

Technical references: ONNX Runtime Python API and quantization guidance.

05 · Execution Providers and Graph Partitioning

Introduction

Requesting a GPU provider does not mean every node runs on the GPU. If a custom operation is unsupported, ONNX Runtime may partition the graph and silently place that node on CPU.

Learning goal

Configure execution-provider priority, inspect graph partitioning, and detect unwanted CPU fallback or costly device-transfer boundaries.

Before you start

ONNX graphs, CPU and GPU as execution devices, sessions, and basic logging.

Lesson plan

  1. Read the provider priority list and learn how capability claims assign graph nodes.
  2. Use the partition simulator to trace supported and unsupported operations across devices.
  3. Inspect provider options, logs, and profiling evidence before claiming accelerator execution.

Predict a partition: if a GPU provider supports MatMul and Add but not a custom final operation, the first nodes can run on GPU while the last falls back to CPU. The session may succeed while device transfers reduce performance.

An Execution Provider is a backend that implements kernels. At session creation ORT walks the graph and asks each EP, in priority order, can you run this node? Contiguous supported runs become subgraphs; everything else falls back — ultimately to the CPU. At boundaries, tensors are copied between devices.

Interactive · Partitioning simulator (illustrative)
The two silent killers

Fallback is silent by default. One unsupported op drags a region to CPU and you only find out by profiling. Partition count costs. Ten tiny GPU subgraphs with PCIe copies between them can lose to one clean CPU subgraph. Both are measurable — the notebook shows how.

avail = ort.get_available_providers()          # what this wheel can do
providers = (["TensorrtExecutionProvider", "CUDAExecutionProvider", "CPUExecutionProvider"]
             if "CUDAExecutionProvider" in avail else ["CPUExecutionProvider"])
sess = ort.InferenceSession("model.onnx", providers=providers)
print(sess.get_providers())                     # the truth after partitioning

Provider cheat sheet

ProviderHardwareTypical use
CPUExecutionProviderany CPUuniversal fallback; vectorized via MLAS
CUDAExecutionProviderNVIDIA GPUdefault NVIDIA path
TensorrtExecutionProviderNVIDIA GPUmax perf; fuses subgraphs into TRT engines
ROCMExecutionProviderAMD GPUROCm stack
DmlExecutionProviderDirectX 12 GPUWindows, broad vendor coverage
OpenVINOExecutionProviderIntel CPU/GPU/NPUIntel-centric deployment
CoreMLExecutionProviderApple siliconmacOS / iOS
QNNExecutionProviderQualcomm NPUAndroid / Snapdragon
XnnpackExecutionProviderARM CPUmobile CPU inference
WebGpuExecutionProvider / WASMbrowserclient-side inference
▶ Run notebook 05 in Colab 05-execution-providers.ipynb CPU runtime · GPU cells light up on a GPU runtime