From e479b011f51ce47e233d58bf744b540d41a55968 Mon Sep 17 00:00:00 2001 From: Vladimir Gavrilov Date: Wed, 11 Nov 2020 17:31:00 +0300 Subject: [PATCH] retinanet onnx model has Upsample error (#3052) * Commit. * Fixed infer function of ONNXResize11 operation. * Small fixes. * Written unit tests for shape calculation for ONNXResize11. --- .../middle/ONNXResize11ToInterpolateV4.py | 4 +- .../extensions/ops/ONNXResize11.py | 6 +- .../extensions/ops/ONNXResize11_test.py | 140 ++++++++++++++++++ 3 files changed, 146 insertions(+), 4 deletions(-) create mode 100644 model-optimizer/extensions/ops/ONNXResize11_test.py diff --git a/model-optimizer/extensions/middle/ONNXResize11ToInterpolateV4.py b/model-optimizer/extensions/middle/ONNXResize11ToInterpolateV4.py index 30e0fd4b3e2..e83973eba64 100644 --- a/model-optimizer/extensions/middle/ONNXResize11ToInterpolateV4.py +++ b/model-optimizer/extensions/middle/ONNXResize11ToInterpolateV4.py @@ -67,7 +67,7 @@ def replace_resize(graph: Graph, resize: Node): {1: int64_array([begin_dim]), 2: int64_array([end_dim]), 3: int64_array([1])}, - {'name': resize_name + '/StridedSlice_', + {'name': resize_name + '/StridedSlice_sizes', 'begin_mask': int64_array([1]), 'end_mask': int64_array([1]), 'new_axis_mask': int64_array([0]), @@ -77,7 +77,7 @@ def replace_resize(graph: Graph, resize: Node): {1: int64_array([begin_dim]), 2: int64_array([end_dim]), 3: int64_array([1])}, - {'name': resize_name + '/StridedSlice_', + {'name': resize_name + '/StridedSlice_scales', 'begin_mask': int64_array([1]), 'end_mask': int64_array([1]), 'new_axis_mask': int64_array([0]), diff --git a/model-optimizer/extensions/ops/ONNXResize11.py b/model-optimizer/extensions/ops/ONNXResize11.py index 38c34c76250..7445b61c27e 100644 --- a/model-optimizer/extensions/ops/ONNXResize11.py +++ b/model-optimizer/extensions/ops/ONNXResize11.py @@ -67,6 +67,8 @@ class ONNXResize11Op(Op): sizes = node.in_port(3).data.get_value() assert sizes is not None, \ "Node {} with op {} has no value in input port 3".format(node.name, node.op) - output_shape = int64_array(sizes) + output_shape = input_shape.copy() + spatial_dimension_indices = range(2, len(input_shape)) + output_shape[spatial_dimension_indices] = int64_array(sizes)[2:] - node.out_port(0).data.set_shape(output_shape.copy()) \ No newline at end of file + node.out_port(0).data.set_shape(output_shape.copy()) diff --git a/model-optimizer/extensions/ops/ONNXResize11_test.py b/model-optimizer/extensions/ops/ONNXResize11_test.py new file mode 100644 index 00000000000..a06e467445d --- /dev/null +++ b/model-optimizer/extensions/ops/ONNXResize11_test.py @@ -0,0 +1,140 @@ +""" + Copyright (C) 2018-2020 Intel Corporation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" + +import unittest + +import numpy as np +from generator import generator, generate + +from extensions.ops.ONNXResize11 import ONNXResize11Op +from mo.front.common.partial_infer.utils import int64_array +from mo.graph.graph import Node +from mo.utils.unittest.graph import build_graph + + +graph_node_attrs_sizes = { + 'input': {'type': 'Parameter', 'kind': 'op'}, + 'input_data': {'kind': 'data', 'shape': None, 'value': None}, + 'roi': {'type': 'Const', 'kind': 'op', 'shape': None, 'value': None}, + 'roi_data': {'kind': 'data', 'shape': None, 'value': None}, + 'scales': {'type': 'Const', 'kind': 'op', 'shape': None, 'value': None}, + 'scales_data': {'kind': 'data', 'shape': None, 'value': None}, + 'sizes': {'type': 'Const', 'kind': 'op', 'shape': None, 'value': None}, + 'sizes_data': {'kind': 'data', 'shape': None, 'value': None}, + 'onnx_resize11': { + 'op': 'ONNXResize11', 'kind': 'op', 'mode': 'nearest', 'nearest_mode': 'round_prefer_floor', + 'coordinate_transformation_mode': 'half_pixel', 'cube_coeff': -0.75 + }, + 'onnx_resize11_data': {'kind': 'data', 'value': None, 'shape': None}, + 'op_output': {'kind': 'op', 'op': 'Result'}, +} + +graph_edges_sizes = [ + ('input', 'input_data'), + ('roi', 'roi_data'), + ('sizes', 'sizes_data'), + ('scales', 'scales_data'), + ('input_data', 'onnx_resize11', {'in': 0}), + ('roi_data', 'onnx_resize11', {'in': 1}), + ('scales_data', 'onnx_resize11', {'in': 2}), + ('sizes_data', 'onnx_resize11', {'in': 3}), + ('onnx_resize11', 'onnx_resize11_data'), + ('onnx_resize11_data', 'op_output'), +] + + +graph_node_attrs_scales = { + 'input': {'type': 'Parameter', 'kind': 'op'}, + 'input_data': {'kind': 'data', 'shape': None, 'value': None}, + 'roi': {'type': 'Const', 'kind': 'op', 'shape': None, 'value': None}, + 'roi_data': {'kind': 'data', 'shape': None, 'value': None}, + 'scales': {'type': 'Const', 'kind': 'op', 'shape': None, 'value': None}, + 'scales_data': {'kind': 'data', 'shape': None, 'value': None}, + 'onnx_resize11': { + 'op': 'ONNXResize11', 'kind': 'op', 'mode': 'nearest', 'nearest_mode': 'round_prefer_floor', + 'coordinate_transformation_mode': 'half_pixel', 'cube_coeff': -0.75 + }, + 'onnx_resize11_data': {'kind': 'data', 'value': None, 'shape': None}, + 'op_output': {'kind': 'op', 'op': 'Result'}, +} + +graph_edges_scales = [ + ('input', 'input_data'), + ('roi', 'roi_data'), + ('scales', 'scales_data'), + ('input_data', 'onnx_resize11', {'in': 0}), + ('roi_data', 'onnx_resize11', {'in': 1}), + ('scales_data', 'onnx_resize11', {'in': 2}), + ('onnx_resize11', 'onnx_resize11_data'), + ('onnx_resize11_data', 'op_output'), +] + + +@generator +class TestONNXResize11Op(unittest.TestCase): + @generate(*[([1, 260, 100, 150], [1, 260, 200, 350], [1, 260, 200, 350], [1.0, 1.0, 1.0, 1.0]), + ([1, 260, 100, 150], [1, 260, 200, 350], [1, 1, 200, 350], [1.0, 1.0, 1.0, 1.0]), + ([5, 14, 300, 40], [5, 14, 140, 280], [1, 1, 140, 280], [1.0, 1.0, 1.0, 1.0]), + ([5, 14, 300, 40], [5, 14, 140, 280], [5, 14, 140, 280], [1.0, 1.0, 1.0, 1.0]), + ([1, 3, 260, 100, 150], [1, 3, 780, 200, 350], [1, 3, 780, 200, 350], [1.0, 1.0, 1.0, 1.0, 1.0]), + ([1, 3, 450, 100, 150], [1, 3, 260, 200, 350], [1, 3, 260, 200, 350], [1.0, 1.0, 1.0, 1.0, 1.0]), + ([5, 14, 1000, 300, 40], [5, 14, 500, 140, 280], [1, 1, 500, 140, 280], [1.0, 1.0, 1.0, 1.0, 1.0]), + ([5, 14, 1000, 300, 40], [5, 14, 500, 140, 280], [5, 14, 500, 140, 280], [1.0, 1.0, 1.0, 1.0, 1.0])]) + def test_onnx_resize11_using_sizes(self, input_shape, output_shape, sizes, scales): + np_scales = np.array(scales) + np_sizes = int64_array(sizes) + graph = build_graph(nodes_attrs=graph_node_attrs_sizes, + edges=graph_edges_sizes, + update_attributes={ + 'input_data': {'shape': int64_array(input_shape)}, + 'scales': {'shape': int64_array(np_scales.shape), 'value': np_scales}, + 'scales_data': {'shape': int64_array(np_scales.shape), 'value': np_scales}, + 'sizes': {'shape': int64_array(np_sizes.shape), 'value': np_sizes}, + 'sizes_data': {'shape': int64_array(np_sizes.shape), 'value': np_sizes}, + }) + node = Node(graph, 'onnx_resize11') + ONNXResize11Op.onnx_resize_infer(node) + + msg = "ONNXResize11 infer failed for case: sizes={}, scales={}, expected_shape={}, actual_shape={}" + + self.assertTrue(np.array_equal(graph.node['onnx_resize11_data']['shape'], int64_array(output_shape)), + msg.format(sizes, scales, output_shape, graph.node['onnx_resize11_data']['shape'])) + + @generate(*[([1, 260, 100, 150], [1, 260, 200, 350], [1.0, 1.0, 2.0, 350 / 150]), + ([1, 3, 100, 200], [1, 3, 350, 150], [1.0, 1.0, 3.5, 150 / 200]), + ([5, 14, 300, 40], [5, 14, 140, 280], [1.0, 1.0, 140 / 300, 7.0]), + ([5, 14, 300, 40], [5, 14, 140, 560], [1.0, 1.0, 140 / 300, 14.0]), + ([1, 3, 260, 100, 150], [1, 3, 780, 200, 350], [1.0, 1.0, 3.0, 2.0, 350 / 150]), + ([1, 3, 450, 100, 150], [1, 3, 260, 200, 350], [1.0, 1.0, 260 / 450, 2.0, 350 / 150]), + ([5, 14, 1000, 300, 40], [5, 14, 500, 140, 280], [1.0, 1.0, 0.5, 140 / 300, 7.0]), + ([4, 3, 180, 1340], [4, 3, 60, 804], [1.0, 1.0, 0.33333334, 0.6]), + ([4, 3, 500, 180, 1340], [4, 3, 750, 60, 804], [1.0, 1.0, 1.5, 0.33333334, 0.6])]) + def test_onnx_resize_using_scales(self, input_shape, output_shape, scales): + np_scales = np.array(scales) + graph = build_graph(nodes_attrs=graph_node_attrs_scales, + edges=graph_edges_scales, + update_attributes={ + 'input_data': {'shape': int64_array(input_shape)}, + 'scales': {'shape': int64_array(np_scales.shape), 'value': np_scales}, + 'scales_data': {'shape': int64_array(np_scales.shape), 'value': np_scales}, + }) + node = Node(graph, 'onnx_resize11') + ONNXResize11Op.onnx_resize_infer(node) + + msg = "ONNXResize11 infer failed for case: scales={}, expected_shape={}, actual_shape={}" + + self.assertTrue(np.array_equal(graph.node['onnx_resize11_data']['shape'], int64_array(output_shape)), + msg.format(scales, output_shape, graph.node['onnx_resize11_data']['shape']))