First examples with onnxruntime

Example First examples with onnx-array-api defines a custom loss and then executes it with class onnx.reference.ReferenceEvaluator. Next example replaces it with onnxruntime.

Example

import numpy as np

from onnx_array_api.npx import absolute, jit_onnx
from onnx_array_api.ort.ort_tensors import JitOrtTensor, OrtTensor


def l1_loss(x, y):
    return absolute(x - y).sum()


def l2_loss(x, y):
    return ((x - y) ** 2).sum()


def myloss(x, y):
    l1 = l1_loss(x[:, 0], y[:, 0])
    l2 = l2_loss(x[:, 1], y[:, 1])
    return l1 + l2


ort_myloss = jit_onnx(myloss, JitOrtTensor, target_opsets={"": 17}, ir_version=8)

x = np.array([[0.1, 0.2], [0.3, 0.4]], dtype=np.float32)
y = np.array([[0.11, 0.22], [0.33, 0.44]], dtype=np.float32)

xort = OrtTensor.from_array(x)
yort = OrtTensor.from_array(y)

res = ort_myloss(xort, yort)
print(res.numpy())
0.042

Profiling

from onnx_array_api.profiling import profile, profile2graph

x = np.random.randn(10000, 2).astype(np.float32)
y = np.random.randn(10000, 2).astype(np.float32)
xort = OrtTensor.from_array(x)
yort = OrtTensor.from_array(y)


def loop_ort(n):
    for _ in range(n):
        ort_myloss(xort, yort)


def loop_numpy(n):
    for _ in range(n):
        myloss(x, y)


def loop(n=1000):
    loop_numpy(n)
    loop_ort(n)


ps = profile(loop)[0]
root, nodes = profile2graph(ps, clean_text=lambda x: x.split("/")[-1])
text = root.to_text()
print(text)
var                                                          --    2000    2000 -- 0.00304 0.02256 -- npx_core_api.py:54:var (var)
    __init__                                                 --    2000    2000 -- 0.01280 0.01952 -- npx_var.py:287:__init__ (__init__) +++
get_cst_var                                                  --    2000    2000 -- 0.00300 0.00494 -- npx_var.py:216:get_cst_var (get_cst_var)
    parent                                                   --    2000    2000 -- 0.00115 0.00194 -- <frozen importlib._bootstrap>:645:parent (parent)
        <method 'rpartition' of 'str' objects>               --    2000    2000 -- 0.00078 0.00078 -- ~:0:<method 'rpartition' of 'str' objects> (<method 'rpartition' of 'str' objects>)
__init__                                                     --    3000    3000 -- 0.02129 0.03181 -- npx_var.py:287:__init__ (__init__)
    __init__                                                 --    3000    3000 -- 0.00080 0.00080 -- npx_var.py:281:__init__ (__init__)
    self_var                                                 --    2000    2000 -- 0.00067 0.00100 -- npx_var.py:375:self_var (self_var) +++
    <method 'items' of 'dict' objects>                       --    3000    3000 -- 0.00067 0.00067 -- ~:0:<method 'items' of 'dict' objects> (<method 'items' of 'dict' objects>) +++
    <built-in method builtins.hasattr>                       --    3000    3000 -- 0.00056 0.00056 -- ~:0:<built-in method builtins.hasattr> (<built-in method builtins.hasattr>) +++
    <built-in method builtins.isinstance>                    --   23000   23000 -- 0.00587 0.00587 -- ~:0:<built-in method builtins.isinstance> (<built-in method builtins.isinstance>) +++
    <built-in method builtins.len>                           --    6000    6000 -- 0.00117 0.00117 -- ~:0:<built-in method builtins.len> (<built-in method builtins.len>) +++
    <method 'ravel' of 'numpy.ndarray' objects>              --    1000    1000 -- 0.00046 0.00046 -- ~:0:<method 'ravel' of 'numpy.ndarray' objects> (<method 'ravel' of 'numpy.ndarray' objects>)
self_var                                                     --    4000    4000 -- 0.00139 0.00211 -- npx_var.py:375:self_var (self_var)
    <built-in method builtins.hasattr>                       --    4000    4000 -- 0.00072 0.00072 -- ~:0:<built-in method builtins.hasattr> (<built-in method builtins.hasattr>) +++
loop_numpy                                                   --       1       1 -- 0.00043 0.09823 -- plot_onnxruntime.py:61:loop_numpy (loop_numpy)
    myloss                                                   --    1000    1000 -- 0.00299 0.09780 -- plot_onnxruntime.py:28:myloss (myloss)
        __add__                                              --    1000    1000 -- 0.00064 0.01949 -- npx_var.py:645:__add__ (__add__)
            _binary_op                                       --    1000    1000 -- 0.00256 0.01885 -- npx_var.py:615:_binary_op (_binary_op)
                var                                          --    1000    1000 -- 0.00184 0.01280 -- npx_core_api.py:54:var (var) +++
                get_cst_var                                  --    1000    1000 -- 0.00147 0.00249 -- npx_var.py:216:get_cst_var (get_cst_var) +++
                self_var                                     --    1000    1000 -- 0.00036 0.00055 -- npx_var.py:375:self_var (self_var) +++
                <built-in method builtins.isinstance>        --    1000    1000 -- 0.00045 0.00045 -- ~:0:<built-in method builtins.isinstance> (<built-in method builtins.isinstance>) +++
        l1_loss                                              --    1000    1000 -- 0.00972 0.05069 -- plot_onnxruntime.py:20:l1_loss (l1_loss)
            wrapper                                          --    1000    1000 -- 0.00902 0.02593 -- npx_core_api.py:142:wrapper (wrapper)
                annotation                                   --    1000    1000 -- 0.00013 0.00013 -- inspect.py:2773:annotation (annotation)
                kind                                         --    2000    2000 -- 0.00025 0.00025 -- inspect.py:2777:kind (kind)
                parameters                                   --    2000    2000 -- 0.00028 0.00028 -- inspect.py:3058:parameters (parameters)
                return_annotation                            --    1000    1000 -- 0.00013 0.00013 -- inspect.py:3062:return_annotation (return_annotation)
                __init__                                     --    1000    1000 -- 0.00849 0.01229 -- npx_var.py:287:__init__ (__init__) +++
                <method 'items' of 'mappingproxy' objects>   --    1000    1000 -- 0.00038 0.00038 -- ~:0:<method 'items' of 'mappingproxy' objects> (<method 'items' of 'mappingproxy' objects>)
                <method 'append' of 'list' objects>          --    1000    1000 -- 0.00028 0.00028 -- ~:0:<method 'append' of 'list' objects> (<method 'append' of 'list' objects>) +++
                <method 'items' of 'dict' objects>           --    1000    1000 -- 0.00023 0.00023 -- ~:0:<method 'items' of 'dict' objects> (<method 'items' of 'dict' objects>) +++
                <built-in method builtins.any>               --    1000    1000 -- 0.00094 0.00184 -- ~:0:<built-in method builtins.any> (<built-in method builtins.any>)
                    <genexpr>                                --    2000    2000 -- 0.00066 0.00089 -- npx_core_api.py:143:<genexpr> (<genexpr>)
                        <built-in method ...tins.isinstance> --    1000    1000 -- 0.00024 0.00024 -- ~:0:<built-in method builtins.isinstance> (<built-in method builtins.isinstance>) +++
                <built-in method builtins.isinstance>        --    2000    2000 -- 0.00042 0.00042 -- ~:0:<built-in method builtins.isinstance> (<built-in method builtins.isinstance>) +++
                <built-in method builtins.issubclass>        --    2000    2000 -- 0.00047 0.00047 -- ~:0:<built-in method builtins.issubclass> (<built-in method builtins.issubclass>) +++
                <built-in method builtins.len>               --    1000    1000 -- 0.00019 0.00019 -- ~:0:<built-in method builtins.len> (<built-in method builtins.len>) +++
            sum                                              --    1000    1000 -- 0.00062 0.01504 -- npx_var.py:890:sum (sum)
                reduce_function                              --    1000    1000 -- 0.00166 0.01442 -- npx_var.py:871:reduce_function (reduce_function)
                    var                                      --    1000    1000 -- 0.00120 0.00976 -- npx_core_api.py:54:var (var) +++
                    get_cst_var                              --    1000    1000 -- 0.00153 0.00244 -- npx_var.py:216:get_cst_var (get_cst_var) +++
                    self_var                                 --    1000    1000 -- 0.00037 0.00056 -- npx_var.py:375:self_var (self_var) +++
        l2_loss                                              --    1000    1000 -- 0.01685 0.02464 -- plot_onnxruntime.py:24:l2_loss (l2_loss)
            <method 'sum' of 'numpy.ndarray' objects>        --    1000    1000 -- 0.00082 0.00779 -- ~:0:<method 'sum' of 'numpy.ndarray' objects> (<method 'sum' of 'numpy.ndarray' objects>)
                _sum                                         --    1000    1000 -- 0.00061 0.00696 -- _methods.py:49:_sum (_sum)
                    <method 'reduce' of...py.ufunc' objects> --    1000    1000 -- 0.00635 0.00635 -- ~:0:<method 'reduce' of 'numpy.ufunc' objects> (<method 'reduce' of 'numpy.ufunc' objects>) +++
<built-in method builtins.isinstance>                        --   59000   59000 -- 0.01767 0.01767 -- ~:0:<built-in method builtins.isinstance> (<built-in method builtins.isinstance>)
<method 'append' of 'list' objects>                          --   13000   13000 -- 0.00433 0.00433 -- ~:0:<method 'append' of 'list' objects> (<method 'append' of 'list' objects>)
<method 'items' of 'dict' objects>                           --   16000   16000 -- 0.00505 0.00505 -- ~:0:<method 'items' of 'dict' objects> (<method 'items' of 'dict' objects>)
<built-in method builtins.issubclass>                        --   38000   38000 -- 0.01102 0.01102 -- ~:0:<built-in method builtins.issubclass> (<built-in method builtins.issubclass>)
<built-in method builtins.len>                               --  576000  576000 -- 0.07698 0.07698 -- ~:0:<built-in method builtins.len> (<built-in method builtins.len>)
<built-in method builtins.hasattr>                           --    7000    7000 -- 0.00128 0.00128 -- ~:0:<built-in method builtins.hasattr> (<built-in method builtins.hasattr>)
<method 'reduce' of 'numpy.ufunc' objects>                   --    9000    9000 -- 0.04297 0.04297 -- ~:0:<method 'reduce' of 'numpy.ufunc' objects> (<method 'reduce' of 'numpy.ufunc' objects>)

Benchmark

from pandas import DataFrame
from tqdm import tqdm

from onnx_array_api.ext_test_case import measure_time

data = []
for n in tqdm([1, 10, 100, 1000, 10000, 100000]):
    x = np.random.randn(n, 2).astype(np.float32)
    y = np.random.randn(n, 2).astype(np.float32)

    obs = measure_time(lambda x=x, y=y: myloss(x, y))
    obs["name"] = "numpy"
    obs["n"] = n
    data.append(obs)

    xort = OrtTensor.from_array(x)
    yort = OrtTensor.from_array(y)
    obs = measure_time(lambda xort=xort, yort=yort: ort_myloss(xort, yort))
    obs["name"] = "ort"
    obs["n"] = n
    data.append(obs)

df = DataFrame(data)
piv = df.pivot(index="n", columns="name", values="average")
piv
  0%|          | 0/6 [00:00<?, ?it/s]
 17%|█▋        | 1/6 [00:00<00:02,  1.75it/s]
 33%|███▎      | 2/6 [00:01<00:02,  1.41it/s]
 50%|█████     | 3/6 [00:04<00:05,  1.69s/it]
 67%|██████▋   | 4/6 [00:04<00:02,  1.32s/it]
 83%|████████▎ | 5/6 [00:05<00:01,  1.17s/it]
100%|██████████| 6/6 [00:07<00:00,  1.16s/it]
100%|██████████| 6/6 [00:07<00:00,  1.17s/it]
name numpy ort
n
1 0.000040 0.001098
10 0.000019 0.001588
100 0.000018 0.005695
1000 0.000025 0.001465
10000 0.000042 0.001741
100000 0.000500 0.001766


Plots

import matplotlib.pyplot as plt

fig, ax = plt.subplots(1, 2, figsize=(12, 4))
piv.plot(
    title="Comparison between numpy and onnxruntime", logx=True, logy=True, ax=ax[0]
)
piv["ort/numpy"] = piv["ort"] / piv["numpy"]
piv["ort/numpy"].plot(title="Ratio ort/numpy", logx=True, ax=ax[1])
fig.savefig("plot_onnxruntime.png")
Comparison between numpy and onnxruntime, Ratio ort/numpy

Total running time of the script: (0 minutes 14.385 seconds)

Gallery generated by Sphinx-Gallery