Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/onnx/onnxmltools into speed
Browse files Browse the repository at this point in the history
  • Loading branch information
sdpython committed Aug 19, 2021
2 parents fe48e76 + c1651b1 commit 6df0b37
Show file tree
Hide file tree
Showing 7 changed files with 140 additions and 39 deletions.
9 changes: 4 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,16 @@ If you choose to install `onnxmltools` from its source code, you must set the en
## Dependencies
This package relies on ONNX, NumPy, and ProtoBuf. If you are converting a model from scikit-learn, Core ML, Keras, LightGBM, SparkML, XGBoost, H2O, CatBoost or LibSVM, you will need an environment with the respective package installed from the list below:
1. scikit-learn
2. CoreMLTools
2. CoreMLTools (version 3.1 or lower)
3. Keras (version 2.0.8 or higher) with the corresponding Tensorflow version
4. LightGBM (scikit-learn interface)
4. LightGBM
5. SparkML
6. XGBoost (scikit-learn interface)
6. XGBoost
7. libsvm
8. H2O
9. CatBoost

ONNXMLTools has been tested with Python **3.5**, **3.6**, and **3.7**.
Version 1.6.1 is the latest version supporting Python 2.7.
ONNXMLTools is tested with Python **3.7+**.

# Examples
If you want the converted ONNX model to be compatible with a certain ONNX version, please specify the target_opset parameter upon invoking the convert function. The following Keras model conversion example demonstrates this below. You can identify the mapping from ONNX Operator Sets (referred to as opsets) to ONNX releases in the [versioning documentation](https://github.com/onnx/onnx/blob/master/docs/Versioning.md#released-versions).
Expand Down
6 changes: 6 additions & 0 deletions docs/api_summary.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,20 @@ in *onnxmltools*.
Converters
==========

.. autofunction:: onnxmltools.convert.h2o.catboost

.. autofunction:: onnxmltools.convert.coreml.convert

.. autofunction:: onnxmltools.convert.h2o.convert

.. autofunction:: onnxmltools.convert.keras.convert

.. autofunction:: onnxmltools.convert.lightgbm.convert

.. autofunction:: onnxmltools.convert.sklearn.convert

.. autofunction:: onnxmltools.convert.xgboost.convert

Utils
=====

Expand Down
7 changes: 5 additions & 2 deletions docs/examples/plot_convert_keras.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@
optimizer='sgd',
metrics=['accuracy'])
model.fit(X_train, y_train, epochs=5, batch_size=16)
print("keras prediction")
print(model.predict(X_test.astype(numpy.float32)))

###########################
# Convert a model into ONNX
Expand All @@ -62,9 +64,10 @@

sess = rt.InferenceSession(onx.SerializeToString())
input_name = sess.get_inputs()[0].name
label_name = sess.get_outputs()[0].name
output_name = sess.get_outputs()[0].name
pred_onx = sess.run(
[label_name], {input_name: X_test.astype(numpy.float32)})[0]
[output_name], {input_name: X_test.astype(numpy.float32)})[0]
print("ONNX prediction")
print(pred_onx)

##################################
Expand Down
13 changes: 2 additions & 11 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,14 @@
onnxmltools: Convert your model into ONNX
=========================================

.. list-table:
:header-rows: 1
:widths: 5 5
* - Linux
- Windows
* - .. image:: https://travis-ci.org/onnx/onnxmltools.svg?branch=master
:target: https://travis-ci.org/onnx/onnxmltools
- .. image:: https://ci.appveyor.com/api/projects/status/d1xav3amubypje4n?svg=true
:target: https://ci.appveyor.com/project/xadupre/onnxmltools
ONNXMLTools enables you to convert models from different machine learning
toolkits into `ONNX <https://onnx.ai>`_.
Currently the following toolkits are supported:

* `Apple Core ML <https://developer.apple.com/documentation/coreml>`_,
(`onnx-coreml <https://github.com/onnx/onnx-coreml>`_ does the reverse
conversion from *onnx* to *Apple Core ML*),
conversion from *onnx* to *Apple Core ML*) (up to version 3.1)
* `catboost <https://catboost.ai/>`_
* `h2o <http://docs.h2o.ai/h2o/latest-stable/h2o-py/docs/intro.html>`_
(a subset only)
* `Keras <https://keras.io/>`_
Expand Down
12 changes: 12 additions & 0 deletions onnxmltools/convert/common/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,16 @@ def hummingbird_installed():
except ImportError:
return False


def tf2onnx_installed():
"""
Checks that *tf2onnx* is available.
"""
try:
import tf2onnx # noqa F401
return True
except ImportError:
return False


from onnxconverter_common.utils import * # noqa
118 changes: 101 additions & 17 deletions onnxmltools/convert/main.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
# SPDX-License-Identifier: Apache-2.0

import warnings
from distutils.version import StrictVersion
import onnx
from .common import utils
import warnings


def convert_coreml(model, name=None, initial_types=None, doc_string='', target_opset=None,
targeted_onnx=onnx.__version__, custom_conversion_functions=None, custom_shape_calculators=None):
targeted_onnx=None, custom_conversion_functions=None, custom_shape_calculators=None):
if targeted_onnx is not None:
warnings.warn("targeted_onnx is deprecated. Use target_opset.", DeprecationWarning)
if not utils.coreml_installed():
raise RuntimeError('coremltools is not installed. Please install coremltools to use this feature.')

Expand All @@ -15,22 +18,93 @@ def convert_coreml(model, name=None, initial_types=None, doc_string='', target_o
custom_conversion_functions, custom_shape_calculators)


def convert_keras(model, name=None, initial_types=None, doc_string='',
target_opset=None, targeted_onnx=onnx.__version__,
channel_first_inputs=None, custom_conversion_functions=None, custom_shape_calculators=None,
def convert_keras(model, name=None,
initial_types=None,
doc_string='',
target_opset=None,
targeted_onnx=None,
channel_first_inputs=None,
custom_conversion_functions=None,
custom_shape_calculators=None,
default_batch_size=1):
if not utils.keras2onnx_installed():
raise RuntimeError('keras2onnx is not installed. Please install it to use this feature.')

if custom_conversion_functions:
warnings.warn('custom_conversion_functions is not supported any more. Please set it to None.')

from keras2onnx import convert_keras as convert
return convert(model, name, doc_string, target_opset, channel_first_inputs)
"""
.. versionchanged:: 1.9.0
The conversion is now using *tf2onnx*.
"""
if targeted_onnx is not None:
warnings.warn("targeted_onnx is deprecated and unused. Use target_opset.", DeprecationWarning)
import tensorflow as tf
if StrictVersion(tf.__version__) < StrictVersion('2.0'):
# Former converter for tensorflow<2.0.
from keras2onnx import convert_keras as convert
return convert(model, name, doc_string, target_opset, channel_first_inputs)
else:
# For tensorflow>=2.0, new converter based on tf2onnx.
import tf2onnx

if not utils.tf2onnx_installed():
raise RuntimeError('tf2onnx is not installed. Please install it to use this feature.')

if custom_conversion_functions is not None:
warnings.warn('custom_conversion_functions is not supported any more. Please set it to None.')
if custom_shape_calculators is not None:
warnings.warn('custom_shape_calculators is not supported any more. Please set it to None.')
if default_batch_size != 1:
warnings.warn('default_batch_size is not supported any more. Please set it to 1.')
if default_batch_size != 1:
warnings.warn('default_batch_size is not supported any more. Please set it to 1.')

if initial_types is not None:
from onnxconverter_common import (
FloatTensorType, DoubleTensorType,
Int64TensorType, Int32TensorType,
StringTensorType, BooleanTensorType)
spec = []
for name, kind in initial_types:
if isinstance(kind, FloatTensorType):
dtype = tf.float32
elif isinstance(kind, Int64TensorType):
dtype = tf.int64
elif isinstance(kind, Int32TensorType):
dtype = tf.int32
elif isinstance(kind, DoubleTensorType):
dtype = tf.float64
elif isinstance(kind, StringTensorType):
dtype = tf.string
elif isinstance(kind, BooleanTensorType):
dtype = tf.bool
else:
raise TypeError(
"Unexpected type %r, cannot infer tensorflow type." % type(kind))
spec.append(tf.TensorSpec(tuple(kind.shape), dtype, name=name))
input_signature = tuple(spec)
else:
input_signature = None

model_proto, external_tensor_storage = tf2onnx.convert.from_keras(
model,
input_signature=input_signature,
opset=target_opset,
custom_ops=None,
custom_op_handlers=None,
custom_rewriter=None,
inputs_as_nchw=channel_first_inputs,
extra_opset=None,
shape_override=None,
target=None,
large_model=False,
output_path=None)
if external_tensor_storage is not None:
warnings.warn("The current API does not expose the second result 'external_tensor_storage'. "
"Use tf2onnx directly to get it.")
model_proto.doc_string = doc_string
return model_proto


def convert_libsvm(model, name=None, initial_types=None, doc_string='', target_opset=None,
targeted_onnx=onnx.__version__, custom_conversion_functions=None, custom_shape_calculators=None):
targeted_onnx=None, custom_conversion_functions=None, custom_shape_calculators=None):
if targeted_onnx is not None:
warnings.warn("targeted_onnx is deprecated. Use target_opset.", DeprecationWarning)
if not utils.libsvm_installed():
raise RuntimeError('libsvm is not installed. Please install libsvm to use this feature.')

Expand All @@ -51,8 +125,10 @@ def convert_catboost(model, name=None, initial_types=None, doc_string='', target


def convert_lightgbm(model, name=None, initial_types=None, doc_string='', target_opset=None,
targeted_onnx=onnx.__version__, custom_conversion_functions=None,
targeted_onnx=None, custom_conversion_functions=None,
custom_shape_calculators=None, without_onnx_ml=False, zipmap=True):
if targeted_onnx is not None:
warnings.warn("targeted_onnx is deprecated. Use target_opset.", DeprecationWarning)
if not utils.lightgbm_installed():
raise RuntimeError('lightgbm is not installed. Please install lightgbm to use this feature.')

Expand All @@ -63,7 +139,9 @@ def convert_lightgbm(model, name=None, initial_types=None, doc_string='', target


def convert_sklearn(model, name=None, initial_types=None, doc_string='', target_opset=None,
targeted_onnx=onnx.__version__, custom_conversion_functions=None, custom_shape_calculators=None):
targeted_onnx=None, custom_conversion_functions=None, custom_shape_calculators=None):
if targeted_onnx is not None:
warnings.warn("targeted_onnx is deprecated. Use target_opset.", DeprecationWarning)
if not utils.sklearn_installed():
raise RuntimeError('scikit-learn is not installed. Please install scikit-learn to use this feature.')

Expand All @@ -76,8 +154,10 @@ def convert_sklearn(model, name=None, initial_types=None, doc_string='', target_


def convert_sparkml(model, name=None, initial_types=None, doc_string='', target_opset=None,
targeted_onnx=onnx.__version__, custom_conversion_functions=None,
targeted_onnx=None, custom_conversion_functions=None,
custom_shape_calculators=None, spark_session=None):
if targeted_onnx is not None:
warnings.warn("targeted_onnx is deprecated. Use target_opset.", DeprecationWarning)
if not utils.sparkml_installed():
raise RuntimeError('Spark is not installed. Please install Spark to use this feature.')

Expand All @@ -87,6 +167,8 @@ def convert_sparkml(model, name=None, initial_types=None, doc_string='', target_


def convert_xgboost(*args, **kwargs):
if kwargs.get('targeted_onnx', None) is not None:
warnings.warn("targeted_onnx is deprecated. Use target_opset.", DeprecationWarning)
if not utils.xgboost_installed():
raise RuntimeError('xgboost is not installed. Please install xgboost to use this feature.')

Expand All @@ -95,6 +177,8 @@ def convert_xgboost(*args, **kwargs):


def convert_h2o(*args, **kwargs):
if kwargs.get('targeted_onnx', None) is not None:
warnings.warn("targeted_onnx is deprecated. Use target_opset.", DeprecationWarning)
if not utils.h2o_installed():
raise RuntimeError('h2o is not installed. Please install h2o to use this feature.')

Expand Down
14 changes: 10 additions & 4 deletions onnxmltools/convert/xgboost/_parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,16 @@ def _get_attributes(booster):
reg = re.compile(b'(multi:[a-z]{1,15})')
objs = list(set(reg.findall(bstate)))
if len(objs) != 1:
raise RuntimeError(
"Unable to guess objective in {}.".format(objs))
kwargs['num_class'] = trees // ntrees
kwargs["objective"] = objs[0].decode('ascii')
if '"name":"binary:logistic"' in str(bstate):
kwargs['num_class'] = 1
kwargs["objective"] = "binary:logistic"
else:
raise RuntimeError(
"Unable to guess objective in %r (trees=%r, ntrees=%r)"
"." % (objs, trees, ntrees))
else:
kwargs['num_class'] = trees // ntrees
kwargs["objective"] = objs[0].decode('ascii')
else:
kwargs['num_class'] = 1
kwargs["objective"] = "binary:logistic"
Expand Down

0 comments on commit 6df0b37

Please sign in to comment.