Black list operators when converting

Some runtimes do not implement a runtime for every available operator in ONNX. The converter does not know that but it is possible to black some operators. Most of the converters do not change their behaviour, they fail if they use a black listed operator, a couple of them produces a different ONNX graph.

GaussianMixture

The first converter to change its behaviour depending on a black list of operators is for model GaussianMixture.

from pyquickhelper.helpgen.graphviz_helper import plot_graphviz
from mlprodict.onnxrt import OnnxInference
from timeit import timeit
import numpy
from onnxruntime import InferenceSession
from sklearn.mixture import GaussianMixture
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from skl2onnx import to_onnx

TARGET_OPSET = 12

data = load_iris()
X_train, X_test = train_test_split(data.data)
model = GaussianMixture()
model.fit(X_train)

Out:

GaussianMixture()

Default conversion

model_onnx = to_onnx(
    model, X_train[:1].astype(numpy.float32),
    options={id(model): {'score_samples': True}},
    target_opset=TARGET_OPSET)
sess = InferenceSession(model_onnx.SerializeToString(),
                        providers=['CPUExecutionProvider'])

xt = X_test[:5].astype(numpy.float32)
print(model.score_samples(xt))
print(sess.run(None, {'X': xt})[2])

Out:

[-3.47700937 -1.76353421 -2.07677071 -2.11023566 -2.16489785]
[[-3.4770093]
 [-1.7635326]
 [-2.0767717]
 [-2.1102371]
 [-2.164897 ]]

Display the ONNX graph.

oinf = OnnxInference(model_onnx)
ax = plot_graphviz(oinf.to_dot())
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
plot dbegin options list

Conversion without ReduceLogSumExp

Parameter black_op is used to tell the converter not to use this operator. Let’s see what the converter produces in that case.

model_onnx2 = to_onnx(
    model, X_train[:1].astype(numpy.float32),
    options={id(model): {'score_samples': True}},
    black_op={'ReduceLogSumExp'},
    target_opset=TARGET_OPSET)
sess2 = InferenceSession(model_onnx2.SerializeToString(),
                         providers=['CPUExecutionProvider'])

xt = X_test[:5].astype(numpy.float32)
print(model.score_samples(xt))
print(sess2.run(None, {'X': xt})[2])

Out:

[-3.47700937 -1.76353421 -2.07677071 -2.11023566 -2.16489785]
[[-3.4770093]
 [-1.7635326]
 [-2.0767717]
 [-2.1102371]
 [-2.164897 ]]

Display the ONNX graph.

oinf = OnnxInference(model_onnx2)
ax = plot_graphviz(oinf.to_dot())
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
plot dbegin options list

Processing time

print(timeit(stmt="sess.run(None, {'X': xt})",
             number=10000, globals={'sess': sess, 'xt': xt}))

print(timeit(stmt="sess2.run(None, {'X': xt})",
             number=10000, globals={'sess2': sess2, 'xt': xt}))

Out:

1.3438124852254987
1.6173968352377415

The model using ReduceLogSumExp is much faster.

If the converter cannot convert without…

Many converters do not consider the white and black lists of operators. If a converter fails to convert without using a blacklisted operator (or only whitelisted operators), skl2onnx raises an error.

try:
    to_onnx(
        model, X_train[:1].astype(numpy.float32),
        options={id(model): {'score_samples': True}},
        black_op={'ReduceLogSumExp', 'Add'},
        target_opset=TARGET_OPSET)
except RuntimeError as e:
    print('Error:', e)

Out:

Error: Operator 'Add' is black listed.

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

Gallery generated by Sphinx-Gallery