From 4f6a32a7df04892def0bc318bf1648b8e291dd08 Mon Sep 17 00:00:00 2001 From: Joe Evans Date: Tue, 12 Jan 2021 21:45:52 +0000 Subject: [PATCH 01/13] Add onnx export function for greater_scalar. --- .../contrib/onnx/mx2onnx/_op_translations.py | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py b/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py index 57ef546de29f..8fa95f1a8c09 100644 --- a/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py +++ b/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py @@ -2861,3 +2861,24 @@ def convert_repeat(node, **kwargs): ] return nodes + +@mx_op.register("_greater_scalar") +def convert_greater_scalar(node, **kwargs): + """Map MXNet's greater_scalar operator attributes to onnx's Greater + operator and return the created node. + """ + from onnx.helper import make_node, make_tensor + name, input_nodes, attrs = get_inputs(node, kwargs) + + scalar = attrs.get('scalar') + input_type = kwargs['in_type'] + dtype = onnx.mapping.TENSOR_TYPE_TO_NP_TYPE[input_type] + + tensor_value = make_tensor(name+"_scalar", input_type, [1], np.array([scalar], dtype=dtype)) + nodes = [ + make_node("Shape", [input_nodes[0]], [name+"_shape"]), + make_node("ConstantOfShape", [name+"_shape"], [name+"_rhs"], value=tensor_value), + make_node("Greater", [input_nodes[0], name+"_rhs"], [name+"_gt"]), + make_node("Cast", [name+"_gt"], [name], to=input_type, name=name) + ] + return nodes From 7fe40828a714ae537a6e4a5e77033578e590332e Mon Sep 17 00:00:00 2001 From: Joe Evans Date: Tue, 12 Jan 2021 21:50:52 +0000 Subject: [PATCH 02/13] Add test for greater_scalar onnx export. --- tests/python-pytest/onnx/test_operators.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/python-pytest/onnx/test_operators.py b/tests/python-pytest/onnx/test_operators.py index c17a03bc3276..14ad118aaac1 100644 --- a/tests/python-pytest/onnx/test_operators.py +++ b/tests/python-pytest/onnx/test_operators.py @@ -378,3 +378,17 @@ def test_onnx_export_contrib_BilinearResize2D(tmp_path, dtype, params): x = mx.nd.arange(0, 160).reshape((2, 2, 5, 8)) M = def_model('contrib.BilinearResize2D', **params) op_export_test('contrib_BilinearResize2D', M, [x], tmp_path) + + +@pytest.mark.parametrize("dtype", ["float32", "float64", "int32", "int64"]) +@pytest.mark.parametrize("scalar", [0.0, 0.1, 1.0, 555]) +def test_onnx_export_greater_scalar(tmp_path, dtype, scalar): + if 'int' in dtype: + scalar = int(scalar) + x = mx.nd.array([[1., 2., 3., 4.], + [5., 6., 7., 8.], + [9., 10, 11., 12.]], dtype=dtype) + else: + x = mx.random.uniform(0, 9999, (5,10), dtype=dtype) + M = def_model('_internal._greater_scalar', scalar=scalar) + op_export_test('_internal._greater_scalar', M, [x], tmp_path) From f2f4a9f5af80a91583888050ec20d5847eb48f2f Mon Sep 17 00:00:00 2001 From: Joe Evans Date: Tue, 12 Jan 2021 22:11:29 +0000 Subject: [PATCH 03/13] Add onnx export support for where operator. --- .../contrib/onnx/mx2onnx/_op_translations.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py b/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py index 8fa95f1a8c09..13519f865e1b 100644 --- a/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py +++ b/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py @@ -2882,3 +2882,18 @@ def convert_greater_scalar(node, **kwargs): make_node("Cast", [name+"_gt"], [name], to=input_type, name=name) ] return nodes + + +@mx_op.register("where") +def convert_where(node, **kwargs): + """Map MXNet's where operator attributes to onnx's Where + operator and return the created node. + """ + from onnx.helper import make_node, make_tensor + from onnx import TensorProto + name, input_nodes, _ = get_inputs(node, kwargs) + nodes = [ + make_node("Cast", [input_nodes[0]], [name+"_bool"], to=int(TensorProto.BOOL)), + make_node("Where", [name+"_bool", input_nodes[1], input_nodes[2]], [name], name=name) + ] + return nodes From 9e34ff0bd02802a9c99a6752def4611ee12e598b Mon Sep 17 00:00:00 2001 From: Joe Evans Date: Tue, 12 Jan 2021 22:13:01 +0000 Subject: [PATCH 04/13] Add unit test for where onnx export operator. --- tests/python-pytest/onnx/test_operators.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/tests/python-pytest/onnx/test_operators.py b/tests/python-pytest/onnx/test_operators.py index 14ad118aaac1..fd2015f6125c 100644 --- a/tests/python-pytest/onnx/test_operators.py +++ b/tests/python-pytest/onnx/test_operators.py @@ -385,10 +385,20 @@ def test_onnx_export_contrib_BilinearResize2D(tmp_path, dtype, params): def test_onnx_export_greater_scalar(tmp_path, dtype, scalar): if 'int' in dtype: scalar = int(scalar) - x = mx.nd.array([[1., 2., 3., 4.], - [5., 6., 7., 8.], - [9., 10, 11., 12.]], dtype=dtype) + x = mx.nd.array([[1., 2., 3., 4.], + [5., 6., 7., 8.], + [9., 10., 11., 12.]], dtype=dtype) else: x = mx.random.uniform(0, 9999, (5,10), dtype=dtype) M = def_model('_internal._greater_scalar', scalar=scalar) op_export_test('_internal._greater_scalar', M, [x], tmp_path) + + +@pytest.mark.parametrize("dtype", ["float16", "float32", "float64", "int32", "int64"]) +@pytest.mark.parametrize("shape", [(1,1), (3,3), (10,2), (20,30,40)]) +def test_onnx_export_where(tmp_path, dtype, shape): + M = def_model('where') + x = mx.nd.zeros(shape, dtype=dtype) + y = mx.nd.ones(shape, dtype=dtype) + cond = mx.nd.random.randint(low=0, high=1, shape=shape, dtype='int32') + op_export_test('where', M, [cond, x, y], tmp_path) From e58be78b90cf779125cbbde0ffc325087a045217 Mon Sep 17 00:00:00 2001 From: Joe Evans Date: Wed, 13 Jan 2021 00:46:24 +0000 Subject: [PATCH 05/13] Properly cast scalar attribute and work around onnx bug. --- python/mxnet/contrib/onnx/mx2onnx/_op_translations.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py b/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py index 13519f865e1b..884d2684339f 100644 --- a/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py +++ b/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py @@ -2870,11 +2870,18 @@ def convert_greater_scalar(node, **kwargs): from onnx.helper import make_node, make_tensor name, input_nodes, attrs = get_inputs(node, kwargs) - scalar = attrs.get('scalar') + scalar = float(attrs.get('scalar')) input_type = kwargs['in_type'] dtype = onnx.mapping.TENSOR_TYPE_TO_NP_TYPE[input_type] - tensor_value = make_tensor(name+"_scalar", input_type, [1], np.array([scalar], dtype=dtype)) + if 'int' in str(dtype): + scalar = int(scalar) + else: + if dtype == 'float16': + # when using float16, a bug in onnx requires us to convert it as below + scalar = np.float16(scalar).view(dtype=np.uint16) + + tensor_value = make_tensor(name+"_scalar", input_type, [1], [scalar]) nodes = [ make_node("Shape", [input_nodes[0]], [name+"_shape"]), make_node("ConstantOfShape", [name+"_shape"], [name+"_rhs"], value=tensor_value), From ed0fc353d7d524f25127c5a7daa5c0e83299efd0 Mon Sep 17 00:00:00 2001 From: Joe Evans Date: Wed, 13 Jan 2021 00:52:07 +0000 Subject: [PATCH 06/13] Remove unused import. --- python/mxnet/contrib/onnx/mx2onnx/_op_translations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py b/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py index 884d2684339f..9d034182c0e6 100644 --- a/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py +++ b/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py @@ -2896,7 +2896,7 @@ def convert_where(node, **kwargs): """Map MXNet's where operator attributes to onnx's Where operator and return the created node. """ - from onnx.helper import make_node, make_tensor + from onnx.helper import make_node from onnx import TensorProto name, input_nodes, _ = get_inputs(node, kwargs) nodes = [ From 758b6761eedddda28c6cf5d224b6f2406e2efaf4 Mon Sep 17 00:00:00 2001 From: Joe Evans Date: Wed, 13 Jan 2021 00:53:36 +0000 Subject: [PATCH 07/13] Update unit test for greater_scalar. --- tests/python-pytest/onnx/test_operators.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/python-pytest/onnx/test_operators.py b/tests/python-pytest/onnx/test_operators.py index fd2015f6125c..a06b043b02c1 100644 --- a/tests/python-pytest/onnx/test_operators.py +++ b/tests/python-pytest/onnx/test_operators.py @@ -380,14 +380,12 @@ def test_onnx_export_contrib_BilinearResize2D(tmp_path, dtype, params): op_export_test('contrib_BilinearResize2D', M, [x], tmp_path) -@pytest.mark.parametrize("dtype", ["float32", "float64", "int32", "int64"]) -@pytest.mark.parametrize("scalar", [0.0, 0.1, 1.0, 555]) +@pytest.mark.parametrize("dtype", ["float16", "float32", "float64", "int32", "int64"]) +@pytest.mark.parametrize("scalar", [0., 0.1, 0.5, 1., 5, 555.]) def test_onnx_export_greater_scalar(tmp_path, dtype, scalar): if 'int' in dtype: scalar = int(scalar) - x = mx.nd.array([[1., 2., 3., 4.], - [5., 6., 7., 8.], - [9., 10., 11., 12.]], dtype=dtype) + x = mx.nd.arange(0, 12, dtype=dtype).reshape((3, 4)) else: x = mx.random.uniform(0, 9999, (5,10), dtype=dtype) M = def_model('_internal._greater_scalar', scalar=scalar) From 1d9ad58e148802fccc4041ca8a1f83c3f7ad4b9a Mon Sep 17 00:00:00 2001 From: Joe Evans Date: Wed, 13 Jan 2021 01:22:06 +0000 Subject: [PATCH 08/13] Fix lint. --- python/mxnet/contrib/onnx/mx2onnx/_op_translations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py b/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py index 9d034182c0e6..398f27bbc985 100644 --- a/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py +++ b/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py @@ -2874,7 +2874,7 @@ def convert_greater_scalar(node, **kwargs): input_type = kwargs['in_type'] dtype = onnx.mapping.TENSOR_TYPE_TO_NP_TYPE[input_type] - if 'int' in str(dtype): + if str(dtype).startswith('int'): scalar = int(scalar) else: if dtype == 'float16': From fd03ff42a3f2ca973c74b05c5ecb681814db8e16 Mon Sep 17 00:00:00 2001 From: Joe Evans Date: Wed, 13 Jan 2021 02:55:49 +0000 Subject: [PATCH 09/13] Fix lint. --- python/mxnet/contrib/onnx/mx2onnx/_op_translations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py b/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py index 398f27bbc985..d83ddcd90dc7 100644 --- a/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py +++ b/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py @@ -2879,7 +2879,7 @@ def convert_greater_scalar(node, **kwargs): else: if dtype == 'float16': # when using float16, a bug in onnx requires us to convert it as below - scalar = np.float16(scalar).view(dtype=np.uint16) + scalar = np.float16(scalar).view(np.uint16) tensor_value = make_tensor(name+"_scalar", input_type, [1], [scalar]) nodes = [ From d65ef30001108047e830ea05e537fa38c29cf44c Mon Sep 17 00:00:00 2001 From: Joe Evans Date: Wed, 13 Jan 2021 03:46:42 +0000 Subject: [PATCH 10/13] fix lint --- python/mxnet/contrib/onnx/mx2onnx/_op_translations.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py b/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py index d83ddcd90dc7..bdaea40f5917 100644 --- a/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py +++ b/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py @@ -2879,7 +2879,8 @@ def convert_greater_scalar(node, **kwargs): else: if dtype == 'float16': # when using float16, a bug in onnx requires us to convert it as below - scalar = np.float16(scalar).view(np.uint16) + scalar = np.float16(scalar) + scalar = scalar.view(np.uint16) tensor_value = make_tensor(name+"_scalar", input_type, [1], [scalar]) nodes = [ From 1ba90439525a2bea958b36214e1719e328a22c7e Mon Sep 17 00:00:00 2001 From: Joe Evans Date: Wed, 13 Jan 2021 17:19:44 +0000 Subject: [PATCH 11/13] Revert change. --- python/mxnet/contrib/onnx/mx2onnx/_op_translations.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py b/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py index bdaea40f5917..d83ddcd90dc7 100644 --- a/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py +++ b/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py @@ -2879,8 +2879,7 @@ def convert_greater_scalar(node, **kwargs): else: if dtype == 'float16': # when using float16, a bug in onnx requires us to convert it as below - scalar = np.float16(scalar) - scalar = scalar.view(np.uint16) + scalar = np.float16(scalar).view(np.uint16) tensor_value = make_tensor(name+"_scalar", input_type, [1], [scalar]) nodes = [ From 8ff68602ea02b4c618013037229ef2b4740c9481 Mon Sep 17 00:00:00 2001 From: Joe Evans Date: Wed, 13 Jan 2021 17:25:55 +0000 Subject: [PATCH 12/13] Fix lint. --- python/mxnet/contrib/onnx/mx2onnx/_op_translations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py b/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py index d83ddcd90dc7..cf36956f30c1 100644 --- a/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py +++ b/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py @@ -46,7 +46,7 @@ # coding: utf-8 # pylint: disable=too-many-locals,no-else-return,too-many-lines -# pylint: disable=anomalous-backslash-in-string,eval-used +# pylint: disable=anomalous-backslash-in-string,eval-used,too-many-function-args """ Conversion Functions for common layers. Add new functions here with a decorator. From 756b5de6b1932e3baf199eee052d6d3911a47395 Mon Sep 17 00:00:00 2001 From: Joe Evans Date: Wed, 13 Jan 2021 17:49:10 +0000 Subject: [PATCH 13/13] Only disable pylint warnings for single line. --- python/mxnet/contrib/onnx/mx2onnx/_op_translations.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py b/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py index cf36956f30c1..ea622cbe0532 100644 --- a/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py +++ b/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py @@ -46,7 +46,7 @@ # coding: utf-8 # pylint: disable=too-many-locals,no-else-return,too-many-lines -# pylint: disable=anomalous-backslash-in-string,eval-used,too-many-function-args +# pylint: disable=anomalous-backslash-in-string,eval-used """ Conversion Functions for common layers. Add new functions here with a decorator. @@ -2878,7 +2878,8 @@ def convert_greater_scalar(node, **kwargs): scalar = int(scalar) else: if dtype == 'float16': - # when using float16, a bug in onnx requires us to convert it as below + # when using float16, we must convert it to np.uint16 view first + # pylint: disable=too-many-function-args scalar = np.float16(scalar).view(np.uint16) tensor_value = make_tensor(name+"_scalar", input_type, [1], [scalar])