CatSnowdrop commited on
Commit
610d9c2
·
verified ·
1 Parent(s): d449ba8

Upload 379 files

Browse files

---
license: mit
tags:
- onnxruntime
- onnx
- inference
- cuda
- tensorrt
- openvino
- directml
- windows
---

# Universal ONNX Runtime (UORT) 1.30.1 — Windows x64 package folder

A self-contained build of **ONNX Runtime 1.30.1** for **Windows x64 / CPython 3.12** with five
execution providers compiled in and every native dependency bundled next to the Python
extension: **TensorRT, CUDA, OpenVINO, DirectML and CPU**.

This repository publishes the package as a **plain directory tree** — `onnxruntime/` at the repo
root, exactly as it has to appear in `Lib\site-packages`. There is no archive to unpack: what you
download is already the installable folder.

The point of the package is that you install it by copying one folder — no CUDA Toolkit, no
cuDNN download, no TensorRT SDK, no `pip install onnxruntime-gpu`. Everything the providers need
is in `capi/`, and the package registers that directory with the Windows loader on import.

| | |
|---|---|
| Contents | `onnxruntime/` — **379 files** in **31 subdirectories** |
| Stored / transferred size | **5 585 491 685 bytes** (5.20 GiB) |
| Python modules | 317 `.py` files |
| Native binaries | 52 `.dll` + 1 `.pyd`, all in `capi/` |
| `__pycache__` | none (removed before publishing) |
| Package version | `uort-python` 1.30.1 |
| Platform | Windows 10/11 x64 only |
| Python ABI | CPython 3.12 x64 (`python312.dll`) |
| Licence | MIT (ONNX Runtime) + third-party terms, see [Licences](#licences) |

## Integrity

There is no single archive hash, because there is no archive. Every file is stored as an
LFS / Xet object keyed by the **SHA-256 of its content**, and both `hf download` and
`git lfs` verify that hash while writing the file — a corrupted transfer is rejected, not
silently accepted.

Spot-check values if you want to confirm a few key binaries yourself:

| File | Bytes | SHA-256 |
|---|---|---|
| `capi\onnxruntime.dll` | 24 535 040 | `a4599b0168c8b3e485e50c4493559280778f7c533d66bbb3ea372073f316b67f` |
| `capi\onnxruntime_pybind11_state.pyd` | 25 851 904 | `e54c4900fc60c521dc597dc0b0c87835a18ea6ee2efd38af78c70ac6f10abcbb` |
| `capi\onnxruntime_providers_cuda.dll` | 689 375 232 | `2c744e0d1683518fa88e229ca006304aad6a29b81b9f0229596969c89ba80c12` |
| `capi\nvinfer_builder_resource_10.dll` | 1 971 797 024 | `2b8496c57a8434534e8a3c56e732207f1c74bc37ce7300d8f0d3542cdff02e12` |

```powershell
(Get-FileHash .\onnxruntime\capi\onnxruntime.dll -Algorithm SHA256).Hash.ToLower()
```

## Download

Grab the whole folder — 379 separate HTTP requests by hand is not a good idea.

```powershell
# Hugging Face CLI: chunked, parallel, resumable
hf download CatSnowdrop/universal_onnxruntime --local-dir .\uort
# result: .\uort\onnxruntime\__init__.py, .\uort\onnxruntime\capi\...

# or git (needs git-lfs; Xet accelerates it if hf_xet is installed)
git clone https://huggingface.co/CatSnowdrop/universal_onnxruntime uort
```

```python
from huggingface_hub import snapshot_download

path = snapshot_download(
repo_id="CatSnowdrop/universal_onnxruntime",
local_dir="uort",
max_workers=8,
)
print(path) # -> uort\onnxruntime
```

Single files can be fetched directly; the endpoint supports HTTP `Range`, so a large `.dll`
resumes instead of restarting:

```powershell
curl.exe -L -C - -o onnxruntime_providers_cuda.dll `
"https://huggingface.co/CatSnowdrop/universal_onnxruntime/resolve/main/onnxruntime/capi/onnxruntime_providers_cuda.dll"
```

`resolve/main` redirects to a commit-pinned CDN path, so re-uploading never invalidates a
download that is already running.

> **Expect ~5.20 GiB of traffic.** Unlike a zip, DLLs are stored uncompressed, so the folder is
> ~1.5× larger on the wire than the equivalent archive (3.48 GiB). In exchange there is no
> unpack step and no second copy on disk: peak usage is 5.20 GiB, not 8.8 GiB.

## What's inside

### Execution providers

`onnxruntime.get_available_providers()` reports, in this order:

```python
['TensorrtExecutionProvider', 'CUDAExecutionProvider', 'OpenVINOExecutionProvider',
'DmlExecutionProvider', 'CPUExecutionProvider']
```

| EP | Bundled runtime | Notes |
|---|---|---|
| `TensorrtExecutionProvider` | TensorRT 10.9, `nvonnxparser`, `nvinfer_dispatch` | engines are built at session creation; requires compute capability ≥ 7.5 |
| `CUDAExecutionProvider` | CUDA 12.9 runtime, cuBLAS, cuFFT, cuRAND, cuDNN 9 | driver is the only system prerequisite |
| `OpenVINOExecutionProvider` | OpenVINO 2026.2.1 + Intel CPU/GPU/NPU plugins, TBB | CPU, GPU and NPU devices |
| `DmlExecutionProvider` | `DirectML.dll` 17.67 MB | any DirectX 12 GPU (NVIDIA/AMD/Intel) |
| `CPUExecutionProvider` | MLAS kernels inside `onnxruntime.dll` | always available |

GPU kernels are compiled for `sm_61;75;80;86;89;90;100;120`. Note that the **TensorRT** EP,
unlike CUDA, does not support 6.1: TensorRT 10 dropped Pascal, so a P10x/GTX 10x0 card can use
CUDA or DirectML but not TensorRT.

### Why the package is 5.2 GiB

Almost all of the volume is the CUDA / TensorRT / OpenVINO runtimes; the Python side is ~4 MiB.

| Group | Main files | Size |
|---|---|---|
| TensorRT | `nvinfer_builder_resource_10.dll` (1880 MB), `nvinfer_10.dll` (421 MB), `nvinfer_plugin_10.dll` (49 MB) | ~2.30 GiB |
| CUDA | `onnxruntime_providers_cuda.dll` (657 MB), `cublasLt64_12.dll` (638 MB), `cudnn_engines_precompiled64_9.dll` (490 MB), `cufft64_11.dll` (274 MB), `cudnn_adv64_9.dll` (269 MB), `cudnn_ops64_9.dll` (121 MB) | ~2.64 GiB |
| OpenVINO | `openvino.dll`, `openvino_intel_{cpu,gpu,npu}_plugin.dll`, `openvino_intel_npu_compiler.dll`, frontends, TBB | ~200 MiB |
| Core | `onnxruntime.dll` (23 MB), `onnxruntime_pybind11_state.pyd` (25 MB), `onnxruntime_providers_shared.dll`, Python modules | ~50 MiB |
| DirectML + MSVC runtime | `DirectML.dll` (18 MB), `msvcp140*`, `vcruntime140*` | ~19 MiB |

`nvinfer_builder_resource_10.dll` (1.88 GiB of precompiled CUDA kernels) is loaded **only** when
a TensorRT engine has to be built from scratch. Do not delete it unless you never use
`TensorrtExecutionProvider`: `nvinfer_10.dll` loads fine without it, but engine construction
fails at runtime.

### Layout

The tree below is the repository tree; drop the `onnxruntime/` prefix and it is a valid
site-packages package.

```
onnxruntime/
├── __init__.py # public API: InferenceSession, get_available_providers, ...
├── uort.py # create_session(): resilient provider fallback helper
├── LICENSE Privacy.md ThirdPartyNotices.txt
├── capi/ # 63 files, 5.20 GiB — everything native
│ ├── onnxruntime.dll # core runtime (C API; also usable via ctypes)
│ ├── onnxruntime_pybind11_state.pyd
│ ├── onnxruntime_providers_{cuda,tensorrt,openvino,shared}.dll
│ ├── nvinfer* / nvonnxparser_10.dll
│ ├── cublas* / cudnn* / cufft* / curand* / cudart64_12.dll
│ ├── openvino*.dll / tbb*.dll / DirectML.dll / msvcp140*.dll / vcruntime140*.dll
│ ├── _uort_dll_dirs.py # registers capi/ with AddDllDirectory + PATH on import
│ ├── _pybind_state.py # patched to call _uort_dll_dirs before loading the extension
│ ├── build_and_package_info.py
│ └── version_info.py
├── backend/ 3 files # ORT EP unit-test harness
├── datasets/ 4 files # three tiny .onnx models used by those tests
├── quantization/ 59 files # Python tooling
├── tools/ 80 files # Python tooling
└── transformers/ 165 files # HF transformers integration layer
```

No C/C++ headers are included — for native code use the `onnxruntime.dll` C API together with
the public ORT 1.30.1 headers.

## Requirements

- **Windows 10/11 x64.**
- **CPython 3.12 x64.** The extension links `python312.dll`; 3.11/3.13 raise a DLL load error.
- **No NVIDIA/Intel SDKs are needed** — CUDA, cuDNN, TensorRT, OpenVINO and the MSVC runtime are
all in `capi/`.
- The **GPU driver stays a system prerequisite** (it is not, and cannot be, bundled):
- CUDA EP: NVIDIA driver with CUDA 12.x support (≥ 527.41; 551+ recommended for CUDA 12.9).
- TensorRT EP: the same driver **and** compute capability ≥ 7.5.
- DirectML EP: any DX12-capable GPU with a WDDM 2.x driver.
- OpenVINO EP: Intel CPU, or Intel GPU/NPU with a recent graphics driver.
- For `import onnxruntime` from a normal Python process nothing else is required; the package
calls `os.add_dll_directory(capi)` and prepends it to `PATH` itself.
- If you load `capi/onnxruntime.dll` from a **non-Python** host, add `capi` to `PATH` (or use
`SetDllDirectoryW`) before loading it.

## Installation

The folder is **not a pip wheel** (there is no `*.dist-info`), so `pip` neither sees nor
uninstalls it. Copy the folder.

### Option A — into a Python environment

```powershell
# the download landed in .\uort\onnxruntime
$sp = python -c "import sysconfig; print(sysconfig.get_paths()['purelib'])"
Remove-Item "$sp\onnxruntime" -Recurse -Force -ErrorAction SilentlyContinue
Copy-Item .\uort\onnxruntime "$sp\onnxruntime" -Recurse -Force

# make sure no other ONNX Runtime is installed next to it
python -m pip uninstall -y onnxruntime onnxruntime-gpu onnxruntime-directml onnxruntime-openvino
```

### Option B — into an application folder

Copy `onnxruntime\` next to your `python.exe` / `python312.dll`, or into
`<app>\_internal\python\Lib\site-packages\onnxruntime`, keeping the directory name exactly
`onnxruntime`. This is how the folder is used by the DeepFaceLive build it was made for.

### Verify

```python
import onnxruntime as ort

print(ort.__version__) # 1.30.1
print(ort.get_available_providers()) # all five providers (compile-time list)
print(ort.__file__) # ...\site-packages\onnxruntime\__init__.py
```

Then confirm that a provider really works on this machine by building a session — see below.
`get_available_providers()` lists what the **build** contains; whether a device can actually be
used depends on the driver, the GPU and the model.

## Usage

### CPU

```python
import onnxruntime as ort

sess = ort.I

This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +46 -0
  2. onnxruntime/LICENSE +21 -0
  3. onnxruntime/Privacy.md +34 -0
  4. onnxruntime/ThirdPartyNotices.txt +0 -0
  5. onnxruntime/__init__.py +500 -0
  6. onnxruntime/backend/__init__.py +6 -0
  7. onnxruntime/backend/backend.py +214 -0
  8. onnxruntime/backend/backend_rep.py +76 -0
  9. onnxruntime/capi/DirectML.dll +3 -0
  10. onnxruntime/capi/__init__.py +4 -0
  11. onnxruntime/capi/_ld_preload.py +7 -0
  12. onnxruntime/capi/_pybind_state.py +43 -0
  13. onnxruntime/capi/_uort_dll_dirs.py +32 -0
  14. onnxruntime/capi/build_and_package_info.py +3 -0
  15. onnxruntime/capi/concrt140.dll +3 -0
  16. onnxruntime/capi/convert_npz_to_onnx_adapter.py +48 -0
  17. onnxruntime/capi/cublas64_12.dll +3 -0
  18. onnxruntime/capi/cublasLt64_12.dll +3 -0
  19. onnxruntime/capi/cudart64_12.dll +3 -0
  20. onnxruntime/capi/cudnn64_9.dll +3 -0
  21. onnxruntime/capi/cudnn_adv64_9.dll +3 -0
  22. onnxruntime/capi/cudnn_cnn64_9.dll +3 -0
  23. onnxruntime/capi/cudnn_engines_precompiled64_9.dll +3 -0
  24. onnxruntime/capi/cudnn_engines_runtime_compiled64_9.dll +3 -0
  25. onnxruntime/capi/cudnn_graph64_9.dll +3 -0
  26. onnxruntime/capi/cudnn_heuristic64_9.dll +3 -0
  27. onnxruntime/capi/cudnn_ops64_9.dll +3 -0
  28. onnxruntime/capi/cufft64_11.dll +3 -0
  29. onnxruntime/capi/curand64_10.dll +3 -0
  30. onnxruntime/capi/msvcp140.dll +3 -0
  31. onnxruntime/capi/msvcp140_1.dll +0 -0
  32. onnxruntime/capi/msvcp140_2.dll +3 -0
  33. onnxruntime/capi/msvcp140_atomic_wait.dll +0 -0
  34. onnxruntime/capi/msvcp140_codecvt_ids.dll +0 -0
  35. onnxruntime/capi/nvinfer_10.dll +3 -0
  36. onnxruntime/capi/nvinfer_builder_resource_10.dll +3 -0
  37. onnxruntime/capi/nvinfer_dispatch_10.dll +3 -0
  38. onnxruntime/capi/nvinfer_plugin_10.dll +3 -0
  39. onnxruntime/capi/nvonnxparser_10.dll +3 -0
  40. onnxruntime/capi/onnxruntime.dll +3 -0
  41. onnxruntime/capi/onnxruntime_collect_build_info.py +47 -0
  42. onnxruntime/capi/onnxruntime_inference_collection.py +1930 -0
  43. onnxruntime/capi/onnxruntime_providers_cuda.dll +3 -0
  44. onnxruntime/capi/onnxruntime_providers_openvino.dll +3 -0
  45. onnxruntime/capi/onnxruntime_providers_shared.dll +0 -0
  46. onnxruntime/capi/onnxruntime_providers_tensorrt.dll +3 -0
  47. onnxruntime/capi/onnxruntime_pybind11_state.pyd +3 -0
  48. onnxruntime/capi/onnxruntime_validation.py +154 -0
  49. onnxruntime/capi/openvino.dll +3 -0
  50. onnxruntime/capi/openvino_auto_batch_plugin.dll +3 -0
.gitattributes CHANGED
@@ -33,3 +33,49 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ onnxruntime/capi/concrt140.dll filter=lfs diff=lfs merge=lfs -text
37
+ onnxruntime/capi/cublas64_12.dll filter=lfs diff=lfs merge=lfs -text
38
+ onnxruntime/capi/cublasLt64_12.dll filter=lfs diff=lfs merge=lfs -text
39
+ onnxruntime/capi/cudart64_12.dll filter=lfs diff=lfs merge=lfs -text
40
+ onnxruntime/capi/cudnn_adv64_9.dll filter=lfs diff=lfs merge=lfs -text
41
+ onnxruntime/capi/cudnn_cnn64_9.dll filter=lfs diff=lfs merge=lfs -text
42
+ onnxruntime/capi/cudnn_engines_precompiled64_9.dll filter=lfs diff=lfs merge=lfs -text
43
+ onnxruntime/capi/cudnn_engines_runtime_compiled64_9.dll filter=lfs diff=lfs merge=lfs -text
44
+ onnxruntime/capi/cudnn_graph64_9.dll filter=lfs diff=lfs merge=lfs -text
45
+ onnxruntime/capi/cudnn_heuristic64_9.dll filter=lfs diff=lfs merge=lfs -text
46
+ onnxruntime/capi/cudnn_ops64_9.dll filter=lfs diff=lfs merge=lfs -text
47
+ onnxruntime/capi/cudnn64_9.dll filter=lfs diff=lfs merge=lfs -text
48
+ onnxruntime/capi/cufft64_11.dll filter=lfs diff=lfs merge=lfs -text
49
+ onnxruntime/capi/curand64_10.dll filter=lfs diff=lfs merge=lfs -text
50
+ onnxruntime/capi/DirectML.dll filter=lfs diff=lfs merge=lfs -text
51
+ onnxruntime/capi/msvcp140_2.dll filter=lfs diff=lfs merge=lfs -text
52
+ onnxruntime/capi/msvcp140.dll filter=lfs diff=lfs merge=lfs -text
53
+ onnxruntime/capi/nvinfer_10.dll filter=lfs diff=lfs merge=lfs -text
54
+ onnxruntime/capi/nvinfer_builder_resource_10.dll filter=lfs diff=lfs merge=lfs -text
55
+ onnxruntime/capi/nvinfer_dispatch_10.dll filter=lfs diff=lfs merge=lfs -text
56
+ onnxruntime/capi/nvinfer_plugin_10.dll filter=lfs diff=lfs merge=lfs -text
57
+ onnxruntime/capi/nvonnxparser_10.dll filter=lfs diff=lfs merge=lfs -text
58
+ onnxruntime/capi/onnxruntime_providers_cuda.dll filter=lfs diff=lfs merge=lfs -text
59
+ onnxruntime/capi/onnxruntime_providers_openvino.dll filter=lfs diff=lfs merge=lfs -text
60
+ onnxruntime/capi/onnxruntime_providers_tensorrt.dll filter=lfs diff=lfs merge=lfs -text
61
+ onnxruntime/capi/onnxruntime_pybind11_state.pyd filter=lfs diff=lfs merge=lfs -text
62
+ onnxruntime/capi/onnxruntime.dll filter=lfs diff=lfs merge=lfs -text
63
+ onnxruntime/capi/openvino_auto_batch_plugin.dll filter=lfs diff=lfs merge=lfs -text
64
+ onnxruntime/capi/openvino_auto_plugin.dll filter=lfs diff=lfs merge=lfs -text
65
+ onnxruntime/capi/openvino_c.dll filter=lfs diff=lfs merge=lfs -text
66
+ onnxruntime/capi/openvino_hetero_plugin.dll filter=lfs diff=lfs merge=lfs -text
67
+ onnxruntime/capi/openvino_intel_cpu_plugin.dll filter=lfs diff=lfs merge=lfs -text
68
+ onnxruntime/capi/openvino_intel_gpu_plugin.dll filter=lfs diff=lfs merge=lfs -text
69
+ onnxruntime/capi/openvino_intel_npu_compiler_loader.dll filter=lfs diff=lfs merge=lfs -text
70
+ onnxruntime/capi/openvino_intel_npu_compiler.dll filter=lfs diff=lfs merge=lfs -text
71
+ onnxruntime/capi/openvino_intel_npu_plugin.dll filter=lfs diff=lfs merge=lfs -text
72
+ onnxruntime/capi/openvino_ir_frontend.dll filter=lfs diff=lfs merge=lfs -text
73
+ onnxruntime/capi/openvino_onnx_frontend.dll filter=lfs diff=lfs merge=lfs -text
74
+ onnxruntime/capi/openvino_paddle_frontend.dll filter=lfs diff=lfs merge=lfs -text
75
+ onnxruntime/capi/openvino_pytorch_frontend.dll filter=lfs diff=lfs merge=lfs -text
76
+ onnxruntime/capi/openvino_tensorflow_frontend.dll filter=lfs diff=lfs merge=lfs -text
77
+ onnxruntime/capi/openvino_tensorflow_lite_frontend.dll filter=lfs diff=lfs merge=lfs -text
78
+ onnxruntime/capi/openvino.dll filter=lfs diff=lfs merge=lfs -text
79
+ onnxruntime/capi/tbb12.dll filter=lfs diff=lfs merge=lfs -text
80
+ onnxruntime/capi/tbbmalloc.dll filter=lfs diff=lfs merge=lfs -text
81
+ onnxruntime/capi/vcruntime140.dll filter=lfs diff=lfs merge=lfs -text
onnxruntime/LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) Microsoft Corporation
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
onnxruntime/Privacy.md ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Privacy
2
+
3
+ ## Data Collection
4
+ The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the repository. There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft's privacy statement. Our privacy statement is located at https://go.microsoft.com/fwlink/?LinkID=824704. You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices.
5
+
6
+ ***
7
+
8
+ ### Official Builds
9
+ ONNX Runtime collects trace events with the goal of improving product quality. On Windows, it uses the platform's built-in ETW telemetry system; on supported Linux architectures, macOS, Android, and iOS, it uses the cross-platform 1DS telemetry SDK that is built into ONNX Runtime. Targets without a supported telemetry provider, including WebAssembly, tvOS, visionOS, Mac Catalyst, AIX, and RISC-V, do not include telemetry. In all cases, collection is subject to user consent and handled following Microsoft's privacy practices.
10
+
11
+ Telemetry is turned **ON** by default in the official builds ([see here](../README.md#binaries)). Both providers are accessed through ONNX Runtime's common telemetry interface (see [telemetry.h](../onnxruntime/core/platform/telemetry.h)).
12
+
13
+ ### Private Builds
14
+ The build driver enables telemetry by default for supported native platforms. The standard Windows `build.bat` wrapper explicitly passes `--no_telemetry`, so private builds made with that wrapper perform no data collection. Targets without a supported provider and builds that disable C++ exceptions automatically exclude telemetry. For information on how to disable telemetry in other builds, see [Disabling Telemetry](#disabling-telemetry) below.
15
+
16
+ #### Technical Details
17
+
18
+ **Windows.** The Windows provider uses the [TraceLogging](https://docs.microsoft.com/en-us/windows/win32/tracelogging/trace-logging-about) API for its implementation. This enables ONNX Runtime trace events to be collected by the operating system, and based on user consent, this data may be periodically sent to Microsoft servers following GDPR and privacy regulations for anonymity and data access controls. Windows ML and ONNX Runtime C APIs allow Trace Logging to be turned on/off (see [API pages](../README.md#api-documentation) for details); there are equivalent APIs in the C#, Python, and Java language bindings as well.
19
+
20
+ **Non-Windows (Linux, macOS, Android, iOS).** These platforms use the cross-platform 1DS SDK (cpp_client_telemetry) to send the same trace events to Microsoft's telemetry backend over HTTPS. Based on user consent, this data is handled following GDPR and privacy regulations for anonymity and data access controls. ONNX Runtime C APIs allow 1DS to be turned on/off (see [API pages](../README.md#api-documentation) for details); there are equivalent APIs in the C#, Python, and Java language bindings as well.
21
+
22
+ For ways to disable telemetry, see the [Disabling Telemetry](#disabling-telemetry) section below.
23
+
24
+ ### Disabling Telemetry
25
+
26
+ Telemetry can be disabled in any of these ways:
27
+
28
+ - **Disable it at build time.** Pass `--no_telemetry` to `build.py` or `build.sh`. This omits the 1DS provider from non-Windows builds and disables the Microsoft telemetry configuration on Windows. The standard Windows `build.bat` wrapper does this automatically. Unsupported targets and exception-free builds never include telemetry.
29
+ - **Disable all telemetry at runtime (non-Windows).** Set `ORT_DISABLE_TELEMETRY=1` before ONNX Runtime initializes. This prevents the uploader, events, and persistent device identifier from being created for the process lifetime.
30
+ - **Disable non-essential events via the API.** The C API (and the C#, Python, and Java bindings) can suppress non-essential telemetry. ONNX Runtime may already have emitted a minimal initialization event before the API can be called. On **Windows**, ETW events are recorded only when an external trace session is collecting.
31
+
32
+ Telemetry-enabled static Linux builds use static curl and mbedTLS. FetchContent packages include those archives;
33
+ vcpkg builds resolve them from the same vcpkg installation. A static consumer that links another curl or mbedTLS
34
+ copy into the same final binary must build ORT with `--no_telemetry` to avoid ordinary static-symbol collisions.
onnxruntime/ThirdPartyNotices.txt ADDED
The diff for this file is too large to render. See raw diff
 
onnxruntime/__init__.py ADDED
@@ -0,0 +1,500 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -------------------------------------------------------------------------
2
+ # Copyright (c) Microsoft Corporation. All rights reserved.
3
+ # Licensed under the MIT License.
4
+ # --------------------------------------------------------------------------
5
+ """
6
+ ONNX Runtime is a performance-focused scoring engine for Open Neural Network Exchange (ONNX) models.
7
+ For more information on ONNX Runtime, please see `aka.ms/onnxruntime <https://aka.ms/onnxruntime/>`_
8
+ or the `Github project <https://github.com/microsoft/onnxruntime/>`_.
9
+ """
10
+
11
+ import contextlib
12
+
13
+ __version__ = "1.30.1"
14
+ __author__ = "Microsoft"
15
+
16
+ # we need to do device version validation (for example to check Cuda version for an onnxruntime-training package).
17
+ # in order to know whether the onnxruntime package is for training it needs
18
+ # to do import onnxruntime.training.ortmodule first.
19
+ # onnxruntime.capi._pybind_state is required before import onnxruntime.training.ortmodule.
20
+ # however, import onnxruntime.capi._pybind_state will already raise an exception if a required Cuda version
21
+ # is not found.
22
+ # here we need to save the exception and continue with Cuda version validation in order to post
23
+ # meaningful messages to the user.
24
+ # the saved exception is raised after device version validation.
25
+ try:
26
+ from onnxruntime.capi._pybind_state import (
27
+ ExecutionMode, # noqa: F401
28
+ ExecutionOrder, # noqa: F401
29
+ GraphOptimizationLevel, # noqa: F401
30
+ LoraAdapter, # noqa: F401
31
+ ModelMetadata, # noqa: F401
32
+ NodeArg, # noqa: F401
33
+ OrtAllocatorType, # noqa: F401
34
+ OrtArenaCfg, # noqa: F401
35
+ OrtCompileApiFlags, # noqa: F401
36
+ OrtDeviceMemoryType, # noqa: F401
37
+ OrtEpAssignedNode, # noqa: F401
38
+ OrtEpAssignedSubgraph, # noqa: F401
39
+ OrtEpDevice, # noqa: F401
40
+ OrtExecutionProviderDevicePolicy, # noqa: F401
41
+ OrtExternalInitializerInfo, # noqa: F401
42
+ OrtHardwareDevice, # noqa: F401
43
+ OrtHardwareDeviceType, # noqa: F401
44
+ OrtMemoryInfo, # noqa: F401
45
+ OrtMemoryInfoDeviceType, # noqa: F401
46
+ OrtMemType, # noqa: F401
47
+ OrtSparseFormat, # noqa: F401
48
+ OrtSyncStream, # noqa: F401
49
+ RunOptions, # noqa: F401
50
+ SessionIOBinding, # noqa: F401
51
+ SessionOptions, # noqa: F401
52
+ create_and_register_allocator, # noqa: F401
53
+ create_and_register_allocator_v2, # noqa: F401
54
+ disable_telemetry_events, # noqa: F401
55
+ enable_telemetry_events, # noqa: F401
56
+ get_all_providers, # noqa: F401
57
+ get_available_providers, # noqa: F401
58
+ get_build_info,
59
+ get_device, # noqa: F401
60
+ get_ep_devices, # noqa: F401
61
+ get_version_string, # noqa: F401
62
+ has_collective_ops, # noqa: F401
63
+ register_execution_provider_library,
64
+ set_default_logger_severity, # noqa: F401
65
+ set_default_logger_verbosity, # noqa: F401
66
+ set_global_thread_pool_sizes, # noqa: F401
67
+ set_seed, # noqa: F401
68
+ unregister_execution_provider_library, # noqa: F401
69
+ )
70
+
71
+ import_capi_exception = None
72
+ except Exception as e:
73
+ import_capi_exception = e
74
+
75
+ from onnxruntime.capi import onnxruntime_validation
76
+
77
+ if import_capi_exception:
78
+ raise import_capi_exception
79
+
80
+ from onnxruntime.capi.onnxruntime_inference_collection import (
81
+ AdapterFormat, # noqa: F401
82
+ InferenceSession, # noqa: F401
83
+ IOBinding, # noqa: F401
84
+ ModelCompiler, # noqa: F401
85
+ OrtDevice, # noqa: F401
86
+ OrtDeviceVendorId, # noqa: F401
87
+ OrtValue, # noqa: F401
88
+ SparseTensor, # noqa: F401
89
+ copy_tensors, # noqa: F401
90
+ )
91
+
92
+ # TODO: thiagofc: Temporary experimental namespace for new PyTorch front-end
93
+ try: # noqa: SIM105
94
+ from . import experimental # noqa: F401
95
+ except ImportError:
96
+ pass
97
+
98
+
99
+ package_name, version, cuda_version = onnxruntime_validation.get_package_name_and_version_info()
100
+
101
+ if version:
102
+ __version__ = version
103
+
104
+ onnxruntime_validation.check_distro_info()
105
+
106
+
107
+ def _get_cuda_plugin_ep_library_path() -> str | None:
108
+ import os # noqa: PLC0415
109
+ import sys # noqa: PLC0415
110
+
111
+ if ", cuda-plugin-ep=" not in get_build_info():
112
+ return None
113
+
114
+ if sys.platform == "win32":
115
+ library_name = "onnxruntime_providers_cuda.dll"
116
+ elif sys.platform == "darwin":
117
+ library_name = "libonnxruntime_providers_cuda.dylib"
118
+ else:
119
+ library_name = "libonnxruntime_providers_cuda.so"
120
+
121
+ library_path = os.path.join(os.path.dirname(__file__), "capi", library_name)
122
+ return library_path if os.path.isfile(library_path) else None
123
+
124
+
125
+ def _register_bundled_cuda_plugin_ep(warn_on_failure: bool = False):
126
+ library_path = _get_cuda_plugin_ep_library_path()
127
+ if not library_path:
128
+ return
129
+
130
+ try:
131
+ register_execution_provider_library("CUDAExecutionProvider", library_path)
132
+ except Exception as e:
133
+ if "already registered" not in str(e).lower():
134
+ if warn_on_failure:
135
+ import warnings # noqa: PLC0415
136
+
137
+ warnings.warn(f"Failed to register bundled CUDA plugin EP from {library_path}: {e}")
138
+
139
+
140
+ _register_bundled_cuda_plugin_ep(warn_on_failure=True)
141
+
142
+
143
+ def _get_package_version(package_name: str):
144
+ from importlib.metadata import PackageNotFoundError, version # noqa: PLC0415
145
+
146
+ try:
147
+ package_version = version(package_name)
148
+ except PackageNotFoundError:
149
+ package_version = None
150
+ return package_version
151
+
152
+
153
+ def _get_package_root(package_name: str, directory_name: str | None = None):
154
+ from importlib.metadata import PackageNotFoundError, distribution # noqa: PLC0415
155
+
156
+ root_directory_name = directory_name or package_name
157
+ try:
158
+ dist = distribution(package_name)
159
+ files = dist.files or []
160
+
161
+ for file in files:
162
+ if file.name.endswith("__init__.py") and root_directory_name in file.parts:
163
+ return file.locate().parent
164
+
165
+ # Fallback to the first __init__.py
166
+ if not directory_name:
167
+ for file in files:
168
+ if file.name.endswith("__init__.py"):
169
+ return file.locate().parent
170
+ except PackageNotFoundError:
171
+ # package not found, do nothing
172
+ pass
173
+
174
+ return None
175
+
176
+
177
+ def _extract_cuda_major_version(version_str: str) -> str:
178
+ """Extract CUDA major version from version string (e.g., '12.1' -> '12').
179
+
180
+ Args:
181
+ version_str: CUDA version string to parse
182
+
183
+ Returns:
184
+ Major version as string, or "12" if parsing fails
185
+ """
186
+ return version_str.split(".", maxsplit=1)[0] if version_str else "12"
187
+
188
+
189
+ def _get_cufft_version(cuda_major_version: str) -> str:
190
+ """Get cufft library version based on CUDA major version.
191
+
192
+ Args:
193
+ cuda_major_version: CUDA major version as string (e.g., "12", "13")
194
+
195
+ Returns:
196
+ cufft version as string
197
+ """
198
+ # cufft versions: CUDA 12.x -> 11, CUDA 13.x -> 12
199
+ return "12" if int(cuda_major_version) >= 13 else "11"
200
+
201
+
202
+ def _get_nvidia_dll_paths(is_windows: bool, cuda: bool = True, cudnn: bool = True):
203
+ # Dynamically determine CUDA major version from build info.
204
+ # build_cuda_version defaults to the version this package was built with; it is a parameter for testability.
205
+ cuda_major_version = _extract_cuda_major_version(cuda_version)
206
+ cufft_version = _get_cufft_version(cuda_major_version)
207
+
208
+ # Starting with CUDA 13, NVIDIA consolidated the per-component CUDA Toolkit wheels
209
+ # (cublas, cufft, cuda_runtime, cuda_nvrtc, curand, ...) into a single "nvidia/cu{major}"
210
+ # package and dropped the "-cuNN" suffix from those package names. On Windows the DLLs
211
+ # moved into an architecture sub-folder ("bin/<arch>", e.g. "bin/x86_64"); on Linux the
212
+ # libraries are placed directly in "lib" (the wheel itself is architecture specific, so
213
+ # there is no arch sub-folder). cuDNN keeps its own "nvidia/cudnn" package and layout.
214
+ use_consolidated_layout = cuda_major_version.isdigit() and int(cuda_major_version) >= 13
215
+
216
+ if use_consolidated_layout:
217
+ cuda_dir = f"cu{cuda_major_version}"
218
+ if is_windows:
219
+ import platform # noqa: PLC0415
220
+
221
+ arch = "arm64" if platform.machine().lower() in ("arm64", "aarch64") else "x86_64"
222
+ cuda_dll_paths = [
223
+ ("nvidia", cuda_dir, "bin", arch, f"cublasLt64_{cuda_major_version}.dll"),
224
+ ("nvidia", cuda_dir, "bin", arch, f"cublas64_{cuda_major_version}.dll"),
225
+ ("nvidia", cuda_dir, "bin", arch, f"cufft64_{cufft_version}.dll"),
226
+ ("nvidia", cuda_dir, "bin", arch, f"cudart64_{cuda_major_version}.dll"),
227
+ ]
228
+ else: # Linux
229
+ # cublas64 depends on cublasLt64, so cublasLt64 should be loaded first.
230
+ cuda_dll_paths = [
231
+ ("nvidia", cuda_dir, "lib", f"libcublasLt.so.{cuda_major_version}"),
232
+ ("nvidia", cuda_dir, "lib", f"libcublas.so.{cuda_major_version}"),
233
+ ("nvidia", cuda_dir, "lib", f"libnvrtc.so.{cuda_major_version}"),
234
+ ("nvidia", cuda_dir, "lib", "libcurand.so.10"),
235
+ ("nvidia", cuda_dir, "lib", f"libcufft.so.{cufft_version}"),
236
+ ("nvidia", cuda_dir, "lib", f"libcudart.so.{cuda_major_version}"),
237
+ ]
238
+ elif is_windows:
239
+ # CUDA 12 and earlier: each component ships its own "nvidia/<component>" package.
240
+ # Path is relative to site-packages directory.
241
+ cuda_dll_paths = [
242
+ ("nvidia", "cublas", "bin", f"cublasLt64_{cuda_major_version}.dll"),
243
+ ("nvidia", "cublas", "bin", f"cublas64_{cuda_major_version}.dll"),
244
+ ("nvidia", "cufft", "bin", f"cufft64_{cufft_version}.dll"),
245
+ ("nvidia", "cuda_runtime", "bin", f"cudart64_{cuda_major_version}.dll"),
246
+ ]
247
+ else: # Linux
248
+ # cublas64 depends on cublasLt64, so cublasLt64 should be loaded first.
249
+ cuda_dll_paths = [
250
+ ("nvidia", "cublas", "lib", f"libcublasLt.so.{cuda_major_version}"),
251
+ ("nvidia", "cublas", "lib", f"libcublas.so.{cuda_major_version}"),
252
+ ("nvidia", "cuda_nvrtc", "lib", f"libnvrtc.so.{cuda_major_version}"),
253
+ ("nvidia", "curand", "lib", "libcurand.so.10"),
254
+ ("nvidia", "cufft", "lib", f"libcufft.so.{cufft_version}"),
255
+ ("nvidia", "cuda_runtime", "lib", f"libcudart.so.{cuda_major_version}"),
256
+ ]
257
+
258
+ # cuDNN keeps its own "nvidia/cudnn" package layout in both old and consolidated schemes.
259
+ if is_windows:
260
+ cudnn_dll_paths = [
261
+ ("nvidia", "cudnn", "bin", "cudnn_engines_runtime_compiled64_9.dll"),
262
+ ("nvidia", "cudnn", "bin", "cudnn_engines_precompiled64_9.dll"),
263
+ ("nvidia", "cudnn", "bin", "cudnn_heuristic64_9.dll"),
264
+ ("nvidia", "cudnn", "bin", "cudnn_ops64_9.dll"),
265
+ ("nvidia", "cudnn", "bin", "cudnn_adv64_9.dll"),
266
+ ("nvidia", "cudnn", "bin", "cudnn_graph64_9.dll"),
267
+ ("nvidia", "cudnn", "bin", "cudnn64_9.dll"),
268
+ ("nvidia", "cudnn", "bin", "cudnn_engines_tensor_ir64_9.dll"),
269
+ ]
270
+ else: # Linux
271
+ # Do not load cudnn sub DLLs (they will be dynamically loaded later) to be consistent with PyTorch in Linux.
272
+ cudnn_dll_paths = [
273
+ ("nvidia", "cudnn", "lib", "libcudnn.so.9"),
274
+ ]
275
+
276
+ return (cuda_dll_paths if cuda else []) + (cudnn_dll_paths if cudnn else [])
277
+
278
+
279
+ def print_debug_info():
280
+ """Print information to help debugging."""
281
+ import importlib.util # noqa: PLC0415
282
+ import os # noqa: PLC0415
283
+ import platform # noqa: PLC0415
284
+ from importlib.metadata import distributions # noqa: PLC0415
285
+
286
+ print(f"{package_name} version: {__version__}")
287
+ if cuda_version:
288
+ print(f"CUDA version used in build: {cuda_version}")
289
+ print("platform:", platform.platform())
290
+
291
+ print("\nPython package, version and location:")
292
+ ort_packages = []
293
+ for dist in distributions():
294
+ package = dist.metadata["Name"]
295
+ if package == "onnxruntime" or package.startswith(("onnxruntime-", "ort-")):
296
+ # Exclude packages whose root directory name is not onnxruntime.
297
+ location = _get_package_root(package, "onnxruntime")
298
+ if location and (package not in ort_packages):
299
+ ort_packages.append(package)
300
+ print(f"{package}=={dist.version} at {location}")
301
+
302
+ if len(ort_packages) > 1:
303
+ print(
304
+ "\033[33mWARNING: multiple onnxruntime packages are installed to the same location. "
305
+ "Please 'pip uninstall` all above packages, then `pip install` only one of them.\033[0m"
306
+ )
307
+
308
+ if cuda_version:
309
+ # Print version of installed packages that is related to CUDA or cuDNN DLLs.
310
+ cuda_major = _extract_cuda_major_version(cuda_version)
311
+
312
+ # Starting with CUDA 13, NVIDIA dropped the "-cuNN" suffix from the per-component
313
+ # CUDA Toolkit packages (cuDNN keeps its suffixed package name).
314
+ cuda_pkg_suffix = "" if (cuda_major.isdigit() and int(cuda_major) >= 13) else f"-cu{cuda_major}"
315
+
316
+ packages = [
317
+ "torch",
318
+ f"nvidia-cuda-runtime{cuda_pkg_suffix}",
319
+ f"nvidia-cudnn-cu{cuda_major}",
320
+ f"nvidia-cublas{cuda_pkg_suffix}",
321
+ f"nvidia-cufft{cuda_pkg_suffix}",
322
+ f"nvidia-curand{cuda_pkg_suffix}",
323
+ f"nvidia-cuda-nvrtc{cuda_pkg_suffix}",
324
+ f"nvidia-nvjitlink{cuda_pkg_suffix}",
325
+ ]
326
+ for package in packages:
327
+ directory_name = "nvidia" if package.startswith("nvidia-") else None
328
+ version = _get_package_version(package)
329
+ if version:
330
+ print(f"{package}=={version} at {_get_package_root(package, directory_name)}")
331
+ else:
332
+ print(f"{package} not installed")
333
+
334
+ if platform.system() == "Windows":
335
+ print(f"\nEnvironment variable:\nPATH={os.environ.get('PATH', '(unset)')}")
336
+ elif platform.system() == "Linux":
337
+ print(f"\nEnvironment variable:\nLD_LIBRARY_PATH={os.environ.get('LD_LIBRARY_PATH', '(unset)')}")
338
+
339
+ if importlib.util.find_spec("psutil"):
340
+
341
+ def is_target_dll(path: str):
342
+ target_keywords = ["vcruntime140", "msvcp140"]
343
+ if cuda_version:
344
+ target_keywords = ["cufft", "cublas", "cudart", "nvrtc", "curand", "cudnn", *target_keywords]
345
+ return any(keyword in path for keyword in target_keywords)
346
+
347
+ import psutil # noqa: PLC0415
348
+
349
+ p = psutil.Process(os.getpid())
350
+
351
+ print("\nList of loaded DLLs:")
352
+ for lib in p.memory_maps():
353
+ if is_target_dll(lib.path.lower()):
354
+ print(lib.path)
355
+
356
+ if cuda_version:
357
+ if importlib.util.find_spec("cpuinfo") and importlib.util.find_spec("py3nvml"):
358
+ from .transformers.machine_info import get_device_info # noqa: PLC0415
359
+
360
+ print("\nDevice information:")
361
+ print(get_device_info())
362
+ else:
363
+ print("please `pip install py-cpuinfo py3nvml` to show device information.")
364
+ else:
365
+ print("please `pip install psutil` to show loaded DLLs.")
366
+
367
+
368
+ def preload_dlls(cuda: bool = True, cudnn: bool = True, msvc: bool = True, directory=None):
369
+ """Preload CUDA 12.x+ and optional cuDNN 9.x DLLs in Windows or Linux, and MSVC runtime DLLs in Windows.
370
+
371
+ When the installed PyTorch is compatible (using same major version of CUDA and cuDNN),
372
+ there is no need to call this function if `import torch` is done before `import onnxruntime`.
373
+
374
+ Args:
375
+ cuda (bool, optional): enable loading CUDA DLLs. Defaults to True.
376
+ cudnn (bool, optional): enable loading cuDNN DLLs. Defaults to True. Missing cuDNN DLLs are ignored.
377
+ msvc (bool, optional): enable loading MSVC DLLs in Windows. Defaults to True.
378
+ directory(str, optional): a directory contains CUDA or cuDNN DLLs. It can be an absolute path,
379
+ or a path relative to the directory of this file.
380
+ If directory is None (default value), the search order: the lib directory of compatible PyTorch in Windows,
381
+ nvidia site packages, default DLL loading paths.
382
+ If directory is empty string (""), the search order: nvidia site packages, default DLL loading paths.
383
+ If directory is a path, the search order: the directory, default DLL loading paths.
384
+ """
385
+ import ctypes # noqa: PLC0415
386
+ import os # noqa: PLC0415
387
+ import platform # noqa: PLC0415
388
+ import sys # noqa: PLC0415
389
+
390
+ if platform.system() not in ["Windows", "Linux"]:
391
+ return
392
+
393
+ is_windows = platform.system() == "Windows"
394
+ if is_windows and msvc:
395
+ try:
396
+ ctypes.CDLL("vcruntime140.dll")
397
+ ctypes.CDLL("msvcp140.dll")
398
+ if platform.machine() != "ARM64":
399
+ ctypes.CDLL("vcruntime140_1.dll")
400
+ except OSError:
401
+ print("Microsoft Visual C++ Redistributable is not installed, this may lead to the DLL load failure.")
402
+ print("It can be downloaded at https://aka.ms/vs/17/release/vc_redist.x64.exe.")
403
+
404
+ # Check if CUDA version is supported (12.x or 13.x+)
405
+ ort_cuda_major = None
406
+ if cuda_version:
407
+ try:
408
+ ort_cuda_major = int(cuda_version.split(".")[0])
409
+ if ort_cuda_major < 12 and (cuda or cudnn):
410
+ print(
411
+ f"\033[33mWARNING: {package_name} is built with CUDA {cuda_version}, which is not supported for preloading. "
412
+ f"CUDA 12.x or newer is required. Call preload_dlls with cuda=False and cudnn=False.\033[0m"
413
+ )
414
+ return
415
+ except ValueError:
416
+ print(
417
+ f"\033[33mWARNING: Unable to parse CUDA version '{cuda_version}'. "
418
+ "Skipping DLL preloading. Call preload_dlls with cuda=False and cudnn=False.\033[0m"
419
+ )
420
+ return
421
+ elif cuda or cudnn:
422
+ # No CUDA version info available but CUDA/cuDNN preloading requested
423
+ return
424
+
425
+ is_cuda_cudnn_imported_by_torch = False
426
+
427
+ if is_windows:
428
+ torch_version = _get_package_version("torch")
429
+ # Check if torch CUDA version matches onnxruntime CUDA version
430
+ torch_cuda_major = None
431
+ if torch_version and "+cu" in torch_version:
432
+ with contextlib.suppress(ValueError):
433
+ # Extract CUDA version from torch (e.g., "2.0.0+cu121" -> 12)
434
+ cu_part = torch_version.split("+cu")[1]
435
+ torch_cuda_major = int(cu_part[:2]) # First 2 digits are major version
436
+
437
+ is_torch_cuda_compatible = (
438
+ torch_cuda_major == ort_cuda_major if (torch_cuda_major and ort_cuda_major) else False
439
+ )
440
+
441
+ if "torch" in sys.modules:
442
+ is_cuda_cudnn_imported_by_torch = is_torch_cuda_compatible
443
+ if torch_cuda_major and ort_cuda_major and torch_cuda_major != ort_cuda_major:
444
+ print(
445
+ f"\033[33mWARNING: The installed PyTorch {torch_version} uses CUDA {torch_cuda_major}.x, "
446
+ f"but {package_name} is built with CUDA {ort_cuda_major}.x. "
447
+ f"Please install PyTorch for CUDA {ort_cuda_major}.x to be compatible.\033[0m"
448
+ )
449
+
450
+ if is_torch_cuda_compatible and directory is None:
451
+ torch_root = _get_package_root("torch", "torch")
452
+ if torch_root:
453
+ directory = os.path.join(torch_root, "lib")
454
+
455
+ base_directory = directory or ".."
456
+ if not os.path.isabs(base_directory):
457
+ base_directory = os.path.join(os.path.dirname(__file__), base_directory)
458
+ base_directory = os.path.normpath(base_directory)
459
+ if not os.path.isdir(base_directory):
460
+ raise RuntimeError(f"Invalid parameter of directory={directory}. The directory does not exist!")
461
+
462
+ if is_cuda_cudnn_imported_by_torch:
463
+ # In Windows, PyTorch has loaded CUDA and cuDNN DLLs during `import torch`, no need to load them again.
464
+ print("Skip loading CUDA and cuDNN DLLs since torch is imported.")
465
+ return
466
+
467
+ # Try load DLLs from nvidia site packages.
468
+ dll_paths = _get_nvidia_dll_paths(is_windows, cuda, cudnn)
469
+ optional_dll_filenames = {relative_path[-1] for relative_path in _get_nvidia_dll_paths(is_windows, False, cudnn)}
470
+ loaded_dlls = []
471
+ for relative_path in dll_paths:
472
+ dll_path = (
473
+ os.path.join(base_directory, relative_path[-1])
474
+ if directory
475
+ else os.path.join(base_directory, *relative_path)
476
+ )
477
+ if os.path.isfile(dll_path):
478
+ try:
479
+ _ = ctypes.CDLL(dll_path)
480
+ loaded_dlls.append(relative_path[-1])
481
+ except Exception as e:
482
+ if relative_path[-1] not in optional_dll_filenames:
483
+ print(f"Failed to load {dll_path}: {e}")
484
+
485
+ # Try load DLLs with default path settings.
486
+ has_failure = False
487
+ for relative_path in dll_paths:
488
+ dll_filename = relative_path[-1]
489
+ if dll_filename not in loaded_dlls:
490
+ try:
491
+ _ = ctypes.CDLL(dll_filename)
492
+ except Exception as e:
493
+ if dll_filename not in optional_dll_filenames:
494
+ has_failure = True
495
+ print(f"Failed to load {dll_filename}: {e}")
496
+
497
+ if has_failure:
498
+ print("Please follow https://onnxruntime.ai/docs/install/#cuda-and-cudnn to install CUDA.")
499
+
500
+ _register_bundled_cuda_plugin_ep(warn_on_failure=True)
onnxruntime/backend/__init__.py ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ # -------------------------------------------------------------------------
2
+ # Copyright (c) Microsoft Corporation. All rights reserved.
3
+ # Licensed under the MIT License.
4
+ # --------------------------------------------------------------------------
5
+
6
+ from .backend import is_compatible, prepare, run, supports_device # noqa: F401
onnxruntime/backend/backend.py ADDED
@@ -0,0 +1,214 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -------------------------------------------------------------------------
2
+ # Copyright (c) Microsoft Corporation. All rights reserved.
3
+ # Licensed under the MIT License.
4
+ # --------------------------------------------------------------------------
5
+ """
6
+ Implements ONNX's backend API.
7
+ """
8
+
9
+ import os
10
+ import unittest
11
+
12
+ import packaging.version
13
+ from onnx import ModelProto, helper, version # noqa: F401
14
+ from onnx.backend.base import Backend
15
+ from onnx.checker import check_model
16
+
17
+ from onnxruntime import InferenceSession, SessionOptions, get_available_providers, get_device
18
+ from onnxruntime.backend.backend_rep import OnnxRuntimeBackendRep
19
+
20
+ # Allowlist of SessionOptions attributes that are safe to set via the backend API.
21
+ # Dangerous attributes intentionally excluded:
22
+ # optimized_model_filepath — triggers Model::Save(), overwrites arbitrary files
23
+ # profile_file_prefix — writes profiling JSON to arbitrary path
24
+ # enable_profiling — causes uncontrolled file writes to cwd
25
+ _ALLOWED_SESSION_OPTIONS = frozenset(
26
+ {
27
+ "enable_cpu_mem_arena",
28
+ "enable_mem_pattern",
29
+ "enable_mem_reuse",
30
+ "execution_mode",
31
+ "execution_order",
32
+ "graph_optimization_level",
33
+ "inter_op_num_threads",
34
+ "intra_op_num_threads",
35
+ "log_severity_level",
36
+ "log_verbosity_level",
37
+ "logid",
38
+ "use_deterministic_compute",
39
+ "use_per_session_threads",
40
+ }
41
+ )
42
+
43
+
44
+ class OnnxRuntimeBackend(Backend):
45
+ """
46
+ Implements
47
+ `ONNX's backend API <https://github.com/onnx/onnx/blob/main/docs/ImplementingAnOnnxBackend.md>`_
48
+ with *ONNX Runtime*.
49
+ The backend is mostly used when you need to switch between
50
+ multiple runtimes with the same API.
51
+ `Importing models from ONNX to Caffe2 <https://github.com/onnx/tutorials/blob/master/tutorials/OnnxCaffe2Import.ipynb>`_
52
+ shows how to use *caffe2* as a backend for a converted model.
53
+ Note: This is not the official Python API.
54
+ """
55
+
56
+ allowReleasedOpsetsOnly = bool(os.getenv("ALLOW_RELEASED_ONNX_OPSET_ONLY", "1") == "1") # noqa: N815
57
+
58
+ @classmethod
59
+ def is_compatible(cls, model, device=None, **kwargs):
60
+ """
61
+ Return whether the model is compatible with the backend.
62
+
63
+ :param model: unused
64
+ :param device: None to use the default device or a string (ex: `'CPU'`)
65
+ :return: boolean
66
+ """
67
+ if device is None:
68
+ device = get_device()
69
+ return cls.supports_device(device)
70
+
71
+ @classmethod
72
+ def is_opset_supported(cls, model):
73
+ """
74
+ Return whether the opset for the model is supported by the backend.
75
+ When By default only released onnx opsets are allowed by the backend
76
+ To test new opsets env variable ALLOW_RELEASED_ONNX_OPSET_ONLY should be set to 0
77
+
78
+ :param model: Model whose opsets needed to be verified.
79
+ :return: boolean and error message if opset is not supported.
80
+ """
81
+ if cls.allowReleasedOpsetsOnly:
82
+ for opset in model.opset_import:
83
+ domain = opset.domain if opset.domain else "ai.onnx"
84
+ try:
85
+ key = (domain, opset.version)
86
+ if key not in helper.OP_SET_ID_VERSION_MAP:
87
+ error_message = (
88
+ "Skipping this test as only released onnx opsets are supported."
89
+ "To run this test set env variable ALLOW_RELEASED_ONNX_OPSET_ONLY to 0."
90
+ f" Got Domain '{domain}' version '{opset.version}'."
91
+ )
92
+ return False, error_message
93
+ except AttributeError:
94
+ # for some CI pipelines accessing helper.OP_SET_ID_VERSION_MAP
95
+ # is generating attribute error. TODO investigate the pipelines to
96
+ # fix this error. Falling back to a simple version check when this error is encountered
97
+ if (domain == "ai.onnx" and opset.version > 12) or (domain == "ai.ommx.ml" and opset.version > 2):
98
+ error_message = (
99
+ "Skipping this test as only released onnx opsets are supported."
100
+ "To run this test set env variable ALLOW_RELEASED_ONNX_OPSET_ONLY to 0."
101
+ f" Got Domain '{domain}' version '{opset.version}'."
102
+ )
103
+ return False, error_message
104
+ return True, ""
105
+
106
+ @classmethod
107
+ def supports_device(cls, device):
108
+ """
109
+ Check whether the backend is compiled with particular device support.
110
+ In particular it's used in the testing suite.
111
+ """
112
+ if device == "CUDA":
113
+ device = "GPU"
114
+ return "-" + device in get_device() or device + "-" in get_device() or device == get_device()
115
+
116
+ @classmethod
117
+ def prepare(cls, model, device=None, **kwargs):
118
+ """
119
+ Load the model and creates an :class:`onnxruntime.backend.backend_rep.OnnxRuntimeBackendRep`
120
+ ready to be used as a backend.
121
+
122
+ :param model: the model to prepare — accepts a file path (str), serialized
123
+ model (bytes), :class:`onnx.ModelProto`, :class:`onnxruntime.InferenceSession`,
124
+ or :class:`onnxruntime.backend.backend_rep.OnnxRuntimeBackendRep` (returned as-is)
125
+ :param device: requested device for the computation,
126
+ None means the default one which depends on
127
+ the compilation settings
128
+ :param kwargs: only a safe subset of :class:`onnxruntime.SessionOptions` attributes are
129
+ accepted; see ``_ALLOWED_SESSION_OPTIONS`` for the list
130
+ :return: :class:`onnxruntime.backend.backend_rep.OnnxRuntimeBackendRep`
131
+ """
132
+ if isinstance(model, OnnxRuntimeBackendRep):
133
+ return model
134
+ elif isinstance(model, InferenceSession):
135
+ return OnnxRuntimeBackendRep(model)
136
+ elif isinstance(model, (str, bytes)):
137
+ options = SessionOptions()
138
+ for k, v in kwargs.items():
139
+ if k in _ALLOWED_SESSION_OPTIONS:
140
+ setattr(options, k, v)
141
+ elif hasattr(options, k):
142
+ raise RuntimeError(
143
+ f"SessionOptions attribute '{k}' is not permitted via the backend API. "
144
+ f"Allowed attributes: {', '.join(sorted(_ALLOWED_SESSION_OPTIONS))}"
145
+ )
146
+ # else: silently ignore unknown keys
147
+
148
+ excluded_providers = os.getenv("ORT_ONNX_BACKEND_EXCLUDE_PROVIDERS", default="").split(",")
149
+ providers = [x for x in get_available_providers() if (x not in excluded_providers)]
150
+
151
+ inf = InferenceSession(model, sess_options=options, providers=providers)
152
+ # backend API is primarily used for ONNX test/validation. As such, we should disable session.run() fallback
153
+ # which may hide test failures.
154
+ inf.disable_fallback()
155
+ if device is not None and not cls.supports_device(device):
156
+ raise RuntimeError(f"Incompatible device expected '{device}', got '{get_device()}'")
157
+ return cls.prepare(inf, device, **kwargs)
158
+ else:
159
+ # type: ModelProto
160
+ # check_model serializes the model anyways, so serialize the model once here
161
+ # and reuse it below in the cls.prepare call to avoid an additional serialization
162
+ # only works with onnx >= 1.10.0 hence the version check
163
+ onnx_version = packaging.version.parse(version.version) or packaging.version.Version("0")
164
+ onnx_supports_serialized_model_check = onnx_version.release >= (1, 10, 0)
165
+ bin_or_model = model.SerializeToString() if onnx_supports_serialized_model_check else model
166
+ check_model(bin_or_model)
167
+ opset_supported, error_message = cls.is_opset_supported(model)
168
+ if not opset_supported:
169
+ raise unittest.SkipTest(error_message)
170
+ # Now bin might be serialized, if it's not we need to serialize it otherwise we'll have
171
+ # an infinite recursive call
172
+ bin = bin_or_model
173
+ if not isinstance(bin, (str, bytes)):
174
+ bin = bin.SerializeToString()
175
+ return cls.prepare(bin, device, **kwargs)
176
+
177
+ @classmethod
178
+ def run_model(cls, model, inputs, device=None, **kwargs):
179
+ """
180
+ Compute the prediction.
181
+
182
+ :param model: the model to run — accepts a file path (str), serialized
183
+ model (bytes), :class:`onnx.ModelProto`, :class:`onnxruntime.InferenceSession`,
184
+ or :class:`onnxruntime.backend.backend_rep.OnnxRuntimeBackendRep`
185
+ :param inputs: inputs
186
+ :param device: requested device for the computation,
187
+ None means the default one which depends on
188
+ the compilation settings
189
+ :param kwargs: ``run_model()`` forwards kwargs to both ``prepare()`` and ``rep.run()``.
190
+ ``prepare()`` validates and applies ``_ALLOWED_SESSION_OPTIONS`` only when creating
191
+ a new session from a model path or bytes; if ``model`` is already an
192
+ ``InferenceSession`` or ``OnnxRuntimeBackendRep``, session-option kwargs are
193
+ silently ignored. ``rep.run()`` always validates against ``_ALLOWED_RUN_OPTIONS``
194
+ and raises ``RuntimeError`` for known-but-blocked run attributes.
195
+ Logging-related kwargs (``log_severity_level``, ``log_verbosity_level``, ``logid``)
196
+ appear in both allowlists.
197
+ :return: predictions
198
+ """
199
+ rep = cls.prepare(model, device, **kwargs)
200
+ return rep.run(inputs, **kwargs)
201
+
202
+ @classmethod
203
+ def run_node(cls, node, inputs, device=None, outputs_info=None, **kwargs):
204
+ """
205
+ This method is not implemented as it is much more efficient
206
+ to run a whole model than every node independently.
207
+ """
208
+ raise NotImplementedError("It is much more efficient to run a whole model than every node independently.")
209
+
210
+
211
+ is_compatible = OnnxRuntimeBackend.is_compatible
212
+ prepare = OnnxRuntimeBackend.prepare
213
+ run = OnnxRuntimeBackend.run_model
214
+ supports_device = OnnxRuntimeBackend.supports_device
onnxruntime/backend/backend_rep.py ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -------------------------------------------------------------------------
2
+ # Copyright (c) Microsoft Corporation. All rights reserved.
3
+ # Licensed under the MIT License.
4
+ # --------------------------------------------------------------------------
5
+ """
6
+ Implements ONNX's backend API.
7
+ """
8
+
9
+ from onnx.backend.base import BackendRep
10
+
11
+ from onnxruntime import RunOptions
12
+
13
+ # Allowlist of RunOptions attributes that are safe to set via the backend API.
14
+ # 'terminate' excluded: setting it True would deny the current inference call.
15
+ # 'training_mode' excluded: silently switches inference behavior in training builds.
16
+ _ALLOWED_RUN_OPTIONS = frozenset(
17
+ {
18
+ "log_severity_level",
19
+ "log_verbosity_level",
20
+ "logid",
21
+ "only_execute_path_to_fetches",
22
+ }
23
+ )
24
+
25
+
26
+ class OnnxRuntimeBackendRep(BackendRep):
27
+ """
28
+ Wraps an :class:`onnxruntime.InferenceSession` to implement ONNX's
29
+ :class:`onnx.backend.base.BackendRep` interface for running predictions.
30
+ """
31
+
32
+ def __init__(self, session):
33
+ """
34
+ :param session: :class:`onnxruntime.InferenceSession`
35
+ """
36
+ self._session = session
37
+
38
+ def run(self, inputs, **kwargs): # type: (Any, **Any) -> Tuple[Any, ...]
39
+ """
40
+ Computes the prediction.
41
+ See :meth:`onnxruntime.InferenceSession.run`.
42
+
43
+ :param inputs: a list of input arrays (one per model input) or a single
44
+ array when the model has exactly one input
45
+ :param kwargs: only a safe subset of :class:`onnxruntime.RunOptions` attributes are
46
+ accepted; see ``_ALLOWED_RUN_OPTIONS`` for the list
47
+ :return: list of output arrays
48
+ """
49
+
50
+ options = RunOptions()
51
+ for k, v in kwargs.items():
52
+ if k in _ALLOWED_RUN_OPTIONS:
53
+ setattr(options, k, v)
54
+ elif hasattr(options, k):
55
+ raise RuntimeError(
56
+ f"RunOptions attribute '{k}' is not permitted via the backend API. "
57
+ f"Allowed attributes: {', '.join(sorted(_ALLOWED_RUN_OPTIONS))}"
58
+ )
59
+ # else: silently ignore unknown keys
60
+
61
+ if isinstance(inputs, list):
62
+ inps = {}
63
+ for i, inp in enumerate(self._session.get_inputs()):
64
+ inps[inp.name] = inputs[i]
65
+ outs = self._session.run(None, inps, options)
66
+ if isinstance(outs, list):
67
+ return outs
68
+ else:
69
+ output_names = [o.name for o in self._session.get_outputs()]
70
+ return [outs[name] for name in output_names]
71
+ else:
72
+ inp = self._session.get_inputs()
73
+ if len(inp) != 1:
74
+ raise RuntimeError(f"Model expect {len(inp)} inputs")
75
+ inps = {inp[0].name: inputs}
76
+ return self._session.run(None, inps, options)
onnxruntime/capi/DirectML.dll ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9c9e6d822561c6c41b90e6994b3e8857cf1d66dbfb1e0c4c799c7c89b4e92da1
3
+ size 18527776
onnxruntime/capi/__init__.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ # -------------------------------------------------------------------------
2
+ # Copyright (c) Microsoft Corporation. All rights reserved.
3
+ # Licensed under the MIT License.
4
+ # --------------------------------------------------------------------------
onnxruntime/capi/_ld_preload.py ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ # -------------------------------------------------------------------------
2
+ # Copyright (c) Microsoft Corporation. All rights reserved.
3
+ # Licensed under the MIT License.
4
+ # --------------------------------------------------------------------------
5
+
6
+ # This file can be modified by setup.py when building a manylinux2010 wheel
7
+ # When modified, it will preload some libraries needed for the python C extension
onnxruntime/capi/_pybind_state.py ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # --- UORT bundle ------------------------------------------------------------
2
+ # Registers the directory of this module with the Windows loader before the
3
+ # pybind11 extension is imported. Added by scripts\runtime\stage_python_bundle.ps1.
4
+ try:
5
+ from ._uort_dll_dirs import add_dll_dirs as _uort_add_dll_dirs
6
+
7
+ _uort_add_dll_dirs()
8
+ except Exception: # noqa: BLE001 - a plain package layout has no _uort_dll_dirs
9
+ pass
10
+ # ----------------------------------------------------------------------------
11
+ # -------------------------------------------------------------------------
12
+ # Copyright (c) Microsoft Corporation. All rights reserved.
13
+ # Licensed under the MIT License.
14
+ # --------------------------------------------------------------------------
15
+ """
16
+ Ensure that dependencies are available and then load the extension module.
17
+ """
18
+ import os
19
+ import platform
20
+ import warnings
21
+
22
+ from . import _ld_preload # noqa: F401
23
+
24
+ if platform.system() == "Windows":
25
+ from . import version_info
26
+
27
+ # If on Windows, check if this import error is caused by the user not installing the 2019 VC Runtime
28
+ # The VC Redist installer usually puts the VC Runtime dlls in the System32 folder, but it may also be found
29
+ # in some other locations.
30
+ # TODO, we may want to try to load the VC Runtime dlls instead of checking if the hardcoded file path
31
+ # is valid, and raise ImportError if the load fails
32
+ if version_info.vs2019 and platform.architecture()[0] == "64bit":
33
+ system_root = os.getenv("SystemRoot") or "C:\\Windows"
34
+ if not os.path.isfile(os.path.join(system_root, "System32", "vcruntime140_1.dll")):
35
+ warnings.warn("Please install the 2019 Visual C++ runtime and then try again. "
36
+ "If you've installed the runtime in a non-standard location "
37
+ "(other than %SystemRoot%\\System32), "
38
+ "make sure it can be found by setting the correct path.")
39
+
40
+
41
+
42
+ from .onnxruntime_pybind11_state import * # noqa
43
+
onnxruntime/capi/_uort_dll_dirs.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """UORT: make the DLLs bundled next to this module visible to the Windows loader.
2
+
3
+ The bundle keeps every native dependency of the pybind11 module (CUDA, cuDNN,
4
+ TensorRT, OpenVINO) in the same directory as the module. CPython already
5
+ searches that directory for the direct imports of the extension module, but
6
+ cuDNN, cuFFT, TensorRT and OpenVINO resolve several libraries themselves with
7
+ plain LoadLibrary, which only looks at the process directory and PATH.
8
+ Registering the directory both ways covers all of them: AddDllDirectory works
9
+ for LoadLibraryEx with LOAD_LIBRARY_SEARCH_USER_DIRS, PATH for plain
10
+ LoadLibrary.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import os
16
+
17
+ _DIR = os.path.dirname(os.path.abspath(__file__))
18
+
19
+
20
+ def add_dll_dirs() -> str:
21
+ """Register the bundle directory; returns the directory that was added."""
22
+ if os.name != "nt":
23
+ return _DIR
24
+ try:
25
+ os.add_dll_directory(_DIR)
26
+ except (AttributeError, OSError):
27
+ pass
28
+ current = os.environ.get("PATH", "")
29
+ parts = [p for p in current.split(os.pathsep) if p]
30
+ if _DIR not in parts:
31
+ os.environ["PATH"] = _DIR + os.pathsep + current
32
+ return _DIR
onnxruntime/capi/build_and_package_info.py ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ package_name = 'uort-python'
2
+ __version__ = '1.30.1'
3
+ cuda_version = '12.9'
onnxruntime/capi/concrt140.dll ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2405355f0a58067b258f8df33c327e3a3d716eaac5a3a5aebb757842d85bd376
3
+ size 324208
onnxruntime/capi/convert_npz_to_onnx_adapter.py ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Microsoft Corporation. All rights reserved.
2
+ # Licensed under the MIT License.
3
+
4
+ # This script helps converting .npz files to .onnx_adapter files
5
+
6
+ import argparse
7
+ import os
8
+ import sys
9
+
10
+ import numpy as np
11
+
12
+ import onnxruntime as ort
13
+
14
+
15
+ def get_args() -> argparse:
16
+ parser = argparse.ArgumentParser()
17
+ parser.add_argument("--npz_file_path", type=str, required=True)
18
+ parser.add_argument("--output_file_path", type=str, required=True)
19
+ parser.add_argument("--adapter_version", type=int, required=True)
20
+ parser.add_argument("--model_version", type=int, required=True)
21
+ return parser.parse_args()
22
+
23
+
24
+ def export_lora_parameters(
25
+ npz_file_path: os.PathLike, adapter_version: int, model_version: int, output_file_path: os.PathLike
26
+ ):
27
+ """The function converts lora parameters in npz to onnx_adapter format"""
28
+ adapter_format = ort.AdapterFormat()
29
+ adapter_format.set_adapter_version(adapter_version)
30
+ adapter_format.set_model_version(model_version)
31
+ name_to_ort_value = {}
32
+ with np.load(npz_file_path) as data:
33
+ for name, np_arr in data.items():
34
+ ort_value = ort.OrtValue.ortvalue_from_numpy(np_arr)
35
+ name_to_ort_value[name] = ort_value
36
+
37
+ adapter_format.set_parameters(name_to_ort_value)
38
+ adapter_format.export_adapter(output_file_path)
39
+
40
+
41
+ def main() -> int:
42
+ args = get_args()
43
+ export_lora_parameters(args.npz_file_path, args.adapter_version, args.model_version, args.output_file_path)
44
+ return 0
45
+
46
+
47
+ if __name__ == "__main__":
48
+ sys.exit(main())
onnxruntime/capi/cublas64_12.dll ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:90052a83efd1b57a8e3616a6590b335855f81b814a4f16eecb7b5bf6d1b1d4eb
3
+ size 102518272
onnxruntime/capi/cublasLt64_12.dll ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c3a05ea244c937314afec09f87b91f814c7e27977681f6c67eb51bb06ced3a4a
3
+ size 668669952
onnxruntime/capi/cudart64_12.dll ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:760c38928bbe5759f7b31ed6692599eb7ec83cedd5702e84c2b72028a89837e1
3
+ size 583680
onnxruntime/capi/cudnn64_9.dll ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9edbcdff73b0af070eb160b2ce66e59feca04aa017351d8eedcc5e8e149967d2
3
+ size 266288
onnxruntime/capi/cudnn_adv64_9.dll ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f202e8ff36209ac4292fe2ef79d4539487495b3b948f0c978cc63298f43a1850
3
+ size 282445872
onnxruntime/capi/cudnn_cnn64_9.dll ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:3f03dec3b81f137f049e1d1c06ff469248eef54ff9424b3b9045fc0f69559d1a
3
+ size 4618272
onnxruntime/capi/cudnn_engines_precompiled64_9.dll ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ebc2c1f74366b029a4350f7f9a3b109ccd5aa9b4ae02527950793dd29f7b74fb
3
+ size 513926688
onnxruntime/capi/cudnn_engines_runtime_compiled64_9.dll ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:93ab6351ca0f2b6ca842f83d284e56c427525778c14657229801a13cf8121bd8
3
+ size 20201008
onnxruntime/capi/cudnn_graph64_9.dll ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a933efeb280a3252297f92d79f7e83003bcbc6f665872d11645d1dbbab9cb598
3
+ size 2420256
onnxruntime/capi/cudnn_heuristic64_9.dll ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:458175f12771a35de0ea39c04250d727c2424d42a7ffe0bc987ae81204748fba
3
+ size 56823328
onnxruntime/capi/cudnn_ops64_9.dll ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:851d8f4191a24b322b0be738d191a3159455f0da4db47a19f5cc7ad6e55edf61
3
+ size 126508576
onnxruntime/capi/cufft64_11.dll ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5b90655ca9cdf5d91cbdf2c72b995ec937eed0aef2d6954370c711b45c929b35
3
+ size 287136768
onnxruntime/capi/curand64_10.dll ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:4d6d16c9941c4f7a7e49d5c43df25d408a2a8503d8cc1eb9808e0e0c2cde36d4
3
+ size 79197696
onnxruntime/capi/msvcp140.dll ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0f885b509a685d2bbfa652fed26b5fb31d88fbdab0a978c641d1c7b8aa460aa9
3
+ size 557728
onnxruntime/capi/msvcp140_1.dll ADDED
Binary file (36 kB). View file
 
onnxruntime/capi/msvcp140_2.dll ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:3ea06f0ee098b4823cb79599df3780e7f23cce52c19aac31d2a0d47efe33a5e9
3
+ size 280200
onnxruntime/capi/msvcp140_atomic_wait.dll ADDED
Binary file (50.3 kB). View file
 
onnxruntime/capi/msvcp140_codecvt_ids.dll ADDED
Binary file (31.9 kB). View file
 
onnxruntime/capi/nvinfer_10.dll ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:55c7ec9272a4b74830d3caaae9106f277fc7df37690067f69fe1fdfd1dbc52ff
3
+ size 440983072
onnxruntime/capi/nvinfer_builder_resource_10.dll ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2b8496c57a8434534e8a3c56e732207f1c74bc37ce7300d8f0d3542cdff02e12
3
+ size 1971797024
onnxruntime/capi/nvinfer_dispatch_10.dll ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:4100a0e46f96088a3e79664c1d719beb462ce1f067b4cadf24feeebc7dd693e1
3
+ size 624672
onnxruntime/capi/nvinfer_plugin_10.dll ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:420aee53c0c2b4b35e76335daba57e0cabd7e22f2b946e47ed77dfb3019ca5a9
3
+ size 51002400
onnxruntime/capi/nvonnxparser_10.dll ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d4ca07f3f392f6f39f1738ed5e615910448d1f98b657551a01c7575881584a2a
3
+ size 2993696
onnxruntime/capi/onnxruntime.dll ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a4599b0168c8b3e485e50c4493559280778f7c533d66bbb3ea372073f316b67f
3
+ size 24535040
onnxruntime/capi/onnxruntime_collect_build_info.py ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -------------------------------------------------------------------------
2
+ # Copyright (c) Microsoft Corporation. All rights reserved.
3
+ # Licensed under the MIT License.
4
+ # --------------------------------------------------------------------------
5
+ import ctypes
6
+ import sys
7
+ import warnings
8
+
9
+
10
+ def find_cudart_versions(build_env=False, build_cuda_version=None):
11
+ # ctypes.CDLL and ctypes.util.find_library load the latest installed library.
12
+ # it may not the the library that would be loaded by onnxruntime.
13
+ # for example, in an environment with Cuda 11.1 and subsequently
14
+ # conda cudatoolkit 10.2.89 installed. ctypes will find cudart 10.2. however,
15
+ # onnxruntime built with Cuda 11.1 will find and load cudart for Cuda 11.1.
16
+ # for the above reason, we need find all versions in the environment and
17
+ # only give warnings if the expected cuda version is not found.
18
+ # in onnxruntime build environment, we expected only one Cuda version.
19
+ if not sys.platform.startswith("linux"):
20
+ warnings.warn("find_cudart_versions only works on Linux")
21
+ return None
22
+
23
+ cudart_possible_versions = {None, build_cuda_version}
24
+
25
+ def get_cudart_version(find_cudart_version=None):
26
+ cudart_lib_filename = "libcudart.so"
27
+ if find_cudart_version:
28
+ cudart_lib_filename = cudart_lib_filename + "." + find_cudart_version
29
+
30
+ try:
31
+ cudart = ctypes.CDLL(cudart_lib_filename)
32
+ cudart.cudaRuntimeGetVersion.restype = int
33
+ cudart.cudaRuntimeGetVersion.argtypes = [ctypes.POINTER(ctypes.c_int)]
34
+ version = ctypes.c_int()
35
+ status = cudart.cudaRuntimeGetVersion(ctypes.byref(version))
36
+ if status != 0:
37
+ return None
38
+ except Exception:
39
+ return None
40
+
41
+ return version.value
42
+
43
+ # use set to avoid duplications
44
+ cudart_found_versions = {get_cudart_version(cudart_version) for cudart_version in cudart_possible_versions}
45
+
46
+ # convert to list and remove None
47
+ return [ver for ver in cudart_found_versions if ver]
onnxruntime/capi/onnxruntime_inference_collection.py ADDED
@@ -0,0 +1,1930 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -------------------------------------------------------------------------
2
+ # Copyright (c) Microsoft Corporation. All rights reserved.
3
+ # Licensed under the MIT License.
4
+ # --------------------------------------------------------------------------
5
+ from __future__ import annotations
6
+
7
+ import collections
8
+ import collections.abc
9
+ import os
10
+ import typing
11
+ import warnings
12
+ import weakref
13
+ from collections.abc import Callable, Sequence
14
+ from enum import IntEnum
15
+ from typing import Any
16
+
17
+ import numpy as np
18
+
19
+ from onnxruntime.capi import _pybind_state as C
20
+
21
+ if typing.TYPE_CHECKING:
22
+ import numpy.typing as npt
23
+
24
+
25
+ def get_ort_device_type(device_type: str) -> int:
26
+ if device_type == "cuda":
27
+ return C.OrtDevice.cuda()
28
+ elif device_type == "cann":
29
+ return C.OrtDevice.cann()
30
+ elif device_type == "cpu":
31
+ return C.OrtDevice.cpu()
32
+ elif device_type == "dml":
33
+ return C.OrtDevice.dml()
34
+ elif device_type == "webgpu":
35
+ return C.OrtDevice.webgpu()
36
+ elif device_type == "gpu":
37
+ return C.OrtDevice.gpu()
38
+ elif device_type == "npu":
39
+ return C.OrtDevice.npu()
40
+ else:
41
+ raise Exception("Unsupported device type: " + device_type)
42
+
43
+
44
+ class OrtDeviceVendorId(IntEnum):
45
+ """Vendor IDs aligned with OrtDevice::VendorIds in ortdevice.h."""
46
+
47
+ NONE = 0x0000
48
+ AMD = 0x1002
49
+ NVIDIA = 0x10DE
50
+ ARM = 0x13B5
51
+ MICROSOFT = 0x1414
52
+ HUAWEI = 0x19E5
53
+ QUALCOMM = 0x5143
54
+ INTEL = 0x8086
55
+
56
+
57
+ def get_vendor_id_for_device_type(device_type: str) -> OrtDeviceVendorId | None:
58
+ if device_type == "cuda":
59
+ return OrtDeviceVendorId.NVIDIA
60
+ elif device_type == "dml":
61
+ return OrtDeviceVendorId.MICROSOFT
62
+ elif device_type == "cann":
63
+ return OrtDeviceVendorId.HUAWEI
64
+ elif device_type == "webgpu":
65
+ return OrtDeviceVendorId.NONE
66
+ else:
67
+ return None
68
+
69
+
70
+ _GPU_GRAPH_ID_RUN_CONFIG_KEY = "gpu_graph_id"
71
+ # Mirrors InferenceSession::kGraphAnnotationSkip; core skips capture and replay for this ID.
72
+ _GRAPH_ANNOTATION_SKIP = -1
73
+
74
+
75
+ def _graph_annotation_id(run_options) -> int:
76
+ """Return the effective ``gpu_graph_id`` for a run, defaulting to 0 when unset."""
77
+ if run_options is None:
78
+ return 0
79
+ try:
80
+ entry = run_options.get_run_config_entry(_GPU_GRAPH_ID_RUN_CONFIG_KEY)
81
+ except RuntimeError:
82
+ return 0
83
+ if not entry:
84
+ return 0
85
+ try:
86
+ return int(entry)
87
+ except ValueError:
88
+ raise ValueError(f"Run option '{_GPU_GRAPH_ID_RUN_CONFIG_KEY}' must be an integer, got {entry!r}.") from None
89
+
90
+
91
+ def _is_ortvalue_session_compatible(ortvalue, target_session) -> bool:
92
+ """Whether ``target_session`` can share ``ortvalue``'s buffer.
93
+
94
+ Sessionless values come from a shared allocator. A session-owned WebGPU buffer is
95
+ usable by any session on the same WebGPU context.
96
+ """
97
+ if ortvalue._session is None or target_session is None or ortvalue._session is target_session:
98
+ return True
99
+ return ortvalue._is_webgpu_buffer and ortvalue._session.webgpu_context_id() == target_session.webgpu_context_id()
100
+
101
+
102
+ def _validate_ortvalue_session_compatibility(ortvalue, target_session, action) -> None:
103
+ """Reject an OrtValue that the target session cannot share buffers with.
104
+
105
+ ``action`` is the verb used in the message, e.g. ``"used with"`` or ``"bound to"``.
106
+ """
107
+ if not _is_ortvalue_session_compatible(ortvalue, target_session):
108
+ raise ValueError(f"Session-scoped OrtValue must be {action} the session that created it.")
109
+
110
+
111
+ class AdapterFormat:
112
+ """
113
+ This class is used to create adapter files from python structures
114
+ """
115
+
116
+ def __init__(self, adapter=None) -> None:
117
+ if adapter is None:
118
+ self._adapter = C.AdapterFormat()
119
+ else:
120
+ self._adapter = adapter
121
+
122
+ @staticmethod
123
+ def read_adapter(file_path: os.PathLike) -> AdapterFormat:
124
+ return AdapterFormat(C.AdapterFormat.read_adapter(file_path))
125
+
126
+ def export_adapter(self, file_path: os.PathLike):
127
+ """
128
+ This function writes a file at the specified location
129
+ in onnxrunitme adapter format containing Lora parameters.
130
+
131
+ :param file_path: absolute path for the adapter
132
+ """
133
+ self._adapter.export_adapter(file_path)
134
+
135
+ def get_format_version(self) -> int:
136
+ return self._adapter.format_version
137
+
138
+ def set_adapter_version(self, adapter_version: int) -> None:
139
+ self._adapter.adapter_version = adapter_version
140
+
141
+ def get_adapter_version(self) -> int:
142
+ return self._adapter.adapter_version
143
+
144
+ def set_model_version(self, model_version: int) -> None:
145
+ self._adapter.model_version = model_version
146
+
147
+ def get_model_version(self) -> int:
148
+ return self._adapter.model_version
149
+
150
+ def set_parameters(self, params: dict[str, OrtValue]) -> None:
151
+ """Set adapter parameters for export."""
152
+ self._adapter.parameters = {k: v._ortvalue for k, v in params.items()}
153
+
154
+ def get_parameters(self) -> dict[str, OrtValue]:
155
+ """Get adapter parameters as a dict of name -> OrtValue.
156
+
157
+ On read instances, the returned OrtValues are zero-copy views; the
158
+ backing memory stays alive as long as any returned OrtValue is referenced.
159
+ """
160
+ return {k: OrtValue(v) for k, v in self._adapter.parameters.items()}
161
+
162
+
163
+ def check_and_normalize_provider_args(
164
+ providers: Sequence[str | tuple[str, dict[Any, Any]]] | None,
165
+ provider_options: Sequence[dict[Any, Any]] | None,
166
+ available_provider_names: Sequence[str],
167
+ ):
168
+ """
169
+ Validates the 'providers' and 'provider_options' arguments and returns a
170
+ normalized version.
171
+
172
+ :param providers: Optional sequence of providers in order of decreasing
173
+ precedence. Values can either be provider names or tuples of
174
+ (provider name, options dict).
175
+ :param provider_options: Optional sequence of options dicts corresponding
176
+ to the providers listed in 'providers'.
177
+ :param available_provider_names: The available provider names.
178
+
179
+ :return: Tuple of (normalized 'providers' sequence, normalized
180
+ 'provider_options' sequence).
181
+
182
+ 'providers' can contain either names or names and options. When any options
183
+ are given in 'providers', 'provider_options' should not be used.
184
+
185
+ The normalized result is a tuple of:
186
+ 1. Sequence of provider names in the same order as 'providers'.
187
+ 2. Sequence of corresponding provider options dicts with string keys and
188
+ values. Unspecified provider options yield empty dicts.
189
+ """
190
+ if providers is None:
191
+ return [], []
192
+
193
+ provider_name_to_options = collections.OrderedDict()
194
+
195
+ def set_provider_options(name, options):
196
+ if name not in available_provider_names:
197
+ warnings.warn(
198
+ "Specified provider '{}' is not in available provider names.Available providers: '{}'".format(
199
+ name, ", ".join(available_provider_names)
200
+ )
201
+ )
202
+
203
+ if name in provider_name_to_options:
204
+ warnings.warn(f"Duplicate provider '{name}' encountered, ignoring.")
205
+ return
206
+
207
+ normalized_options = {str(key): str(value) for key, value in options.items()}
208
+ provider_name_to_options[name] = normalized_options
209
+
210
+ if not isinstance(providers, collections.abc.Sequence):
211
+ raise ValueError("'providers' should be a sequence.")
212
+
213
+ if provider_options is not None:
214
+ if not isinstance(provider_options, collections.abc.Sequence):
215
+ raise ValueError("'provider_options' should be a sequence.")
216
+
217
+ if len(providers) != len(provider_options):
218
+ raise ValueError("'providers' and 'provider_options' should be the same length if both are given.")
219
+
220
+ if not all(isinstance(provider, str) for provider in providers):
221
+ raise ValueError("Only string values for 'providers' are supported if 'provider_options' is given.")
222
+
223
+ if not all(isinstance(options_for_provider, dict) for options_for_provider in provider_options):
224
+ raise ValueError("'provider_options' values must be dicts.")
225
+
226
+ for name, options in zip(providers, provider_options, strict=False):
227
+ set_provider_options(name, options)
228
+
229
+ else:
230
+ for provider in providers:
231
+ if isinstance(provider, str):
232
+ set_provider_options(provider, {})
233
+ elif (
234
+ isinstance(provider, tuple)
235
+ and len(provider) == 2
236
+ and isinstance(provider[0], str)
237
+ and isinstance(provider[1], dict)
238
+ ):
239
+ set_provider_options(provider[0], provider[1])
240
+ else:
241
+ raise ValueError("'providers' values must be either strings or (string, dict) tuples.")
242
+
243
+ return list(provider_name_to_options.keys()), list(provider_name_to_options.values())
244
+
245
+
246
+ class Session:
247
+ """
248
+ This is the main class used to run a model.
249
+ """
250
+
251
+ def __init__(self, enable_fallback: bool = True):
252
+ # self._sess is managed by the derived class and relies on bindings from C.InferenceSession
253
+ self._sess = None
254
+ self._enable_fallback = enable_fallback
255
+ # Captured graphs retain buffer signatures without extending the IOBinding lifetime.
256
+ self._captured_graph_bindings: dict[int, tuple[weakref.ref, tuple]] = {}
257
+
258
+ def get_session_options(self) -> C.SessionOptions:
259
+ "Return the session options. See :class:`onnxruntime.SessionOptions`."
260
+ return self._sess_options
261
+
262
+ def get_inputs(self) -> Sequence[C.NodeArg]:
263
+ "Return the inputs metadata as a list of :class:`onnxruntime.NodeArg`."
264
+ return self._inputs_meta
265
+
266
+ def get_outputs(self) -> Sequence[C.NodeArg]:
267
+ "Return the outputs metadata as a list of :class:`onnxruntime.NodeArg`."
268
+ return self._outputs_meta
269
+
270
+ def get_overridable_initializers(self) -> Sequence[C.NodeArg]:
271
+ "Return the inputs (including initializers) metadata as a list of :class:`onnxruntime.NodeArg`."
272
+ return self._overridable_initializers
273
+
274
+ def get_modelmeta(self) -> C.ModelMetadata:
275
+ "Return the metadata. See :class:`onnxruntime.ModelMetadata`."
276
+ return self._model_meta
277
+
278
+ def get_input_memory_infos(self) -> Sequence[C.OrtMemoryInfo]:
279
+ "Return the memory info for the inputs."
280
+ return self._input_meminfos
281
+
282
+ def get_output_memory_infos(self) -> Sequence[C.OrtMemoryInfo]:
283
+ "Return the memory info for the outputs."
284
+ return self._output_meminfos
285
+
286
+ def get_input_epdevices(self) -> Sequence[C.OrtEpDevice]:
287
+ "Return the execution providers for the inputs."
288
+ return self._input_epdevices
289
+
290
+ def get_providers(self) -> Sequence[str]:
291
+ "Return list of registered execution providers."
292
+ return self._providers
293
+
294
+ def get_provider_options(self):
295
+ "Return registered execution providers' configurations."
296
+ return self._provider_options
297
+
298
+ def get_provider_graph_assignment_info(self) -> Sequence[C.OrtEpAssignedSubgraph]:
299
+ """
300
+ Get information about the subgraphs assigned to each execution provider and the nodes within.
301
+
302
+ Application must enable the recording of graph assignment information by setting the session configuration
303
+ for the key "session.record_ep_graph_assignment_info" to "1".
304
+ """
305
+ return self._sess.get_provider_graph_assignment_info()
306
+
307
+ def set_providers(self, providers=None, provider_options=None) -> None:
308
+ """
309
+ Register the input list of execution providers. The underlying session is re-created.
310
+
311
+ :param providers: Optional sequence of providers in order of decreasing
312
+ precedence. Values can either be provider names or tuples of
313
+ (provider name, options dict). If not provided, then all available
314
+ providers are used with the default precedence.
315
+ :param provider_options: Optional sequence of options dicts corresponding
316
+ to the providers listed in 'providers'.
317
+
318
+ 'providers' can contain either names or names and options. When any options
319
+ are given in 'providers', 'provider_options' should not be used.
320
+
321
+ The list of providers is ordered by precedence. For example
322
+ `['CUDAExecutionProvider', 'CPUExecutionProvider']`
323
+ means execute a node using CUDAExecutionProvider if capable,
324
+ otherwise execute using CPUExecutionProvider.
325
+ """
326
+ # recreate the underlying C.InferenceSession
327
+ self._reset_session(providers, provider_options)
328
+
329
+ def disable_fallback(self) -> None:
330
+ """
331
+ Disable session.run() fallback mechanism.
332
+ """
333
+ self._enable_fallback = False
334
+
335
+ def enable_fallback(self) -> None:
336
+ """
337
+ Enable session.Run() fallback mechanism. If session.Run() fails due to an internal Execution Provider failure,
338
+ reset the Execution Providers enabled for this session.
339
+ If GPU is enabled, fall back to CUDAExecutionProvider.
340
+ otherwise fall back to CPUExecutionProvider.
341
+ """
342
+ self._enable_fallback = True
343
+
344
+ def _validate_input(self, feed_input_names):
345
+ missing_input_names = []
346
+ for input in self._inputs_meta:
347
+ if input.name not in feed_input_names and not input.type.startswith("optional"):
348
+ missing_input_names.append(input.name)
349
+ if missing_input_names:
350
+ raise ValueError(
351
+ f"Required inputs ({missing_input_names}) are missing from input feed ({feed_input_names})."
352
+ )
353
+
354
+ def _validate_ortvalue_ownership(self, values):
355
+ for value in values:
356
+ if not isinstance(value, OrtValue):
357
+ continue
358
+ _validate_ortvalue_session_compatibility(value, self._sess, "used with")
359
+
360
+ def _validate_graph_capture_run_api(self, run_options=None):
361
+ if not self._sess.is_webgpu_graph_capture_enabled():
362
+ return
363
+ if _graph_annotation_id(run_options) == _GRAPH_ANNOTATION_SKIP:
364
+ # gpu_graph_id=-1 skips capture, so transient feeds remain valid.
365
+ return
366
+ raise ValueError(
367
+ "WebGPU graph capture requires fixed device OrtValues and run_with_iobinding. "
368
+ f"Set the '{_GPU_GRAPH_ID_RUN_CONFIG_KEY}' run option to "
369
+ f"{_GRAPH_ANNOTATION_SKIP} to opt a single run out of capture."
370
+ )
371
+
372
+ def run(self, output_names, input_feed, run_options=None) -> Sequence[np.ndarray | SparseTensor | list | dict]:
373
+ """
374
+ Compute the predictions.
375
+
376
+ WebGPU graph capture requires fixed device OrtValues bound with
377
+ :meth:`run_with_iobinding`; do not use this convenience API for captured replay.
378
+
379
+ :param output_names: name of the outputs
380
+ :param input_feed: dictionary ``{ input_name: input_value }``
381
+ :param run_options: See :class:`onnxruntime.RunOptions`.
382
+ :return: list of results, every result is either a numpy array,
383
+ a sparse tensor, a list or a dictionary.
384
+
385
+ ::
386
+
387
+ sess.run([output_name], {input_name: x})
388
+ """
389
+ self._validate_graph_capture_run_api(run_options)
390
+ self._validate_input(list(input_feed.keys()))
391
+ self._validate_ortvalue_ownership(input_feed.values())
392
+ if not output_names:
393
+ output_names = [output.name for output in self._outputs_meta]
394
+ try:
395
+ return self._sess.run(output_names, input_feed, run_options)
396
+ except C.EPFail as err:
397
+ if self._enable_fallback:
398
+ print(f"EP Error: {err!s} using {self._providers}")
399
+ print(f"Falling back to {self._fallback_providers} and retrying.")
400
+ self.set_providers(self._fallback_providers)
401
+ # Fallback only once.
402
+ self.disable_fallback()
403
+ self._validate_ortvalue_ownership(input_feed.values())
404
+ return self._sess.run(output_names, input_feed, run_options)
405
+ raise
406
+
407
+ def run_async(self, output_names, input_feed, callback, user_data, run_options=None):
408
+ """
409
+ Compute the predictions asynchronously in a separate cxx thread from ort intra-op threadpool.
410
+
411
+ :param output_names: name of the outputs
412
+ :param input_feed: dictionary ``{ input_name: input_value }``
413
+ :param callback: python function that accept array of results, and a status string on error.
414
+ The callback will be invoked by a cxx thread from ort intra-op threadpool.
415
+ :param run_options: See :class:`onnxruntime.RunOptions`.
416
+
417
+ ::
418
+ class MyData:
419
+ def __init__(self):
420
+ # ...
421
+ def save_results(self, results):
422
+ # ...
423
+
424
+ def callback(results: np.ndarray, user_data: MyData, err: str) -> None:
425
+ if err:
426
+ print (err)
427
+ else:
428
+ # save results to user_data
429
+
430
+ sess.run_async([output_name], {input_name: x}, callback)
431
+ """
432
+ self._validate_graph_capture_run_api(run_options)
433
+ self._validate_input(list(input_feed.keys()))
434
+ self._validate_ortvalue_ownership(input_feed.values())
435
+ if not output_names:
436
+ output_names = [output.name for output in self._outputs_meta]
437
+ return self._sess.run_async(output_names, input_feed, callback, user_data, run_options)
438
+
439
+ def run_with_ort_values(self, output_names, input_dict_ort_values, run_options=None) -> Sequence[OrtValue]:
440
+ """
441
+ Compute the predictions.
442
+
443
+ :param output_names: name of the outputs
444
+ :param input_dict_ort_values: dictionary ``{ input_name: input_ort_value }``
445
+ See ``OrtValue`` class how to create `OrtValue`
446
+ from numpy array or `SparseTensor`
447
+ :param run_options: See :class:`onnxruntime.RunOptions`.
448
+ :return: an array of `OrtValue`
449
+
450
+ ::
451
+
452
+ sess.run([output_name], {input_name: x})
453
+ """
454
+
455
+ def invoke(sess, output_names, input_dict_ort_values, run_options):
456
+ input_dict = {}
457
+ for n, v in input_dict_ort_values.items():
458
+ input_dict[n] = v._get_c_value()
459
+ result = sess.run_with_ort_values(input_dict, output_names, run_options)
460
+ if not isinstance(result, C.OrtValueVector):
461
+ raise TypeError("run_with_ort_values() must return a instance of type 'OrtValueVector'.")
462
+ ort_values = [OrtValue(v) for v in result]
463
+ return ort_values
464
+
465
+ self._validate_graph_capture_run_api(run_options)
466
+ self._validate_input(list(input_dict_ort_values.keys()))
467
+ self._validate_ortvalue_ownership(input_dict_ort_values.values())
468
+ if not output_names:
469
+ output_names = [output.name for output in self._outputs_meta]
470
+ try:
471
+ return invoke(self._sess, output_names, input_dict_ort_values, run_options)
472
+ except C.EPFail as err:
473
+ if self._enable_fallback:
474
+ print(f"EP Error: {err!s} using {self._providers}")
475
+ print(f"Falling back to {self._fallback_providers} and retrying.")
476
+ self.set_providers(self._fallback_providers)
477
+ # Fallback only once.
478
+ self.disable_fallback()
479
+ self._validate_ortvalue_ownership(input_dict_ort_values.values())
480
+ return invoke(self._sess, output_names, input_dict_ort_values, run_options)
481
+ raise
482
+
483
+ def end_profiling(self):
484
+ """
485
+ End profiling and return results in a file.
486
+
487
+ The results are stored in a filename if the option
488
+ :meth:`onnxruntime.SessionOptions.enable_profiling`.
489
+ """
490
+ return self._sess.end_profiling()
491
+
492
+ def get_profiling_start_time_ns(self):
493
+ """
494
+ Return the nanoseconds of profiling's start time
495
+ Comparable to time.monotonic_ns() after Python 3.3
496
+ On some platforms, this timer may not be as precise as nanoseconds
497
+ For instance, on Windows and MacOS, the precision will be ~100ns
498
+ """
499
+ return self._sess.get_profiling_start_time_ns
500
+
501
+ def io_binding(self) -> IOBinding:
502
+ "Return an onnxruntime.IOBinding object`."
503
+ return IOBinding(self)
504
+
505
+ def create_ortvalue_from_shape_and_type(
506
+ self,
507
+ shape: Sequence[int],
508
+ element_type,
509
+ device_type: str,
510
+ device_id: int = 0,
511
+ vendor_id: int | OrtDeviceVendorId = -1,
512
+ ) -> OrtValue:
513
+ """Create an OrtValue using this session's allocator.
514
+
515
+ The value retains this session and may only be updated or bound through it.
516
+ A matching allocator and a numeric tensor type are required.
517
+ """
518
+ device = OrtDevice.make(device_type, device_id, vendor_id)._get_c_device()
519
+ if isinstance(element_type, int):
520
+ ortvalue = self._sess.create_ortvalue_from_shape_and_onnx_type(shape, element_type, device)
521
+ else:
522
+ ortvalue = self._sess.create_ortvalue_from_shape_and_type(shape, element_type, device)
523
+ return OrtValue(ortvalue, session=self._sess)
524
+
525
+ def release_captured_graph(self, graph_annotation_id: int = 0) -> None:
526
+ """Release a captured graph and unpin its IOBinding.
527
+
528
+ ``graph_annotation_id`` matches the capture's ``gpu_graph_id`` and defaults to zero.
529
+ EPs without captured-graph release support treat this as a no-op.
530
+ """
531
+ self._sess.release_captured_graph(graph_annotation_id)
532
+ pinned = self._captured_graph_bindings.pop(graph_annotation_id, None)
533
+ if pinned is not None:
534
+ iobinding = pinned[0]()
535
+ if iobinding is not None:
536
+ iobinding._pinned_graph_ids.discard(graph_annotation_id)
537
+
538
+ def run_with_iobinding(self, iobinding, run_options=None):
539
+ """
540
+ Compute the predictions.
541
+
542
+ :param iobinding: the iobinding object that has graph inputs/outputs bind.
543
+ :param run_options: See :class:`onnxruntime.RunOptions`.
544
+
545
+ WebGPU capture requires static shapes, disabled memory patterns, fixed WebGPU OrtValues
546
+ (session-owned or shared), and no CPU compute nodes other than shape-only nodes. Each
547
+ ``gpu_graph_id`` pins one IOBinding and its buffers until :meth:`release_captured_graph`.
548
+ Update inputs in place and use :meth:`IOBinding.copy_outputs_to_cpu` for readback;
549
+ ``gpu_graph_id=-1`` disables capture.
550
+ """
551
+ if iobinding._session is not self._sess:
552
+ raise ValueError("IOBinding must be used with the session that created it.")
553
+
554
+ graph_annotation_id = _graph_annotation_id(run_options)
555
+ capturing = self._sess.is_webgpu_graph_capture_enabled() and graph_annotation_id != _GRAPH_ANNOTATION_SKIP
556
+ if capturing:
557
+ iobinding._validate_capture_bindings()
558
+ signature = iobinding._capture_signature()
559
+ pinned = self._captured_graph_bindings.get(graph_annotation_id)
560
+ if pinned is not None:
561
+ pinned_iobinding, pinned_signature = pinned[0](), pinned[1]
562
+ if pinned_iobinding is not iobinding:
563
+ raise ValueError(
564
+ f"WebGPU graph {graph_annotation_id} was captured with a different "
565
+ "IOBinding. Replay re-issues the buffers recorded at capture and would "
566
+ "silently ignore this binding. Reuse the original IOBinding, or call "
567
+ f"release_captured_graph({graph_annotation_id}) first."
568
+ )
569
+ if pinned_signature != signature:
570
+ raise ValueError(
571
+ f"WebGPU graph {graph_annotation_id} was captured with different I/O "
572
+ "buffers. Replay writes to the buffers recorded at capture, so the "
573
+ "rebound values would never be read or written. Update the original "
574
+ "buffers in place, or call "
575
+ f"release_captured_graph({graph_annotation_id}) first."
576
+ )
577
+
578
+ self._sess.run_with_iobinding(iobinding._iobinding, run_options)
579
+
580
+ if capturing and graph_annotation_id not in self._captured_graph_bindings:
581
+ self._captured_graph_bindings[graph_annotation_id] = (weakref.ref(iobinding), signature)
582
+ iobinding._pinned_graph_ids.add(graph_annotation_id)
583
+
584
+ def set_ep_dynamic_options(self, options: dict[str, str]):
585
+ """
586
+ Set dynamic options for execution providers.
587
+
588
+ :param options: Dictionary of key-value pairs where both keys and values are strings.
589
+ These options will be passed to the execution providers to modify
590
+ their runtime behavior.
591
+ """
592
+ self._sess.set_ep_dynamic_options(options)
593
+
594
+ def get_tuning_results(self):
595
+ return self._sess.get_tuning_results()
596
+
597
+ def set_tuning_results(self, results, *, error_on_invalid=False):
598
+ return self._sess.set_tuning_results(results, error_on_invalid)
599
+
600
+ def run_with_ortvaluevector(self, run_options, feed_names, feeds, fetch_names, fetches, fetch_devices):
601
+ """
602
+ Compute the predictions similar to other run_*() methods but with minimal C++/Python conversion overhead.
603
+
604
+ :param run_options: See :class:`onnxruntime.RunOptions`.
605
+ :param feed_names: list of input names.
606
+ :param feeds: list of input OrtValue.
607
+ :param fetch_names: list of output names.
608
+ :param fetches: list of output OrtValue.
609
+ :param fetch_devices: list of output devices.
610
+ """
611
+ # Same capture check as run(), run_with_ort_values() and run_async(): replay re-issues the
612
+ # buffers recorded at capture, so transient vectors would be silently ignored. Nothing about
613
+ # a raw vector is unsafe outside capture, including on a WebGPU session.
614
+ self._validate_graph_capture_run_api(run_options)
615
+ self._sess.run_with_ortvaluevector(run_options, feed_names, feeds, fetch_names, fetches, fetch_devices)
616
+
617
+
618
+ class InferenceSession(Session):
619
+ """
620
+ This is the main class used to run a model.
621
+ """
622
+
623
+ def __init__(
624
+ self,
625
+ path_or_bytes: str | bytes | os.PathLike,
626
+ sess_options: C.SessionOptions | None = None,
627
+ providers: Sequence[str | tuple[str, dict[Any, Any]]] | None = None,
628
+ provider_options: Sequence[dict[Any, Any]] | None = None,
629
+ **kwargs,
630
+ ) -> None:
631
+ """
632
+ :param path_or_bytes: Filename or serialized ONNX or ORT format model in a byte string.
633
+ :param sess_options: Session options.
634
+ :param providers: Optional sequence of providers in order of decreasing
635
+ precedence. Values can either be provider names or tuples of
636
+ (provider name, options dict). If not provided, then all available
637
+ providers are used with the default precedence.
638
+ :param provider_options: Optional sequence of options dicts corresponding
639
+ to the providers listed in 'providers'.
640
+
641
+ The model type will be inferred unless explicitly set in the SessionOptions.
642
+ To explicitly set:
643
+
644
+ ::
645
+
646
+ so = onnxruntime.SessionOptions()
647
+ # so.add_session_config_entry('session.load_model_format', 'ONNX') or
648
+ so.add_session_config_entry('session.load_model_format', 'ORT')
649
+
650
+ A file extension of '.ort' will be inferred as an ORT format model.
651
+ All other filenames are assumed to be ONNX format models.
652
+
653
+ 'providers' can contain either names or names and options. When any options
654
+ are given in 'providers', 'provider_options' should not be used.
655
+
656
+ The list of providers is ordered by precedence. For example
657
+ `['CUDAExecutionProvider', 'CPUExecutionProvider']`
658
+ means execute a node using `CUDAExecutionProvider`
659
+ if capable, otherwise execute using `CPUExecutionProvider`.
660
+ """
661
+ super().__init__(enable_fallback=int(kwargs.get("enable_fallback", 1)) == 1)
662
+
663
+ if isinstance(path_or_bytes, (str, os.PathLike)):
664
+ self._model_path = os.fspath(path_or_bytes)
665
+ self._model_bytes = None
666
+ elif isinstance(path_or_bytes, bytes):
667
+ self._model_path = None
668
+ self._model_bytes = path_or_bytes # TODO: This is bad as we're holding the memory indefinitely
669
+ else:
670
+ raise TypeError(f"Unable to load from type '{type(path_or_bytes)}'")
671
+
672
+ self._sess_options = sess_options
673
+ self._sess_options_initial = sess_options
674
+ if "read_config_from_model" in kwargs:
675
+ self._read_config_from_model = int(kwargs["read_config_from_model"]) == 1
676
+ else:
677
+ self._read_config_from_model = os.environ.get("ORT_LOAD_CONFIG_FROM_MODEL") == "1"
678
+
679
+ # internal parameters that we don't expect to be used in general so aren't documented
680
+ disabled_optimizers = kwargs.get("disabled_optimizers")
681
+
682
+ try:
683
+ self._create_inference_session(providers, provider_options, disabled_optimizers)
684
+ except (ValueError, RuntimeError) as e:
685
+ if self._enable_fallback:
686
+ try:
687
+ print("*************** EP Error ***************")
688
+ print(f"EP Error {e} when using {providers}")
689
+ print(f"Falling back to {self._fallback_providers} and retrying.")
690
+ print("****************************************")
691
+ self._create_inference_session(self._fallback_providers, None)
692
+ # Fallback only once.
693
+ self.disable_fallback()
694
+ return
695
+ except Exception as fallback_error:
696
+ raise fallback_error from e
697
+ # Fallback is disabled. Raise the original error.
698
+ raise e
699
+
700
+ def _create_inference_session(self, providers, provider_options, disabled_optimizers=None):
701
+ available_providers = C.get_available_providers()
702
+
703
+ # Validate that TensorrtExecutionProvider and NvTensorRTRTXExecutionProvider are not both specified
704
+ if providers:
705
+ has_tensorrt = any(
706
+ provider == "TensorrtExecutionProvider"
707
+ or (isinstance(provider, tuple) and provider[0] == "TensorrtExecutionProvider")
708
+ for provider in providers
709
+ )
710
+ has_tensorrt_rtx = any(
711
+ provider == "NvTensorRTRTXExecutionProvider"
712
+ or (isinstance(provider, tuple) and provider[0] == "NvTensorRTRTXExecutionProvider")
713
+ for provider in providers
714
+ )
715
+ if has_tensorrt and has_tensorrt_rtx:
716
+ raise ValueError(
717
+ "Cannot enable both 'TensorrtExecutionProvider' and 'NvTensorRTRTXExecutionProvider' "
718
+ "in the same session."
719
+ )
720
+ # Tensorrt and TensorRT RTX can fall back to CUDA if it's explicitly assigned. All others fall back to CPU.
721
+ if "NvTensorRTRTXExecutionProvider" in available_providers:
722
+ if (
723
+ providers
724
+ and any(
725
+ provider == "CUDAExecutionProvider"
726
+ or (isinstance(provider, tuple) and provider[0] == "CUDAExecutionProvider")
727
+ for provider in providers
728
+ )
729
+ and any(
730
+ provider == "NvTensorRTRTXExecutionProvider"
731
+ or (isinstance(provider, tuple) and provider[0] == "NvTensorRTRTXExecutionProvider")
732
+ for provider in providers
733
+ )
734
+ ):
735
+ self._fallback_providers = ["CUDAExecutionProvider", "CPUExecutionProvider"]
736
+ else:
737
+ self._fallback_providers = ["CPUExecutionProvider"]
738
+ elif "TensorrtExecutionProvider" in available_providers:
739
+ if (
740
+ providers
741
+ and any(
742
+ provider == "CUDAExecutionProvider"
743
+ or (isinstance(provider, tuple) and provider[0] == "CUDAExecutionProvider")
744
+ for provider in providers
745
+ )
746
+ and any(
747
+ provider == "TensorrtExecutionProvider"
748
+ or (isinstance(provider, tuple) and provider[0] == "TensorrtExecutionProvider")
749
+ for provider in providers
750
+ )
751
+ ):
752
+ self._fallback_providers = ["CUDAExecutionProvider", "CPUExecutionProvider"]
753
+ else:
754
+ self._fallback_providers = ["CPUExecutionProvider"]
755
+ else:
756
+ self._fallback_providers = ["CPUExecutionProvider"]
757
+
758
+ # validate providers and provider_options before other initialization
759
+ providers, provider_options = check_and_normalize_provider_args(
760
+ providers, provider_options, available_providers
761
+ )
762
+
763
+ # Print a warning if user passed providers to InferenceSession() but the SessionOptions instance
764
+ # already has provider information (e.g., via add_provider_for_devices()). The providers specified
765
+ # here will take precedence.
766
+ if self._sess_options is not None and (providers or provider_options) and self._sess_options.has_providers():
767
+ warnings.warn(
768
+ "Specified 'providers'/'provider_options' when creating InferenceSession but SessionOptions has "
769
+ "already been configured with providers. InferenceSession will only use the providers "
770
+ "passed to InferenceSession()."
771
+ )
772
+
773
+ session_options = self._sess_options if self._sess_options else C.get_default_session_options()
774
+
775
+ self._register_ep_custom_ops(session_options, providers, provider_options, available_providers)
776
+
777
+ if self._model_path:
778
+ sess = C.InferenceSession(session_options, self._model_path, True, self._read_config_from_model)
779
+ else:
780
+ sess = C.InferenceSession(session_options, self._model_bytes, False, self._read_config_from_model)
781
+
782
+ if disabled_optimizers is None:
783
+ disabled_optimizers = set()
784
+ elif not isinstance(disabled_optimizers, set):
785
+ # convert to set. assumes iterable
786
+ disabled_optimizers = set(disabled_optimizers)
787
+
788
+ # initialize the C++ InferenceSession
789
+ sess.initialize_session(providers, provider_options, disabled_optimizers)
790
+
791
+ self._sess = sess
792
+ self._sess_options = self._sess.session_options
793
+ self._inputs_meta = self._sess.inputs_meta
794
+ self._outputs_meta = self._sess.outputs_meta
795
+ self._overridable_initializers = self._sess.overridable_initializers
796
+ self._input_meminfos = self._sess.input_meminfos
797
+ self._output_meminfos = self._sess.output_meminfos
798
+ self._input_epdevices = self._sess.input_epdevices
799
+ self._model_meta = self._sess.model_meta
800
+ self._providers = self._sess.get_providers()
801
+ self._provider_options = self._sess.get_provider_options()
802
+ self._profiling_start_time_ns = self._sess.get_profiling_start_time_ns
803
+
804
+ def _release_captured_graphs(self) -> None:
805
+ """Release every graph captured by the current session handle and unpin its IOBinding.
806
+
807
+ A captured graph belongs to the ``C.InferenceSession`` that captured it, so it must be
808
+ released before that handle is replaced. Otherwise the stale bookkeeping would reject an
809
+ IOBinding created by the replacement session and a later ``release_captured_graph`` would
810
+ act on the replacement session while unpinning the old binding.
811
+ """
812
+ for graph_annotation_id in sorted(self._captured_graph_bindings):
813
+ self.release_captured_graph(graph_annotation_id)
814
+
815
+ def _reset_session(self, providers, provider_options) -> None:
816
+ "release underlying session object."
817
+ # Captured graphs outlive neither the session handle nor its bookkeeping. Release them
818
+ # first so a failure here leaves the session intact instead of half torn down.
819
+ self._release_captured_graphs()
820
+
821
+ # meta data references session internal structures
822
+ # so they must be set to None to decrement _sess reference count.
823
+ self._sess_options = None
824
+ self._inputs_meta = None
825
+ self._outputs_meta = None
826
+ self._overridable_initializers = None
827
+ self._input_meminfos = None
828
+ self._output_meminfos = None
829
+ self._input_epdevices = None
830
+ self._model_meta = None
831
+ self._providers = None
832
+ self._provider_options = None
833
+ self._profiling_start_time_ns = None
834
+
835
+ # create a new C.InferenceSession
836
+ self._sess = None
837
+ self._sess_options = self._sess_options_initial
838
+ self._create_inference_session(providers, provider_options)
839
+
840
+ def _register_ep_custom_ops(self, session_options, providers, provider_options, available_providers):
841
+ for i in range(len(providers)):
842
+ if providers[i] in available_providers and providers[i] == "TensorrtExecutionProvider":
843
+ C.register_tensorrt_plugins_as_custom_ops(session_options, provider_options[i])
844
+ elif (
845
+ isinstance(providers[i], tuple)
846
+ and providers[i][0] in available_providers
847
+ and providers[i][0] == "TensorrtExecutionProvider"
848
+ ):
849
+ C.register_tensorrt_plugins_as_custom_ops(session_options, providers[i][1])
850
+
851
+ if providers[i] in available_providers and providers[i] == "NvTensorRTRTXExecutionProvider":
852
+ C.register_nv_tensorrt_rtx_plugins_as_custom_ops(session_options, provider_options[i])
853
+ elif (
854
+ isinstance(providers[i], tuple)
855
+ and providers[i][0] in available_providers
856
+ and providers[i][0] == "NvTensorrtRTXExecutionProvider"
857
+ ):
858
+ C.register_nv_tensorrt_rtx_plugins_as_custom_ops(session_options, providers[i][1])
859
+
860
+
861
+ def make_get_initializer_location_func_wrapper(
862
+ get_initializer_location_func: GetInitializerLocationFunc,
863
+ ) -> GetInitializerLocationWrapperFunc:
864
+ """
865
+ Wraps a user's "get initializer location" function. The returned wrapper function adheres to the
866
+ signature expected by ORT.
867
+
868
+ Need this wrapper to:
869
+ - Convert the `initializer_value` parameter from `C.OrtValue` to `onnxruntime.OrtValue`, which is more
870
+ convenient for the user's function to use.
871
+ - Allow the user's function to return the original `external_info` parameter (this wrapper makes a copy)
872
+ """
873
+
874
+ def get_initializer_location_func_wrapper(
875
+ initializer_name: str,
876
+ initializer_value: C.OrtValue,
877
+ external_info: C.OrtExternalInitializerInfo | None,
878
+ ) -> C.OrtExternalInitializerInfo | None:
879
+ ret_val: C.OrtExternalInitializerInfo | None = get_initializer_location_func(
880
+ initializer_name, OrtValue(initializer_value), external_info
881
+ )
882
+ if ret_val is not None and ret_val == external_info:
883
+ # User returned `external_info` (const and owned by ORT). ORT expects the returned value to be
884
+ # a new instance (that it deletes), so make a copy.
885
+ ret_val = C.OrtExternalInitializerInfo(ret_val.filepath, ret_val.file_offset, ret_val.byte_size)
886
+ return ret_val
887
+
888
+ return get_initializer_location_func_wrapper
889
+
890
+
891
+ class ModelCompiler:
892
+ """
893
+ This class is used to compile an ONNX model. A compiled ONNX model has EPContext nodes that each
894
+ encapsulates a subgraph compiled/optimized for a specific execution provider.
895
+
896
+ Refer to the EPContext design document for more information about EPContext models:
897
+ https://onnxruntime.ai/docs/execution-providers/EP-Context-Design.html
898
+
899
+ ::
900
+
901
+ sess_options = onnxruntime.SessionOptions()
902
+ sess_options.add_provider("SomeExecutionProvider", {"option1": "value1"})
903
+ # Alternatively, allow ONNX Runtime to select the provider automatically given a policy:
904
+ # sess_options.set_provider_selection_policy(onnxrt.OrtExecutionProviderDevicePolicy.PREFER_NPU)
905
+
906
+ model_compiler = onnxruntime.ModelCompiler(sess_options, "input_model.onnx")
907
+ model_compiler.compile_to_file("output_model.onnx")
908
+ """
909
+
910
+ def __init__(
911
+ self,
912
+ sess_options: C.SessionOptions,
913
+ input_model_path_or_bytes: str | os.PathLike | bytes,
914
+ embed_compiled_data_into_model: bool = False,
915
+ external_initializers_file_path: str | os.PathLike | None = None,
916
+ external_initializers_size_threshold: int = 1024,
917
+ flags: int = C.OrtCompileApiFlags.NONE,
918
+ graph_optimization_level: C.GraphOptimizationLevel = C.GraphOptimizationLevel.ORT_DISABLE_ALL,
919
+ get_initializer_location_func: GetInitializerLocationFunc | None = None,
920
+ ):
921
+ """
922
+ Creates a ModelCompiler instance.
923
+
924
+ :param sess_options: Session options containing the providers for which the model will be compiled.
925
+ Refer to SessionOptions.add_provider() and SessionOptions.set_provider_selection_policy().
926
+ :param input_model_path_or_bytes: The path to the input model file or bytes representing a serialized
927
+ ONNX model.
928
+ :param embed_compiled_data_into_model: Defaults to False. Set to True to embed compiled binary data into
929
+ EPContext nodes in the compiled model.
930
+ :param external_initializers_file_path: Defaults to None. Set to a path for a file that will store the
931
+ initializers for non-compiled nodes.
932
+ :param external_initializers_size_threshold: Defaults to 1024. Ignored if `external_initializers_file_path`
933
+ is None or empty. Initializers larger than this threshold are stored in the external initializers file.
934
+ :param flags: Additional boolean options to enable. Set this parameter to a bitwise OR of
935
+ flags in onnxruntime.OrtCompileApiFlags.
936
+ :param graph_optimization_level: The graph optimization level.
937
+ Defaults to onnxruntime.GraphOptimizationLevel.ORT_DISABLE_ALL.
938
+ :param get_initializer_location_func: Optional function called for every initializer to allow user to specify
939
+ whether an initializer should be stored within the model or externally. Example:
940
+ ```
941
+ def get_initializer_location(
942
+ initializer_name: str,
943
+ initializer_value: onnxrt.OrtValue,
944
+ external_info: onnxrt.OrtExternalInitializerInfo | None,
945
+ ) -> onnxrt.OrtExternalInitializerInfo | None:
946
+ byte_size = initializer_value.tensor_size_in_bytes()
947
+
948
+ if byte_size < 64:
949
+ return None # Store small initializer within compiled model.
950
+
951
+ # Else, write initializer to new external file.
952
+ value_np = initializer_value.numpy()
953
+ file_offset = ext_init_file.tell()
954
+ ext_init_file.write(value_np.tobytes())
955
+ return onnxrt.OrtExternalInitializerInfo(initializer_file_path, file_offset, byte_size)
956
+ ```
957
+ """
958
+ input_model_path: str | os.PathLike | None = None
959
+ input_model_bytes: bytes | None = None
960
+ if isinstance(input_model_path_or_bytes, (str, os.PathLike)):
961
+ if not input_model_path_or_bytes:
962
+ raise ValueError("Input model path is empty")
963
+ input_model_path = os.fspath(input_model_path_or_bytes)
964
+ elif isinstance(input_model_path_or_bytes, bytes):
965
+ if len(input_model_path_or_bytes) == 0:
966
+ raise ValueError("Input model bytes array is empty")
967
+ input_model_bytes = input_model_path_or_bytes
968
+ else:
969
+ raise TypeError(f"Unable to load from type '{type(input_model_path_or_bytes)}'")
970
+
971
+ if external_initializers_file_path:
972
+ if not isinstance(external_initializers_file_path, (str, os.PathLike)):
973
+ arg_type = type(external_initializers_file_path)
974
+ raise TypeError(f"Output external initializer filepath is of unexpected type '{arg_type}'")
975
+ external_initializers_file_path = os.fspath(external_initializers_file_path)
976
+ else:
977
+ external_initializers_file_path = ""
978
+
979
+ if get_initializer_location_func is not None:
980
+ if external_initializers_file_path:
981
+ raise ValueError(
982
+ "Cannot initialize ModelCompiler with both `external_initializers_file_path` "
983
+ "and `get_initializer_location_func`"
984
+ )
985
+ self.get_initializer_location_func_wrapper = make_get_initializer_location_func_wrapper(
986
+ get_initializer_location_func
987
+ )
988
+ else:
989
+ self.get_initializer_location_func_wrapper = None
990
+
991
+ if input_model_path:
992
+ self._model_compiler = C.ModelCompiler(
993
+ sess_options,
994
+ input_model_path,
995
+ True, # is path
996
+ embed_compiled_data_into_model,
997
+ external_initializers_file_path,
998
+ external_initializers_size_threshold,
999
+ flags,
1000
+ graph_optimization_level,
1001
+ self.get_initializer_location_func_wrapper,
1002
+ )
1003
+ else:
1004
+ self._model_compiler = C.ModelCompiler(
1005
+ sess_options,
1006
+ input_model_bytes,
1007
+ False, # is bytes
1008
+ embed_compiled_data_into_model,
1009
+ external_initializers_file_path,
1010
+ external_initializers_size_threshold,
1011
+ flags,
1012
+ graph_optimization_level,
1013
+ self.get_initializer_location_func_wrapper,
1014
+ )
1015
+
1016
+ def compile_to_file(self, output_model_path: str | None = None):
1017
+ """
1018
+ Compiles to an output file. If an output file path is not provided,
1019
+ the output file path is generated based on the input model path by replacing
1020
+ '.onnx' with '_ctx.onnx'. Ex: The generated output file is 'model_ctx.onnx' for
1021
+ an input model with path 'model.onnx'.
1022
+
1023
+ Raises an 'InvalidArgument' exception if the compilation options are invalid.
1024
+
1025
+ :param output_model_path: Defaults to None. The path for the output/compiled model.
1026
+ """
1027
+ if output_model_path:
1028
+ if not isinstance(output_model_path, (str, os.PathLike)):
1029
+ raise TypeError(f"Output model's filepath is of unexpected type '{type(output_model_path)}'")
1030
+ output_model_path = os.fspath(output_model_path)
1031
+ self._model_compiler.compile_to_file(output_model_path)
1032
+
1033
+ def compile_to_bytes(self) -> bytes:
1034
+ """
1035
+ Compiles to bytes representing the serialized compiled ONNX model.
1036
+
1037
+ Raises an 'InvalidArgument' exception if the compilation options are invalid.
1038
+
1039
+ :return: A bytes object representing the compiled ONNX model.
1040
+ """
1041
+ return self._model_compiler.compile_to_bytes()
1042
+
1043
+ def compile_to_stream(self, write_function: Callable[[bytes], None]):
1044
+ """
1045
+ Compiles the input model and writes the serialized ONNX bytes to a stream using the provided write function.
1046
+ Raises an 'InvalidArgument' exception if the compilation options are invalid.
1047
+ :param write_function: A callable that accepts a bytes buffer to write.
1048
+ """
1049
+ self._model_compiler.compile_to_stream(write_function)
1050
+
1051
+
1052
+ class IOBinding:
1053
+ """
1054
+ This class provides API to bind input/output to a specified device, e.g. GPU.
1055
+ """
1056
+
1057
+ def __init__(self, session: Session):
1058
+ self._session = session._sess
1059
+ self._is_webgpu_session = "WebGpuExecutionProvider" in session.get_providers()
1060
+ self._is_webgpu_graph_capture_enabled = self._session.is_webgpu_graph_capture_enabled()
1061
+ self._iobinding = C.SessionIOBinding(session._sess)
1062
+ self._numpy_obj_references = {}
1063
+ # Capture tracks fixed OrtValues; None marks host or raw-pointer bindings.
1064
+ self._bound_inputs: dict[str, OrtValue | None] = {}
1065
+ self._bound_outputs: dict[str, OrtValue | None] = {}
1066
+ # Captured graph IDs freeze these bindings until release.
1067
+ self._pinned_graph_ids: set[int] = set()
1068
+
1069
+ def _reject_if_pinned(self, action: str) -> None:
1070
+ if self._pinned_graph_ids:
1071
+ pinned = ", ".join(str(graph_id) for graph_id in sorted(self._pinned_graph_ids))
1072
+ raise ValueError(
1073
+ f"Cannot {action} while captured WebGPU graph(s) [{pinned}] still reference this "
1074
+ "IOBinding. Replay re-issues the buffers recorded at capture, so a change here "
1075
+ "would not affect replay and releasing the buffers could invalidate it. Call "
1076
+ "release_captured_graph(id) first."
1077
+ )
1078
+
1079
+ def _capture_signature(self):
1080
+ """Return bound OrtValues whose identity and lifetime must remain fixed during replay."""
1081
+ return (
1082
+ tuple(sorted(self._bound_inputs.items(), key=lambda item: item[0])),
1083
+ tuple(sorted(self._bound_outputs.items(), key=lambda item: item[0])),
1084
+ )
1085
+
1086
+ def _validate_capture_bindings(self) -> None:
1087
+ """Every binding participating in capture must be a fixed WebGPU device OrtValue."""
1088
+ for kind, bound in (("input", self._bound_inputs), ("output", self._bound_outputs)):
1089
+ for name, value in bound.items():
1090
+ if value is None or not value._is_webgpu_buffer:
1091
+ raise ValueError(
1092
+ f"WebGPU graph capture requires fixed WebGPU device OrtValues; {kind} "
1093
+ f"'{name}' is not one. Bind values created by this session or backed by an "
1094
+ f"environment-registered shared allocator, or set the "
1095
+ f"'{_GPU_GRAPH_ID_RUN_CONFIG_KEY}' run option to {_GRAPH_ANNOTATION_SKIP} "
1096
+ "to run without capture."
1097
+ )
1098
+
1099
+ def bind_cpu_input(self, name, arr_on_cpu):
1100
+ """
1101
+ bind an input to array on CPU
1102
+ :param name: input name
1103
+ :param arr_on_cpu: input values as a python array on CPU
1104
+ """
1105
+ self._reject_if_pinned("rebind inputs")
1106
+
1107
+ # Hold a reference to the numpy object as the bound OrtValue is backed
1108
+ # directly by the data buffer of the numpy object and so the numpy object
1109
+ # must be around until this IOBinding instance is around
1110
+ self._numpy_obj_references[name] = arr_on_cpu
1111
+ self._iobinding.bind_input(name, arr_on_cpu)
1112
+ self._bound_inputs[name] = None
1113
+
1114
+ def bind_input(self, name, device_type, device_id, element_type, shape, buffer_ptr):
1115
+ """
1116
+ :param name: input name
1117
+ :param device_type: e.g. cpu, cuda, cann
1118
+ :param device_id: device id, e.g. 0
1119
+ :param element_type: input element type. It can be either numpy type (like numpy.float32) or an integer for onnx type (like onnx.TensorProto.BFLOAT16)
1120
+ :param shape: input shape
1121
+ :param buffer_ptr: memory pointer to input data
1122
+ """
1123
+ self._reject_if_pinned("rebind inputs")
1124
+ self._iobinding.bind_input(
1125
+ name,
1126
+ OrtDevice.make(device_type, device_id)._get_c_device(),
1127
+ element_type,
1128
+ shape,
1129
+ buffer_ptr,
1130
+ )
1131
+ self._bound_inputs[name] = None
1132
+
1133
+ def bind_ortvalue_input(self, name, ortvalue):
1134
+ """
1135
+ :param name: input name
1136
+ :param ortvalue: OrtValue instance to bind
1137
+ """
1138
+ _validate_ortvalue_session_compatibility(ortvalue, self._session, "bound to")
1139
+ self._reject_if_pinned("rebind inputs")
1140
+ self._iobinding.bind_ortvalue_input(name, ortvalue._ortvalue)
1141
+ self._bound_inputs[name] = ortvalue
1142
+
1143
+ def synchronize_inputs(self):
1144
+ self._iobinding.synchronize_inputs()
1145
+
1146
+ def bind_output(
1147
+ self,
1148
+ name,
1149
+ device_type="cpu",
1150
+ device_id=0,
1151
+ element_type=None,
1152
+ shape=None,
1153
+ buffer_ptr=None,
1154
+ ):
1155
+ """
1156
+ :param name: output name
1157
+ :param device_type: e.g. cpu, cuda, cann, cpu by default
1158
+ :param device_id: device id, e.g. 0
1159
+ :param element_type: output element type. It can be either numpy type (like numpy.float32) or an integer for onnx type (like onnx.TensorProto.BFLOAT16)
1160
+ :param shape: output shape
1161
+ :param buffer_ptr: memory pointer to output data
1162
+ """
1163
+
1164
+ self._reject_if_pinned("rebind outputs")
1165
+
1166
+ # Follow the `if` path when the user has not provided any pre-allocated buffer but still
1167
+ # would like to bind an output to a specific device (e.g. cuda).
1168
+ # Pre-allocating an output buffer may not be an option for the user as :
1169
+ # (1) They may not want to use a custom allocator specific to the device they want to bind the output to,
1170
+ # in which case ORT will allocate the memory for the user
1171
+ # (2) The output has a dynamic shape and hence the size of the buffer may not be fixed across runs
1172
+ if buffer_ptr is None:
1173
+ self._iobinding.bind_output(
1174
+ name,
1175
+ OrtDevice.make(device_type, device_id)._get_c_device(),
1176
+ )
1177
+ else:
1178
+ if element_type is None or shape is None:
1179
+ raise ValueError("`element_type` and `shape` are to be provided if pre-allocated memory is provided")
1180
+ self._iobinding.bind_output(
1181
+ name,
1182
+ OrtDevice.make(device_type, device_id)._get_c_device(),
1183
+ element_type,
1184
+ shape,
1185
+ buffer_ptr,
1186
+ )
1187
+ self._bound_outputs[name] = None
1188
+
1189
+ def bind_ortvalue_output(self, name, ortvalue):
1190
+ """
1191
+ :param name: output name
1192
+ :param ortvalue: OrtValue instance to bind
1193
+ """
1194
+ _validate_ortvalue_session_compatibility(ortvalue, self._session, "bound to")
1195
+ self._reject_if_pinned("rebind outputs")
1196
+ self._iobinding.bind_ortvalue_output(name, ortvalue._ortvalue)
1197
+ self._bound_outputs[name] = ortvalue
1198
+
1199
+ def synchronize_outputs(self):
1200
+ self._iobinding.synchronize_outputs()
1201
+
1202
+ def get_outputs(self):
1203
+ """
1204
+ Returns the output OrtValues from the Run() that preceded the call.
1205
+ The data buffer of the obtained OrtValues may not reside on CPU memory
1206
+ """
1207
+ outputs = self._iobinding.get_outputs()
1208
+ if not isinstance(outputs, C.OrtValueVector):
1209
+ raise TypeError("get_outputs() must return an instance of type 'OrtValueVector'.")
1210
+ result = []
1211
+ for index in range(len(outputs)):
1212
+ ortvalue = outputs[index]
1213
+ result.append(
1214
+ OrtValue(
1215
+ ortvalue,
1216
+ session=self._session if ortvalue._is_webgpu_buffer() else None,
1217
+ )
1218
+ )
1219
+ return result
1220
+
1221
+ def get_outputs_as_ortvaluevector(self):
1222
+ """Return the raw OrtValueVector of outputs from the Run() that preceded the call.
1223
+
1224
+ The vector is a reference into this IOBinding (pybind ``reference_internal``), so it keeps the
1225
+ IOBinding alive, which in turn keeps the session alive. Device-resident outputs are therefore
1226
+ safe to hold past the session going out of scope.
1227
+ """
1228
+ return self._iobinding.get_outputs()
1229
+
1230
+ def copy_outputs_to_cpu(self):
1231
+ """Copy output contents to CPU."""
1232
+ return self._iobinding.copy_outputs_to_cpu()
1233
+
1234
+ def clear_binding_inputs(self):
1235
+ self._reject_if_pinned("clear input bindings")
1236
+ self._iobinding.clear_binding_inputs()
1237
+ self._bound_inputs.clear()
1238
+
1239
+ def clear_binding_outputs(self):
1240
+ self._reject_if_pinned("clear output bindings")
1241
+ self._iobinding.clear_binding_outputs()
1242
+ self._bound_outputs.clear()
1243
+
1244
+
1245
+ class OrtValue:
1246
+ """
1247
+ A data structure that supports all ONNX data formats (tensors and non-tensors) that allows users
1248
+ to place the data backing these on a device, for example, on a CUDA supported device.
1249
+ This class provides APIs to construct and deal with OrtValues.
1250
+ """
1251
+
1252
+ def __init__(
1253
+ self,
1254
+ ortvalue: C.OrtValue,
1255
+ numpy_obj: np.ndarray | None = None,
1256
+ session: C.InferenceSession | None = None,
1257
+ ):
1258
+ if isinstance(ortvalue, C.OrtValue):
1259
+ self._ortvalue = ortvalue
1260
+ # Hold a ref count to the numpy object if the OrtValue is backed directly
1261
+ # by its data buffer so that it isn't destroyed when the OrtValue is in use
1262
+ self._numpy_obj = numpy_obj
1263
+ # Session-scoped device allocators can be invalidated when their session is destroyed.
1264
+ self._session = session
1265
+ else:
1266
+ # An end user won't hit this error
1267
+ raise ValueError(
1268
+ "`Provided ortvalue` needs to be of type `onnxruntime.capi.onnxruntime_pybind11_state.OrtValue`"
1269
+ )
1270
+
1271
+ @property
1272
+ def _is_webgpu_buffer(self) -> bool:
1273
+ """Whether this value is backed by a WebGPU buffer.
1274
+
1275
+ Resolved from the native OrtValue on every access and deliberately read-only: graph-capture
1276
+ validation and the copy-path checks below refuse host memory, so a settable attribute would
1277
+ let a CPU tensor pass itself off as a device tensor.
1278
+ """
1279
+ return self._ortvalue._is_webgpu_buffer()
1280
+
1281
+ def _get_c_value(self) -> C.OrtValue:
1282
+ return self._ortvalue
1283
+
1284
+ @classmethod
1285
+ def ortvalue_from_numpy(
1286
+ cls, numpy_obj: np.ndarray, /, device_type="cpu", device_id=0, vendor_id: int | OrtDeviceVendorId = -1
1287
+ ) -> OrtValue:
1288
+ """
1289
+ Factory method to construct an OrtValue (which holds a Tensor) from a given Numpy object
1290
+ A copy of the data in the Numpy object is held by the OrtValue only if the device is NOT cpu
1291
+
1292
+ :param numpy_obj: The Numpy object to construct the OrtValue from
1293
+ :param device_type: e.g. cpu, cuda, cann, cpu by default
1294
+ :param device_id: device id, e.g. 0
1295
+ :param vendor_id: The device's PCI vendor id as an int or OrtDeviceVendorId. If provided, the device_type should be "gpu" or "npu".
1296
+ """
1297
+ # Hold a reference to the numpy object (if device_type is 'cpu') as the OrtValue
1298
+ # is backed directly by the data buffer of the numpy object and so the numpy object
1299
+ # must be around until this OrtValue instance is around
1300
+ return cls(
1301
+ C.OrtValue.ortvalue_from_numpy(
1302
+ numpy_obj,
1303
+ OrtDevice.make(device_type, device_id, vendor_id)._get_c_device(),
1304
+ ),
1305
+ numpy_obj if device_type.lower() == "cpu" else None,
1306
+ )
1307
+
1308
+ @classmethod
1309
+ def ortvalue_from_numpy_with_onnx_type(cls, data: np.ndarray, /, onnx_element_type: int) -> OrtValue:
1310
+ """
1311
+ This method creates an instance of OrtValue on top of the numpy array.
1312
+ No data copy is made and the lifespan of the resulting OrtValue should never
1313
+ exceed the lifespan of bytes object. The API attempts to reinterpret
1314
+ the data type which is expected to be the same size. This is useful
1315
+ when we want to use an ONNX data type that is not supported by numpy.
1316
+
1317
+ :param data: numpy.ndarray.
1318
+ :param onnx_element_type: a valid onnx TensorProto::DataType enum value
1319
+ """
1320
+ return cls(C.OrtValue.ortvalue_from_numpy_with_onnx_type(data, onnx_element_type), data)
1321
+
1322
+ @classmethod
1323
+ def ortvalue_from_shape_and_type(
1324
+ cls,
1325
+ shape: Sequence[int],
1326
+ element_type,
1327
+ device_type: str = "cpu",
1328
+ device_id: int = 0,
1329
+ vendor_id: int | OrtDeviceVendorId = -1,
1330
+ memory_info: C.OrtMemoryInfo | None = None,
1331
+ ) -> OrtValue:
1332
+ """
1333
+ Factory method to construct an OrtValue (which holds a Tensor) from given shape and element_type
1334
+
1335
+ :param shape: List of integers indicating the shape of the OrtValue
1336
+ :param element_type: The data type of the elements. It can be either numpy type (like numpy.float32) or an integer for onnx type (like onnx.TensorProto.BFLOAT16).
1337
+ :param device_type: e.g. cpu, cuda, cann, cpu by default
1338
+ :param device_id: device id, e.g. 0
1339
+ :param vendor_id: The device's PCI vendor id as an int or OrtDeviceVendorId. If provided, the device type should be "gpu" or "npu".
1340
+ :param memory_info: An OrtMemoryInfo from an OrtEpDevice (e.g. via ep_device.memory_info(OrtDeviceMemoryType.HOST_ACCESSIBLE)). When provided, the allocator matching this memory info is used directly, which allows allocating HOST_ACCESSIBLE memory for zero-copy numpy interop. The device_type, device_id, and vendor_id parameters are ignored when memory_info is provided.
1341
+ """
1342
+
1343
+ if memory_info is not None:
1344
+ if device_type != "cpu" or device_id != 0 or vendor_id != -1:
1345
+ warnings.warn(
1346
+ "device_type, device_id, and vendor_id are ignored when memory_info is provided.",
1347
+ stacklevel=2,
1348
+ )
1349
+ if isinstance(element_type, int):
1350
+ return cls(
1351
+ C.OrtValue.ortvalue_from_shape_and_onnx_type_for_memory_info(
1352
+ shape,
1353
+ element_type,
1354
+ memory_info,
1355
+ )
1356
+ )
1357
+ return cls(
1358
+ C.OrtValue.ortvalue_from_shape_and_type_for_memory_info(
1359
+ shape,
1360
+ element_type,
1361
+ memory_info,
1362
+ )
1363
+ )
1364
+
1365
+ device = OrtDevice.make(device_type, device_id, vendor_id)._get_c_device()
1366
+
1367
+ # Integer for onnx element type (see https://onnx.ai/onnx/api/mapping.html).
1368
+ # This is helpful for some data type (like TensorProto.BFLOAT16) that is not available in numpy.
1369
+ if isinstance(element_type, int):
1370
+ return cls(
1371
+ C.OrtValue.ortvalue_from_shape_and_onnx_type(
1372
+ shape,
1373
+ element_type,
1374
+ device,
1375
+ )
1376
+ )
1377
+
1378
+ return cls(
1379
+ C.OrtValue.ortvalue_from_shape_and_type(
1380
+ shape,
1381
+ element_type,
1382
+ device,
1383
+ )
1384
+ )
1385
+
1386
+ @classmethod
1387
+ def ort_value_from_sparse_tensor(cls, sparse_tensor: SparseTensor) -> OrtValue:
1388
+ """
1389
+ The function will construct an OrtValue instance from a valid SparseTensor
1390
+ The new instance of OrtValue will assume the ownership of sparse_tensor
1391
+ """
1392
+ return cls(C.OrtValue.ort_value_from_sparse_tensor(sparse_tensor._get_c_tensor()))
1393
+
1394
+ def as_sparse_tensor(self) -> SparseTensor:
1395
+ """
1396
+ The function will return SparseTensor contained in this OrtValue
1397
+ """
1398
+ return SparseTensor(self._ortvalue.as_sparse_tensor())
1399
+
1400
+ def data_ptr(self) -> int:
1401
+ """
1402
+ Returns the address of the first element in the OrtValue's data buffer
1403
+
1404
+ WebGPU buffers are opaque handles and do not expose a data pointer.
1405
+ """
1406
+ return self._ortvalue.data_ptr()
1407
+
1408
+ def device_name(self) -> str:
1409
+ """
1410
+ Returns the name of the device where the OrtValue's data buffer resides e.g. cpu, cuda, cann, webgpu
1411
+ """
1412
+ return self._ortvalue.device_name().lower()
1413
+
1414
+ def shape(self) -> Sequence[int]:
1415
+ """
1416
+ Returns the shape of the data in the OrtValue
1417
+ """
1418
+ return self._ortvalue.shape()
1419
+
1420
+ def data_type(self) -> str:
1421
+ """
1422
+ Returns the data type of the data in the OrtValue. E.g. 'tensor(int64)'
1423
+ """
1424
+ return self._ortvalue.data_type()
1425
+
1426
+ def element_type(self) -> int:
1427
+ """
1428
+ Returns the proto type of the data in the OrtValue
1429
+ if the OrtValue is a tensor.
1430
+ """
1431
+ return self._ortvalue.element_type()
1432
+
1433
+ def tensor_size_in_bytes(self) -> int:
1434
+ """
1435
+ Returns the size of the data in the OrtValue in bytes
1436
+ if the OrtValue is a tensor.
1437
+ """
1438
+ return self._ortvalue.tensor_size_in_bytes()
1439
+
1440
+ def has_value(self) -> bool:
1441
+ """
1442
+ Returns True if the OrtValue corresponding to an
1443
+ optional type contains data, else returns False
1444
+ """
1445
+ return self._ortvalue.has_value()
1446
+
1447
+ def is_tensor(self) -> bool:
1448
+ """
1449
+ Returns True if the OrtValue contains a Tensor, else returns False
1450
+ """
1451
+ return self._ortvalue.is_tensor()
1452
+
1453
+ def is_sparse_tensor(self) -> bool:
1454
+ """
1455
+ Returns True if the OrtValue contains a SparseTensor, else returns False
1456
+ """
1457
+ return self._ortvalue.is_sparse_tensor()
1458
+
1459
+ def is_tensor_sequence(self) -> bool:
1460
+ """
1461
+ Returns True if the OrtValue contains a Tensor Sequence, else returns False
1462
+ """
1463
+ return self._ortvalue.is_tensor_sequence()
1464
+
1465
+ def numpy(self) -> np.ndarray:
1466
+ """
1467
+ Returns a Numpy object from the OrtValue.
1468
+ Valid only for OrtValues holding Tensors. Throws for OrtValues holding non-Tensors.
1469
+ Use accessors to gain a reference to non-Tensor objects such as SparseTensor
1470
+ WebGPU device values require explicit readback with
1471
+ :meth:`IOBinding.copy_outputs_to_cpu`.
1472
+ """
1473
+ return self._ortvalue.numpy()
1474
+
1475
+ def __array__(self, dtype=None, copy=None) -> np.ndarray:
1476
+ """
1477
+ Supports ``numpy.asarray(ortvalue)`` and ``numpy.array(ortvalue)`` via the
1478
+ `numpy __array__ protocol <https://numpy.org/devdocs/user/basics.interoperability.html>`_.
1479
+
1480
+ Valid only for OrtValues holding Tensors on CPU.
1481
+
1482
+ :param dtype: Optional numpy dtype to cast the result to.
1483
+ :param copy: Optional bool (numpy >= 2.0). If ``False``, a copy will
1484
+ only be made if necessary. If ``True``, a copy is always forced.
1485
+ If ``None`` (default), a copy will be made only if needed.
1486
+ :return: A numpy array with the same data as the OrtValue.
1487
+ """
1488
+ arr = self.numpy()
1489
+
1490
+ if copy is not None:
1491
+ # numpy >= 2.0 added the copy kwarg to np.asarray;
1492
+ # np.array has always accepted it but with weaker semantics pre-2.0.
1493
+ arr = np.array(arr, dtype=dtype, copy=copy)
1494
+ elif dtype is not None:
1495
+ # np.asarray avoids a copy when the dtype already matches,
1496
+ # preserving memory sharing with the underlying OrtValue.
1497
+ arr = np.asarray(arr, dtype=dtype)
1498
+
1499
+ return arr
1500
+
1501
+ def __dlpack__(self, *, stream=None):
1502
+ """
1503
+ Returns a DLPack capsule representing the tensor (part of the
1504
+ `DLPack protocol <https://dmlc.github.io/dlpack/latest/>`_).
1505
+
1506
+ This enables interoperability with other frameworks via
1507
+ ``from_dlpack(ortvalue)`` (e.g. ``torch.from_dlpack``,
1508
+ ``jax.dlpack.from_dlpack``, ``numpy.from_dlpack``).
1509
+
1510
+ The OrtValue must hold a contiguous tensor. No data is copied;
1511
+ the consumer shares memory with this OrtValue, which must remain
1512
+ alive while the capsule is in use.
1513
+ WebGPU OrtValues cannot be exported through DLPack because their data
1514
+ is stored in opaque WebGPU buffers rather than CUDA-addressable memory.
1515
+
1516
+ :param stream: Optional stream on which the tensor data is accessible.
1517
+ Currently unused; included for protocol compliance.
1518
+ :return: A PyCapsule holding a DLManagedTensor.
1519
+ """
1520
+ return self._ortvalue.__dlpack__(stream=stream)
1521
+
1522
+ def __dlpack_device__(self) -> tuple[int, int]:
1523
+ """
1524
+ Returns ``(device_type, device_id)`` indicating where the tensor data
1525
+ resides (part of the `DLPack protocol
1526
+ <https://dmlc.github.io/dlpack/latest/>`_).
1527
+
1528
+ WebGPU OrtValues do not expose a DLPack device.
1529
+
1530
+ :return: Tuple of ``(device_type, device_id)`` as ints following DLPack
1531
+ ``DLDeviceType`` enum values.
1532
+ """
1533
+ return self._ortvalue.__dlpack_device__()
1534
+
1535
+ @classmethod
1536
+ def from_dlpack(cls, data, /) -> OrtValue:
1537
+ """
1538
+ Construct an OrtValue from an object that implements the DLPack protocol.
1539
+
1540
+ Accepts either:
1541
+
1542
+ * An object with ``__dlpack__`` / ``__dlpack_device__`` methods
1543
+ (e.g. a PyTorch tensor, JAX array, or numpy array).
1544
+ * A raw DLPack PyCapsule (legacy path).
1545
+
1546
+ Boolean tensors are automatically detected when the source object
1547
+ exposes a ``dtype`` attribute (numpy, PyTorch, etc.) or is an
1548
+ ``OrtValue``. For raw DLPack capsules where the original dtype cannot
1549
+ be inspected, bool tensors encoded as uint8 by older DLPack versions
1550
+ are not distinguishable from true uint8 tensors and will be imported
1551
+ as uint8.
1552
+
1553
+ No data is copied; the new OrtValue shares memory with the source.
1554
+
1555
+ :param data: A tensor object supporting the DLPack protocol, or a raw
1556
+ DLPack PyCapsule.
1557
+ :return: An OrtValue wrapping the tensor data.
1558
+ """
1559
+ # Detect boolean dtype from the source object before consuming it,
1560
+ # because DLPack encodes bool as uint8 and the capsule alone cannot
1561
+ # distinguish between the two.
1562
+ is_bool = False
1563
+ if isinstance(data, OrtValue):
1564
+ is_bool = data.data_type() == "tensor(bool)"
1565
+ elif hasattr(data, "dtype"):
1566
+ dtype_obj = data.dtype
1567
+ # Use .name when available (numpy, cupy, tensorflow all expose it).
1568
+ # Fall back to str() for frameworks that don't (e.g. PyTorch).
1569
+ dtype_name = getattr(dtype_obj, "name", str(dtype_obj))
1570
+ is_bool = dtype_name in ("bool", "bool_", "torch.bool")
1571
+
1572
+ # If the input supports the __dlpack__ protocol, call it to get the capsule.
1573
+ if hasattr(data, "__dlpack__"):
1574
+ capsule = data.__dlpack__()
1575
+ else:
1576
+ capsule = data
1577
+
1578
+ return cls(C.OrtValue.from_dlpack(capsule, is_bool))
1579
+
1580
+ def update_inplace(self, data) -> None:
1581
+ """
1582
+ Update the OrtValue in place. The source data is copied over to the device
1583
+ memory backing the OrtValue. It can be used to update the input values for
1584
+ an InferenceSession with CUDA graph enabled or other scenarios where the
1585
+ OrtValue needs to be updated while the memory address can not be changed.
1586
+
1587
+ :param data: The source data, which can be a Numpy array or another OrtValue.
1588
+ When an OrtValue is provided, data can be copied between devices (e.g.,
1589
+ GPU to GPU) without going through the CPU.
1590
+ """
1591
+ if isinstance(data, OrtValue):
1592
+ if self._is_webgpu_buffer != data._is_webgpu_buffer:
1593
+ raise ValueError(
1594
+ "WebGPU OrtValue copies require WebGPU source and destination values; "
1595
+ "use IOBinding.copy_outputs_to_cpu for readback."
1596
+ )
1597
+ if not _is_ortvalue_session_compatible(data, self._session):
1598
+ raise ValueError("Session-scoped OrtValues must originate from the same session.")
1599
+
1600
+ self._ortvalue.update_inplace(data._ortvalue)
1601
+ return
1602
+
1603
+ if not isinstance(data, np.ndarray):
1604
+ raise TypeError("data must be a numpy.ndarray or an OrtValue.")
1605
+
1606
+ # Every copy path requires contiguous source storage.
1607
+ if not data.flags.c_contiguous:
1608
+ data = np.ascontiguousarray(data)
1609
+
1610
+ self._ortvalue.update_inplace(data)
1611
+
1612
+
1613
+ _DEFAULT_WEBGPU_CONTEXT_ID = 0
1614
+
1615
+
1616
+ def _session_webgpu_context_id(session: C.InferenceSession) -> int:
1617
+ """Return a session's WebGPU context id, or -1 when it has no WebGPU EP."""
1618
+ return session.webgpu_context_id()
1619
+
1620
+
1621
+ def _has_foreign_webgpu_context(
1622
+ values: Sequence[OrtValue],
1623
+ context_id_getter=_session_webgpu_context_id,
1624
+ ) -> bool:
1625
+ """Whether any value provably belongs to a WebGPU context other than the default one.
1626
+
1627
+ The environment data transfer resolves the default WebGPU context, so copying a buffer that
1628
+ belongs to a caller-supplied context would silently run on the wrong device. A value with no
1629
+ owning session cannot be attributed to a context and is treated as default-context, as is a
1630
+ session with no WebGPU EP.
1631
+
1632
+ TODO: this can only attribute a value that carries session provenance, because every WebGPU
1633
+ allocation reports OrtDevice(GPU, VendorIds::NONE, 0) regardless of its context. Supporting a
1634
+ custom external WebGPU context requires the shared allocator and its data transfer to retain and
1635
+ use that external device instead of resolving WebGpuContextFactory::DefaultContext(), which
1636
+ would also let the transfer itself reject the copy instead of relying on this Python-side guard.
1637
+ """
1638
+ for value in values:
1639
+ if not value._is_webgpu_buffer or value._session is None:
1640
+ continue
1641
+ if context_id_getter(value._session) not in (-1, _DEFAULT_WEBGPU_CONTEXT_ID):
1642
+ return True
1643
+ return False
1644
+
1645
+
1646
+ def copy_tensors(src: Sequence[OrtValue], dst: Sequence[OrtValue], stream=None) -> None:
1647
+ """
1648
+ Copy tensor data from source OrtValue sequence to destination OrtValue sequence.
1649
+
1650
+ WebGPU values belonging to the default context are supported in either direction. A value from a
1651
+ caller-supplied WebGPU context is not, because the shared data transfer is bound to the default
1652
+ context.
1653
+ """
1654
+ if _has_foreign_webgpu_context([*src, *dst]):
1655
+ raise ValueError(
1656
+ "copy_tensors cannot copy a WebGPU OrtValue that belongs to a custom WebGPU context "
1657
+ "because the shared data transfer is bound to the default context; use IOBinding "
1658
+ "readback instead."
1659
+ )
1660
+ c_sources = [s._get_c_value() for s in src]
1661
+ c_dsts = [d._get_c_value() for d in dst]
1662
+ C.copy_tensors(c_sources, c_dsts, stream)
1663
+
1664
+
1665
+ class OrtDevice:
1666
+ """
1667
+ A data structure that exposes the underlying C++ OrtDevice
1668
+ """
1669
+
1670
+ def __init__(self, c_ort_device):
1671
+ """
1672
+ Internal constructor
1673
+ """
1674
+ if isinstance(c_ort_device, C.OrtDevice):
1675
+ self._ort_device = c_ort_device
1676
+ else:
1677
+ # An end user won't hit this error
1678
+ raise ValueError(
1679
+ "`Provided object` needs to be of type `onnxruntime.capi.onnxruntime_pybind11_state.OrtDevice`"
1680
+ )
1681
+
1682
+ def _get_c_device(self):
1683
+ """
1684
+ Internal accessor to underlying object
1685
+ """
1686
+ return self._ort_device
1687
+
1688
+ @staticmethod
1689
+ def make(ort_device_name, device_id, vendor_id: int | OrtDeviceVendorId = -1):
1690
+ if vendor_id < 0:
1691
+ # Preserve the historical convenience aliases ("cuda", "dml", "cann")
1692
+ # while making them work with plugin EP shared allocators. Those
1693
+ # allocators are keyed by vendor-specific OrtDevice values even when the
1694
+ # Python package itself was built without the corresponding built-in EP.
1695
+ alias_vendor_id = get_vendor_id_for_device_type(ort_device_name)
1696
+ if alias_vendor_id is not None:
1697
+ return OrtDevice(
1698
+ C.OrtDevice(
1699
+ get_ort_device_type(ort_device_name),
1700
+ C.OrtDevice.default_memory(),
1701
+ int(alias_vendor_id),
1702
+ device_id,
1703
+ )
1704
+ )
1705
+
1706
+ # backwards compatibility with generic predefined OrtDevice names
1707
+ return OrtDevice(
1708
+ C.OrtDevice(
1709
+ get_ort_device_type(ort_device_name),
1710
+ C.OrtDevice.default_memory(),
1711
+ device_id,
1712
+ )
1713
+ )
1714
+ else:
1715
+ # generic. use GPU or NPU for ort_device_name and provide a vendor id.
1716
+ # vendor id of 0 is valid in some cases (e.g. webgpu is generic and does not have a vendor id)
1717
+ return OrtDevice(
1718
+ C.OrtDevice(
1719
+ get_ort_device_type(ort_device_name),
1720
+ C.OrtDevice.default_memory(),
1721
+ int(vendor_id),
1722
+ device_id,
1723
+ )
1724
+ )
1725
+
1726
+ def device_id(self):
1727
+ return self._ort_device.device_id()
1728
+
1729
+ def device_type(self):
1730
+ return self._ort_device.device_type()
1731
+
1732
+ def device_vendor_id(self):
1733
+ return self._ort_device.vendor_id()
1734
+
1735
+ def device_mem_type(self):
1736
+ return self._ort_device.mem_type()
1737
+
1738
+
1739
+ class SparseTensor:
1740
+ """
1741
+ A data structure that project the C++ SparseTensor object
1742
+ The class provides API to work with the object.
1743
+ Depending on the format, the class will hold more than one buffer
1744
+ depending on the format
1745
+ """
1746
+
1747
+ def __init__(self, sparse_tensor: C.SparseTensor):
1748
+ """
1749
+ Internal constructor
1750
+ """
1751
+ if isinstance(sparse_tensor, C.SparseTensor):
1752
+ self._tensor = sparse_tensor
1753
+ else:
1754
+ # An end user won't hit this error
1755
+ raise ValueError(
1756
+ "`Provided object` needs to be of type `onnxruntime.capi.onnxruntime_pybind11_state.SparseTensor`"
1757
+ )
1758
+
1759
+ def _get_c_tensor(self) -> C.SparseTensor:
1760
+ return self._tensor
1761
+
1762
+ @classmethod
1763
+ def sparse_coo_from_numpy(
1764
+ cls,
1765
+ dense_shape: npt.NDArray[np.int64],
1766
+ values: np.ndarray,
1767
+ coo_indices: npt.NDArray[np.int64],
1768
+ ort_device: OrtDevice,
1769
+ ) -> SparseTensor:
1770
+ """
1771
+ Factory method to construct a SparseTensor in COO format from given arguments
1772
+
1773
+ :param dense_shape: 1-D numpy array(int64) or a python list that contains a dense_shape of the sparse tensor
1774
+ must be on cpu memory
1775
+ :param values: a homogeneous, contiguous 1-D numpy array that contains non-zero elements of the tensor
1776
+ of a type.
1777
+ :param coo_indices: contiguous numpy array(int64) that contains COO indices for the tensor. coo_indices may
1778
+ have a 1-D shape when it contains a linear index of non-zero values and its length must be equal to
1779
+ that of the values. It can also be of 2-D shape, in which has it contains pairs of coordinates for
1780
+ each of the nnz values and its length must be exactly twice of the values length.
1781
+ :param ort_device: - describes the backing memory owned by the supplied nummpy arrays. Only CPU memory is
1782
+ suppored for non-numeric data types.
1783
+
1784
+ For primitive types, the method will map values and coo_indices arrays into native memory and will use
1785
+ them as backing storage. It will increment the reference count for numpy arrays and it will decrement it
1786
+ on GC. The buffers may reside in any storage either CPU or GPU.
1787
+ For strings and objects, it will create a copy of the arrays in CPU memory as ORT does not support those
1788
+ on other devices and their memory can not be mapped.
1789
+ """
1790
+ return cls(C.SparseTensor.sparse_coo_from_numpy(dense_shape, values, coo_indices, ort_device._get_c_device()))
1791
+
1792
+ @classmethod
1793
+ def sparse_csr_from_numpy(
1794
+ cls,
1795
+ dense_shape: npt.NDArray[np.int64],
1796
+ values: np.ndarray,
1797
+ inner_indices: npt.NDArray[np.int64],
1798
+ outer_indices: npt.NDArray[np.int64],
1799
+ ort_device: OrtDevice,
1800
+ ) -> SparseTensor:
1801
+ """
1802
+ Factory method to construct a SparseTensor in CSR format from given arguments
1803
+
1804
+ :param dense_shape: 1-D numpy array(int64) or a python list that contains a dense_shape of the
1805
+ sparse tensor (rows, cols) must be on cpu memory
1806
+ :param values: a contiguous, homogeneous 1-D numpy array that contains non-zero elements of the tensor
1807
+ of a type.
1808
+ :param inner_indices: contiguous 1-D numpy array(int64) that contains CSR inner indices for the tensor.
1809
+ Its length must be equal to that of the values.
1810
+ :param outer_indices: contiguous 1-D numpy array(int64) that contains CSR outer indices for the tensor.
1811
+ Its length must be equal to the number of rows + 1.
1812
+ :param ort_device: - describes the backing memory owned by the supplied nummpy arrays. Only CPU memory is
1813
+ suppored for non-numeric data types.
1814
+
1815
+ For primitive types, the method will map values and indices arrays into native memory and will use them as
1816
+ backing storage. It will increment the reference count and it will decrement then count when it is GCed.
1817
+ The buffers may reside in any storage either CPU or GPU.
1818
+ For strings and objects, it will create a copy of the arrays in CPU memory as ORT does not support those
1819
+ on other devices and their memory can not be mapped.
1820
+ """
1821
+ return cls(
1822
+ C.SparseTensor.sparse_csr_from_numpy(
1823
+ dense_shape,
1824
+ values,
1825
+ inner_indices,
1826
+ outer_indices,
1827
+ ort_device._get_c_device(),
1828
+ )
1829
+ )
1830
+
1831
+ def values(self) -> np.ndarray:
1832
+ """
1833
+ The method returns a numpy array that is backed by the native memory
1834
+ if the data type is numeric. Otherwise, the returned numpy array that contains
1835
+ copies of the strings.
1836
+ """
1837
+ return self._tensor.values()
1838
+
1839
+ def as_coo_view(self):
1840
+ """
1841
+ The method will return coo representation of the sparse tensor which will enable
1842
+ querying COO indices. If the instance did not contain COO format, it would throw.
1843
+ You can query coo indices as:
1844
+
1845
+ ::
1846
+
1847
+ coo_indices = sparse_tensor.as_coo_view().indices()
1848
+
1849
+ which will return a numpy array that is backed by the native memory.
1850
+ """
1851
+ return self._tensor.get_coo_data()
1852
+
1853
+ def as_csrc_view(self):
1854
+ """
1855
+ The method will return CSR(C) representation of the sparse tensor which will enable
1856
+ querying CRS(C) indices. If the instance dit not contain CSR(C) format, it would throw.
1857
+ You can query indices as:
1858
+
1859
+ ::
1860
+
1861
+ inner_ndices = sparse_tensor.as_csrc_view().inner()
1862
+ outer_ndices = sparse_tensor.as_csrc_view().outer()
1863
+
1864
+ returning numpy arrays backed by the native memory.
1865
+ """
1866
+ return self._tensor.get_csrc_data()
1867
+
1868
+ def as_blocksparse_view(self):
1869
+ """
1870
+ The method will return coo representation of the sparse tensor which will enable
1871
+ querying BlockSparse indices. If the instance did not contain BlockSparse format, it would throw.
1872
+ You can query coo indices as:
1873
+
1874
+ ::
1875
+
1876
+ block_sparse_indices = sparse_tensor.as_blocksparse_view().indices()
1877
+
1878
+ which will return a numpy array that is backed by the native memory
1879
+ """
1880
+ return self._tensor.get_blocksparse_data()
1881
+
1882
+ def to_cuda(self, ort_device):
1883
+ """
1884
+ Returns a copy of this instance on the specified cuda device
1885
+
1886
+ :param ort_device: with name 'cuda' and valid gpu device id
1887
+
1888
+ The method will throw if:
1889
+
1890
+ - this instance contains strings
1891
+ - this instance is already on GPU. Cross GPU copy is not supported
1892
+ - CUDA is not present in this build
1893
+ - if the specified device is not valid
1894
+ """
1895
+ return SparseTensor(self._tensor.to_cuda(ort_device._get_c_device()))
1896
+
1897
+ def format(self):
1898
+ """
1899
+ Returns a OrtSparseFormat enumeration
1900
+ """
1901
+ return self._tensor.format
1902
+
1903
+ def dense_shape(self) -> npt.NDArray[np.int64]:
1904
+ """
1905
+ Returns a numpy array(int64) containing a dense shape of a sparse tensor
1906
+ """
1907
+ return self._tensor.dense_shape()
1908
+
1909
+ def data_type(self) -> str:
1910
+ """
1911
+ Returns a string data type of the data in the OrtValue
1912
+ """
1913
+ return self._tensor.data_type()
1914
+
1915
+ def device_name(self) -> str:
1916
+ """
1917
+ Returns the name of the device where the SparseTensor data buffers reside e.g. cpu, cuda
1918
+ """
1919
+ return self._tensor.device_name().lower()
1920
+
1921
+
1922
+ # Type hint for user-specified function that allows the user to specify initializer locations when compiling a model.
1923
+ GetInitializerLocationFunc = Callable[
1924
+ [str, OrtValue, C.OrtExternalInitializerInfo | None], C.OrtExternalInitializerInfo | None
1925
+ ]
1926
+
1927
+ # Type hint that adheres to the signature expected by ORT.
1928
+ GetInitializerLocationWrapperFunc = Callable[
1929
+ [str, C.OrtValue, C.OrtExternalInitializerInfo | None], C.OrtExternalInitializerInfo | None
1930
+ ]
onnxruntime/capi/onnxruntime_providers_cuda.dll ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2c744e0d1683518fa88e229ca006304aad6a29b81b9f0229596969c89ba80c12
3
+ size 689375232
onnxruntime/capi/onnxruntime_providers_openvino.dll ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:15664f6d9bad3f65705df0ec6275eb029cc7efa2310e0243e30349a9195b71ce
3
+ size 1345024
onnxruntime/capi/onnxruntime_providers_shared.dll ADDED
Binary file (10.8 kB). View file
 
onnxruntime/capi/onnxruntime_providers_tensorrt.dll ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:67264756a9b187e9329c8a9b6c013bb39dfe3a52eaa4f44bc19be283d68afcac
3
+ size 744448
onnxruntime/capi/onnxruntime_pybind11_state.pyd ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e54c4900fc60c521dc597dc0b0c87835a18ea6ee2efd38af78c70ac6f10abcbb
3
+ size 25851904
onnxruntime/capi/onnxruntime_validation.py ADDED
@@ -0,0 +1,154 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -------------------------------------------------------------------------
2
+ # Copyright (c) Microsoft Corporation. All rights reserved.
3
+ # Licensed under the MIT License.
4
+ # --------------------------------------------------------------------------
5
+ """
6
+ Check OS requirements for ONNX Runtime Python Bindings.
7
+ """
8
+
9
+ import linecache
10
+ import platform
11
+ import warnings
12
+
13
+
14
+ def check_distro_info():
15
+ __my_distro__ = ""
16
+ __my_distro_ver__ = ""
17
+ __my_system__ = platform.system().lower()
18
+
19
+ __OS_RELEASE_FILE__ = "/etc/os-release" # noqa: N806
20
+ __LSB_RELEASE_FILE__ = "/etc/lsb-release" # noqa: N806
21
+
22
+ if __my_system__ == "windows":
23
+ __my_distro__ = __my_system__
24
+ __my_distro_ver__ = platform.release().lower()
25
+
26
+ if __my_distro_ver__ not in ["10", "11", "2016server", "2019server", "2022server", "2025server"]:
27
+ warnings.warn(
28
+ f"Unsupported Windows version ({__my_distro_ver__}). ONNX Runtime supports Windows 10 and above, or Windows Server 2016 and above."
29
+ )
30
+ elif __my_system__ == "linux":
31
+ """Although the 'platform' python module for getting Distro information works well on standard OS images
32
+ running on real hardware, it is not accurate when running on Azure VMs, Git Bash, Cygwin, etc.
33
+ The returned values for release and version are unpredictable for virtualized or emulated environments.
34
+ /etc/os-release and /etc/lsb_release files, on the other hand, are guaranteed to exist and have standard values
35
+ in all OSes supported by onnxruntime. The former is the current standard file to check OS info and the latter
36
+ is its predecessor.
37
+ """
38
+ # Newer systems have /etc/os-release with relevant distro info
39
+ __my_distro__ = linecache.getline(__OS_RELEASE_FILE__, 3)[3:-1]
40
+ __my_distro_ver__ = linecache.getline(__OS_RELEASE_FILE__, 6)[12:-2]
41
+
42
+ # Older systems may have /etc/os-release instead
43
+ if not __my_distro__:
44
+ __my_distro__ = linecache.getline(__LSB_RELEASE_FILE__, 1)[11:-1]
45
+ __my_distro_ver__ = linecache.getline(__LSB_RELEASE_FILE__, 2)[16:-1]
46
+
47
+ # Instead of trying to parse distro specific files,
48
+ # warn the user ONNX Runtime may not work out of the box
49
+ __my_distro__ = __my_distro__.lower()
50
+ __my_distro_ver__ = __my_distro_ver__.lower()
51
+ elif __my_system__ == "darwin":
52
+ __my_distro__ = __my_system__
53
+ __my_distro_ver__ = platform.release().lower()
54
+
55
+ if int(__my_distro_ver__.split(".")[0]) < 11:
56
+ warnings.warn(
57
+ f"Unsupported macOS version ({__my_distro_ver__}). ONNX Runtime supports macOS 11.0 or later."
58
+ )
59
+ elif __my_system__ == "aix":
60
+ import subprocess # noqa: PLC0415
61
+
62
+ returned_output = subprocess.check_output("oslevel")
63
+ __my_distro_ver__str = returned_output.decode("utf-8")
64
+ __my_distro_ver = __my_distro_ver__str[:3]
65
+ else:
66
+ warnings.warn(
67
+ f"Unsupported platform ({__my_system__}). ONNX Runtime supports Linux, macOS, AIX and Windows platforms, only."
68
+ )
69
+
70
+
71
+ def get_package_name_and_version_info():
72
+ package_name = ""
73
+ version = ""
74
+ cuda_version = ""
75
+
76
+ try:
77
+ from .build_and_package_info import __version__ as version # noqa: PLC0415
78
+ from .build_and_package_info import package_name # noqa: PLC0415
79
+
80
+ try: # noqa: SIM105
81
+ from .build_and_package_info import cuda_version # noqa: PLC0415
82
+ except ImportError:
83
+ # cuda_version is optional. For example, cpu only package does not have the attribute.
84
+ pass
85
+ except Exception as e:
86
+ warnings.warn("WARNING: failed to collect package name and version info")
87
+ print(e)
88
+
89
+ return package_name, version, cuda_version
90
+
91
+
92
+ def check_training_module():
93
+ import_ortmodule_exception = None
94
+
95
+ has_ortmodule = False
96
+ try:
97
+ from onnxruntime.training.ortmodule import ORTModule # noqa: F401, PLC0415
98
+
99
+ has_ortmodule = True
100
+ except ImportError:
101
+ # ORTModule not present
102
+ has_ortmodule = False
103
+ except Exception as e:
104
+ # this may happen if Cuda is not installed, we want to raise it after
105
+ # for any exception other than not having ortmodule, we want to continue
106
+ # device version validation and raise the exception after.
107
+ try:
108
+ from onnxruntime.training.ortmodule._fallback import ORTModuleInitException # noqa: PLC0415
109
+
110
+ if isinstance(e, ORTModuleInitException):
111
+ # ORTModule is present but not ready to run yet
112
+ has_ortmodule = True
113
+ except Exception:
114
+ # ORTModule not present
115
+ has_ortmodule = False
116
+
117
+ if not has_ortmodule:
118
+ import_ortmodule_exception = e
119
+
120
+ # collect onnxruntime package name, version, and cuda version
121
+ package_name, version, cuda_version = get_package_name_and_version_info()
122
+
123
+ if has_ortmodule and cuda_version:
124
+ try:
125
+ # collect cuda library build info. the library info may not be available
126
+ # when the build environment has none or multiple libraries installed
127
+ try:
128
+ from .build_and_package_info import cudart_version # noqa: PLC0415
129
+ except ImportError:
130
+ warnings.warn("WARNING: failed to get cudart_version from onnxruntime build info.")
131
+ cudart_version = None
132
+
133
+ def print_build_package_info():
134
+ warnings.warn(f"onnxruntime training package info: package_name: {package_name}")
135
+ warnings.warn(f"onnxruntime training package info: __version__: {version}")
136
+ warnings.warn(f"onnxruntime training package info: cuda_version: {cuda_version}")
137
+ warnings.warn(f"onnxruntime build info: cudart_version: {cudart_version}")
138
+
139
+ # collection cuda library info from current environment.
140
+ from onnxruntime.capi.onnxruntime_collect_build_info import find_cudart_versions # noqa: PLC0415
141
+
142
+ local_cudart_versions = find_cudart_versions(build_env=False, build_cuda_version=cuda_version)
143
+ if cudart_version and local_cudart_versions and cudart_version not in local_cudart_versions:
144
+ print_build_package_info()
145
+ warnings.warn("WARNING: failed to find cudart version that matches onnxruntime build info")
146
+ warnings.warn(f"WARNING: found cudart versions: {local_cudart_versions}")
147
+ except Exception as e:
148
+ warnings.warn("WARNING: failed to collect onnxruntime version and build info")
149
+ print(e)
150
+
151
+ if import_ortmodule_exception:
152
+ raise import_ortmodule_exception
153
+
154
+ return has_ortmodule, package_name, version, cuda_version
onnxruntime/capi/openvino.dll ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:7040243fc8037d65482f974ae2dd1a99394b4fa522e1be05616ef5881f8737ec
3
+ size 16048120
onnxruntime/capi/openvino_auto_batch_plugin.dll ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:db26036e4f1335f5ed7b9da3e334f159dc28b79496c2e8cdfe0455fa04121c72
3
+ size 317944