Skip to content
This repository has been archived by the owner on Jan 13, 2024. It is now read-only.

Commit

Permalink
Adds an example to check export issues (#447)
Browse files Browse the repository at this point in the history
  • Loading branch information
xadupre committed Jul 5, 2022
1 parent d487b91 commit 9b115fd
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 13 deletions.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -325,3 +325,9 @@ mlprodict/npy/_cache/*.rst
*.so
*.dylib
*.dll
_doc/examples/cpp/*
_doc/examples/numpy/*
_doc/examples/onnx/*
_doc/examples/python/*
_doc/examples/tf2onnx/*
_doc/examples/xop/*
94 changes: 94 additions & 0 deletions _doc/examples/plot_export_onnx_tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
"""
.. _l-export-onnx-test:
Walk through all methods to export an ONNX model
================================================
An ONNX model can be exported into many formats
(see :ref:`l-api-export-onnx`). This example checks the
availibility through all onnx examples and all formats.
.. contents::
:local:
"""
import os
import numpy
from pandas import DataFrame
import matplotlib.pyplot as plt
from tqdm import tqdm
from mlprodict.testing.onnx_backend import enumerate_onnx_tests
from mlprodict.onnx_tools.onnx_export import (
export2onnx, export2tf2onnx, export2xop,
export2python, export2numpy, export2cpp)

#####################################
# Load the tests
# ++++++++++++++

tests = []
for test in tqdm(enumerate_onnx_tests('node')):
tests.append(test)

#####################################
# Code
# ++++

conv = dict(onnx=export2onnx,
tf2onnx=export2tf2onnx,
xop=export2xop,
python=export2python,
numpy=export2numpy,
cpp=export2cpp)

for fmt in conv:
if not os.path.exists(fmt):
os.mkdir(fmt)


data = []
for test in tqdm(tests):
for fmt, fct in conv.items():
onx = test.onnx_model
ext = ".cpp" if 'cpp' in fmt else ".py"
try:
code = fct(onx)
error = ""
except Exception as e:
error = str(e)
code = None
obs = dict(name=test.name, format=fmt, error=error,
ok=1 if error == "" else 0, code=code)
data.append(obs)
if code is not None:
filename = os.path.join(fmt, test.name + ext)
with open(filename, "w", encoding="utf-8") as f:
f.write(code)


#####################################
# Status and summary
# ++++++++++++++++++

df = DataFrame(data)
summary = df.pivot("name", "format", "ok").mean(axis=0).T
print(summary)


#####################################
# Graph
# +++++

summary.plot.bar(title="Conversion coverage")


#####################################
# Errors
# ++++++

for obs in data:
if obs['error'] != '':
print("%s | %s | %s" % (obs['name'], obs['format'], obs['error']))


# plt.show()
27 changes: 20 additions & 7 deletions _doc/sphinxdoc/source/api/tools.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,21 @@ Accessor

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

Export
++++++
.. _l-api-export-onnx:

Export from onnx to...
++++++++++++++++++++++

.. autosignature:: mlprodict.onnx_tools.onnx_export.export2numpy

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

.. autosignature:: mlprodict.onnx_tools.onnx_export.export2python

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

.. autosignature:: mlprodict.onnx_tools.onnx_export.export2xop

Graphs helper, manipulations
++++++++++++++++++++++++++++

Expand Down Expand Up @@ -115,6 +121,13 @@ Validation of scikit-learn models

.. autosignature:: mlprodict.onnxrt.validate.validate_summary.summary_report

Testing
+++++++

.. autosignature:: mlprodict.testing.onnx_backend.enumerate_onnx_tests

.. autosignature:: mlprodict.testing.onnx_backend.OnnxBackendTest

Visualization
+++++++++++++

Expand Down Expand Up @@ -167,6 +180,11 @@ Versions

.. autosignature:: mlprodict.__max_supported_opsets__

skl2onnx
========

.. autosignature:: mlprodict.onnx_tools.exports.skl2onnx_helper.add_onnx_graph

Type conversion
===============

Expand Down Expand Up @@ -269,8 +287,3 @@ The last example summarizes all the possibilities.
print()
for e in errors:
print(e)

skl2onnx
========

.. autosignature:: mlprodict.onnx_tools.exports.skl2onnx_helper.add_onnx_graph
8 changes: 5 additions & 3 deletions mlprodict/onnx_tools/exports/numpy_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,11 @@ def _make_numpy_code_onnx(self):
return "%s = %s %s" % (
outs, self.inputs[0], unary_ops_[self.op_type])

if self.op_type in {'Abs', 'Ceil', 'Cos', 'Cosh',
'Exp', 'Log', 'Sin', 'Sinh',
'Tan', 'Tanh'}:
return "%s = numpy.%s(%s)" % (outs, self.op_type.lower(), self.inputs[0])

if self.op_type == 'ArgMax':
self._make_sure_opsets(12)
self._make_sure_inputs(1)
Expand Down Expand Up @@ -305,9 +310,6 @@ def _make_numpy_code_onnx(self):
return "%s = numpy.full(%s, %s)" % (
outs, shape, value)

if self.op_type == 'Exp':
return "%s = numpy.exp(%s)" % (outs, self.inputs[0])

if self.op_type == 'Max':
return "%s = numpy.maximum(%s)" % (outs, ", ".join(self.inputs))

Expand Down
5 changes: 3 additions & 2 deletions mlprodict/onnx_tools/onnx_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ def _nodes(graph, rename_name, used, output_names, use_onnx_tensor,
use_onnx_tensor=use_onnx_tensor,
autopep_options=autopep_options,
function_name=fname)
subgraphs.append((body, node.op_type + "_" + node.name + "_body"))
subgraphs.append(
(body, node.op_type + "_" + node.name + "_body"))
attributes.append((at.name, fname + "()"))
continue
if node.op_type == 'If' and at.name in {'then_branch', 'else_branch'}:
Expand Down Expand Up @@ -274,7 +275,7 @@ def _python_make_node(onnx_node, version, indent=0):
name = _python_make_node_name(
node.domain, version, node.op_type, node=True)
attributes_str = _python_make_node_make_attribute_str(node)
if len(node.input) > 0:
if len(node.input) > 0 and len(attributes_str) > 0:
attributes_str = ", " + attributes_str
output = ", ".join(node.output)
text = [sindent, output, " = ", name,
Expand Down
3 changes: 2 additions & 1 deletion mlprodict/testing/onnx_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,8 @@ def enumerate_onnx_tests(series, fct_filter=None):
Works as an enumerator to start processing them
without waiting or storing too much of them.
:param series: which subfolder to load
:param series: which subfolder to load, possible values:
(`'node'`, ...)
:param fct_filter: function `lambda testname: boolean`
to load or skip the test, None for all
:return: list of @see cl OnnxBackendTest
Expand Down

0 comments on commit 9b115fd

Please sign in to comment.