Examples

  1. Computes predictions with any runtime

  2. Convert ONNX into DOT

  3. Convert ONNX into JSON

  4. Convert ONNX into graph

  5. Convert a function into ONNX code

  6. Convert a function into ONNX code and run

  7. Converts an array into bytes (serialization)

  8. Converts bytes into an array (serialization)

  9. Extract information from a model

  10. Get the tree of a simple function

  11. Plot benchmark improvments

  12. Run a model with runtime 'python_compiled'

Computes predictions with any runtime

The following example compares predictions between scikit-learn and this runtime for the python runtime.

<<<

import numpy
from sklearn.linear_model import LinearRegression
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from mlprodict.onnxrt import OnnxInference
from mlprodict.onnx_conv import to_onnx

iris = load_iris()
X, y = iris.data, iris.target
X_train, X_test, y_train, _ = train_test_split(X, y)
clr = LinearRegression()
clr.fit(X_train, y_train)

exp = clr.predict(X_test[:5])
print(exp)

model_def = to_onnx(clr, X_train.astype(numpy.float32),
                    target_opset=12)
oinf = OnnxInference(model_def)
y = oinf.run({'X': X_test[:5]})
print(y)

>>>

    [ 1.612  1.768 -0.066  2.274  1.932]
    {'variable': array([[ 1.612],
           [ 1.768],
           [-0.066],
           [ 2.274],
           [ 1.932]])}

(original entry : onnx_inference.py:docstring of mlprodict.onnxrt.onnx_inference.OnnxInference.run, line 17)

Convert ONNX into DOT

An example on how to convert an ONNX graph into DOT.

<<<

import numpy
from skl2onnx.algebra.onnx_ops import OnnxLinearRegressor
from skl2onnx.common.data_types import FloatTensorType
from mlprodict.onnxrt import OnnxInference

pars = dict(coefficients=numpy.array([1., 2.]),
            intercepts=numpy.array([1.]),
            post_transform='NONE')
onx = OnnxLinearRegressor('X', output_names=['Y'], **pars)
model_def = onx.to_onnx({'X': pars['coefficients'].astype(numpy.float32)},
                        outputs=[('Y', FloatTensorType([1]))],
                        target_opset=12)
oinf = OnnxInference(model_def)
print(oinf.to_dot())

>>>

    digraph{
      ranksep=0.25;
      orientation=portrait;
      nodesep=0.05;
    
      X [shape=box color=red label="X\nfloat((0,))" fontsize=10];
    
      Y [shape=box color=green label="Y\nfloat((1,))" fontsize=10];
    
    
      Li_LinearRegressor [shape=box style="filled,rounded" color=orange label="LinearRegressor\n(Li_LinearRegressor)\ncoefficients=[1. 2.]\nintercepts=[1.]\npost_transform=b'NONE'" fontsize=10];
      X -> Li_LinearRegressor;
      Li_LinearRegressor -> Y;
    }

See an example of representation in notebook ONNX visualization.

(original entry : onnx_inference_exports.py:docstring of mlprodict.onnxrt.onnx_inference_exports.OnnxInferenceExport.to_dot, line 24)

Convert ONNX into JSON

An example on how to convert an ONNX graph into JSON.

<<<

import numpy
from skl2onnx.algebra.onnx_ops import OnnxLinearRegressor
from skl2onnx.common.data_types import FloatTensorType
from mlprodict.onnxrt import OnnxInference

pars = dict(coefficients=numpy.array([1., 2.]),
            intercepts=numpy.array([1.]),
            post_transform='NONE')
onx = OnnxLinearRegressor('X', output_names=['Y'], **pars)
model_def = onx.to_onnx({'X': pars['coefficients'].astype(numpy.float32)},
                        outputs=[('Y', FloatTensorType([1]))],
                        target_opset=12)
oinf = OnnxInference(model_def)
print(oinf.to_json())

>>>

    {
      "doc_string": "",
      "model_version": 0,
      "producer_version": "1.7.1092",
      "producer_name": "skl2onnx",
      "ir_version": 6,
      "domain": "ai.onnx",
      "inputs": [
        {
          "name": "X",
          "type": {
            "tensor_type": {
              "elem_type": 1,
              "shape": {
                "dim": {}
              }
            }
          }
        }
      ],
      "outputs": [
        {
          "name": "Y",
          "type": {
            "tensor_type": {
              "elem_type": 1,
              "shape": {
                "dim": {
                  "dim_value": 1
                }
              }
            }
          }
        }
      ],
      "initializers": {},
      "nodes": [
        {
          "name": "Li_LinearRegressor",
          "op_type": "LinearRegressor",
          "domain": "ai.onnx.ml",
          "inputs": [
            "X"
          ],
          "outputs": [
            "Y"
          ],
          "attributes": {
            "coefficients": {
              "t": {
                "dims": 2,
                "data_type": 11,
                "name": "coefficients",
                "double_data": 2.0
              },
              "type": "TENSOR"
            },
            "intercepts": {
              "t": {
                "dims": 1,
                "data_type": 11,
                "name": "intercepts",
                "double_data": 1.0
              },
              "type": "TENSOR"
            },
            "post_transform": {
              "s": "NONE",
              "type": "STRING"
            }
          }
        }
      ]
    }

(original entry : onnx_inference_exports.py:docstring of mlprodict.onnxrt.onnx_inference_exports.OnnxInferenceExport.to_json, line 6)

Convert ONNX into graph

An example on how to convert an ONNX graph into a graph.

<<<

import pprint
import numpy
from skl2onnx.algebra.onnx_ops import OnnxLinearRegressor
from skl2onnx.common.data_types import FloatTensorType
from mlprodict.onnxrt import OnnxInference

pars = dict(coefficients=numpy.array([1., 2.]),
            intercepts=numpy.array([1.]),
            post_transform='NONE')
onx = OnnxLinearRegressor('X', output_names=['Y'], **pars)
model_def = onx.to_onnx({'X': pars['coefficients'].astype(numpy.float32)},
                        outputs=[('Y', FloatTensorType([1]))],
                        target_opset=12)
oinf = OnnxInference(model_def)
pprint.pprint(oinf.to_sequence())

>>>

    {'inits': {},
     'inputs': {'X': {'name': 'X',
                      'type': {'elem': 'float', 'kind': 'tensor', 'shape': (0,)}}},
     'intermediate': {'Y': None},
     'ir_version': 6,
     'nodes': {'Li_LinearRegressor': Onnx-LinearRegressor(X) -> Y},
     'outputs': {'Y': {'name': 'Y',
                       'type': {'elem': 'float', 'kind': 'tensor', 'shape': (1,)}}},
     'sequence': [Onnx-LinearRegressor(X) -> Y],
     'targets': {'ai.onnx.ml': 1}}

See an example of representation in notebook ONNX visualization.

(original entry : onnx_inference.py:docstring of mlprodict.onnxrt.onnx_inference.OnnxInference.to_sequence, line 5)

Convert a function into ONNX code

The following code parses a python function and returns another python function which produces an ONNX graph if executed.

<<<

import numpy
from mlprodict.onnx_grammar import translate_fct2onnx


def trs(x, y):
    z = x + numpy.transpose(y, axes=[1, 0])
    return x * z


onnx_code = translate_fct2onnx(
    trs, context={'numpy.transpose': numpy.transpose})
print(onnx_code)

>>>

    def trs(x, y, dtype=numpy.float32, op_version=None):
        z = (
            OnnxAdd(
                x,
                OnnxTranspose(
                    y,
                    perm=[1, 0],
                    op_version=op_version
                ),
                op_version=op_version
            )
        )
        return (
            OnnxMul(
                x,
                z,
                op_version=op_version
            )
        )

(original entry : onnx_translation.py:docstring of mlprodict.onnx_grammar.onnx_translation.translate_fct2onnx, line 23)

Convert a function into ONNX code and run

The following code parses a python function and returns another python function which produces an ONNX graph if executed. The example executes the function, creates an ONNX then uses OnnxInference to compute predictions. Finally it compares them to the original.

<<<

import numpy
from mlprodict.onnx_grammar import translate_fct2onnx
from mlprodict.onnxrt import OnnxInference
from skl2onnx.algebra.onnx_ops import (
    OnnxAdd, OnnxTranspose, OnnxMul, OnnxIdentity
)

ctx = {'OnnxAdd': OnnxAdd,
       'OnnxTranspose': OnnxTranspose,
       'OnnxMul': OnnxMul,
       'OnnxIdentity': OnnxIdentity}


def trs(x, y):
    z = x + numpy.transpose(y, axes=[1, 0])
    return x * z


inputs = {'x': numpy.array([[1, 2]], dtype=numpy.float32),
          'y': numpy.array([[-0.3, 0.4]], dtype=numpy.float32).T}

original = trs(inputs['x'], inputs['y'])

print('original output:', original)

onnx_fct = translate_fct2onnx(
    trs, context={'numpy.transpose': numpy.transpose},
    cpl=True, context_cpl=ctx, output_names=['Z'])

onnx_code = onnx_fct('x', 'y', opset_version=12)
print('ONNX code:', onnx_code)

onnx_g = onnx_code.to_onnx(inputs, target_opset=12)

oinf = OnnxInference(onnx_g)
res = oinf.run(inputs)

print("ONNX inference:", res['Z'])
print("ONNX graph:", onnx_g)

>>>

    original output: [[0.7 4.8]]
    [runpythonerror]
    Traceback (most recent call last):
      File "fct2onnx3.py", line 36, in <module>
        onnx_code = onnx_fct('x', 'y', opset_version=12)
    TypeError: trs() got an unexpected keyword argument 'opset_version'

(original entry : onnx_translation.py:docstring of mlprodict.onnx_grammar.onnx_translation.translate_fct2onnx, line 48)

Converts an array into bytes (serialization)

Useful to serialize.

<<<

import numpy
from mlprodict.onnxrt.onnx2py_helper import to_bytes

data = numpy.array([[0, 1], [2, 3], [4, 5]], dtype=numpy.float32)
pb = to_bytes(data)
print(len(pb), data.size * data.itemsize, pb[:10])

>>>

    32 24 b'\x08\x03\x08\x02\x10\x01J\x18\x00\x00'

(original entry : onnx2py_helper.py:docstring of mlprodict.onnxrt.onnx2py_helper.to_bytes, line 6)

Converts bytes into an array (serialization)

Useful to deserialize.

<<<

import numpy
from mlprodict.onnxrt.onnx2py_helper import to_bytes, from_bytes

data = numpy.array([[0, 1], [2, 3], [4, 5]], dtype=numpy.float32)
pb = to_bytes(data)
data2 = from_bytes(pb)
print(data2)

>>>

    [[0. 1.]
     [2. 3.]
     [4. 5.]]

(original entry : onnx2py_helper.py:docstring of mlprodict.onnxrt.onnx2py_helper.from_bytes, line 6)

Extract information from a model

The function analyze_model extracts global figures about a model, whatever it is.

<<<

import pprint
from sklearn.datasets import load_iris
from sklearn.ensemble import RandomForestClassifier
from mlprodict.tools.model_info import analyze_model

data = load_iris()
X, y = data.data, data.target
model = RandomForestClassifier().fit(X, y)
infos = analyze_model(model)
pprint.pprint(infos)

>>>

    {'classes_.shape': 3,
     'estimators_.classes_.shape': 3,
     'estimators_.max|tree_.max_depth': 9,
     'estimators_.n_classes_': 3,
     'estimators_.n_features_': 4,
     'estimators_.size': 100,
     'estimators_.sum|tree_.leave_count': 882,
     'estimators_.sum|tree_.node_count': 1664,
     'n_classes_': 3,
     'n_features_': 4}

(original entry : model_info.py:docstring of mlprodict.tools.model_info.analyze_model, line 8)

Get the tree of a simple function

The following code uses Python syntax but follows a SQL logic.

<<<

import ast
import inspect
from textwrap import dedent
from mlprodict.onnx_grammar import CodeNodeVisitor


def norm2(x, y):
    delta = x - y
    n = delta ** 2
    return n


code = dedent(inspect.getsource(norm2))
node = ast.parse(code)
v = CodeNodeVisitor()
v.visit(node)
for r in v.Rows:
    print("{0}{1}: {2}".format("    " * r["indent"], r["type"], r["str"]))

>>>

    Module: 
        FunctionDef: norm2
            arguments: 
                arg: x
                arg: y
            Assign: 
                Name: delta
                BinOp: 
                    Name: x
                    Sub: 
                    Name: y
            Assign: 
                Name: n
                BinOp: 
                    Name: delta
                    Pow: 
                    Num: 2
            Return: 
                Name: n

(original entry : node_visitor_translator.py:docstring of mlprodict.onnx_grammar.node_visitor_translator.CodeNodeVisitor, line 3)

Plot benchmark improvments

System Message: WARNING/2 (somewhere/workspace/mlprodict/mlprodict_UT_37_std/_doc/sphinxdoc/source/mlprodict/plotting/plotting_benchmark.py:docstring of mlprodict.plotting.plotting_benchmark.plot_benchmark_metrics, line 22)

Exception occurred in plotting plotting_benchmark-1 from somewhere/workspace/mlprodict/mlprodict_UT_37_std/_doc/sphinxdoc/source/mlprodict/plotting/plotting_benchmark.rst: Traceback (most recent call last): File “/usr/local/lib/python3.7/site-packages/matplotlib/sphinxext/plot_directive.py”, line 472, in run_code exec(code, ns) File “<string>”, line 2, in <module> ModuleNotFoundError: No module named ‘mlprodict.tools.plotting’

import matplotlib.pyplot as plt
from mlprodict.tools.plotting import plot_benchmark_metrics

data = {(1, 1): 0.1, (10, 1): 1, (1, 10): 2,
        (10, 10): 100, (100, 1): 100, (100, 10): 1000}

fig, ax = plt.subplots(1, 2, figsize=(10, 4))
plot_benchmark_metrics(data, ax=ax[0], cbar_kw={'shrink': 0.6})
plot_benchmark_metrics(data, ax=ax[1], transpose=True,
                       xlabel='X', ylabel='Y',
                       cbarlabel="ratio")
plt.show()

(original entry : plotting_benchmark.py:docstring of mlprodict.plotting.plotting_benchmark.plot_benchmark_metrics, line 18)

Run a model with runtime ‘python_compiled’

The following code trains a model and compute the predictions with runtime 'python_compiled'. It converts the onnx graph into a python function which calls every operator. Its code is printed below.

<<<

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.ensemble import AdaBoostClassifier
from sklearn.tree import DecisionTreeClassifier
from skl2onnx import to_onnx
from mlprodict.onnxrt import OnnxInference

iris = load_iris()
X, y = iris.data, iris.target
X_train, X_test, y_train, __ = train_test_split(X, y, random_state=11)
y_train = y_train.astype(numpy.float32)
clr = AdaBoostClassifier(
    base_estimator=DecisionTreeClassifier(max_depth=3),
    n_estimators=3)
clr.fit(X_train, y_train)

model_def = to_onnx(clr, X_train.astype(numpy.float32),
                    target_opset=12)

oinf2 = OnnxInference(model_def, runtime='python_compiled')
print(oinf2.run({'X': X_test[:5]}))

# prints out the python function equivalent
# to the onnx graph
print(oinf2)

>>>

    {'output_label': array([2, 2, 1, 1, 2]), 'output_probability': []}
    OnnxInference(...)
        def compiled_run(dict_inputs):
            # init: classes
            # init: inverted_n_classes
            # init: n_classes_minus_one
            # init: clip_min
            # init: shape_tensor
            # init: mul_operand
            # init: zero_scalar
            # init: shape_tensor3
            # inputs
            X = dict_inputs['X']
            (elab_name_0, eprob_name_0, ) = n0_treeensembleclassifier(X)
            (elab_name_1, eprob_name_1, ) = n1_treeensembleclassifier(X)
            (clipped_proba, ) = n2_clip_11(eprob_name_0, clip_min)
            (log_proba, ) = n3_log(clipped_proba)
            (reduced_proba, ) = n4_reducesum_11(log_proba)
            (reshaped_result, ) = n5_reshape(reduced_proba, shape_tensor)
            (prod_result, ) = n6_mul(reshaped_result, inverted_n_classes)
            (sub_result, ) = n7_sub(log_proba, prod_result)
            (samme_proba, ) = n8_mul(sub_result, n_classes_minus_one)
            (clipped_proba1, ) = n9_clip_11(eprob_name_1, clip_min)
            (log_proba1, ) = n10_log(clipped_proba1)
            (reduced_proba1, ) = n11_reducesum_11(log_proba1)
            (reshaped_result1, ) = n12_reshape(reduced_proba1, shape_tensor)
            (prod_result1, ) = n13_mul(reshaped_result1, inverted_n_classes)
            (sub_result1, ) = n14_sub(log_proba1, prod_result1)
            (samme_proba1, ) = n15_mul(sub_result1, n_classes_minus_one)
            (summation_prob, ) = n16_sum(samme_proba, samme_proba1)
            (div_result, ) = n17_div(summation_prob, n_classes_minus_one)
            (exp_operand, ) = n18_mul(div_result, mul_operand)
            (exp_result, ) = n19_exp(exp_operand)
            (reduced_exp_result, ) = n20_reducesum_11(exp_result)
            (normaliser, ) = n21_reshape(reduced_exp_result, shape_tensor)
            (cast_normaliser, ) = n22_cast(normaliser)
            (comparison_result, ) = n23_equal(cast_normaliser, zero_scalar)
            (cast_output, ) = n24_cast(comparison_result)
            (zero_filtered_normaliser, ) = n25_add(normaliser, cast_output)
            (probabilities, ) = n26_div(exp_result, zero_filtered_normaliser)
            (argmax_output, ) = n27_argmax_12(probabilities)
            (array_feature_extractor_result, ) = n28_arrayfeatureextractor(classes, argmax_output)
            (reshaped_result2, ) = n29_reshape(array_feature_extractor_result, shape_tensor3)
            (label, ) = n30_cast(reshaped_result2)
            (output_label, ) = n31_cast(label)
            (output_probability, ) = n32_zipmap(probabilities)
            return {
                'output_label': output_label,
                'output_probability': output_probability,
            }

(original entry : onnx_inference.py:docstring of mlprodict.onnxrt.onnx_inference.OnnxInference._build_compile_run, line 7)