Skip to content
This repository was archived by the owner on Jan 13, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3,643 changes: 2,822 additions & 821 deletions _doc/notebooks/onnx_fft.ipynb

Large diffs are not rendered by default.

24 changes: 21 additions & 3 deletions _doc/sphinxdoc/source/api/tools.rst
Original file line numberDiff line numberDiff line change
Expand Up@@ -18,6 +18,13 @@ Accessor

.. autosignature:: mlprodict.onnx_tools.onnx_tools.insert_node

Export
++++++

.. autosignature:: mlprodict.onnx_tools.onnx_export.export2onnx

.. autosignature:: mlprodict.onnx_tools.onnx_export.export2tf2onnx

Graphs
++++++

Expand DownExpand Up@@ -48,6 +55,8 @@ The following functions reduce the number of ONNX operators in a graph
while keeping the same results. The optimized graph
is left unchanged.

.. autosignature:: mlprodict.onnx_tools.onnx_tools.ensure_topological_order

.. autosignature:: mlprodict.onnx_tools.optim.onnx_optimisation.onnx_remove_node

.. autosignature:: mlprodict.onnx_tools.optim.onnx_optimisation_identity.onnx_remove_node_identity
Expand All@@ -68,15 +77,24 @@ Serialization

.. autosignature:: mlprodict.onnx_tools.onnx2py_helper.to_bytes

Runtime
=======

.. autosignature:: mlprodict.tools.onnx_micro_runtime.OnnxMicroRuntime

Validation
++++++++++

.. autosignature:: mlprodict.onnx_tools.model_checker.onnx_shaker

Runtime
=======
Visualization
+++++++++++++

.. autosignature:: mlprodict.tools.onnx_micro_runtime.OnnxMicroRuntime
Many times I had to debug and I was thinking about a way to see
a graph in a text editor. That's the goal of this function with
the possibility later to only show a part of a graph.

.. autosignature:: mlprodict.onnx_tools.graphs.onnx2bigraph

Others
======
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -136,7 +136,7 @@
pipe.fit(X_train, y_train)
print(pipe.predict_proba(X_test[:2]))

onx = to_onnx(pipe, X_train[:1], rewrite_ops=True,
onx = to_onnx(pipe, X_train[:1],
options={LogisticRegression:{'zipmap': False}})
oinf = OnnxInference(onx)
print(oinf.run({'X': X_test[:2]})['probabilities'])
Expand Down
49 changes: 49 additions & 0 deletions _unittests/ut_cli/test_cli_onnx_code.py
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
"""
@brief test tree node (time=10s)
"""
import os
import unittest
from pyquickhelper.loghelper import BufferedPrint
from pyquickhelper.pycode import ExtTestCase, get_temp_folder
from mlprodict.__main__ import main


class TestCliOnnxCode(ExtTestCase):

def test_cli_onnx_code(self):
st = BufferedPrint()
main(args=["onnx_code", "--help"], fLOG=st.fprint)
res = str(st)
self.assertIn("verbose", res)

def test_cli_onnx_code_onnx(self):
temp = get_temp_folder(__file__, "temp_cli_onnx_code_onnx")
name = os.path.join(
temp, "..", "..", "ut_tools", "data", "fft2d_any.onnx")
self.assertExists(name)
output = os.path.join(temp, "code_onnx.py")
st = BufferedPrint()
main(args=["onnx_code", "--filename", name,
"--output", output, "--verbose", "1"], fLOG=st.fprint)
self.assertExists(output)
with open(output, "r", encoding='utf-8') as f:
content = f.read()
self.assertIn("create_model()", content)

def test_cli_onnx_code_tf2onnx(self):
temp = get_temp_folder(__file__, "temp_cli_onnx_code_tf2onnx")
name = os.path.join(
temp, "..", "..", "ut_tools", "data", "fft2d_any.onnx")
self.assertExists(name)
output = os.path.join(temp, "code_tf2onnx.py")
st = BufferedPrint()
main(args=["onnx_code", "--filename", name, '--format', 'tf2onnx',
"--output", output, "--verbose", "1"], fLOG=st.fprint)
self.assertExists(output)
with open(output, "r", encoding='utf-8') as f:
content = f.read()
self.assertIn("tf_op", content)


if __name__ == "__main__":
unittest.main()
12 changes: 12 additions & 0 deletions _unittests/ut_npy/test_onnx_variable.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -102,6 +102,13 @@ def test_abs_matmul(x: NDArray[Any, numpy.float32],
return nxnp.abs(x) @ x


@onnxnumpy_default
def test_abs_matmul2(x: NDArray[Any, numpy.float32],
) -> NDArray[Any, numpy.float32]:
"onnx numpy addition"
return nxnp.matmul(nxnp.abs(x), x)


@onnxnumpy_default
def test_abs_div(x: NDArray[Any, numpy.float32],
) -> NDArray[Any, numpy.float32]:
Expand DownExpand Up@@ -515,6 +522,11 @@ def test_py_abs_matmul(self):
y = test_abs_matmul(x)
self.assertEqualArray(y, numpy.abs(x) @ x)

def test_py_abs_matmul2(self):
x = numpy.array([[6.1, -5], [3.5, -7.8]], dtype=numpy.float32)
y = test_abs_matmul2(x)
self.assertEqualArray(y, numpy.abs(x) @ x)

def test_py_abs_div(self):
x = numpy.array([[6.1, -5], [3.5, -7.8]], dtype=numpy.float32)
y = test_abs_div(x)
Expand Down
1 change: 1 addition & 0 deletions _unittests/ut_onnx_conv/test_onnxrt_runtime_lightgbm.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -273,6 +273,7 @@ def test_onnxrt_python_lightgbm_categorical_iris_dataframe(self):
values = pandas.DataFrame(got['output_probability']).values
self.assertEqualArray(exp, values[:, 1], decimal=5)

@skipif_circleci('stuck')
@unittest.skipIf(sys.platform == 'darwin', 'stuck')
def test_lightgbm_booster_classifier(self):
from lightgbm import Dataset, train as lgb_train
Expand Down
134 changes: 134 additions & 0 deletions _unittests/ut_onnx_conv/test_onnxrt_runtime_lightgbm_bug.py
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
"""
@brief test log(time=3s)
"""
import sys
import unittest
from logging import getLogger
import numpy
from pyquickhelper.pycode import ExtTestCase, skipif_circleci
from skl2onnx.common.data_types import FloatTensorType
from mlprodict.onnxrt import OnnxInference
from mlprodict.onnx_conv import register_converters, to_onnx


class TestOnnxrtRuntimeLightGbmBug(ExtTestCase):

def setUp(self):
logger = getLogger('skl2onnx')
logger.disabled = True
register_converters()

@skipif_circleci('stuck')
@unittest.skipIf(sys.platform == 'darwin', 'stuck')
def test_lightgbm_regressor(self):
from lightgbm import LGBMRegressor
try:
from onnxmltools.convert import convert_lightgbm
except ImportError:
convert_lightgbm = None

X = numpy.abs(numpy.random.randn(7, 227)).astype(numpy.float32)
y = X.sum(axis=1) + numpy.random.randn(
X.shape[0]).astype(numpy.float32) / 10
model = LGBMRegressor(
max_depth=8, n_estimators=100, min_child_samples=1,
learning_rate=0.0000001)
model.fit(X, y)
expected = model.predict(X)

model_onnx = to_onnx(model, X)
if convert_lightgbm is not None:
model_onnx2 = convert_lightgbm(
model, initial_types=[('X', FloatTensorType([None, 227]))])
else:
model_onnx2 = None

for i, mo in enumerate([model_onnx, model_onnx2]):
if mo is None:
continue
for rt in ['python', 'onnxruntime1']:
with self.subTest(i=i, rt=rt):
oinf = OnnxInference(mo, runtime=rt)
got = oinf.run({'X': X})['variable']
diff = numpy.abs(got.ravel() - expected.ravel()).max()
if __name__ == "__main__":
print("lgb", i, rt, diff)
self.assertLess(diff, 1e-3)

@skipif_circleci('stuck')
@unittest.skipIf(sys.platform == 'darwin', 'stuck')
def test_lightgbm_regressor_double(self):
from lightgbm import LGBMRegressor

X = numpy.abs(numpy.random.randn(7, 227)).astype(numpy.float32)
y = X.sum(axis=1) + numpy.random.randn(
X.shape[0]).astype(numpy.float32) / 10
model = LGBMRegressor(
max_depth=8, n_estimators=100, min_child_samples=1,
learning_rate=0.0000001)
model.fit(X, y)
expected = model.predict(X)

model_onnx = to_onnx(model, X, rewrite_ops=True)
model_onnx2 = to_onnx(model, X.astype(numpy.float64),
rewrite_ops=True)

for i, mo in enumerate([model_onnx, model_onnx2]):
for rt in ['python', 'onnxruntime1']:
if "TreeEnsembleRegressorDouble" in str(mo):
x = X.astype(numpy.float64)
if rt == 'onnxruntime1':
continue
else:
x = X
with self.subTest(i=i, rt=rt):
oinf = OnnxInference(mo, runtime=rt)
got = oinf.run({'X': x})['variable']
diff = numpy.abs(got.ravel() - expected.ravel()).max()
if __name__ == "__main__":
print("lgbd", i, rt, diff)
if i == 1 and rt == 'python':
self.assertLess(diff, 1e-5)
else:
self.assertLess(diff, 1e-3)

@skipif_circleci('stuck')
@unittest.skipIf(sys.platform == 'darwin', 'stuck')
def test_xgboost_regressor(self):
from xgboost import XGBRegressor
try:
from onnxmltools.convert import convert_xgboost
except ImportError:
convert_xgboost = None

X = numpy.abs(numpy.random.randn(7, 227)).astype(numpy.float32)
y = X.sum(axis=1) + numpy.random.randn(
X.shape[0]).astype(numpy.float32) / 10
model = XGBRegressor(
max_depth=8, n_estimators=100,
learning_rate=0.000001)
model.fit(X, y)
expected = model.predict(X)

model_onnx = to_onnx(model, X)
if convert_xgboost is not None:
model_onnx2 = convert_xgboost(
model, initial_types=[('X', FloatTensorType([None, 227]))])
else:
model_onnx2 = None

for i, mo in enumerate([model_onnx, model_onnx2]):
if mo is None:
continue
for rt in ['python', 'onnxruntime1']:
with self.subTest(i=i, rt=rt):
oinf = OnnxInference(mo, runtime=rt)
got = oinf.run({'X': X})['variable']
diff = numpy.abs(got.ravel() - expected.ravel()).max()
if __name__ == "__main__":
print("xgb", i, rt, diff)
self.assertLess(diff, 1e-5)


if __name__ == "__main__":
unittest.main()
21 changes: 14 additions & 7 deletions _unittests/ut_onnxrt/test_onnxrt_python_runtime_custom.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -98,7 +98,8 @@ def test_onnxt_runtime_fft(self):
if dim == 1:
X = numpy.arange(16).astype(numpy.float32)
elif dim == 2:
X = numpy.arange(48).astype(numpy.float32).reshape((3, -1))
X = numpy.arange(48).astype(
numpy.float32).reshape((3, -1))
Y = numpy.fft.fft(X.astype(numpy.float32), axis=axis)

onx = OnnxFFT('X', output_names=['Y'],
Expand All@@ -125,7 +126,8 @@ def test_onnxt_runtime_fft(self):
if dim == 1:
X = numpy.arange(16).astype(numpy.float32)
elif dim == 2:
X = numpy.arange(48).astype(numpy.float32).reshape((3, -1))
X = numpy.arange(48).astype(
numpy.float32).reshape((3, -1))
Y = numpy.fft.fft(X.astype(numpy.float32), 8, axis=axis)

onx = OnnxFFT('X', numpy.array([8], dtype=numpy.int64),
Expand DownExpand Up@@ -155,7 +157,8 @@ def test_onnxt_runtime_rfft(self):
if dim == 1:
X = numpy.arange(16).astype(numpy.float32)
elif dim == 2:
X = numpy.arange(48).astype(numpy.float32).reshape((3, -1))
X = numpy.arange(48).astype(
numpy.float32).reshape((3, -1))
Y = numpy.fft.rfft(X.astype(numpy.float32), axis=axis)

onx = OnnxRFFT('X', output_names=['Y'],
Expand All@@ -182,7 +185,8 @@ def test_onnxt_runtime_rfft(self):
if dim == 1:
X = numpy.arange(16).astype(numpy.float32)
elif dim == 2:
X = numpy.arange(48).astype(numpy.float32).reshape((3, -1))
X = numpy.arange(48).astype(
numpy.float32).reshape((3, -1))
Y = numpy.fft.rfft(X.astype(numpy.float32), 8, axis=axis)

onx = OnnxRFFT('X', numpy.array([8], dtype=numpy.int64),
Expand DownExpand Up@@ -210,7 +214,8 @@ def test_onnxt_runtime_fft2d(self):
if dim == 1:
X = numpy.arange(16).astype(numpy.float32)
elif dim == 2:
X = numpy.arange(48).astype(numpy.float32).reshape((3, -1))
X = numpy.arange(48).astype(
numpy.float32).reshape((3, -1))
Y = numpy.fft.fft2(X.astype(numpy.float32), axes=axis)

if axis is not None:
Expand DownExpand Up@@ -239,8 +244,10 @@ def test_onnxt_runtime_fft2d(self):
if dim == 1:
X = numpy.arange(16).astype(numpy.float32)
elif dim == 2:
X = numpy.arange(48).astype(numpy.float32).reshape((3, -1))
Y = numpy.fft.fft2(X.astype(numpy.float32), (8, 8), axes=axis)
X = numpy.arange(48).astype(
numpy.float32).reshape((3, -1))
Y = numpy.fft.fft2(
X.astype(numpy.float32), (8, 8), axes=axis)

if axis is not None:
onx = OnnxFFT2D('X', numpy.array([8, 8], dtype=numpy.int64),
Expand Down
Binary file added_unittests/ut_tools/data/fft2d_any.onnx
Binary file not shown.
Loading