Skip to content

Commit

Permalink
Update CI with latext onnxruntime, xgboost (#602)
Browse files Browse the repository at this point in the history
* Update CI with latext onnxruntime, xgboost

Signed-off-by: xadupre <xadupre@microsoft.com>

* add one unit test for issue 601

Signed-off-by: xadupre <xadupre@microsoft.com>

* fix iterable

Signed-off-by: xadupre <xadupre@microsoft.com>

* fix .str_

Signed-off-by: xadupre <xadupre@microsoft.com>

* hinge

Signed-off-by: xadupre <xadupre@microsoft.com>

* fix hinge

Signed-off-by: xadupre <xadupre@microsoft.com>

* fix str

Signed-off-by: xadupre <xadupre@microsoft.com>

* update CI

Signed-off-by: xadupre <xadupre@microsoft.com>

* fix yml

Signed-off-by: xadupre <xadupre@microsoft.com>

* fix coreml issue

Signed-off-by: xadupre <xadupre@microsoft.com>

* update CI

Signed-off-by: xadupre <xadupre@microsoft.com>

* update CI

Signed-off-by: xadupre <xadupre@microsoft.com>

* fix CI

Signed-off-by: xadupre <xadupre@microsoft.com>

* fix CI

Signed-off-by: xadupre <xadupre@microsoft.com>

* update CI

Signed-off-by: xadupre <xadupre@microsoft.com>

* update CI

Signed-off-by: xadupre <xadupre@microsoft.com>

* update CI

Signed-off-by: xadupre <xadupre@microsoft.com>

* update CI

Signed-off-by: xadupre <xadupre@microsoft.com>

Signed-off-by: xadupre <xadupre@microsoft.com>
  • Loading branch information
xadupre authored Jan 18, 2023
1 parent d9a6108 commit cfb2cc0
Show file tree
Hide file tree
Showing 13 changed files with 247 additions and 51 deletions.
38 changes: 30 additions & 8 deletions .azure-pipelines/linux-conda-CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,53 +14,68 @@ jobs:
vmImage: 'ubuntu-latest'
strategy:
matrix:
Python310-1130-RT1131-xgb173:
python.version: '3.10'
ONNX_PATH: 'onnx==1.13.0' #'-i https://test.pypi.org/simple/ onnx==1.12.0rc4'
ONNXRT_PATH: onnxruntime==1.13.1 #'-i https://test.pypi.org/simple/ ort-nightly==1.11.0.dev20220311003'
COREML_PATH: NONE
xgboost.version: '>=1.7.3'
numpy.version: ''
Python310-1120-RT1121-xgb161:
python.version: '3.9'
python.version: '3.10'
ONNX_PATH: 'onnx==1.12.0' #'-i https://test.pypi.org/simple/ onnx==1.12.0rc4'
ONNXRT_PATH: onnxruntime==1.12.1 #'-i https://test.pypi.org/simple/ ort-nightly==1.11.0.dev20220311003'
COREML_PATH: git+https://github.com/apple/coremltools@3.1
xgboost.version: '>=1.6.1'
COREML_PATH: NONE
xgboost.version: '==1.6.1'
numpy.version: ''
Python39-1120-RT1110-xgb161:
python.version: '3.9'
ONNX_PATH: 'onnx==1.12.0' #'-i https://test.pypi.org/simple/ onnx==1.12.0rc4'
ONNXRT_PATH: onnxruntime==1.11.0 #'-i https://test.pypi.org/simple/ ort-nightly==1.11.0.dev20220311003'
COREML_PATH: git+https://github.com/apple/coremltools@3.1
xgboost.version: '>=1.6.1'
numpy.version: ''
Python39-1120-RT1110-xgb142:
python.version: '3.9'
ONNX_PATH: 'onnx==1.12.0' #'-i https://test.pypi.org/simple/ onnx==1.12.0rc4'
ONNXRT_PATH: onnxruntime==1.11.0 #'-i https://test.pypi.org/simple/ ort-nightly==1.11.0.dev20220311003'
COREML_PATH: git+https://github.com/apple/coremltools@3.1
xgboost.version: '==1.4.2'
numpy.version: ''
Python39-1110-RT1110:
python.version: '3.9'
ONNX_PATH: onnx==1.11.0 # '-i https://test.pypi.org/simple/ onnx==1.9.101'
ONNXRT_PATH: onnxruntime==1.11.0 #'-i https://test.pypi.org/simple/ ort-nightly==1.11.0.dev20220311003'
COREML_PATH: git+https://github.com/apple/coremltools@3.1
numpy.version: ''
Python39-1110-RT1100:
python.version: '3.9'
ONNX_PATH: onnx==1.11.0 # '-i https://test.pypi.org/simple/ onnx==1.9.101'
ONNXRT_PATH: onnxruntime==1.10.0
COREML_PATH: git+https://github.com/apple/coremltools@3.1
xgboost.version: '>=1.2'
numpy.version: ''
Python39-1101-RT190:
python.version: '3.9'
ONNX_PATH: onnx==1.10.1
ONNXRT_PATH: onnxruntime==1.9.0
COREML_PATH: git+https://github.com/apple/coremltools@3.1
xgboost.version: '>=1.2'
numpy.version: '<=1.23.5'
Python39-190-RT180-xgb11:
python.version: '3.9'
ONNX_PATH: onnx==1.9.0
ONNXRT_PATH: onnxruntime==1.8.0
COREML_PATH: git+https://github.com/apple/coremltools@3.1
xgboost.version: '>=1.2'
numpy.version: '<=1.23.5'
Python38-181-RT170-xgb11:
python.version: '3.8'
ONNX_PATH: onnx==1.8.1
ONNXRT_PATH: onnxruntime==1.7.0
COREML_PATH: git+https://github.com/apple/coremltools@3.1
xgboost.version: '>=1.2'
numpy.version: '<=1.23.5'

maxParallel: 3

Expand All @@ -85,7 +100,7 @@ jobs:
pip install xgboost$(xgboost.version)
pip install $(ONNX_PATH)
pip install $(ONNXRT_PATH)
pip install $(COREML_PATH)
pip install "numpy$(numpy.version)"
displayName: 'Install xgboost, onnxruntime'
- script: |
Expand Down Expand Up @@ -149,7 +164,7 @@ jobs:
displayName: 'pytest - h2o'
- script: |
pip install torch==1.8.1+cpu torchvision==0.9.1+cpu torchaudio==0.8.1 -f https://download.pytorch.org/whl/torch_stable.html
pip install torch --extra-index-url https://download.pytorch.org/whl/cpu
pip install hummingbird-ml --no-deps
displayName: 'Install hummingbird-ml'
Expand All @@ -159,9 +174,16 @@ jobs:
displayName: 'pytest - hummingbirdml'
- script: |
export PYTHONPATH=.
pytest tests/coreml --durations=0
displayName: 'pytest - coreml'
if [ '$(COREML_PATH)' == 'NONE' ]
then
echo "required version of coremltools does not work on python 3.10"
else
export PYTHONPATH=.
pip install $(COREML_PATH)
pytest tests/coreml --durations=0
fi
displayName: 'pytest - coreml [$(COREML_PATH)]'
# condition: ne('$(COREML_PATH)', 'NONE')
- task: PublishTestResults@2
inputs:
Expand Down
30 changes: 21 additions & 9 deletions .azure-pipelines/win32-conda-CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,47 +15,61 @@ jobs:
strategy:
matrix:

Python310-1130-RT1131:
python.version: '3.10'
ONNX_PATH: 'onnx==1.13.0' # '-i https://test.pypi.org/simple/ onnx==1.12.0rc4'
ONNXRT_PATH: onnxruntime==1.13.1 #'-i https://test.pypi.org/simple/ ort-nightly==1.11.0.dev20220311003'
COREML_PATH: NONE
numpy.version: ''

Python39-1120-RT1110:
python.version: '3.9'
ONNX_PATH: 'onnx==1.12.0' # '-i https://test.pypi.org/simple/ onnx==1.12.0rc4'
ONNXRT_PATH: onnxruntime==1.11.0 #'-i https://test.pypi.org/simple/ ort-nightly==1.11.0.dev20220311003'
COREML_PATH: git+https://github.com/apple/coremltools@3.1
numpy.version: ''

Python39-1110-RT1110:
python.version: '3.9'
ONNX_PATH: onnx==1.11.0 # '-i https://test.pypi.org/simple/ onnx==1.9.101'
ONNXRT_PATH: onnxruntime==1.11.0 #'-i https://test.pypi.org/simple/ ort-nightly==1.11.0.dev20220311003'
COREML_PATH: git+https://github.com/apple/coremltools@3.1
numpy.version: ''

Python39-1110-RT190:
python.version: '3.9'
ONNX_PATH: 'onnx==1.11.0' # '-i https://test.pypi.org/simple/ onnx==1.9.101'
ONNXRT_PATH: onnxruntime==1.10.0
COREML_PATH: git+https://github.com/apple/coremltools@3.1
numpy.version: ''

Python39-1102-RT190:
python.version: '3.9'
ONNX_PATH: 'onnx==1.10.2' # '-i https://test.pypi.org/simple/ onnx==1.9.101'
ONNXRT_PATH: onnxruntime==1.9.0
COREML_PATH: git+https://github.com/apple/coremltools@3.1
numpy.version: '<=1.23.5'

Python39-190-RT181:
python.version: '3.9'
ONNX_PATH: 'onnx==1.9.0'
ONNXRT_PATH: onnxruntime==1.8.1
COREML_PATH: git+https://github.com/apple/coremltools@3.1
numpy.version: '<=1.23.5'

Python39-190-RT180:
python.version: '3.9'
ONNX_PATH: onnx==1.9.0
ONNXRT_PATH: onnxruntime==1.8.0
COREML_PATH: git+https://github.com/apple/coremltools@3.1
numpy.version: '<=1.23.5'

Python38-181-RT170:
python.version: '3.8'
ONNX_PATH: onnx==1.8.1
ONNXRT_PATH: onnxruntime==1.7.0
COREML_PATH: git+https://github.com/apple/coremltools@3.1
numpy.version: '<=1.23.5'

maxParallel: 3

Expand Down Expand Up @@ -83,15 +97,11 @@ jobs:
python -m pip install --upgrade scikit-learn
displayName: 'Install scikit-learn'
- script: |
call activate py$(python.version)
python -m pip install %COREML_PATH%
displayName: 'Install coremltools'
- script: |
call activate py$(python.version)
python -m pip install %ONNX_PATH%
python -m pip install %ONNXRT_PATH%
python -m pip install "numpy$(numpy.version)"
displayName: 'Install onnxruntime'
- script: |
Expand Down Expand Up @@ -124,9 +134,11 @@ jobs:
- script: |
call activate py$(python.version)
export PYTHONPATH=.
python -m pytest tests/coreml --durations=0
displayName: 'pytest coreml'
set PYTHONPATH=.
if "$(COREML_PATH)" neq "NONE" python -m pip install %COREML_PATH%
if "$(COREML_PATH)" neq "NONE" python -m pytest tests/coreml --durations=0
displayName: 'pytest coreml - [$(COREML_PATH)]'
#condition: ne('$(COREML_PATH)', 'NONE')
- script: |
call activate py$(python.version)
Expand Down Expand Up @@ -160,7 +172,7 @@ jobs:
- script: |
call activate py$(python.version)
python -m pip install torch==1.8.1+cpu torchvision==0.9.1+cpu torchaudio===0.8.1 -f https://download.pytorch.org/whl/torch_stable.html
python -m pip install torch
python -m pip install hummingbird-ml --no-deps
displayName: 'Install hummingbird-ml'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ def convert_aft_survival_regression(scope, operator, container):
coefficients = op.coefficients.toArray().astype(float)
coefficients_tensor = scope.get_unique_variable_name('coefficients_tensor')
container.add_initializer(coefficients_tensor, onnx_proto.TensorProto.FLOAT, [1, len(coefficients)], coefficients)
intercepts = op.intercept.astype(float) if isinstance(op.intercept, collections.Iterable) else [float(op.intercept)]
intercepts = (
op.intercept.astype(float)
if isinstance(op.intercept, collections.abc.Iterable)
else [float(op.intercept)])
intercepts_tensor = scope.get_unique_variable_name('intercepts_tensor')
container.add_initializer(intercepts_tensor, onnx_proto.TensorProto.FLOAT, [len(intercepts)], intercepts)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ def convert_sparkml_linear_regressor(scope, operator, container):
attrs = {
'name': scope.get_unique_operator_name(op_type),
'coefficients': op.coefficients.astype(float),
'intercepts': op.intercept.astype(float) if isinstance(op.intercept, collections.Iterable) else [
float(op.intercept)]
'intercepts': (
op.intercept.astype(float)
if isinstance(op.intercept, collections.abc.Iterable)
else [float(op.intercept)])
}
container.add_node(op_type, operator.input_full_names, operator.output_full_names, op_domain='ai.onnx.ml', **attrs)

Expand Down
9 changes: 9 additions & 0 deletions onnxmltools/convert/xgboost/convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,13 @@ def convert(model, name=None, initial_types=None, doc_string='', target_opset=No
topology = parse_xgboost(model, initial_types, target_opset, custom_conversion_functions, custom_shape_calculators)
topology.compile()
onnx_model = convert_topology(topology, name, doc_string, target_opset, targeted_onnx)
opsets = {d.domain: d.version for d in onnx_model.opset_import}
if '' in opsets and opsets[''] < 9 and target_opset >= 9:
# a bug?
opsets[''] = 9
del onnx_model.opset_import[:]
for k, v in opsets.items():
opset = onnx_model.opset_import.add()
opset.domain = k
opset.version = v
return onnx_model
46 changes: 35 additions & 11 deletions onnxmltools/convert/xgboost/operator_converters/XGBoost.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import json
import numpy as np
from onnx import TensorProto
from xgboost import XGBClassifier
from ...common._registration import register_converter
from ..common import get_xgb_params
Expand Down Expand Up @@ -241,14 +242,17 @@ def convert(scope, operator, container):
raise RuntimeError("XGBoost model is empty.")
if ncl <= 1:
ncl = 2
# See https://github.com/dmlc/xgboost/blob/master/src/common/math.h#L23.
attr_pairs['post_transform'] = "LOGISTIC"
attr_pairs['class_ids'] = [0 for v in attr_pairs['class_treeids']]
if js_trees[0].get('leaf', None) == 0:
attr_pairs['base_values'] = [0.5]
elif base_score != 0.5:
cst = - np.log(1 / np.float32(base_score) - 1.)
attr_pairs['base_values'] = [cst]
if objective != 'binary:hinge':
# See https://github.com/dmlc/xgboost/blob/master/src/common/math.h#L23.
attr_pairs['post_transform'] = "LOGISTIC"
attr_pairs['class_ids'] = [0 for v in attr_pairs['class_treeids']]
if js_trees[0].get('leaf', None) == 0:
attr_pairs['base_values'] = [0.5]
elif base_score != 0.5:
cst = - np.log(1 / np.float32(base_score) - 1.)
attr_pairs['base_values'] = [cst]
else:
attr_pairs['base_values'] = [base_score]
else:
# See https://github.com/dmlc/xgboost/blob/master/src/common/math.h#L35.
attr_pairs['post_transform'] = "SOFTMAX"
Expand All @@ -264,13 +268,33 @@ def convert(scope, operator, container):
attr_pairs['classlabels_strings'] = classes

# add nodes
if objective == "binary:logistic":
if objective in ("binary:logistic", "binary:hinge"):
ncl = 2
container.add_node('TreeEnsembleClassifier', operator.input_full_names,
operator.output_full_names,
if objective == "binary:hinge":
attr_pairs['post_transform'] = 'NONE'
output_names = [operator.output_full_names[0],
scope.get_unique_variable_name("output_prob")]
else:
output_names = operator.output_full_names
container.add_node('TreeEnsembleClassifier',
operator.input_full_names,
output_names,
op_domain='ai.onnx.ml',
name=scope.get_unique_operator_name('TreeEnsembleClassifier'),
**attr_pairs)
if objective == "binary:hinge":
if container.target_opset < 9:
raise RuntimeError(
f"hinge function cannot be implemented because "
f"opset={container.target_opset}<9.")
zero = scope.get_unique_variable_name("zero")
one = scope.get_unique_variable_name("one")
container.add_initializer(zero, TensorProto.FLOAT, [1], [0.])
container.add_initializer(one, TensorProto.FLOAT, [1], [1.])
greater = scope.get_unique_variable_name("output_prob")
container.add_node("Greater", [output_names[1], zero], [greater])
container.add_node('Where', [greater, one, zero],
operator.output_full_names[1])
elif objective in ("multi:softprob", "multi:softmax"):
ncl = len(js_trees) // params['n_estimators']
if objective == 'multi:softmax':
Expand Down
5 changes: 1 addition & 4 deletions onnxmltools/proto/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def _check_onnx_version():
_check_onnx_version()


def _make_tensor_fixed(name, data_type, dims, vals, raw=False):
def make_tensor_fixed(name, data_type, dims, vals, raw=False):
'''
Make a TensorProto with specified arguments. If raw is False, this
function will choose the corresponding proto field to store the
Expand All @@ -45,6 +45,3 @@ def _make_tensor_fixed(name, data_type, dims, vals, raw=False):

tensor.dims.extend(dims)
return tensor


helper.make_tensor = _make_tensor_fixed
4 changes: 2 additions & 2 deletions onnxmltools/utils/utils_backend_onnxruntime.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def compare_runtime(test, decimal=5, options=None, verbose=False, context=None):
return

try:
sess = onnxruntime.InferenceSession(onx)
sess = onnxruntime.InferenceSession(onx, providers=["CPUExecutionProvider"])
except ExpectedAssertionError as expe:
raise expe
except Exception as e:
Expand Down Expand Up @@ -312,7 +312,7 @@ def run_with_runtime(inputs, model_path):
'''
try:
import onnxruntime
session = onnxruntime.InferenceSession(model_path)
session = onnxruntime.InferenceSession(model_path, providers=["CPUExecutionProvider"])
output = session.run(None, inputs)
return (output, session)
except Exception as e:
Expand Down
7 changes: 6 additions & 1 deletion tests/baseline/test_convert_baseline.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@
from onnx.defs import onnx_opset_version
from onnxmltools.convert import convert_coreml
from onnxconverter_common.onnx_ex import DEFAULT_OPSET_NUMBER
import coremltools
try:
import coremltools
except ImportError:
coremltools = None


TARGET_OPSET = min(DEFAULT_OPSET_NUMBER, onnx_opset_version())
Expand All @@ -24,6 +27,8 @@ def check_baseline(self, input_file, ref_file):
def get_diff(self, input_file, ref_file):
this = os.path.dirname(__file__)
coreml_file = os.path.join(this, "models", input_file)
if coremltools is None:
return []
cml = coremltools.utils.load_spec(coreml_file)
onnx_model = convert_coreml(cml, target_opset=TARGET_OPSET)
output_dir = os.path.join(this, "outmodels")
Expand Down
4 changes: 2 additions & 2 deletions tests/h2o/test_h2o_converters.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def _prepare_one_hot(file, y, exclude_cols=None):


def _train_test_split_as_frames(x, y, is_str=False, is_classifier=False):
y = y.astype(np.str) if is_str else y.astype(np.int64)
y = y.astype(np.str_) if is_str else y.astype(np.int64)
x_train, x_test, y_train, _ = train_test_split(x, y, test_size=0.3, random_state=42)
f_train_x = H2OFrame(x_train)
f_train_y = H2OFrame(y_train)
Expand Down Expand Up @@ -138,7 +138,7 @@ def predict_with_probabilities(self, data):
return [preds.to_numpy()]
else:
return [
preds.iloc[:, 0].to_numpy().astype(np.str),
preds.iloc[:, 0].to_numpy().astype(np.str_),
preds.iloc[:, 1:].to_numpy()
]

Expand Down
Loading

0 comments on commit cfb2cc0

Please sign in to comment.