From 4a439262601cbe92a75122e8007f64c8fa5e3474 Mon Sep 17 00:00:00 2001 From: zha0q1 Date: Wed, 20 Jan 2021 00:20:05 +0000 Subject: [PATCH 1/4] broadcast_mod --- .../contrib/onnx/mx2onnx/_op_translations.py | 28 +++++++++++++++++++ tests/python-pytest/onnx/test_operators.py | 11 ++++++++ 2 files changed, 39 insertions(+) diff --git a/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py b/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py index 1a5d3ed1eb79..cb88ed883b4f 100644 --- a/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py +++ b/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py @@ -3050,3 +3050,31 @@ def convert_contrib_AdaptiveAvgPooling2D(node, **kwargs): make_node("GlobalAveragePool", [input_nodes[0]], [name], name=name) ] return nodes + + +@mx_op.register('broadcast_mod') +def convert_broadcast_mod(node, **kwargs): + """Map MXNet's broadcast_mod operator + """ + from onnx.helper import make_node + name, input_nodes, attrs = get_inputs(node, kwargs) + + # The behavior of MXNet mod is a mixture of np.mod and np.fmod + # note: the behavior when divison by 0 is supposed to be platform dependent + # but here we set the result to 0 to be consistent with MXNet + nodes = [ + make_node('Sub', [input_nodes[1], input_nodes[1]], [name+'_zero']), + make_node('Mod', [input_nodes[0], input_nodes[1]], [name+'_mod'], fmod=1), + make_node('Less', [input_nodes[0], name+'_zero'], [name+'_mask_0']), + make_node('Less', [input_nodes[1], name+'_zero'], [name+'_mask_1']), + make_node('Equal', [name+'_mod', name+'_zero'], [name+'_mask_2_']), + make_node('Not', [name+'_mask_2_'], [name+'_mask_2']), + make_node('Xor', [name+'_mask_0', name+'_mask_1'], [name+'_mask_']), + make_node('And', [name+'_mask_', name+'_mask_2'], [name+'_mask']), + make_node('Where', [name+'_mask', input_nodes[1], name+'_zero'], [name+'_adjustment']), + make_node('Add', [name+'_mod', name+'_adjustment'], [name+'_adjusted']), + make_node('Equal', [input_nodes[1], name+'_zero'], [name+'_mask_div_0']), + make_node('Where', [name+'_mask_div_0', name+'_zero', name+'_adjusted'], [name]) + ] + + return nodes diff --git a/tests/python-pytest/onnx/test_operators.py b/tests/python-pytest/onnx/test_operators.py index 66c0454c8d0a..90ea3a0674e9 100644 --- a/tests/python-pytest/onnx/test_operators.py +++ b/tests/python-pytest/onnx/test_operators.py @@ -434,3 +434,14 @@ def test_onnx_export_contrib_AdaptiveAvgPooling2D(tmp_path, dtype): op_export_test('contrib_AdaptiveAvgPooling2D', M3, [x], tmp_path) M4 = def_model('contrib.AdaptiveAvgPooling2D', output_size=[1,1]) op_export_test('contrib_AdaptiveAvgPooling2D', M4, [x], tmp_path) + + +@pytest.mark.parametrize('dtype', ['float16', 'float32', 'int32', 'int64']) +@pytest.mark.parametrize('shapes', [((3, 3, 3), (3)), ((4, 5, 6, 7), (7))]) +def test_onnx_export_broadcast_mod(tmp_path, dtype, shapes): + A = mx.nd.random.uniform(-300, 300, shapes[0]).astype(dtype) + B = mx.nd.random.uniform(-30, 30, shapes[1]).astype(dtype) + # test when dividend is zero + B[-1] = 0 + M = def_model('broadcast_mod') + op_export_test('broadcast_mod', M, [A, B], tmp_path) From 52f303552a8011217b4473af851461b6197abb0a Mon Sep 17 00:00:00 2001 From: Zhaoqi Zhu Date: Wed, 20 Jan 2021 18:25:03 -0800 Subject: [PATCH 2/4] Update _op_translations.py --- python/mxnet/contrib/onnx/mx2onnx/_op_translations.py | 1 + 1 file changed, 1 insertion(+) diff --git a/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py b/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py index 688c2f6b9e56..d6ed55fe77cc 100644 --- a/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py +++ b/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py @@ -3055,6 +3055,7 @@ def convert_contrib_AdaptiveAvgPooling2D(node, **kwargs): @mx_op.register('broadcast_mod') def convert_broadcast_mod(node, **kwargs): """Map MXNet's broadcast_mod operator + """ from onnx.helper import make_node name, input_nodes, attrs = get_inputs(node, kwargs) From e4a16c815134b8881c22835a4e92bd1607fce841 Mon Sep 17 00:00:00 2001 From: Zhaoqi Zhu Date: Wed, 20 Jan 2021 18:46:03 -0800 Subject: [PATCH 3/4] Update _op_translations.py --- python/mxnet/contrib/onnx/mx2onnx/_op_translations.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py b/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py index d6ed55fe77cc..8484751d6279 100644 --- a/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py +++ b/python/mxnet/contrib/onnx/mx2onnx/_op_translations.py @@ -3057,8 +3057,8 @@ def convert_broadcast_mod(node, **kwargs): """Map MXNet's broadcast_mod operator """ from onnx.helper import make_node - name, input_nodes, attrs = get_inputs(node, kwargs) - + name, input_nodes, _ = get_inputs(node, kwargs) + # The behavior of MXNet mod is a mixture of np.mod and np.fmod # note: the behavior when divison by 0 is supposed to be platform dependent # but here we set the result to 0 to be consistent with MXNet From 4e7dc0d993d77ebbb6f679b217c13ab6a27bcfa7 Mon Sep 17 00:00:00 2001 From: zha0q1 Date: Thu, 21 Jan 2021 18:54:30 +0000 Subject: [PATCH 4/4] improve tests --- tests/python-pytest/onnx/test_operators.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/python-pytest/onnx/test_operators.py b/tests/python-pytest/onnx/test_operators.py index 90ea3a0674e9..427a9863bb07 100644 --- a/tests/python-pytest/onnx/test_operators.py +++ b/tests/python-pytest/onnx/test_operators.py @@ -437,7 +437,7 @@ def test_onnx_export_contrib_AdaptiveAvgPooling2D(tmp_path, dtype): @pytest.mark.parametrize('dtype', ['float16', 'float32', 'int32', 'int64']) -@pytest.mark.parametrize('shapes', [((3, 3, 3), (3)), ((4, 5, 6, 7), (7))]) +@pytest.mark.parametrize('shapes', [((3, 3, 3), (1, 3)), ((4, 5, 6, 7), (6, 7))]) def test_onnx_export_broadcast_mod(tmp_path, dtype, shapes): A = mx.nd.random.uniform(-300, 300, shapes[0]).astype(dtype) B = mx.nd.random.uniform(-30, 30, shapes[1]).astype(dtype)