diff --git a/_unittests/ut__skl2onnx/test_sklearn_gaussian_mixture_converter.py b/_unittests/ut__skl2onnx/test_sklearn_gaussian_mixture_converter.py index 1a30c1b5a..f0f626dd5 100644 --- a/_unittests/ut__skl2onnx/test_sklearn_gaussian_mixture_converter.py +++ b/_unittests/ut__skl2onnx/test_sklearn_gaussian_mixture_converter.py @@ -8,7 +8,7 @@ from sklearn.mixture import GaussianMixture, BayesianGaussianMixture from skl2onnx import convert_sklearn, to_onnx from skl2onnx.common.data_types import FloatTensorType -from mlprodict.tools.ort_wrapper import OrtFail +from onnxruntime.capi._pybind_state import Fail as OrtFail # pylint: disable=E0611 from mlprodict.tools.ort_wrapper import InferenceSession from mlprodict.testing.test_utils import dump_data_and_model from mlprodict import __max_supported_opset__ as TARGET_OPSET diff --git a/_unittests/ut_documentation/test_run_notebooks_onnx_numpy.py b/_unittests/ut_documentation/test_run_notebooks_onnx_numpy.py index c6ddb8137..e4bc69d60 100644 --- a/_unittests/ut_documentation/test_run_notebooks_onnx_numpy.py +++ b/_unittests/ut_documentation/test_run_notebooks_onnx_numpy.py @@ -14,9 +14,9 @@ from pyquickhelper.ipythonhelper import test_notebook_execution_coverage from pyquickhelper.pycode import ( add_missing_development_version, ExtTestCase) +from onnxruntime import __version__ as ort_version from skl2onnx import __version__ as skl2onnx_version import mlprodict -from mlprodict.tools.ort_wrapper import onnxrt_version as ort_version class TestNotebookNumpyOnnx(ExtTestCase): diff --git a/_unittests/ut_documentation/test_run_notebooks_onnx_sbs.py b/_unittests/ut_documentation/test_run_notebooks_onnx_sbs.py index 2423276e4..9b058aa2c 100644 --- a/_unittests/ut_documentation/test_run_notebooks_onnx_sbs.py +++ b/_unittests/ut_documentation/test_run_notebooks_onnx_sbs.py @@ -15,8 +15,8 @@ from pyquickhelper.pycode import ( add_missing_development_version, ExtTestCase) from skl2onnx import __version__ as skl2onnx_version +from onnxruntime import __version__ as ort_version import mlprodict -from mlprodict.tools.ort_wrapper import onnxrt_version as ort_version class TestNotebookOnnxSbs(ExtTestCase): diff --git a/_unittests/ut_npy/test_a_onnx_variable_ort.py b/_unittests/ut_npy/test_a_onnx_variable_ort.py index b4622b103..3dcb4dc78 100644 --- a/_unittests/ut_npy/test_a_onnx_variable_ort.py +++ b/_unittests/ut_npy/test_a_onnx_variable_ort.py @@ -6,11 +6,12 @@ from typing import Any import numpy from pyquickhelper.pycode import ExtTestCase, ignore_warnings -from mlprodict.tools.ort_wrapper import OrtInvalidArgument +from onnxruntime.capi._pybind_state import ( # pylint: disable=E0611 + InvalidArgument as OrtInvalidArgument) from mlprodict.npy import onnxnumpy, onnxnumpy_np -import mlprodict.npy.numpy_onnx_impl as nxnp from mlprodict.npy import ( OnnxNumpyCompiler as ONC, NDArray, NDArraySameTypeSameShape) +import mlprodict.npy.numpy_onnx_impl as nxnp @ignore_warnings(DeprecationWarning) diff --git a/_unittests/ut_npy/test_a_onnxpy.py b/_unittests/ut_npy/test_a_onnxpy.py index dcf28b9cc..92a13e8a6 100644 --- a/_unittests/ut_npy/test_a_onnxpy.py +++ b/_unittests/ut_npy/test_a_onnxpy.py @@ -6,7 +6,8 @@ from typing import Any import numpy from pyquickhelper.pycode import ExtTestCase -from mlprodict.tools.ort_wrapper import OrtInvalidArgument +from onnxruntime.capi._pybind_state import ( # pylint: disable=E0611 + InvalidArgument as OrtInvalidArgument) from mlprodict.npy import OnnxNumpyCompiler as ONC, NDArray from mlprodict.npy.onnx_variable import OnnxVar from mlprodict.npy.onnx_numpy_annotation import _NDArrayAlias diff --git a/_unittests/ut_npy/test_b_numpy_onnx_pyrt.py b/_unittests/ut_npy/test_b_numpy_onnx_pyrt.py index 0c196890d..30d19895d 100644 --- a/_unittests/ut_npy/test_b_numpy_onnx_pyrt.py +++ b/_unittests/ut_npy/test_b_numpy_onnx_pyrt.py @@ -7,10 +7,10 @@ import scipy.special as sp from pyquickhelper.pycode import ExtTestCase, ignore_warnings from pyquickhelper.texthelper import compare_module_version +from onnxruntime import __version__ as ort_version from mlprodict.onnxrt import OnnxInference from mlprodict.onnxrt.ops_cpu.op_pad import onnx_pad from mlprodict.npy.onnx_version import FctVersion -from mlprodict.tools.ort_wrapper import onnxrt_version as ort_version from mlprodict.plotting.text_plot import onnx_simple_text_plot import mlprodict.npy.numpy_onnx_pyrt as nxnpy diff --git a/_unittests/ut_onnx_conv/test_onnx_conv_knn.py b/_unittests/ut_onnx_conv/test_onnx_conv_knn.py index 171556c78..d21c7cdc4 100644 --- a/_unittests/ut_onnx_conv/test_onnx_conv_knn.py +++ b/_unittests/ut_onnx_conv/test_onnx_conv_knn.py @@ -8,6 +8,8 @@ from pandas import DataFrame from scipy.spatial.distance import cdist as scipy_cdist from pyquickhelper.pycode import ExtTestCase, ignore_warnings as igw +from onnxruntime.capi._pybind_state import ( # pylint: disable=E0611 + InvalidArgument as OrtInvalidArgument) from sklearn.calibration import CalibratedClassifierCV from sklearn.datasets import load_iris, make_regression from sklearn.model_selection import train_test_split @@ -26,7 +28,6 @@ from mlprodict.onnxrt.ops_cpu.op_topk import topk_sorted_implementation from mlprodict import __max_supported_opset__ as TARGET_OPSET, get_ir_version from mlprodict.testing.test_utils import _capture_output -from mlprodict.tools.ort_wrapper import OrtInvalidArgument def old_topk_sorted_implementation(X, k, axis, largest): diff --git a/_unittests/ut_onnxrt/test_bugs_onnxconverter.py b/_unittests/ut_onnxrt/test_bugs_onnxconverter.py index a8bfb9f8d..133043194 100644 --- a/_unittests/ut_onnxrt/test_bugs_onnxconverter.py +++ b/_unittests/ut_onnxrt/test_bugs_onnxconverter.py @@ -14,7 +14,7 @@ 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.onnx_conv import to_onnx from mlprodict.onnxrt import OnnxInference diff --git a/_unittests/ut_onnxrt/test_onnx_helper.py b/_unittests/ut_onnxrt/test_onnx_helper.py index d43de9320..fe5744575 100644 --- a/_unittests/ut_onnxrt/test_onnx_helper.py +++ b/_unittests/ut_onnxrt/test_onnx_helper.py @@ -14,7 +14,6 @@ _numpy_array) from mlprodict.onnxrt.ops_cpu._op_helper import proto2dtype from mlprodict.onnxrt import OnnxInference -from mlprodict.tools.ort_wrapper import OrtInvalidArgument class TestOnnxHelper(ExtTestCase): @@ -39,6 +38,8 @@ def test_conversion_int64(self): @skipif_appveyor("unstable") def test_change_input_first_dimension(self): + from onnxruntime.capi._pybind_state import ( # pylint: disable=E0611 + InvalidArgument as OrtInvalidArgument) iris = load_iris() X, _ = iris.data, iris.target clr = KMeans() diff --git a/_unittests/ut_onnxrt/test_onnx_inference.py b/_unittests/ut_onnxrt/test_onnx_inference.py index 1136c3568..d51c8ae0a 100644 --- a/_unittests/ut_onnxrt/test_onnx_inference.py +++ b/_unittests/ut_onnxrt/test_onnx_inference.py @@ -16,7 +16,6 @@ from mlprodict.onnx_conv import to_onnx from mlprodict.onnxrt import OnnxInference from mlprodict import __max_supported_opset__ as TARGET_OPSET -from mlprodict.tools.ort_wrapper import SessionOptions class TestOnnxInference(ExtTestCase): @@ -53,6 +52,7 @@ def test_onnx_inference_name_confusion(self): @ignore_warnings(DeprecationWarning) def test_onnx_inference_so(self): + from onnxruntime import SessionOptions X = helper.make_tensor_value_info( 'X', TensorProto.FLOAT, [None, 2]) # pylint: disable=E1101 Y = helper.make_tensor_value_info( diff --git a/_unittests/ut_onnxrt/test_onnxrt_iobinding.py b/_unittests/ut_onnxrt/test_onnxrt_iobinding.py index e2f835651..5798d7940 100644 --- a/_unittests/ut_onnxrt/test_onnxrt_iobinding.py +++ b/_unittests/ut_onnxrt/test_onnxrt_iobinding.py @@ -7,15 +7,16 @@ from onnxruntime.capi._pybind_state import ( # pylint: disable=E0611,W0611 OrtDevice as C_OrtDevice, OrtValue as C_OrtValue) from onnxruntime import get_device -from skl2onnx.algebra.onnx_ops import ( # pylint: disable=E0611,W0611 - OnnxAdd) from mlprodict.onnxrt import OnnxInference from mlprodict.tools.onnx_inference_ort_helper import get_ort_device +from mlprodict.npy.xop import loadop from mlprodict import __max_supported_opset__ as TARGET_OPSET DEVICE = "cuda" if get_device().upper() == 'GPU' else 'cpu' +OnnxAdd = loadop('Add') + class TestOnnxrtIOBinding(ExtTestCase): diff --git a/_unittests/ut_onnxrt/test_onnxrt_python_runtime_.py b/_unittests/ut_onnxrt/test_onnxrt_python_runtime_.py index a2b452843..903eba6f4 100644 --- a/_unittests/ut_onnxrt/test_onnxrt_python_runtime_.py +++ b/_unittests/ut_onnxrt/test_onnxrt_python_runtime_.py @@ -106,11 +106,6 @@ from mlprodict.onnxrt.ops_cpu._op_helper import proto2dtype from mlprodict.onnx_tools.onnx2py_helper import ( guess_proto_dtype, _elem_type_as_str) -from mlprodict.tools.data_types import ( - FloatTensorType, Int64TensorType, DoubleTensorType, StringTensorType, - Int32TensorType, BooleanTensorType, UInt8TensorType, - Int16TensorType, Int8TensorType, UInt16TensorType, - UInt32TensorType, UInt64TensorType, Float16TensorType) from mlprodict.testing.test_utils.quantized_tensor import ( QuantizedTensor, QuantizedBiasTensor, test_qlinear_conv) from mlprodict.onnxrt.ops_cpu.op_qlinear_conv_ import ( # pylint: disable=W0611,E0611,E0401 @@ -120,6 +115,12 @@ from mlprodict.plotting.text_plot import onnx_simple_text_plot from mlprodict import __max_supported_opset__ as TARGET_OPSET, get_ir_version +from skl2onnx.common.data_types import ( # pylint: disable=C0412 + FloatTensorType, Int64TensorType, DoubleTensorType, StringTensorType, + Int32TensorType, BooleanTensorType, UInt8TensorType, + Int16TensorType, Int8TensorType, UInt16TensorType, + UInt32TensorType, UInt64TensorType, Float16TensorType) + try: numpy_str = numpy.str_ except ImportError: diff --git a/_unittests/ut_onnxrt/test_onnxrt_side_by_side.py b/_unittests/ut_onnxrt/test_onnxrt_side_by_side.py index 27c7b75e9..68937012d 100644 --- a/_unittests/ut_onnxrt/test_onnxrt_side_by_side.py +++ b/_unittests/ut_onnxrt/test_onnxrt_side_by_side.py @@ -9,6 +9,7 @@ from sklearn.gaussian_process.kernels import RBF, ConstantKernel as CK, Sum from pyquickhelper.pycode import ExtTestCase, ignore_warnings from pyquickhelper.texthelper.version_helper import compare_module_version +from onnxruntime import __version__ as ort_version from skl2onnx.common.data_types import FloatTensorType try: from skl2onnx.operator_converters.gaussian_process import convert_kernel @@ -19,7 +20,6 @@ side_by_side_by_values, merge_results, _side_by_side_by_values_inputs) from mlprodict.testing.test_utils import _capture_output -from mlprodict.tools.ort_wrapper import onnxrt_version as ort_version from mlprodict import __max_supported_opset__ as TARGET_OPSET, get_ir_version diff --git a/_unittests/ut_onnxrt/test_rt_valid_model_gaussian_process_ort.py b/_unittests/ut_onnxrt/test_rt_valid_model_gaussian_process_ort.py index b4be046a6..f91c89501 100644 --- a/_unittests/ut_onnxrt/test_rt_valid_model_gaussian_process_ort.py +++ b/_unittests/ut_onnxrt/test_rt_valid_model_gaussian_process_ort.py @@ -7,6 +7,7 @@ from pyquickhelper.loghelper import fLOG from pyquickhelper.pycode import ExtTestCase, skipif_circleci from pyquickhelper.texthelper.version_helper import compare_module_version +from onnxruntime import __version__ as ort_version from sklearn.exceptions import ConvergenceWarning try: from sklearn.utils._testing import ignore_warnings @@ -18,7 +19,6 @@ from skl2onnx.common.data_types import FloatTensorType from mlprodict.onnxrt.validate import enumerate_validated_operator_opsets from mlprodict.onnxrt import OnnxInference -from mlprodict.tools.ort_wrapper import onnxrt_version as ort_version from mlprodict import __max_supported_opset__ as TARGET_OPSET, get_ir_version diff --git a/_unittests/ut_onnxrt/test_rt_valid_model_gaussian_process_ort2.py b/_unittests/ut_onnxrt/test_rt_valid_model_gaussian_process_ort2.py index 5fa96e3fa..ae45e9b42 100644 --- a/_unittests/ut_onnxrt/test_rt_valid_model_gaussian_process_ort2.py +++ b/_unittests/ut_onnxrt/test_rt_valid_model_gaussian_process_ort2.py @@ -6,6 +6,7 @@ from pyquickhelper.loghelper import fLOG from pyquickhelper.pycode import ExtTestCase, skipif_circleci from pyquickhelper.texthelper.version_helper import compare_module_version +from onnxruntime import __version__ as ort_version from sklearn.exceptions import ConvergenceWarning try: from sklearn.utils._testing import ignore_warnings @@ -13,7 +14,6 @@ from sklearn.utils.testing import ignore_warnings from skl2onnx import __version__ as skl2onnx_version from mlprodict.onnxrt.validate import enumerate_validated_operator_opsets -from mlprodict.tools.ort_wrapper import onnxrt_version as ort_version threshold = "0.4.0" diff --git a/_unittests/ut_plotting/test_plotting.py b/_unittests/ut_plotting/test_plotting.py index 49dcc4539..851f07d85 100644 --- a/_unittests/ut_plotting/test_plotting.py +++ b/_unittests/ut_plotting/test_plotting.py @@ -3,6 +3,7 @@ @brief test log(time=2s) """ import os +import platform import unittest from pyquickhelper.pycode import ExtTestCase, get_temp_folder from mlprodict.plotting.plotting import plot_benchmark_metrics @@ -10,23 +11,24 @@ class TestPlotBenchScatter(ExtTestCase): + @unittest.skipIf(platform.platform() != 'win32' and __name__ != '__main__', + reason="stream not closed by matplotlib") def test_plot_logreg_xtime(self): - from matplotlib import pyplot as plt temp = get_temp_folder(__file__, "temp_plot_benchmark_metrics") img = os.path.join(temp, "plot_bench.png") data = {(1, 1): 0.1, (10, 1): 1, (1, 10): 2, (10, 10): 100, (100, 1): 100, (100, 10): 1000} + import matplotlib.pyplot as plt 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") - # fig = ax[0].get_figure() - fig.savefig(img) if __name__ == "__main__": + fig.savefig(img) + self.assertExists(img) plt.show() plt.close('all') - self.assertExists(img) if __name__ == "__main__": diff --git a/_unittests/ut_sklapi/test_onnx_transformer.py b/_unittests/ut_sklapi/test_onnx_transformer.py index e3f38b73d..1f9dc42c7 100644 --- a/_unittests/ut_sklapi/test_onnx_transformer.py +++ b/_unittests/ut_sklapi/test_onnx_transformer.py @@ -15,7 +15,6 @@ from pyquickhelper.pycode import ExtTestCase, skipif_appveyor, ignore_warnings from mlprodict.sklapi import OnnxTransformer from mlprodict import __max_supported_opset__ as TARGET_OPSET -from mlprodict.tools.ort_wrapper import OrtInvalidArgument class TestOnnxTransformer(ExtTestCase): @@ -110,6 +109,8 @@ def test_pipeline_iris(self): @ignore_warnings(DeprecationWarning) @skipif_appveyor("crashes") def test_pipeline_iris_change_dim(self): + from onnxruntime.capi._pybind_state import ( # pylint: disable=E0611 + InvalidArgument as OrtInvalidArgument) iris = load_iris() X, y = iris.data, iris.target pipe = make_pipeline(PCA(n_components=2), LogisticRegression()) diff --git a/_unittests/ut_testing/test_einsum.py b/_unittests/ut_testing/test_einsum.py index ca0459a52..f23e5fcce 100644 --- a/_unittests/ut_testing/test_einsum.py +++ b/_unittests/ut_testing/test_einsum.py @@ -8,7 +8,7 @@ import numpy from onnx import numpy_helper from pyquickhelper.pycode import ExtTestCase -from mlprodict.tools.ort_wrapper import ( +from onnxruntime import ( InferenceSession, GraphOptimizationLevel, SessionOptions) from mlprodict.testing.einsum.einsum_impl_ext import ( numpy_diagonal, numpy_extended_dot, numpy_extended_dot_python) diff --git a/_unittests/ut_testing/test_filename.py b/_unittests/ut_testing/test_filename.py index 756868d98..77f2637ff 100644 --- a/_unittests/ut_testing/test_filename.py +++ b/_unittests/ut_testing/test_filename.py @@ -5,8 +5,7 @@ from pyquickhelper.pycode import ExtTestCase from mlprodict.tools.filename_helper import ( extract_information_from_filename, - make_readable_title -) + make_readable_title) class TestFilename(ExtTestCase): diff --git a/_unittests/ut_testing/test_onnx_backend.py b/_unittests/ut_testing/test_onnx_backend.py index 0468065c8..779a322a0 100644 --- a/_unittests/ut_testing/test_onnx_backend.py +++ b/_unittests/ut_testing/test_onnx_backend.py @@ -60,12 +60,12 @@ def test_enumerate_onnx_tests_run(self): if __name__ == '__main__': print(len(missed), len(failed), len(mismatch)) - for t in missed: - print("missed", t[0]) for t in failed: print("failed", t[0]) for t in mismatch: print("mismatch", t[0]) + for t in missed: + print("missed", t[0]) if __name__ == "__main__": diff --git a/_unittests/ut_testing/test_sklearn_example.py b/_unittests/ut_testing/test_sklearn_example.py index 873fe58ae..96f4625b7 100644 --- a/_unittests/ut_testing/test_sklearn_example.py +++ b/_unittests/ut_testing/test_sklearn_example.py @@ -46,5 +46,5 @@ def test_plot_kernel_ridge_regression(self): if __name__ == "__main__": - TestSklearnExample().test_plot_kernel_ridge_regression() + # TestSklearnExample().test_plot_kernel_ridge_regression() unittest.main() diff --git a/_unittests/ut_tools/test_display.py b/_unittests/ut_tools/test_display.py index e0b21e7d7..2a3f89ddb 100644 --- a/_unittests/ut_tools/test_display.py +++ b/_unittests/ut_tools/test_display.py @@ -3,6 +3,7 @@ @brief test log(time=2s) """ import unittest +import platform import numpy from sklearn.linear_model import LinearRegression from sklearn.datasets import load_iris @@ -13,8 +14,11 @@ class TestDisplay(ExtTestCase): + @unittest.skipIf(platform.platform() != 'win32' and __name__ != '__main__', + reason="stream not closed by matplotlib") def test_plot_logreg_xtime(self): + import matplotlib.pyplot as plt iris = load_iris() X = iris.data[:, :2] y = iris.target @@ -25,6 +29,7 @@ def test_plot_logreg_xtime(self): self.assertIn('opset_import', disp) self.assertIn('producer_version', disp) self.assertLess(len(disp), 1010) + plt.close('all') if __name__ == "__main__": diff --git a/_unittests/ut_tools/test_onnxrt_validate_rt_graph.py b/_unittests/ut_tools/test_onnxrt_validate_rt_graph.py index 6d5168c1c..94342a6bd 100644 --- a/_unittests/ut_tools/test_onnxrt_validate_rt_graph.py +++ b/_unittests/ut_tools/test_onnxrt_validate_rt_graph.py @@ -19,7 +19,6 @@ class TestOnnxrtValidateRtGraph(ExtTestCase): @ignore_warnings(category=(UserWarning, ConvergenceWarning, RuntimeWarning)) def test_validate_pyrt_ort(self): - fLOG(__file__, self._testMethodName, OutputPrint=__name__ == "__main__") logger = getLogger('skl2onnx') logger.disabled = True verbose = 1 if __name__ == "__main__" else 0 @@ -37,10 +36,10 @@ def test_validate_pyrt_ort(self): plt.clf() self.assertNotEmpty(fig) self.assertNotEmpty(ax) + plt.close('all') @ignore_warnings(category=(UserWarning, ConvergenceWarning, RuntimeWarning)) def test_validate_pyrt_ort2(self): - fLOG(__file__, self._testMethodName, OutputPrint=__name__ == "__main__") logger = getLogger('skl2onnx') logger.disabled = True verbose = 0 if __name__ == "__main__" else 0 @@ -60,6 +59,7 @@ def test_validate_pyrt_ort2(self): plt.clf() self.assertNotEmpty(fig) self.assertNotEmpty(ax) + plt.close('all') if __name__ == "__main__": diff --git a/mlprodict/asv_benchmark/common_asv_skl.py b/mlprodict/asv_benchmark/common_asv_skl.py index 9a951005a..c6f961b8a 100644 --- a/mlprodict/asv_benchmark/common_asv_skl.py +++ b/mlprodict/asv_benchmark/common_asv_skl.py @@ -19,8 +19,7 @@ from sklearn import set_config from sklearn.datasets import load_iris from sklearn.metrics import ( - accuracy_score, mean_absolute_error, - silhouette_score) + accuracy_score, mean_absolute_error, silhouette_score) from sklearn.model_selection import train_test_split from mlprodict import get_ir_version, __max_supported_opset__ from mlprodict.onnxrt import OnnxInference @@ -32,7 +31,6 @@ from mlprodict.tools.asv_options_helper import ( expand_onnx_options, version2number) from mlprodict.tools.model_info import set_random_state -from mlprodict.tools.ort_wrapper import onnxrt_version class _CommonAsvSklBenchmark: @@ -94,6 +92,10 @@ def _get_dataset(self, nf, dtype): X, y, random_state=42) Xt = X_test.astype(xdtype) yt = y_test.astype(self.par_ydtype) + if X_train.shape[0] < X_train.shape[1]: + raise RuntimeError( + "Unable to train a model with less observations than features " + "shape=%r." % (X_train.shape, )) return (X_train, y_train), (Xt, yt) def _to_onnx(self, model, X, opset, dtype, optim): @@ -118,8 +120,8 @@ def _create_onnx_inference(self, onx, runtime): try: res = OnnxInference( - onx, runtime=runtime, runtime_options=dict( - log_severity_level=3)) + onx, runtime=runtime, + runtime_options=dict(log_severity_level=3)) except RuntimeError as e: # pragma: no cover if "[ONNXRuntimeError]" in str(e): return RuntimeError("onnxruntime fails due to {}".format(str(e))) @@ -236,6 +238,7 @@ def track_vsklearn(self, runtime, N, nf, opset, dtype, optim): def track_vort(self, runtime, N, nf, opset, dtype, optim): "asv API" + from onnxruntime import __version__ as onnxrt_version return version2number(onnxrt_version) def check_method_name(self, method_name): diff --git a/mlprodict/asv_benchmark/template/skl_model_trainable_transform.py b/mlprodict/asv_benchmark/template/skl_model_trainable_transform.py index eb36ab78c..80baf30f6 100644 --- a/mlprodict/asv_benchmark/template/skl_model_trainable_transform.py +++ b/mlprodict/asv_benchmark/template/skl_model_trainable_transform.py @@ -42,4 +42,4 @@ def setup_cache(self): # pylint: disable=W0235 super().setup_cache() def _create_model(self): - return PLSCanonical() + return PLSCanonical(n_components=1) diff --git a/mlprodict/cli/convert_validate.py b/mlprodict/cli/convert_validate.py index ed3d83807..213ff4c21 100644 --- a/mlprodict/cli/convert_validate.py +++ b/mlprodict/cli/convert_validate.py @@ -7,7 +7,6 @@ from logging import getLogger import warnings from pandas import read_csv -from skl2onnx.common.data_types import FloatTensorType, DoubleTensorType from ..onnx_conv import to_onnx from ..onnxrt import OnnxInference from ..onnx_tools.optim import onnx_optimisations @@ -53,7 +52,7 @@ def convert_validate(pkl, data=None, schema=None, :param optim: applies optimisations on the first ONNX graph, use 'onnx' to reduce the number of node Identity and redundant subgraphs - :param rewrite_ops: rewrites some converters from skl2onnx + :param rewrite_ops: rewrites some converters from :epkg:`sklearn-onnx` :param options: additional options for conversion, dictionary as a string :param verbose: verbose level @@ -100,6 +99,7 @@ def convert_validate(pkl, data=None, schema=None, --name output_label,output_probability --verbose 1 """ + from skl2onnx.common.data_types import FloatTensorType, DoubleTensorType # delayed if fLOG is None: verbose = 0 # pragma: no cover if use_double not in (None, 'float64', 'switch'): diff --git a/mlprodict/npy/onnx_sklearn_wrapper.py b/mlprodict/npy/onnx_sklearn_wrapper.py index b886290f3..45b9dee91 100644 --- a/mlprodict/npy/onnx_sklearn_wrapper.py +++ b/mlprodict/npy/onnx_sklearn_wrapper.py @@ -147,7 +147,7 @@ def _common_shape_calculator_int_t(operator): raise RuntimeError( "This function only supports two outputs not %r." % len( operator.outputs)) - from skl2onnx.common.data_types import Int64TensorType + from skl2onnx.common.data_types import Int64TensorType # delayed op = operator.raw_operator cl = X[0].type.__class__ dim = [X[0].type.shape[0], getattr(op, 'n_outputs_', None)] @@ -391,7 +391,7 @@ def addattr(operator, obj): lambda scope, operator, container: cvtc(scope, addattr(operator, obj), container)) - from skl2onnx import update_registered_converter + from skl2onnx import update_registered_converter # delayed update_registered_converter( model, alias, convert_fct=local_convert_fct, shape_fct=local_shape_fct, overwrite=overwrite, diff --git a/mlprodict/npy/xop.py b/mlprodict/npy/xop.py index bbe04bcd0..41d3cbb35 100644 --- a/mlprodict/npy/xop.py +++ b/mlprodict/npy/xop.py @@ -1,7 +1,7 @@ # pylint: disable=E1101,C0302 """ @file -@brief Xop API to build onnx graphs. Inspired from :epkg:`skl2onnx`. +@brief Xop API to build onnx graphs. Inspired from :epkg:`sklearn-onnx`. .. versionadded:: 0.9 """ @@ -1113,7 +1113,7 @@ def _node_to_graph_preprocess_list(inputs): elif isinstance(el, Variable): new_inputs[el.name] = el elif isinstance(el, tuple) and len(el) == 2: - # skl2onnx + # sklearn-onnx new_inputs[el[0]] = Variable( el[0], guess_numpy_type(el[1]), el[1].shape) else: diff --git a/mlprodict/npy/xop_convert.py b/mlprodict/npy/xop_convert.py index 3ae9f043d..afb8a6ae5 100644 --- a/mlprodict/npy/xop_convert.py +++ b/mlprodict/npy/xop_convert.py @@ -267,7 +267,7 @@ def _to_onnx_sklearn(model, inputs, op_version=None, options=None, options = {'zipmap': False} if initial_types is None: # adding more information - from skl2onnx.common.data_types import _guess_numpy_type + from skl2onnx.common.data_types import _guess_numpy_type # delayed for i, n in enumerate(inputs): if not isinstance(n, Variable): raise NotImplementedError( diff --git a/mlprodict/npy/xop_opset.py b/mlprodict/npy/xop_opset.py index d5f790c39..fb1866617 100644 --- a/mlprodict/npy/xop_opset.py +++ b/mlprodict/npy/xop_opset.py @@ -1,7 +1,7 @@ # pylint: disable=E0602 """ @file -@brief Xop API to build onnx graphs. Inspired from :epkg:`skl2onnx`. +@brief Xop API to build onnx graphs. Inspired from :epkg:`sklearn-onnx`. .. versionadded:: 0.9 """ diff --git a/mlprodict/npy/xop_variable.py b/mlprodict/npy/xop_variable.py index a5de9abb7..09b82065b 100644 --- a/mlprodict/npy/xop_variable.py +++ b/mlprodict/npy/xop_variable.py @@ -1,10 +1,12 @@ """ @file -@brief Xop API to build onnx graphs. Inspired from :epkg:`skl2onnx`. +@brief Xop API to build onnx graphs. Inspired from :epkg:`sklearn-onnx`. .. versionadded:: 0.9 """ import numpy +from onnx import ValueInfoProto, TensorProto +from onnx.helper import make_tensor_type_proto from onnx.mapping import NP_TYPE_TO_TENSOR_TYPE from onnx.defs import onnx_opset_version from .. import __max_supported_opset__ @@ -143,10 +145,10 @@ def __init__(self, name, dtype=None, shape=None, added_dtype=None, def to_skl2onnx(self, scope=None): """ Converts this instance into an instance of *Variable* - from :epkg:`skl2onnx`. + from :epkg:`sklearn-onnx`. """ - from skl2onnx.common._topology import Variable as skl2onnxVariable - from skl2onnx.common.data_types import _guess_numpy_type + from skl2onnx.common._topology import Variable as skl2onnxVariable # delayed + from skl2onnx.common.data_types import _guess_numpy_type # delayed inst = _guess_numpy_type(self.dtype, self.shape) var = skl2onnxVariable(self.name, self.name, type=inst, scope=scope) return var @@ -154,7 +156,7 @@ def to_skl2onnx(self, scope=None): @staticmethod def from_skl2onnx(var): """ - Converts var from skl2onnx into this class. + Converts var from :epkg:`sklearn-onnx` into this class. """ return Variable(var.onnx_name, guess_numpy_type(var.type), shape=var.type.shape) @@ -272,6 +274,74 @@ def __eq__(self, other): return False return True + def make_value_info(self): + """ + Converts the variable into `onnx.ValueInfoProto`. + + :return: instance of `onnx.ValueInfoProto` + """ + value_info = ValueInfoProto() + value_info.name = self.name + tensor_type_proto = make_tensor_type_proto(self.proto_type, self.shape) + value_info.type.CopyFrom(tensor_type_proto) # pylint: disable=E1101 + return value_info + + @staticmethod + def from_pb(obj): + """ + Creates a Variable from a protobuf object. + + :param obj: initializer, tensor + :return: @see cl Variable + """ + def get_dim(d): + r = d.dim_value + if "dim_param" in str(d): + return None + if r == 0: + # dim_value is 0 when it is 0 or undefined + return 0 if "0" in str(d) else None + return r + + def get_shape(tt): + return [get_dim(tt.shape.dim[i]) + for i in range(len(tt.shape.dim))] + + if hasattr(obj, 'extend'): + return [Variable.from_pb(o) for o in obj] + + name = obj.name + if obj.type.tensor_type: + tt = obj.type.tensor_type + elem = tt.elem_type + shape = get_shape(tt) + if elem == TensorProto.FLOAT: # pylint: disable=E1101 + ty = numpy.float32 + elif elem == TensorProto.BOOL: # pylint: disable=E1101 + ty = numpy.bool_ + elif elem == TensorProto.DOUBLE: # pylint: disable=E1101 + ty = numpy.float64 + elif elem == TensorProto.STRING: # pylint: disable=E1101 + ty = numpy.str_ + elif elem == TensorProto.INT64: # pylint: disable=E1101 + ty = numpy.int64 + elif elem == TensorProto.INT32: # pylint: disable=E1101 + ty = numpy.int32 + elif elem == TensorProto.UINT8: # pylint: disable=E1101 + ty = numpy.uint8 + elif elem == TensorProto.INT8: # pylint: disable=E1101 + ty = numpy.int8 + else: + raise NotImplementedError( + "Unsupported type '{}' (elem_type={}).".format( + type(obj.type.tensor_type), elem)) + else: + raise NotImplementedError("Unsupported type '{}' as " + "a string ({}).".format( + type(obj), obj)) + + return Variable(name, ty, shape=shape) + class NodeResultName: """ diff --git a/mlprodict/onnx_conv/__init__.py b/mlprodict/onnx_conv/__init__.py index d9434cd28..602fe0839 100644 --- a/mlprodict/onnx_conv/__init__.py +++ b/mlprodict/onnx_conv/__init__.py @@ -1,7 +1,8 @@ # -*- encoding: utf-8 -*- """ @file -@brief Shortcut to *onnx_conv*. +@brief Shortcut to *onnx_conv*. Importing this file +means importing :epkg:`sklearn-onnx`. """ import onnx from .register import register_converters, register_scorers diff --git a/mlprodict/onnx_tools/onnx2py_helper.py b/mlprodict/onnx_tools/onnx2py_helper.py index 77ad8d0d5..b8d2dabbf 100644 --- a/mlprodict/onnx_tools/onnx2py_helper.py +++ b/mlprodict/onnx_tools/onnx2py_helper.py @@ -7,7 +7,7 @@ import warnings import numpy from scipy.sparse import coo_matrix -from onnx import onnx_pb as onnx_proto, TensorProto +from onnx import TensorProto from onnx.numpy_helper import to_array, from_array as onnx_from_array @@ -200,35 +200,35 @@ def guess_numpy_type_from_dtype(dt): def _elem_type_as_str(elem_type): - if elem_type == onnx_proto.TensorProto.FLOAT: # pylint: disable=E1101 + if elem_type == TensorProto.FLOAT: # pylint: disable=E1101 return 'float' - if elem_type == onnx_proto.TensorProto.BOOL: # pylint: disable=E1101 + if elem_type == TensorProto.BOOL: # pylint: disable=E1101 return 'bool' - if elem_type == onnx_proto.TensorProto.DOUBLE: # pylint: disable=E1101 + if elem_type == TensorProto.DOUBLE: # pylint: disable=E1101 return 'double' - if elem_type == onnx_proto.TensorProto.STRING: # pylint: disable=E1101 + if elem_type == TensorProto.STRING: # pylint: disable=E1101 return 'str' - if elem_type == onnx_proto.TensorProto.INT64: # pylint: disable=E1101 + if elem_type == TensorProto.INT64: # pylint: disable=E1101 return 'int64' - if elem_type == onnx_proto.TensorProto.INT32: # pylint: disable=E1101 + if elem_type == TensorProto.INT32: # pylint: disable=E1101 return 'int32' - if elem_type == onnx_proto.TensorProto.UINT32: # pylint: disable=E1101 + if elem_type == TensorProto.UINT32: # pylint: disable=E1101 return 'uint32' - if elem_type == onnx_proto.TensorProto.UINT64: # pylint: disable=E1101 + if elem_type == TensorProto.UINT64: # pylint: disable=E1101 return 'uint64' - if elem_type == onnx_proto.TensorProto.INT16: # pylint: disable=E1101 + if elem_type == TensorProto.INT16: # pylint: disable=E1101 return 'int16' - if elem_type == onnx_proto.TensorProto.UINT16: # pylint: disable=E1101 + if elem_type == TensorProto.UINT16: # pylint: disable=E1101 return 'uint16' - if elem_type == onnx_proto.TensorProto.UINT8: # pylint: disable=E1101 + if elem_type == TensorProto.UINT8: # pylint: disable=E1101 return 'uint8' - if elem_type == onnx_proto.TensorProto.INT8: # pylint: disable=E1101 + if elem_type == TensorProto.INT8: # pylint: disable=E1101 return 'int8' - if elem_type == onnx_proto.TensorProto.FLOAT16: # pylint: disable=E1101 + if elem_type == TensorProto.FLOAT16: # pylint: disable=E1101 return 'float16' - if elem_type == onnx_proto.TensorProto.COMPLEX64: # pylint: disable=E1101 + if elem_type == TensorProto.COMPLEX64: # pylint: disable=E1101 return 'complex64' - if elem_type == onnx_proto.TensorProto.COMPLEX128: # pylint: disable=E1101 + if elem_type == TensorProto.COMPLEX128: # pylint: disable=E1101 return 'complex128' if elem_type == 0: # pylint: disable=E1101 return 'unk' @@ -641,7 +641,7 @@ def to_skl2onnx_type(name, elem_type, shape): :param shape: expected shape :return: data type """ - from skl2onnx.common.data_types import _guess_numpy_type + from skl2onnx.common.data_types import _guess_numpy_type # delayed elem = guess_numpy_type_from_string(elem_type) shape = list(None if d == 0 else d for d in shape) return (name, _guess_numpy_type(elem, shape)) diff --git a/mlprodict/onnx_tools/onnx_export.py b/mlprodict/onnx_tools/onnx_export.py index 9ff3ead03..179863cc7 100644 --- a/mlprodict/onnx_tools/onnx_export.py +++ b/mlprodict/onnx_tools/onnx_export.py @@ -288,7 +288,7 @@ def export2onnx(model_onnx, opset=None, verbose=True, name=None, rename=False, import numpy from sklearn.cluster import KMeans - from skl2onnx import to_onnx + from mlprodict.onnx_conv import to_onnx from mlprodict.onnx_tools.onnx_export import export2onnx X = numpy.arange(20).reshape(10, 2).astype(numpy.float32) @@ -330,7 +330,7 @@ def export2tf2onnx(model_onnx, opset=None, verbose=True, name=None, import numpy from sklearn.cluster import KMeans - from skl2onnx import to_onnx + from mlprodict.onnx_conv import to_onnx from mlprodict.onnx_tools.onnx_export import export2tf2onnx X = numpy.arange(20).reshape(10, 2).astype(numpy.float32) @@ -374,7 +374,7 @@ def export2numpy(model_onnx, opset=None, verbose=True, name=None, import numpy from sklearn.cluster import KMeans - from skl2onnx import to_onnx + from mlprodict.onnx_conv import to_onnx from mlprodict.onnx_tools.onnx_export import export2numpy X = numpy.arange(20).reshape(10, 2).astype(numpy.float32) diff --git a/mlprodict/onnx_tools/onnx_grammar/onnx_translation.py b/mlprodict/onnx_tools/onnx_grammar/onnx_translation.py index c33dc8dff..187535585 100644 --- a/mlprodict/onnx_tools/onnx_grammar/onnx_translation.py +++ b/mlprodict/onnx_tools/onnx_grammar/onnx_translation.py @@ -106,16 +106,16 @@ def get_default_context_cpl(): 'py_pow': py_pow, 'py_mul': py_mul, 'py_opp': py_opp, 'numpy': numpy} try: - from skl2onnx.algebra.complex_functions import onnx_squareform_pdist - from skl2onnx.algebra.complex_functions import onnx_cdist + from skl2onnx.algebra.complex_functions import onnx_squareform_pdist # delayed + from skl2onnx.algebra.complex_functions import onnx_cdist # delayed ctx['onnx_squareform_pdist'] = onnx_squareform_pdist ctx['onnx_cdist'] = onnx_cdist except ImportError: # pragma: no cover # Too old version for skl2onnx. pass - from skl2onnx.algebra import onnx_ops - from skl2onnx.algebra.onnx_operator import OnnxOperator + from skl2onnx.algebra import onnx_ops # delayed + from skl2onnx.algebra.onnx_operator import OnnxOperator # delayed d = onnx_ops.__dict__ for k, v in d.items(): try: @@ -199,20 +199,24 @@ def trs(x, y): from mlprodict.onnx_tools.onnx_grammar import translate_fct2onnx from mlprodict.plotting.text_plot import onnx_simple_text_plot from mlprodict.onnxrt import OnnxInference - from skl2onnx.algebra.onnx_ops import ( - OnnxAdd, OnnxTranspose, OnnxMul, OnnxIdentity) + from mlprodict.npy.xop import loadop + + + OnnxAdd, OnnxTranspose, OnnxMul, OnnxIdentity = loadop( + 'Add', 'Transpose', 'Mul', 'Identity') + ctx = {'OnnxAdd': OnnxAdd, - 'OnnxTranspose': OnnxTranspose, - 'OnnxMul': OnnxMul, - 'OnnxIdentity': OnnxIdentity} + '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} + 'y': numpy.array([[-0.3, 0.4]], dtype=numpy.float32).T} original = trs(inputs['x'], inputs['y']) diff --git a/mlprodict/onnx_tools/optim/graph_schema_helper.py b/mlprodict/onnx_tools/optim/graph_schema_helper.py index e30db0a78..86bcfc7bd 100644 --- a/mlprodict/onnx_tools/optim/graph_schema_helper.py +++ b/mlprodict/onnx_tools/optim/graph_schema_helper.py @@ -3,23 +3,11 @@ @brief Functions to help guessing the final graph structure. """ import numpy -try: - from onnxconverter_common.data_types import Float16TensorType -except ImportError: # pragma: no cover - Float16TensorType = None -from skl2onnx.common.data_types import ( - DataType, - FloatTensorType, SequenceType, DictionaryType, - Int64Type, Int64TensorType, BooleanTensorType, - Int32TensorType, DoubleTensorType, FloatType, - StringTensorType) -from skl2onnx.common.data_types import ( - _guess_type_proto, _guess_type_proto_str) -from skl2onnx.algebra.type_helper import _guess_type as skl2onnx__guess_type -from skl2onnx.proto import TensorProto +from onnx import TensorProto def _guess_type(var): + from skl2onnx.algebra.type_helper import _guess_type as skl2onnx__guess_type # delayed if isinstance(var, dict) and 'value' in var: return skl2onnx__guess_type(var['value']) # pragma: no cover return skl2onnx__guess_type(var) @@ -36,9 +24,11 @@ def get_defined_inputs(input_names, variables=None, dtype=None, by previous operators @param dtype float computational type @param schema defined inputs by schema (*expected_inputs*) - @return typed inputs - as ``tuple(name, type)`` + @return typed inputs as ``tuple(name, type)`` """ + from skl2onnx.common.data_types import ( # delayed + DataType, FloatTensorType, DoubleTensorType) + def guess_type_variable(name, schema): if variables is None: if (schema is None or @@ -99,6 +89,12 @@ def get_defined_outputs(outputs, onnx_node, typed_inputs=None, variables=None, :param schema_inputs: defined inputs by schema (*expected_inputs*) :return: typed outputs as ``tuple(name, type)`` """ + from skl2onnx.common.data_types import ( # delayed + DataType, + FloatTensorType, SequenceType, DictionaryType, + Int64Type, Int64TensorType, BooleanTensorType, + DoubleTensorType, _guess_type_proto, _guess_type_proto_str) + if schema is None: ft = DoubleTensorType if dtype == numpy.float64 else FloatTensorType elif len(schema) != 1: @@ -221,6 +217,12 @@ def proto2vars(values): """ Converts proto values to Variables. """ + from skl2onnx.common.data_types import ( # delayed + FloatTensorType, SequenceType, DictionaryType, + Int64Type, Int64TensorType, BooleanTensorType, + Int32TensorType, DoubleTensorType, FloatType, + StringTensorType, Float16TensorType) + def ptype2vttype(it, shape): if it == TensorProto.FLOAT: # pylint: disable=E1101 return FloatTensorType(shape) diff --git a/mlprodict/onnx_tools/optim/onnx_helper.py b/mlprodict/onnx_tools/optim/onnx_helper.py index f8f124adb..f23e55dd5 100644 --- a/mlprodict/onnx_tools/optim/onnx_helper.py +++ b/mlprodict/onnx_tools/optim/onnx_helper.py @@ -4,7 +4,6 @@ """ from collections import Counter from onnx.helper import make_graph -from onnx import ValueInfoProto from ._onnx_optimisation_common import _apply_optimisation_on_graph from .onnx_optimisation import onnx_remove_node @@ -145,16 +144,7 @@ def change_input_first_dimension(onnx_model, N=None, debug_info=None): @param debug_info unused @return modified model onnx """ - from skl2onnx.common._topology import Variable - - def _make_value_info(variable): - value_info = ValueInfoProto() - value_info.name = variable.full_name - value_info.type.CopyFrom( # pylint: disable=E1101 - variable.type.to_onnx_type()) # pylint: disable=E1101 - if variable.type.doc_string: # pylint: disable=E0611 - value_info.doc_string = variable.type.doc_string # pragma: no cover - return value_info + from ...npy.xop_variable import Variable if hasattr(onnx_model, 'graph'): return _apply_optimisation_on_graph( @@ -169,8 +159,8 @@ def _make_value_info(variable): if N <= 0: N = None for input in inputs: - input.type.shape[0] = N - inputs = [_make_value_info(v) for v in inputs] + input.shape[0] = N + inputs = [v.make_value_info() for v in inputs] graph = make_graph(nodes, onnx_model.name, inputs, outputs, onnx_model.initializer) diff --git a/mlprodict/onnxrt/onnx_inference.py b/mlprodict/onnxrt/onnx_inference.py index 2ea62a6e7..29e1acd64 100644 --- a/mlprodict/onnxrt/onnx_inference.py +++ b/mlprodict/onnxrt/onnx_inference.py @@ -455,16 +455,17 @@ def to_sequence(self): import pprint import numpy - from skl2onnx.algebra.onnx_ops import OnnxLinearRegressor - from skl2onnx.common.data_types import FloatTensorType + from mlprodict.npy.xop import loadop from mlprodict.onnxrt import OnnxInference + OnnxAiOnnxMlLinearRegressor = loadop('LinearRegressor') + pars = dict(coefficients=numpy.array([1., 2.]), intercepts=numpy.array([1.]), post_transform='NONE') - onx = OnnxLinearRegressor('X', output_names=['Y'], **pars) + onx = OnnxAiOnnxMlLinearRegressor('X', output_names=['Y'], **pars) model_def = onx.to_onnx({'X': pars['coefficients'].astype(numpy.float32)}, - outputs=[('Y', FloatTensorType([1]))], + outputs={'Y': numpy.float32}, target_opset=12) oinf = OnnxInference(model_def) pprint.pprint(oinf.to_sequence()) @@ -1520,7 +1521,7 @@ def _build_compile_run(self, debug=False): 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.onnx_conv import to_onnx from mlprodict.onnxrt import OnnxInference iris = load_iris() diff --git a/mlprodict/onnxrt/onnx_inference_exports.py b/mlprodict/onnxrt/onnx_inference_exports.py index 5d961f0c9..42ec2dda4 100644 --- a/mlprodict/onnxrt/onnx_inference_exports.py +++ b/mlprodict/onnxrt/onnx_inference_exports.py @@ -66,16 +66,17 @@ def to_dot(self, recursive=False, prefix='', # pylint: disable=R0914 :warningout: DeprecationWarning import numpy - from skl2onnx.algebra.onnx_ops import OnnxLinearRegressor - from skl2onnx.common.data_types import FloatTensorType + from mlprodict.npy.xop import loadop from mlprodict.onnxrt import OnnxInference + onx = OnnxAiOnnxMlLinearRegressor('X', output_names=['Y'], **pars) + pars = dict(coefficients=numpy.array([1., 2.]), intercepts=numpy.array([1.]), post_transform='NONE') - onx = OnnxLinearRegressor('X', output_names=['Y'], **pars) + onx = OnnxAiOnnxMlLinearRegressor('X', output_names=['Y'], **pars) model_def = onx.to_onnx({'X': pars['coefficients'].astype(numpy.float32)}, - outputs=[('Y', FloatTensorType([1]))], + outputs={'Y': numpy.float32}, target_opset=12) oinf = OnnxInference(model_def) print(oinf.to_dot()) @@ -323,16 +324,17 @@ def to_json(self, indent=2): :warningout: DeprecationWarning import numpy - from skl2onnx.algebra.onnx_ops import OnnxLinearRegressor - from skl2onnx.common.data_types import FloatTensorType + from mlprodict.npy.xop import loadop from mlprodict.onnxrt import OnnxInference + onx = OnnxAiOnnxMlLinearRegressor('X', output_names=['Y'], **pars) + pars = dict(coefficients=numpy.array([1., 2.]), intercepts=numpy.array([1.]), post_transform='NONE') - onx = OnnxLinearRegressor('X', output_names=['Y'], **pars) + onx = OnnxAiOnnxMlLinearRegressor('X', output_names=['Y'], **pars) model_def = onx.to_onnx({'X': pars['coefficients'].astype(numpy.float32)}, - outputs=[('Y', FloatTensorType([1]))], + outputs={'Y': numpy.float32}, target_opset=12) oinf = OnnxInference(model_def) print(oinf.to_json()) @@ -456,9 +458,11 @@ def to_python(self, prefix="onnx_pyrt_", dest=None, inline=True): :warningout: DeprecationWarning import numpy - from skl2onnx.algebra.onnx_ops import OnnxAdd + from mlprodict.npy.xop import loadop from mlprodict.onnxrt import OnnxInference + OnnxAdd = loadop('Add') + idi = numpy.identity(2).astype(numpy.float32) onx = OnnxAdd('X', idi, output_names=['Y'], op_version=12) diff --git a/mlprodict/onnxrt/ops_onnxruntime/_op.py b/mlprodict/onnxrt/ops_onnxruntime/_op.py index 89bb72c69..79024f05c 100644 --- a/mlprodict/onnxrt/ops_onnxruntime/_op.py +++ b/mlprodict/onnxrt/ops_onnxruntime/_op.py @@ -7,22 +7,10 @@ import onnx.defs from onnx.helper import make_tensor from onnx.onnx_cpp2py_export.shape_inference import InferenceError # pylint: disable=E0401,E0611 -from skl2onnx.common.data_types import ( - DictionaryType, FloatTensorType, Int64TensorType, StringTensorType) -import skl2onnx.algebra.onnx_ops as alg -try: - import skl2onnx.algebra.custom_ops as alg2 -except ImportError: # pragma: no cover - # older version of skl2onnx - alg2 = alg -from ...tools.ort_wrapper import ( - InferenceSession, SessionOptions, RunOptions, - GraphOptimizationLevel, OrtInvalidArgument, - OrtNotImplemented, OrtInvalidGraph, OrtFail) +from ...tools.ort_wrapper import InferenceSession from ...onnx_tools.onnx2py_helper import guess_proto_dtype from ...onnx_tools.optim.graph_schema_helper import ( get_defined_inputs, get_defined_outputs, proto2vars) -from ...onnx_conv import onnx_ops as alg3 _schemas = { @@ -60,6 +48,10 @@ def __init__(self, onnx_node, desc=None, variables=None, self.dtype = dtype self._init(variables) + from onnxruntime.capi._pybind_state import ( # pylint: disable=E0611 + InvalidArgument as OrtInvalidArgument) + self.OrtInvalidArgument = OrtInvalidArgument + def _name_mapping(self, inputs): mapping = {} new_inputs = [] @@ -95,14 +87,17 @@ def _init(self, variables=None): self.alg_class = custom_nodes[self.onnx_node.op_type] else: try: - self.alg_class = getattr(alg2, 'Onnx' + self.onnx_node.op_type) + import mlprodict.onnx_conv.onnx_ops as alg0 + self.alg_class = getattr(alg0, 'Onnx' + self.onnx_node.op_type) except AttributeError: + import skl2onnx.algebra.custom_ops as alg2 # delayed try: self.alg_class = getattr( - alg, 'Onnx' + self.onnx_node.op_type) + alg2, 'Onnx' + self.onnx_node.op_type) except AttributeError: + import skl2onnx.algebra.onnx_ops as alg # delayed self.alg_class = getattr( - alg3, 'Onnx' + self.onnx_node.op_type) + alg, 'Onnx' + self.onnx_node.op_type) inputs = list(self.onnx_node.input) self.mapping, self.inputs = self._name_mapping(inputs) @@ -122,6 +117,8 @@ def _init(self, variables=None): pass if self.onnx_node.op_type == 'ZipMap': + from skl2onnx.common.data_types import ( # delayed + DictionaryType, FloatTensorType, Int64TensorType, StringTensorType) self.inst_ = self.alg_class(*self.inputs, output_names=self.outputs, op_version=target_opset, **options) inputs = get_defined_inputs( @@ -237,6 +234,12 @@ def _init(self, variables=None): lo = list(self.onnx_.graph.output) outputs = proto2vars(lo) + from onnxruntime import ( # pylint: disable=E0611 + SessionOptions, RunOptions, GraphOptimizationLevel) + from onnxruntime.capi._pybind_state import ( # pylint: disable=E0611 + Fail as OrtFail, InvalidGraph as OrtInvalidGraph, + NotImplemented as OrtNotImplemented) + sess_options = session_options or SessionOptions() self.run_options = RunOptions() @@ -288,7 +291,7 @@ def run(self, *args, **kwargs): try: res = self.sess_.run(None, inputs, self.run_options) - except (RuntimeError, OrtInvalidArgument) as e: # pragma: no cover + except (RuntimeError, self.OrtInvalidArgument) as e: # pragma: no cover dtypes = {k: v.dtype for k, v in inputs.items()} shapes = {k: v.shape for k, v in inputs.items()} exp = [_.name for _ in self.sess_.get_inputs()] diff --git a/mlprodict/onnxrt/ops_whole/session.py b/mlprodict/onnxrt/ops_whole/session.py index 56636bd92..61624f51d 100644 --- a/mlprodict/onnxrt/ops_whole/session.py +++ b/mlprodict/onnxrt/ops_whole/session.py @@ -5,13 +5,8 @@ """ import json from io import BytesIO +import numpy import onnx -from ...tools.ort_wrapper import ( - InferenceSession, SessionOptions, RunOptions, - GraphOptimizationLevel, OrtFail, - OrtInvalidGraph, OrtInvalidArgument, - OrtNotImplemented, OrtRuntimeException) -from ...tools.asv_options_helper import display_onnx class OnnxWholeSession: @@ -32,6 +27,16 @@ def __init__(self, onnx_data, runtime, runtime_options=None, device=None): if runtime != 'onnxruntime1': raise NotImplementedError( # pragma: no cover "runtime '{}' is not implemented.".format(runtime)) + + from onnxruntime import ( # delayed + InferenceSession, SessionOptions, RunOptions, + GraphOptimizationLevel) + from onnxruntime.capi._pybind_state import ( # pylint: disable=E0611 + Fail as OrtFail, InvalidGraph as OrtInvalidGraph, + InvalidArgument as OrtInvalidArgument, + NotImplemented as OrtNotImplemented, + RuntimeException as OrtRuntimeException) + if hasattr(onnx_data, 'SerializeToString'): onnx_data = onnx_data.SerializeToString() if isinstance(runtime_options, SessionOptions): @@ -76,9 +81,11 @@ def __init__(self, onnx_data, runtime, runtime_options=None, device=None): device=device) except (OrtFail, OrtNotImplemented, OrtInvalidGraph, OrtInvalidArgument, OrtRuntimeException, RuntimeError) as e: + from ...tools.asv_options_helper import display_onnx raise RuntimeError( "Unable to create InferenceSession due to '{}'\n{}.".format( e, display_onnx(onnx.load(BytesIO(onnx_data))))) from e + self.output_names = [_.name for _ in self.sess.get_outputs()] def run(self, inputs): """ @@ -87,7 +94,16 @@ def run(self, inputs): @param inputs dictionary *{variable, value}* @return list of outputs """ - return self.sess.run(None, inputs, self.run_options) + v = next(iter(inputs.values())) + if isinstance(v, (numpy.ndarray, dict)): + return self.sess.run(None, inputs, self.run_options) + try: + return self.sess._sess.run_with_ort_values( + inputs, self.output_names, self.run_options) + except RuntimeError: + return self.sess._sess.run_with_ort_values( + {k: v._get_c_value() for k, v in inputs.items()}, + self.output_names, self.run_options) @staticmethod def process_profiling(js): diff --git a/mlprodict/onnxrt/validate/_validate_problems_helper.py b/mlprodict/onnxrt/validate/_validate_problems_helper.py index ba21cb7e3..8d7d7d729 100644 --- a/mlprodict/onnxrt/validate/_validate_problems_helper.py +++ b/mlprodict/onnxrt/validate/_validate_problems_helper.py @@ -5,8 +5,6 @@ :epkg:`sklearn-onnx`. """ import numpy -from skl2onnx.common.data_types import ( - FloatTensorType, DoubleTensorType) text_alpha_num = [ @@ -46,8 +44,12 @@ def _guess_noshape(obj, shape): if isinstance(obj, numpy.ndarray): if obj.dtype == numpy.float32: + from skl2onnx.common.data_types import ( # delayed + FloatTensorType) return FloatTensorType(shape) # pragma: no cover if obj.dtype == numpy.float64: + from skl2onnx.common.data_types import ( # delayed + DoubleTensorType) return DoubleTensorType(shape) raise NotImplementedError( # pragma: no cover "Unable to process object(1) [{}].".format(obj)) diff --git a/mlprodict/onnxrt/validate/validate.py b/mlprodict/onnxrt/validate/validate.py index c3fc9dfd8..e126325af 100644 --- a/mlprodict/onnxrt/validate/validate.py +++ b/mlprodict/onnxrt/validate/validate.py @@ -17,7 +17,6 @@ __max_supported_opset__, get_ir_version, __max_supported_opsets__) from ...onnx_conv import to_onnx, register_converters, register_rewritten_operators -from ...tools.ort_wrapper import onnxrt_version from ...tools.model_info import analyze_model, set_random_state from ..onnx_inference import OnnxInference from ...onnx_tools.optim.sklearn_helper import inspect_sklearn_model, set_n_jobs @@ -760,10 +759,11 @@ def _enumerate_validated_operator_opsets_ops(extended_list, models, skip_models) def _enumerate_validated_operator_opsets_version(runtime): - from numpy import __version__ as numpy_version - from onnx import __version__ as onnx_version - from scipy import __version__ as scipy_version - from skl2onnx import __version__ as skl2onnx_version + from numpy import __version__ as numpy_version # delayed + from onnx import __version__ as onnx_version # delayed + from scipy import __version__ as scipy_version # delayed + from skl2onnx import __version__ as skl2onnx_version # delayed + from onnxruntime import __version__ as onnxrt_version # delayed add_versions = {'v_numpy': numpy_version, 'v_onnx': onnx_version, 'v_scipy': scipy_version, 'v_skl2onnx': skl2onnx_version, 'v_sklearn': sklearn_version, 'v_onnxruntime': ort_version} diff --git a/mlprodict/onnxrt/validate/validate_benchmark_replay.py b/mlprodict/onnxrt/validate/validate_benchmark_replay.py index 4f87cc08e..a94589440 100644 --- a/mlprodict/onnxrt/validate/validate_benchmark_replay.py +++ b/mlprodict/onnxrt/validate/validate_benchmark_replay.py @@ -5,7 +5,7 @@ import pickle import os import sklearn -from ...tools.ort_wrapper import InferenceSession, OrtFail +from ...tools.ort_wrapper import InferenceSession from .. import OnnxInference from .validate_helper import default_time_kwargs, measure_time, _multiply_time_kwargs from .validate_benchmark import make_n_rows @@ -48,6 +48,8 @@ def enumerate_benchmark_replay(folder, runtime='python', time_kwargs=None, @param fLOG logging function @return iterator on results """ + from onnxruntime.capi._pybind_state import Fail as OrtFail # pylint: disable=E0611 + files = [_ for _ in os.listdir(folder) if _.endswith( ".pkl") or _.endswith("_.pickle")] if len(files) == 0: diff --git a/mlprodict/onnxrt/validate/validate_latency.py b/mlprodict/onnxrt/validate/validate_latency.py index bdac59206..0a954e191 100644 --- a/mlprodict/onnxrt/validate/validate_latency.py +++ b/mlprodict/onnxrt/validate/validate_latency.py @@ -8,8 +8,6 @@ import numpy from onnx import TensorProto from pandas import DataFrame -from cpyquickhelper.numbers import measure_time -from onnxruntime import InferenceSession, SessionOptions, get_all_providers from .. import OnnxInference from ..ops_whole.session import OnnxWholeSession @@ -90,6 +88,8 @@ def latency(model, law='normal', size=1, number=10, repeat=10, max_time=0, python -m mlprodict latency --model "model.onnx" """ + from cpyquickhelper.numbers import measure_time # delayed import + if isinstance(model, str) and not os.path.exists(model): raise FileNotFoundError( # pragma: no cover "Unable to find model %r." % model) @@ -119,6 +119,7 @@ def latency(model, law='normal', size=1, number=10, repeat=10, max_time=0, "%r." % device) providers = ['CUDAExecutionProviders'] elif ',' in device: + from onnxruntime import get_all_providers # delayed import if runtime != 'onnxruntime': raise NotImplementedError( # pragma: no cover "Only runtime 'onnxruntime' supports this device or provider " @@ -135,6 +136,7 @@ def latency(model, law='normal', size=1, number=10, repeat=10, max_time=0, "Device %r not supported." % device) if runtime == "onnxruntime": + from onnxruntime import InferenceSession, SessionOptions # delayed import if profiling in ('name', 'type'): so = SessionOptions() so.enable_profiling = True diff --git a/mlprodict/onnxrt/validate/validate_problems.py b/mlprodict/onnxrt/validate/validate_problems.py index 01bf501f9..edfa3cfa6 100644 --- a/mlprodict/onnxrt/validate/validate_problems.py +++ b/mlprodict/onnxrt/validate/validate_problems.py @@ -60,8 +60,6 @@ from sklearn.svm import LinearSVC, LinearSVR, NuSVR, SVR, SVC, NuSVC from sklearn.tree import DecisionTreeRegressor, DecisionTreeClassifier, ExtraTreeClassifier from sklearn.utils import shuffle -from skl2onnx.common.data_types import ( - FloatTensorType, DoubleTensorType, StringTensorType, DictionaryType) from ._validate_problems_helper import ( _noshapevar, _1d_problem, text_alpha_num) @@ -511,6 +509,8 @@ def _problem_for_dict_vectorizer(dtype=numpy.float32, n_features=None): """ Returns a problem for the :epkg:`sklearn:feature_extraction:DictVectorizer`. """ + from skl2onnx.common.data_types import ( # delayed + FloatTensorType, DoubleTensorType, StringTensorType, DictionaryType) data = load_iris() # X = data.data y = data.target @@ -527,6 +527,8 @@ def _problem_for_tfidf_vectorizer(dtype=numpy.float32, n_features=None): """ Returns a problem for the :epkg:`sklearn:feature_extraction:text:TfidfVectorizer`. """ + from skl2onnx.common.data_types import ( # delayed + StringTensorType) X = numpy.array([_[0] for _ in text_alpha_num]) y = numpy.array([_[1] for _ in text_alpha_num], dtype=dtype) itt = [("X", StringTensorType([None]))] @@ -537,6 +539,8 @@ def _problem_for_tfidf_transformer(dtype=numpy.float32, n_features=None): """ Returns a problem for the :epkg:`sklearn:feature_extraction:text:TfidfTransformer`. """ + from skl2onnx.common.data_types import ( # delayed + FloatTensorType, DoubleTensorType) X = numpy.array([_[0] for _ in text_alpha_num]) y = numpy.array([_[1] for _ in text_alpha_num], dtype=dtype) X2 = CountVectorizer().fit_transform(X).astype(dtype) @@ -549,6 +553,8 @@ def _problem_for_feature_hasher(dtype=numpy.float32, n_features=None): """ Returns a problem for the :epkg:`sklearn:feature_extraction:DictVectorizer`. """ + from skl2onnx.common.data_types import ( # delayed + FloatTensorType, DoubleTensorType, StringTensorType, DictionaryType) data = load_iris() # X = data.data y = data.target diff --git a/mlprodict/onnxrt/validate/validate_summary.py b/mlprodict/onnxrt/validate/validate_summary.py index bb7967635..47ff36e1f 100644 --- a/mlprodict/onnxrt/validate/validate_summary.py +++ b/mlprodict/onnxrt/validate/validate_summary.py @@ -188,7 +188,7 @@ def aggfunc(values): if "available-ERROR" in df.columns: - from skl2onnx.common.exceptions import MissingShapeCalculator + from skl2onnx.common.exceptions import MissingShapeCalculator # delayed def replace_msg(text): if isinstance(text, MissingShapeCalculator): diff --git a/mlprodict/plotting/plotting_benchmark.py b/mlprodict/plotting/plotting_benchmark.py index ca1548573..a045ad714 100644 --- a/mlprodict/plotting/plotting_benchmark.py +++ b/mlprodict/plotting/plotting_benchmark.py @@ -2,11 +2,7 @@ @file @brief Useful plots. """ - import numpy -import matplotlib -import matplotlib.pyplot as plt -from matplotlib.colors import LogNorm def heatmap(data, row_labels, col_labels, ax=None, @@ -28,6 +24,7 @@ def heatmap(data, row_labels, col_labels, ax=None, `_ @return ax, image, color bar """ + import matplotlib.pyplot as plt # delayed if not ax: ax = plt.gca() # pragma: no cover @@ -102,6 +99,7 @@ def annotate_heatmap(im, data=None, valfmt="{x:.2f}", # Get the formatter in case a string is supplied if isinstance(valfmt, str): + import matplotlib # delayed valfmt = matplotlib.ticker.StrMethodFormatter(valfmt) texts = [] @@ -160,6 +158,8 @@ def plot_benchmark_metrics(metric, xlabel=None, ylabel=None, middle=middle, transpose=False, cbar_kw=cbar_kw, cbarlabel=cbarlabel) + from matplotlib.colors import LogNorm # delayed + x = numpy.array(list(sorted(set(k[0] for k in metric)))) y = numpy.array(list(sorted(set(k[1] for k in metric)))) rx = {v: i for i, v in enumerate(x)} diff --git a/mlprodict/plotting/plotting_onnx.py b/mlprodict/plotting/plotting_onnx.py index e60e69250..cdca82ffe 100644 --- a/mlprodict/plotting/plotting_onnx.py +++ b/mlprodict/plotting/plotting_onnx.py @@ -2,7 +2,6 @@ @file @brief Useful plots. """ -import matplotlib.pyplot as plt from ..onnxrt import OnnxInference @@ -21,8 +20,9 @@ def plot_onnx(onx, ax=None, dpi=300, temp_dot=None, temp_img=None, :param show: calls `plt.show()` :return: axes """ - # delayed import + # delayed import, because too long from pyquickhelper.helpgen.graphviz_helper import plot_graphviz + import matplotlib.pyplot as plt if ax is None: ax = plt.gca() # pragma: no cover diff --git a/mlprodict/plotting/plotting_validate_graph.py b/mlprodict/plotting/plotting_validate_graph.py index f30922b8c..e8bf2feb4 100644 --- a/mlprodict/plotting/plotting_validate_graph.py +++ b/mlprodict/plotting/plotting_validate_graph.py @@ -45,9 +45,6 @@ def plot_validate_benchmark(df): from mlprodict.onnxrt.validate import enumerate_validated_operator_opsets, summary_report from mlprodict.tools.plotting import plot_validate_benchmark - logger = getLogger('skl2onnx') - logger.disabled = True - rows = list(enumerate_validated_operator_opsets( verbose=0, models={"LinearRegression"}, opset_min=11, runtime=['python', 'onnxruntime1'], debug=False, diff --git a/mlprodict/plotting/text_plot.py b/mlprodict/plotting/text_plot.py index aa8876ed2..daee10c20 100644 --- a/mlprodict/plotting/text_plot.py +++ b/mlprodict/plotting/text_plot.py @@ -30,10 +30,12 @@ def onnx_text_plot(model_onnx, recursive=False, graph_type='basic', :warningout: DeprecationWarning import numpy - from skl2onnx.algebra.onnx_ops import OnnxAdd, OnnxSub from mlprodict.onnx_conv import to_onnx from mlprodict import __max_supported_opset__ as opv from mlprodict.plotting.plotting import onnx_text_plot + from mlprodict.npy.xop import loadop + + OnnxAdd, OnnxSub = loadop('Add', 'Sub') idi = numpy.identity(2).astype(numpy.float32) A = OnnxAdd('X', idi, op_version=opv) diff --git a/mlprodict/sklapi/__init__.py b/mlprodict/sklapi/__init__.py index 5a11bd8a5..8323ed935 100644 --- a/mlprodict/sklapi/__init__.py +++ b/mlprodict/sklapi/__init__.py @@ -2,6 +2,7 @@ """ @file @brief Shortcut to *sklapi*. +Importing this file imports :epkg:`sklearn-onnx` as well. """ from .onnx_pipeline import OnnxPipeline from .onnx_transformer import OnnxTransformer diff --git a/mlprodict/sklapi/onnx_tokenizer.py b/mlprodict/sklapi/onnx_tokenizer.py index b45c73acb..e30fbd881 100644 --- a/mlprodict/sklapi/onnx_tokenizer.py +++ b/mlprodict/sklapi/onnx_tokenizer.py @@ -10,7 +10,6 @@ from sklearn.base import BaseEstimator, TransformerMixin from onnx import helper, TensorProto, load from onnx.defs import onnx_opset_version -from onnxruntime import InferenceSession, SessionOptions try: from onnxruntime_extensions import get_library_path except ImportError: @@ -18,7 +17,43 @@ from mlprodict import __max_supported_opset__ -class SentencePieceTokenizerTransformer(BaseEstimator, TransformerMixin): +class TokenizerTransformerBase(BaseEstimator, TransformerMixin): + """ + Base class for @see cl SentencePieceTokenizerTransformer and + @see cl GPT2TokenizerTransformer. + """ + + def __init__(self): + BaseEstimator.__init__(self) + TransformerMixin.__init__(self) + from onnxruntime import InferenceSession, SessionOptions # delayed + self._InferenceSession = InferenceSession + self._SessionOptions = SessionOptions + + def __getstate__(self): + state = BaseEstimator.__getstate__(self) + del state['sess_'] + del state['_InferenceSession'] + del state['_SessionOptions'] + state['onnx_'] = state['onnx_'].SerializeToString() + return state + + def __setstate__(self, state): + if get_library_path is None: + raise ImportError( + "onnxruntime_extensions is not installed.") + from onnxruntime import InferenceSession, SessionOptions # delayed + state['onnx_'] = load(BytesIO(state['onnx_'])) + BaseEstimator.__setstate__(self, state) + self._InferenceSession = InferenceSession + self._SessionOptions = SessionOptions + so = SessionOptions() + so.register_custom_ops_library(get_library_path()) + self.sess_ = InferenceSession(self.onnx_.SerializeToString(), so) + return self + + +class SentencePieceTokenizerTransformer(TokenizerTransformerBase): """ Wraps `SentencePieceTokenizer ')[0].split(',') model = helper.make_model( opset_imports=[helper.make_operatorsetid('', opset)], - ir_version=OPSET_TO_IR_VERSION.get(opset, 7), + ir_version=get_ir_version(opset), producer_name='mlprodict', producer_version='0.1', graph=helper.make_graph( diff --git a/mlprodict/testing/einsum/einsum_fct.py b/mlprodict/testing/einsum/einsum_fct.py index 2fc96315d..16ab936b0 100644 --- a/mlprodict/testing/einsum/einsum_fct.py +++ b/mlprodict/testing/einsum/einsum_fct.py @@ -8,7 +8,6 @@ import math import numpy from onnx import helper -from skl2onnx.common.data_types import FloatTensorType from ...onnx_tools.onnx2py_helper import guess_proto_dtype from ...onnxrt.onnx_micro_runtime import OnnxMicroRuntime from ... import __max_supported_opset__, get_ir_version @@ -195,6 +194,7 @@ def _build_optimize_ml(self): if hasattr(inst, 'onnx_'): onx = inst.onnx_ else: + from skl2onnx.common.data_types import FloatTensorType # delayed inits = [ ('X%d' % i, FloatTensorType(list(inputs[i].shape))) for i in range(len(inputs))] diff --git a/mlprodict/testing/einsum/einsum_impl_classes.py b/mlprodict/testing/einsum/einsum_impl_classes.py index 1d1ad90c2..8b196bfec 100644 --- a/mlprodict/testing/einsum/einsum_impl_classes.py +++ b/mlprodict/testing/einsum/einsum_impl_classes.py @@ -6,8 +6,8 @@ """ import numpy from onnx import helper, numpy_helper -from skl2onnx.common.data_types import guess_proto_type from ...onnx_tools.onnx2py_helper import guess_proto_dtype +from ...npy.xop_variable import guess_numpy_type from ... import __max_supported_opset__, get_ir_version from .blas_lapack import gemm_dot from .einsum_impl_ext import ( @@ -1455,13 +1455,14 @@ def to_onnx(self, output, *inputs, dtype=None, verbose=False, raise ValueError( # pragma: no cover "Irreconcialable shapes for input %r: " "%r != len(%r)." % (name, le, typ.shape)) - proto = guess_proto_type(typ) - onx_inputs.append(helper.make_tensor_value_info( - name, proto, typ.shape)) + proto = guess_proto_dtype(guess_numpy_type(typ)) + onx_inputs.append( + helper.make_tensor_value_info(name, proto, typ.shape)) names[len(names)] = name else: - onx_inputs.append(helper.make_tensor_value_info( - inp, proto, [None for i in range(le)])) + onx_inputs.append( + helper.make_tensor_value_info( + inp, proto, [None for i in range(le)])) names[len(names)] = inp # output diff --git a/mlprodict/testing/test_utils/__init__.py b/mlprodict/testing/test_utils/__init__.py index 0fc3d6759..c5085d726 100644 --- a/mlprodict/testing/test_utils/__init__.py +++ b/mlprodict/testing/test_utils/__init__.py @@ -1,6 +1,6 @@ """ @file -@brief Inspired from skl2onnx, handles two backends. +@brief Inspired from sklearn-onnx, handles two backends. """ import numpy from .utils_backend_onnxruntime import _capture_output diff --git a/mlprodict/testing/test_utils/quantized_tensor.py b/mlprodict/testing/test_utils/quantized_tensor.py index 97cdc50f6..a9ddc8618 100644 --- a/mlprodict/testing/test_utils/quantized_tensor.py +++ b/mlprodict/testing/test_utils/quantized_tensor.py @@ -3,7 +3,7 @@ @brief Initializes a quantized tensor from float values. """ import numpy -from skl2onnx.algebra.onnx_ops import OnnxQLinearConv # pylint: disable=E0611 +from ...npy.xop import loadop from ...onnxrt import OnnxInference @@ -105,6 +105,8 @@ def test_qlinear_conv(x: QuantizedTensor, x_shape, :param strides: optional parameter for operator `QLinearConv` :param group: optional paramerer for operator `QLinearConv` """ + OnnxQLinearConv = loadop('QLinearConv') + if opset is None: from ... import __max_supported_opset__ opset = __max_supported_opset__ diff --git a/mlprodict/testing/test_utils/tests_helper.py b/mlprodict/testing/test_utils/tests_helper.py index b36afff5b..469b8d7c1 100644 --- a/mlprodict/testing/test_utils/tests_helper.py +++ b/mlprodict/testing/test_utils/tests_helper.py @@ -1,6 +1,6 @@ """ @file -@brief Inspired from skl2onnx, handles two backends. +@brief Inspired from sklearn-onnx, handles two backends. """ import pickle import os @@ -15,7 +15,6 @@ make_regression) from sklearn.model_selection import train_test_split from sklearn.preprocessing import MultiLabelBinarizer -from skl2onnx.common.data_types import FloatTensorType, DoubleTensorType from .utils_backend import compare_backend from .utils_backend_common import ( extract_options, evaluate_condition, is_backend_enabled, @@ -231,6 +230,9 @@ def dump_data_and_model( # pylint: disable=R0912 if the comparison between the expected outputs and the backend outputs fails or it saves the backend output and adds it to the results. """ + # delayed import because too long + from skl2onnx.common.data_types import FloatTensorType, DoubleTensorType # delayed + runtime_test = dict(model=model, data=data) if folder is None: @@ -445,7 +447,7 @@ def convert_model(model, name, input_types): :param input_types: input types :return: *onnx* model """ - from skl2onnx import convert_sklearn + from skl2onnx import convert_sklearn # delayed model, prefix = convert_sklearn(model, name, input_types), "Sklearn" if model is None: # pragma: no cover @@ -466,6 +468,7 @@ def dump_one_class_classification( Every created filename will follow the pattern: ``/..``. """ + from skl2onnx.common.data_types import FloatTensorType # delayed X = [[0.0, 1.0], [1.0, 1.0], [2.0, 0.0]] X = numpy.array(X, dtype=numpy.float32) y = [1, 1, 1] @@ -492,6 +495,7 @@ def dump_binary_classification( Every created filename will follow the pattern: ``/..``. """ + from skl2onnx.common.data_types import FloatTensorType # delayed X = [[0, 1], [1, 1], [2, 0]] X = numpy.array(X, dtype=numpy.float32) if label_string: @@ -541,6 +545,7 @@ def dump_multiple_classification( Every created filename will follow the pattern: ``/..``. """ + from skl2onnx.common.data_types import FloatTensorType # delayed X = [[0, 1], [1, 1], [2, 0], [0.5, 0.5], [1.1, 1.1], [2.1, 0.1]] X = numpy.array(X, dtype=numpy.float32) y = [0, 1, 2, 1, 1, 2] @@ -593,6 +598,7 @@ def dump_multilabel_classification( Every created filename will follow the pattern: ``/..``. """ + from skl2onnx.common.data_types import FloatTensorType # delayed X = [[0, 1], [1, 1], [2, 0], [0.5, 0.5], [1.1, 1.1], [2.1, 0.1]] X = numpy.array(X, dtype=numpy.float32) if label_string: @@ -617,8 +623,8 @@ def dump_multilabel_classification( verbose=verbose, comparable_outputs=comparable_outputs, backend=backend) - X, y = make_multilabel_classification(40, n_features=4, random_state=42, # pylint: disable=W0632 - n_classes=3) + X, y = make_multilabel_classification( # pylint: disable=W0632 + 40, n_features=4, random_state=42, n_classes=3) X = X[:, :2] model.fit(X, y) if verbose: # pragma: no cover @@ -647,6 +653,7 @@ def dump_multiple_regression( Every created filename will follow the pattern: ``/..``. """ + from skl2onnx.common.data_types import FloatTensorType # delayed X = [[0, 1], [1, 1], [2, 0]] X = numpy.array(X, dtype=numpy.float32) y = numpy.array([[100, 50], [100, 49], [100, 99]], dtype=numpy.float32) @@ -670,6 +677,7 @@ def dump_single_regression(model, suffix="", folder=None, allow_failure=None, Every created filename will follow the pattern: ``/..``. """ + from skl2onnx.common.data_types import FloatTensorType # delayed X = [[0, 1], [1, 1], [2, 0]] X = numpy.array(X, dtype=numpy.float32) y = numpy.array([100, -10, 50], dtype=numpy.float32) diff --git a/mlprodict/testing/test_utils/utils_backend_common_compare.py b/mlprodict/testing/test_utils/utils_backend_common_compare.py index 8e9766c94..46f324c4c 100644 --- a/mlprodict/testing/test_utils/utils_backend_common_compare.py +++ b/mlprodict/testing/test_utils/utils_backend_common_compare.py @@ -1,11 +1,10 @@ """ @file -@brief Inspired from skl2onnx, handles two backends. +@brief Inspired from sklearn-onnx, handles two backends. """ import numpy import onnx import pandas -from ...tools.ort_wrapper import OrtInvalidArgument from .utils_backend_common import ( load_data_and_model, extract_options, ExpectedAssertionError, OnnxBackendAssertionError, @@ -201,6 +200,10 @@ def compare_runtime_session( # pylint: disable=R0912 run_options = {'verbose': 2, 'fLOG': print} else: run_options = {} + + from onnxruntime.capi._pybind_state import ( # pylint: disable=E0611 + InvalidArgument as OrtInvalidArgument) + try: try: output = sess.run(None, inputs, **run_options) diff --git a/mlprodict/testing/test_utils/utils_backend_onnxruntime.py b/mlprodict/testing/test_utils/utils_backend_onnxruntime.py index 33cb26bb5..7dace1098 100644 --- a/mlprodict/testing/test_utils/utils_backend_onnxruntime.py +++ b/mlprodict/testing/test_utils/utils_backend_onnxruntime.py @@ -1,11 +1,9 @@ """ @file -@brief Inspired from skl2onnx, handles two backends. +@brief Inspired from sklearn-onnx, handles two backends. """ from pyquickhelper.pycode import is_travis_or_appveyor from .utils_backend_common_compare import compare_runtime_session -from ...tools.ort_wrapper import ( - InferenceSession, GraphOptimizationLevel, SessionOptions) def _capture_output(fct, kind): @@ -27,6 +25,8 @@ class InferenceSession2: def __init__(self, *args, **kwargs): "Overwrites the constructor." + from onnxruntime import ( + InferenceSession, GraphOptimizationLevel, SessionOptions) runtime_options = kwargs.pop('runtime_options', {}) disable_optimisation = runtime_options.pop( 'disable_optimisation', False) diff --git a/mlprodict/testing/test_utils/utils_backend_python.py b/mlprodict/testing/test_utils/utils_backend_python.py index 8ba1ade55..f9d0c5bc8 100644 --- a/mlprodict/testing/test_utils/utils_backend_python.py +++ b/mlprodict/testing/test_utils/utils_backend_python.py @@ -1,6 +1,6 @@ """ @file -@brief Inspired from skl2onnx, handles two backends. +@brief Inspired from sklearn-onnx, handles two backends. """ from ...onnxrt import OnnxInference from .utils_backend_common_compare import compare_runtime_session diff --git a/mlprodict/tools/data_types.py b/mlprodict/tools/data_types.py deleted file mode 100644 index 464d9615b..000000000 --- a/mlprodict/tools/data_types.py +++ /dev/null @@ -1,14 +0,0 @@ -""" -@file -@brief Creates missing types in onnxconverter-common. - -.. versionadded:: 0.6 -""" -from onnx import onnx_pb as onnx_proto # pylint: disable=W0611,E0611 -from skl2onnx.common.data_types import ( # pylint: disable=W0611,E0611 - TensorType, FloatTensorType, Int64TensorType, DoubleTensorType, - StringTensorType, Int32TensorType, BooleanTensorType, - UInt8TensorType) -from skl2onnx.common.data_types import ( # pylint: disable=W0611,E0611 - Int16TensorType, Int8TensorType, UInt16TensorType, - UInt32TensorType, UInt64TensorType, Float16TensorType) diff --git a/mlprodict/tools/graphs.py b/mlprodict/tools/graphs.py index c423f9af4..712bcbd03 100644 --- a/mlprodict/tools/graphs.py +++ b/mlprodict/tools/graphs.py @@ -586,10 +586,12 @@ def onnx2bigraph(model_onnx, recursive=False, graph_type='basic'): :showcode: import numpy - from skl2onnx.algebra.onnx_ops import OnnxAdd, OnnxSub from mlprodict.onnx_conv import to_onnx from mlprodict import __max_supported_opset__ as opv from mlprodict.tools.graphs import onnx2bigraph + from mlprodict.npy.xop import loadop + + OnnxAdd, OnnxSub = loadop('Add', 'Sub') idi = numpy.identity(2).astype(numpy.float32) A = OnnxAdd('X', idi, op_version=opv) diff --git a/mlprodict/tools/onnx_inference_ort_helper.py b/mlprodict/tools/onnx_inference_ort_helper.py index e7bb0040e..1fb00bbf0 100644 --- a/mlprodict/tools/onnx_inference_ort_helper.py +++ b/mlprodict/tools/onnx_inference_ort_helper.py @@ -3,8 +3,6 @@ @file @brief Helpers for :epkg:`onnxruntime`. """ -from onnxruntime.capi._pybind_state import ( # pylint: disable=E0611,W0611 - OrtDevice as C_OrtDevice) def get_ort_device(device): @@ -23,6 +21,8 @@ def get_ort_device(device): get_ort_device('cuda') get_ort_device('cuda:0') """ + from onnxruntime.capi._pybind_state import ( # pylint: disable=E0611,W0611 + OrtDevice as C_OrtDevice) # delayed if isinstance(device, C_OrtDevice): return device if isinstance(device, str): diff --git a/mlprodict/tools/ort_wrapper.py b/mlprodict/tools/ort_wrapper.py index a6f127f5a..d3d68a136 100644 --- a/mlprodict/tools/ort_wrapper.py +++ b/mlprodict/tools/ort_wrapper.py @@ -6,45 +6,7 @@ """ import os from onnx import numpy_helper - -try: - from onnxruntime import ( # pylint: disable=W0611 - SessionOptions, RunOptions, - InferenceSession as OrtInferenceSession, - __version__ as onnxrt_version, - GraphOptimizationLevel, - set_default_logger_severity) - from .onnx_inference_ort_helper import get_ort_device, device_to_providers -except ImportError: # pragma: no cover - SessionOptions = None - RunOptions = None - OrtInferenceSession = None - onnxrt_version = "0.0.0" - GraphOptimizationLevel = None - get_ort_device = None - device_to_providers = None - set_default_logger_severity = None - -try: - from onnxruntime.capi.onnxruntime_pybind11_state import ( # pylint: disable=W0611 - Fail as OrtFail, - NotImplemented as OrtNotImplemented, - InvalidArgument as OrtInvalidArgument, - InvalidGraph as OrtInvalidGraph, - RuntimeException as OrtRuntimeException, - OrtValue as C_OrtValue) -except ImportError: # pragma: no cover - SessionOptions = None - RunOptions = None - InferenceSession = None - onnxrt_version = "0.0.0" - GraphOptimizationLevel = None - OrtFail = RuntimeError - OrtNotImplemented = RuntimeError - OrtInvalidArgument = RuntimeError - OrtInvalidGraph = RuntimeError - OrtRuntimeException = RuntimeError - C_OrtValue = None +from .onnx_inference_ort_helper import get_ort_device, device_to_providers class InferenceSession: # pylint: disable=E0102 @@ -59,9 +21,15 @@ class InferenceSession: # pylint: disable=E0102 def __init__(self, onnx_bytes, sess_options=None, log_severity_level=4, device=None): - if InferenceSession is None: - raise ImportError( # pragma: no cover - "onnxruntime is not available.") + from onnxruntime import ( # pylint: disable=W0611 + SessionOptions, RunOptions, + InferenceSession as OrtInferenceSession, + set_default_logger_severity) + from onnxruntime.capi._pybind_state import ( # pylint: disable=E0611 + OrtValue as C_OrtValue) + + self.C_OrtValue = C_OrtValue + self.log_severity_level = log_severity_level if device is None: self.device = get_ort_device('cpu') @@ -94,7 +62,7 @@ def run(self, output_names, input_feed, run_options=None): :param run_options: None or RunOptions :return: array """ - if any(map(lambda v: isinstance(v, C_OrtValue), + if any(map(lambda v: isinstance(v, self.C_OrtValue), input_feed.values())): return self.sess._sess.run_with_ort_values( input_feed, self.output_names, run_options or self.ro)