mrkeyoor.com_
Sun 20 Sept 04:57 UTC
PyPIAI / MLupdated 20 Sept 2026

onnxruntime review

onnxruntime 1.29.0 executes trained models represented as ONNX graphs. Python code opens an InferenceSession, sends NumPy arrays under the graph's declared input names, and reads named outputs without loading the framework that trained the model. Execution providers map supported operators to CPU, CUDA, TensorRT, OpenVINO, DirectML, and other hardware paths. This release adds environment variables for default thread counts and many validation fixes for paths, shapes, ranks, bounds, buffers, and operator attributes. Our CPU-wheel install occupied 121 MB and imported in 0.44 seconds.

Verdict

onnxruntime 1.29.0 installed in 0.9 seconds but used 121 MB in our sandbox, and its compiled CPU wheel imported in 0.44 seconds with no audit findings. Pay that cost when a parity-tested ONNX graph removes a training framework or reaches a required provider; otherwise keep the existing runtime and avoid a second model contract.

We installed it

Lab card: what happened when we installed onnxruntimeScreenshot of onnxruntime documentation
Install✓ · 0.9s5 packages on disk · 121 MB
Importimport onnxruntime in 0.44s · compiled extensions · requires Python >=3.11
Known vulns0(pip-audit)

Answers from our run

Does onnxruntime install cleanly?

Yes. In a fresh container with an empty cache, pip install onnxruntime finished in 0.9s, leaving 5 packages and 121 MB on disk. pip-audit reported no known vulnerabilities.

What does onnxruntime need to run?

Python >=3.11, and a platform wheel with compiled extensions. In our run import onnxruntime succeeded in 0.44s.

onnxruntime or openvino: which should you use?

openvino: Choose it when Intel CPUs, integrated GPUs, or NPUs are the fixed target and Intel-specific optimization is the main goal. onnxruntime 1.29.0 installed in 0.9 seconds but used 121 MB in our sandbox, and its compiled CPU wheel imported in 0.44 seconds with no audit findings.

When should you not use onnxruntime?

Export requires unsupported custom operators or produces unacceptable output drift. The runtime cannot correct a graph that already changed the model's semantics.

API stability4/5InferenceSession, SessionOptions, provider priority, get_inputs, get_outputs, run, profiling, and IO binding have remained recognizable throughout the 1.x Python line. ONNX operator-set metadata also makes the artifact contract inspectable. Provider options and package compatibility move faster than the CPU call surface, and 1.29.0 changes environment defaults plus many provider kernels, so every hardware-backed image still needs versioned acceptance tests.
Docs4/5The official site covers Python inference, model inspection, performance tuning, graph optimization, quantization, profiling, IO binding, mobile and web targets, plus separate setup pages for execution providers. Examples give enough detail to open a session and control threads. The provider documentation remains the critical source for CUDA and system-library compatibility, and the site's breadth makes it easy to land on guidance for a different language or package variant.
Maintenance5/5Microsoft's unarchived repository has 21,652 stars, 1,636 open issues and pull requests, and a push on 2026-08-26. Release 1.29.0 shipped on 2026-08-12 with path traversal, buffer, rank, shape, attribute, and bounds validation fixes, alongside provider kernels and packaging changes. The queue is large because one repository covers multiple languages, operating systems, chip families, and execution providers.
Ecosystem5/5The catalog records 18,896,688 weekly downloads. Export paths exist from major training frameworks, and execution providers cover CPU, NVIDIA, Intel, Windows, Apple, Qualcomm, browsers, mobile devices, and other targets. That range supports a shared exchange format, but compatibility is never just 'ONNX supported': each model's operator set, shapes, numeric tolerances, runtime build, provider, and device need their own proof.

Use it if

  • The exported ONNX graph matches its source model numerically and deployment should omit the training framework.
  • One model artifact needs tested execution on CPU plus a specific supported accelerator provider.
  • A CPU inference service needs graph optimization, quantization tools, explicit thread limits, and a stable session call.
  • Startup code can inspect names, element types, and dynamic dimensions and reject a model that violates the service contract.
Skip it if

Setup reality

We installed onnxruntime 1.29.0 in a fresh, unprivileged Python 3.12 Bookworm container. pip completed in 0.9 seconds, left 5 packages, and consumed 121 MB. The package declares 6 direct dependencies, requires Python 3.11 or later, includes compiled .so files, and does not ship py.typed. import onnxruntime succeeded in 0.44 seconds. pip-audit found zero known vulnerabilities, and the installed metadata names the MIT License.

The CPU wheel needs no account or background service. It does require an ONNX artifact whose operator versions, names, shapes, and element types match the caller. Read get_inputs() and get_outputs() at startup instead of copying identifiers from training code. Export dynamic axes intentionally and compare representative outputs against the source framework. A converter returning successfully says nothing about acceptable numerical drift.

Accelerator providers add the difficult packaging layer. Install the distribution for the chosen provider, supply providers in priority order, and inspect get_providers() after creating the session. A CPU fallback can return correct results slowly enough to break a service objective. CUDA and cuDNN versions, provider options, optimized graph files, and target hardware belong in one tested image contract. Do not reuse a provider-specific optimized model without retesting it.

Thread pools can oversubscribe a shared worker. Version 1.29.0 adds ORT_INTRA_OP_NUM_THREADS and ORT_INTER_OP_NUM_THREADS; explicit SessionOptions values win over those defaults. Load-test thread limits under real request concurrency. Builds with telemetry enabled can send usage data, and ORT_DISABLE_TELEMETRY=1 must be set before initialization to disable POSIX telemetry. Treat models and external tensor data as untrusted files because this release fixes multiple validation and path-handling bugs.

Patterns

Execute every output on CPU run-cpu-model

import numpy as np
import onnxruntime as ort

session = ort.InferenceSession(
    'model.onnx',
    providers=['CPUExecutionProvider'],
)
feed = {'input': np.zeros((1, 3, 224, 224), dtype=np.float32)}
outputs = session.run(None, feed)

The input key, dimensions, and dtype must match the graph. Passing None as the output list requests every output in graph order.

Print the graph's public contract inspect-model-interface

for value in session.get_inputs():
    print('input', value.name, value.shape, value.type)

for value in session.get_outputs():
    print('output', value.name, value.shape, value.type)

A dynamic dimension may be a symbolic string instead of an integer. Validate permitted ranges separately before accepting a request.

Fail startup when CUDA is unavailable require-cuda-provider

session = ort.InferenceSession(
    'model.onnx',
    providers=['CUDAExecutionProvider', 'CPUExecutionProvider'],
)

active = session.get_providers()
if active[0] != 'CUDAExecutionProvider':
    raise RuntimeError(f'CUDA provider inactive: {active}')

Install onnxruntime-gpu and its documented CUDA libraries. This check prevents an accidental CPU fallback from passing health checks with poor latency.

Set session-owned thread counts limit-cpu-threads

options = ort.SessionOptions()
options.intra_op_num_threads = 4
options.inter_op_num_threads = 1
options.graph_optimization_level = ort.GraphOptimizationLevel.ORT_ENABLE_ALL

session = ort.InferenceSession(
    'model.onnx',
    options,
    providers=['CPUExecutionProvider'],
)

SessionOptions overrides the 1.29.0 ORT_INTRA_OP_NUM_THREADS and ORT_INTER_OP_NUM_THREADS defaults. Tune against concurrent traffic, not one request.

Check numerical parity after conversion compare-export-output

expected = model(example).detach().cpu().numpy()
input_name = session.get_inputs()[0].name
actual = session.run(None, {
    input_name: example.detach().cpu().numpy(),
})[0]

np.testing.assert_allclose(expected, actual, rtol=1e-3, atol=1e-5)

Choose tolerances for the model and dtype. Include every production shape boundary, especially axes exported as dynamic.

Fetch one output by name request-named-output

output_name = session.get_outputs()[0].name
result, = session.run([output_name], feed)

Naming outputs avoids relying on graph order and can skip materializing outputs the request does not use.

Write a dynamic int8 variant quantize-model-weights

from onnxruntime.quantization import QuantType, quantize_dynamic

quantize_dynamic(
    'model.onnx',
    'model.int8.onnx',
    weight_type=QuantType.QInt8,
)

Quantization can change accuracy and may not improve latency on every provider. Benchmark this derived file on the actual device.

Persist the graph optimized for CPU save-optimized-model

options = ort.SessionOptions()
options.optimized_model_filepath = 'model.cpu.ort.onnx'

ort.InferenceSession(
    'model.onnx',
    options,
    providers=['CPUExecutionProvider'],
)

The output can depend on runtime and provider choices. Version it as a derived artifact and regenerate it after those inputs change.

Write an operator timing trace profile-one-session

options = ort.SessionOptions()
options.enable_profiling = True
session = ort.InferenceSession('model.onnx', options)

session.run(None, feed)
trace_file = session.end_profiling()
print(trace_file)

Warm the session before the run you analyze. end_profiling closes the trace, which can be opened in Perfetto or Chromium tracing tools.

Keep input and output on the GPU bind-cuda-buffer

binding = session.io_binding()
device_input = ort.OrtValue.ortvalue_from_numpy(array, 'cuda', 0)
binding.bind_ortvalue_input('input', device_input)
binding.bind_output('output', 'cuda')

session.run_with_iobinding(binding)
device_outputs = binding.get_outputs()

IO binding avoids automatic host copies only when provider placement and buffer devices match. Measure transfers as part of end-to-end latency.

Opt out before runtime initialization disable-runtime-telemetry

import os

os.environ['ORT_DISABLE_TELEMETRY'] = '1'
import onnxruntime as ort

Set this before the first onnxruntime import. Version 1.29.0 adds the POSIX opt-out for builds compiled with telemetry; WebAssembly remains telemetry-free.

Reduce runtime log noise configure-log-severity

options = ort.SessionOptions()
options.log_severity_level = 3  # errors only
options.logid = 'fraud-model'

session = ort.InferenceSession('model.onnx', options)

Severity values run from 0 for verbose through 4 for fatal. Keep warnings visible while validating a new provider image.

Alternatives

PackageRegistryPick it when
openvinoPyPIChoose it when Intel CPUs, integrated GPUs, or NPUs are the fixed target and Intel-specific optimization is the main goal.
torchPyPIChoose it when PyTorch already belongs in the production image and an ONNX conversion would add more testing than it removes.
tflite-runtimePyPIChoose it for a supported TensorFlow Lite artifact on a constrained edge target where that format is already established.
vllmPyPIChoose it for GPU language-model serving that needs continuous batching and KV-cache-aware scheduling.

More ai / ml guides

openai · mcp · huggingface-hub · scikit-learn · tiktoken · @modelcontextprotocol/sdk · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.