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
2 changes: 2 additions & 0 deletions _unittests/ut_onnxrt/test_onnx_inference.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,8 @@ def test_onnx_inference_verbose_intermediate(self):
self.assertIsInstance(inp, list)
out = oinf.output_names_shapes
self.assertIsInstance(out, list)
out = oinf.output_names_shapes_types
self.assertIsInstance(out, list)


if __name__ == "__main__":
Expand Down
248 changes: 182 additions & 66 deletions _unittests/ut_onnxrt/test_onnxrt_python_runtime_control_loop.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,71 @@ def setUp(self):
logger = getLogger('skl2onnx')
logger.disabled = True

@ignore_warnings(DeprecationWarning)
def test_sequence_insert(self):

def expect(node, inputs, outputs, name):
ginputs = [
make_sequence_value_info(
node.input[0], TensorProto.FLOAT, []), # pylint: disable=E1101,
make_sequence_value_info(
node.input[1], TensorProto.FLOAT, []), # pylint: disable=E1101,
]
if len(node.input) > 2:
ginputs.append(
make_tensor_value_info(
node.input[2], TensorProto.INT64, []), # pylint: disable=E1101
)
goutputs = [
make_sequence_value_info(
node.output[0], TensorProto.FLOAT, []), # pylint: disable=E1101,
]
model_def = make_model(
opset_imports=[
make_operatorsetid('', get_opset_number_from_onnx())],
graph=make_graph(
name=name, inputs=ginputs, outputs=goutputs,
nodes=[node]))
oinf = OnnxInference(model_def)
got = oinf.run({n: v for n, v in zip(node.input, inputs)})
self.assertEqual(len(got), 1)
oseq = got['output_sequence']
self.assertEqual(len(oseq), len(outputs))
for e, g in zip(outputs, oseq):
self.assertEqualArray(e, g)

test_cases = {
'at_back': [numpy.array([10, 11, 12]).astype(numpy.int64)],
'at_front': [numpy.array([-2, -1, 0]),
numpy.array([0]).astype(numpy.int64)]}
sequence = [numpy.array([1, 2, 3, 4]).astype(numpy.int64),
numpy.array([5, 6, 7]).astype(numpy.int64),
numpy.array([8, 9]).astype(numpy.int64)]

for test_name, test_inputs in test_cases.items():
with self.subTest(test_name=test_name):
tensor = test_inputs[0].astype(numpy.int64)

if len(test_inputs) > 1:
node = make_node(
'SequenceInsert',
inputs=['sequence', 'tensor', 'position'],
outputs=['output_sequence'])
position = test_inputs[1]
inserted = self.sequence_insert_reference_implementation(
sequence, tensor, position)
expect(node, inputs=[sequence, tensor, position], outputs=inserted,
name='test_sequence_insert_' + test_name)
else:
node = make_node(
'SequenceInsert',
inputs=['sequence', 'tensor'],
outputs=['output_sequence'])
inserted = self.sequence_insert_reference_implementation(
sequence, tensor)
expect(node, inputs=[sequence, tensor], outputs=inserted,
name='test_sequence_insert_' + test_name)

@ignore_warnings(DeprecationWarning)
def test_loop(self):
# Given a tensor x of values [x1, ..., xN],
Expand Down Expand Up @@ -120,7 +185,7 @@ def test_loop(self):
expected = numpy.array([
1., 1., 2., 1., 2., 3., 1., 2.,
3., 4., 1., 2., 3., 4., 5.], dtype=numpy.float32)
for rt in ['onnxruntime1', 'python']:
for rt in ['onnxruntime1', 'python', 'python_compiled']:
with self.subTest(rt=rt):
oinf = OnnxInference(model_def, runtime=rt)
inputs = {
Expand All @@ -140,6 +205,122 @@ def test_loop(self):
continue
self.assertIsInstance(v, SequenceType)

@ignore_warnings(DeprecationWarning)
def test_loop_additional_input(self):
# Given a tensor x of values [x1, ..., xN],
# Return a sequence of tensors of
# [[x1], [x1, x2], ..., [x1, ..., xN]]

cond_in = make_tensor_value_info(
'cond_in', TensorProto.BOOL, []) # pylint: disable=E1101
cond_out = make_tensor_value_info(
'cond_out', TensorProto.BOOL, []) # pylint: disable=E1101
iter_count = make_tensor_value_info(
'iter_count', TensorProto.INT64, []) # pylint: disable=E1101
seq_in = make_tensor_sequence_value_info(
'seq_in', TensorProto.FLOAT, None) # pylint: disable=E1101
seq_out = make_tensor_sequence_value_info(
'seq_out', TensorProto.FLOAT, None) # pylint: disable=E1101

x = numpy.array([1, 2, 3, 4, 5]).astype(numpy.float32)

x_const_node = make_node(
'Constant', inputs=[], outputs=['x'],
value=make_tensor(
name='const_tensor_x', data_type=TensorProto.FLOAT, # pylint: disable=E1101
dims=x.shape, vals=x.flatten().astype(float)))

zero_const_node = make_node(
'Constant', inputs=[], outputs=['slice_start'],
value=make_tensor(
name='const_tensor_zero', data_type=TensorProto.INT64, # pylint: disable=E1101
dims=(1,), vals=[0]))

axes_node = make_node(
'Constant', inputs=[], outputs=['axes'],
value=make_tensor(
name='const_tensor_axes', data_type=TensorProto.INT64, # pylint: disable=E1101
dims=(), vals=[0]))

add_node = make_node(
'Add', inputs=['iter_count', 'XI'], outputs=['slice_end'])

slice_node = make_node(
'Slice', inputs=['x', 'slice_start', 'slice_end'], outputs=['slice_out'])

insert_node = make_node(
'SequenceInsert', inputs=['seq_in', 'slice_out'], outputs=['seq_out'])

identity_node = make_node(
'Identity', inputs=['cond_in'], outputs=['cond_out'])

loop_body = make_graph(
[identity_node, x_const_node, zero_const_node, add_node,
axes_node, slice_node, insert_node],
'loop_body', [iter_count, cond_in, seq_in], [cond_out, seq_out])

node = make_node(
'Loop', inputs=['trip_count', 'cond', 'seq_empty'],
outputs=['seq_res'], body=loop_body)
node1 = make_node('Neg', inputs=['XI'], outputs=['Y'])
node_concat = make_node(
'ConcatFromSequence', inputs=['seq_res'],
outputs=['res'], axis=0, new_axis=0)

trip_count = numpy.array(5).astype(numpy.int64)
seq_empty = [] # type: List[Any]
cond = numpy.array(1).astype(numpy.bool)

model_def = make_model(
opset_imports=[
make_operatorsetid('', get_opset_number_from_onnx())],
graph=make_graph(
name='loop_test',
inputs=[
make_tensor_value_info(
'trip_count', TensorProto.INT64, trip_count.shape), # pylint: disable=E1101
make_tensor_value_info(
'cond', TensorProto.BOOL, cond.shape), # pylint: disable=E1101
make_sequence_value_info(
'seq_empty', TensorProto.FLOAT, []), # pylint: disable=E1101
make_tensor_value_info(
'XI', TensorProto.INT64, [])], # pylint: disable=E1101
outputs=[
make_tensor_value_info(
'res', TensorProto.FLOAT, None), # pylint: disable=E1101
make_tensor_value_info(
'Y', TensorProto.INT64, [])], # pylint: disable=E1101
nodes=[node1, node, node_concat]))

expected = numpy.array([
1., 1., 2., 1., 2., 3., 1., 2.,
3., 4., 1., 2., 3., 4., 5.], dtype=numpy.float32)
X = numpy.array([1], dtype=numpy.int64)
for rt in ['python', 'onnxruntime1', 'python_compiled']:
with self.subTest(rt=rt):
oinf = OnnxInference(model_def, runtime=rt)
inputs = {
'trip_count': trip_count, 'cond': cond,
'seq_empty': seq_empty,
'XI': X}
if rt == 'python_compiled':
code = str(oinf)
self.assertIn("context={'XI': XI}", code)
got = oinf.run(inputs)
self.assertEqualArray(-X, got['Y'])
self.assertEqualArray(expected, got['res'])
if rt == 'python':
siz = oinf.infer_sizes(inputs)
self.assertIsInstance(siz, dict)
typ = oinf.infer_types()
self.assertEqual(typ["trip_count"], numpy.int64)
if 'cond' in typ:
self.assertEqual(typ["cond"], numpy.bool_)
for k, v in typ.items():
if k in {'trip_count', 'cond', 'Y', 'XI'}:
continue
self.assertIsInstance(v, SequenceType)

def sequence_insert_reference_implementation(
self, sequence, tensor, position=None):
seq = list(sequence)
Expand All @@ -150,71 +331,6 @@ def sequence_insert_reference_implementation(
seq.append(tensor)
return seq

@ignore_warnings(DeprecationWarning)
def test_sequence_insert(self):

def expect(node, inputs, outputs, name):
ginputs = [
make_sequence_value_info(
node.input[0], TensorProto.FLOAT, []), # pylint: disable=E1101,
make_sequence_value_info(
node.input[1], TensorProto.FLOAT, []), # pylint: disable=E1101,
]
if len(node.input) > 2:
ginputs.append(
make_tensor_value_info(
node.input[2], TensorProto.INT64, []), # pylint: disable=E1101
)
goutputs = [
make_sequence_value_info(
node.output[0], TensorProto.FLOAT, []), # pylint: disable=E1101,
]
model_def = make_model(
opset_imports=[
make_operatorsetid('', get_opset_number_from_onnx())],
graph=make_graph(
name=name, inputs=ginputs, outputs=goutputs,
nodes=[node]))
oinf = OnnxInference(model_def)
got = oinf.run({n: v for n, v in zip(node.input, inputs)})
self.assertEqual(len(got), 1)
oseq = got['output_sequence']
self.assertEqual(len(oseq), len(outputs))
for e, g in zip(outputs, oseq):
self.assertEqualArray(e, g)

test_cases = {
'at_back': [numpy.array([10, 11, 12]).astype(numpy.int64)],
'at_front': [numpy.array([-2, -1, 0]),
numpy.array([0]).astype(numpy.int64)]}
sequence = [numpy.array([1, 2, 3, 4]).astype(numpy.int64),
numpy.array([5, 6, 7]).astype(numpy.int64),
numpy.array([8, 9]).astype(numpy.int64)]

for test_name, test_inputs in test_cases.items():
with self.subTest(test_name=test_name):
tensor = test_inputs[0].astype(numpy.int64)

if len(test_inputs) > 1:
node = make_node(
'SequenceInsert',
inputs=['sequence', 'tensor', 'position'],
outputs=['output_sequence'])
position = test_inputs[1]
inserted = self.sequence_insert_reference_implementation(
sequence, tensor, position)
expect(node, inputs=[sequence, tensor, position], outputs=inserted,
name='test_sequence_insert_' + test_name)
else:
node = make_node(
'SequenceInsert',
inputs=['sequence', 'tensor'],
outputs=['output_sequence'])
inserted = self.sequence_insert_reference_implementation(
sequence, tensor)
expect(node, inputs=[sequence, tensor], outputs=inserted,
name='test_sequence_insert_' + test_name)


if __name__ == "__main__":
unittest.main()
Binary file added _unittests/ut_tools/data/bug_graph.onnx
Binary file not shown.
Binary file added _unittests/ut_tools/data/bug_graph_infinite.onnx
Binary file not shown.
8 changes: 7 additions & 1 deletion _unittests/ut_tools/test_code_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
from scipy.sparse import csr_matrix
from pyquickhelper.pycode import ExtTestCase, get_temp_folder
from mlprodict.tools.code_helper import (
debug_print, debug_dump, numpy_min, numpy_max, make_callable)
debug_print, debug_dump, numpy_min, numpy_max, make_callable,
print_code)


class TestCodeHelper(ExtTestCase):
Expand Down Expand Up @@ -84,6 +85,11 @@ def fctf(b=True):
self.assertTrue(fct(True)) # pylint: disable=E1102
self.assertFalse(fct(False)) # pylint: disable=E1102

def test_print_code(self):
code = "a=1\nb=2"
cc = print_code(code)
self.assertEqual(cc, "001 a=1\n002 b=2")


if __name__ == "__main__":
unittest.main()
20 changes: 20 additions & 0 deletions _unittests/ut_tools/test_graphs.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"""
@brief test log(time=3s)
"""
import os
import unittest
import numpy
from sklearn.datasets import load_iris
Expand All @@ -11,6 +12,7 @@
from pyquickhelper.pycode import ExtTestCase
from skl2onnx.algebra.onnx_ops import OnnxAdd, OnnxSub # pylint: disable=E0611
from mlprodict.onnx_conv import to_onnx
from mlprodict.onnxrt import OnnxInference
from mlprodict.tools import get_opset_number_from_onnx
from mlprodict.tools.graphs import onnx2bigraph, BiGraph

Expand Down Expand Up @@ -86,6 +88,24 @@ def test_pipe_graph_display_text(self):
'inout', 'O0 I0', 'A S']:
self.assertIn(c, text)

def test_bug_graph(self):
this = os.path.abspath(os.path.dirname(__file__))
data = os.path.join(this, "data", "bug_graph.onnx")
oinf = OnnxInference(
data, inside_loop=True,
static_inputs=['StatefulPartitionedCall/Reshape:0'])
text = oinf.to_text(distance=8)
self.assertIn(
"cond___pcen/simple_rnn/while/Identity_graph_outputs_Identity__4:0",
text)

def test_bug_graph_infinite(self):
this = os.path.abspath(os.path.dirname(__file__))
data = os.path.join(this, "data", "bug_graph_infinite.onnx")
oinf = OnnxInference(data, inside_loop=True)
text = oinf.to_text(distance=8)
self.assertIn("slice_end", text)


if __name__ == "__main__":
unittest.main()
2 changes: 1 addition & 1 deletion mlprodict/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
@brief Ways to speed up predictions for a machine learned model.
"""

__version__ = "0.6.1522"
__version__ = "0.6.1545"
__author__ = "Xavier Dupré"


Expand Down
Loading