From b010e0337ebdaa1c9811251d503600451fab3f6d Mon Sep 17 00:00:00 2001 From: "jack.river@evas.ai" Date: Thu, 16 Nov 2023 15:32:31 +0800 Subject: [PATCH 1/2] [BugFix][TOPI] fix resize accuracy issue (#12567) --- python/tvm/topi/image/resize.py | 5 +++-- tests/python/contrib/test_onnx.py | 1 - 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/python/tvm/topi/image/resize.py b/python/tvm/topi/image/resize.py index 29ed03f62e74..f7c519f58145 100644 --- a/python/tvm/topi/image/resize.py +++ b/python/tvm/topi/image/resize.py @@ -592,8 +592,9 @@ def _cast_output(value, data_dtype="float32", out_dtype=None): height_use_int_div = False width_use_int_div = False if method == "nearest_neighbor" and coordinate_transformation_mode == "asymmetric": - height_use_int_div = can_convert_multiply_to_intdiv(image_height, target_height) - width_use_int_div = can_convert_multiply_to_intdiv(image_width, target_width) + if rounding_method == "floor" or rounding_method == "": + height_use_int_div = can_convert_multiply_to_intdiv(image_height, target_height) + width_use_int_div = can_convert_multiply_to_intdiv(image_width, target_width) n, c, y, x, cc, inum, ic = get_2d_indices(indices, layout) box_idx = box_indices(n) if box_indices is not None else n diff --git a/tests/python/contrib/test_onnx.py b/tests/python/contrib/test_onnx.py index afebc2295a68..214166cebb9d 100644 --- a/tests/python/contrib/test_onnx.py +++ b/tests/python/contrib/test_onnx.py @@ -655,7 +655,6 @@ def verify_cast(dshape, dtype): verify_cast(i, o_dtype) -@pytest.mark.xfail(reason="Known failing test. See issue #12567.") def test_resize(): """Resize unit test.""" From 43b90e79558feaa9a91ef78432515f7c6f0785b1 Mon Sep 17 00:00:00 2001 From: "jack.river@evas.ai" Date: Thu, 16 Nov 2023 16:51:18 +0800 Subject: [PATCH 2/2] [Tests] add topi tests for resize2d --- python/tvm/topi/testing/resize_python.py | 39 ++++-- tests/python/topi/test_topi_resize2d.py | 153 +++++++++++++++++++++++ 2 files changed, 181 insertions(+), 11 deletions(-) create mode 100644 tests/python/topi/test_topi_resize2d.py diff --git a/python/tvm/topi/testing/resize_python.py b/python/tvm/topi/testing/resize_python.py index 7d2cce8bd2a7..96f78f1d7f01 100644 --- a/python/tvm/topi/testing/resize_python.py +++ b/python/tvm/topi/testing/resize_python.py @@ -37,19 +37,25 @@ def get_inx(x, image_width, target_width, coordinate_transformation_mode): return in_x -def get_index(x, image_width, target_width, coordinate_transformation_mode): +def get_index(x, image_width, target_width, coordinate_transformation_mode, rounding_method=""): """get and round the nearest index for nearest_neighbor""" in_x = get_inx(x, image_width, target_width, coordinate_transformation_mode) - if coordinate_transformation_mode == "align_corners": + + if rounding_method == "": + rounding_method = "round" if coordinate_transformation_mode == "align_corners" else "floor" + + if rounding_method == "round": # round prefer ceil out = int(math.floor(in_x + 0.5)) + elif rounding_method == "ceil": + out = int(math.ceil(in_x)) else: out = int(math.floor(in_x)) out = max(min(out, image_width - 1), 0) return out -def resize3d_nearest(arr, scale, coordinate_transformation_mode): +def resize3d_nearest(arr, scale, coordinate_transformation_mode, rounding_method=""): """Populate the array by scale factor""" d, h, w = arr.shape out_d, out_h, out_w = [int(round(i * s)) for i, s in zip(arr.shape, scale)] @@ -57,9 +63,9 @@ def resize3d_nearest(arr, scale, coordinate_transformation_mode): for z in range(out_d): for y in range(out_h): for x in range(out_w): - in_z = get_index(z, d, out_d, coordinate_transformation_mode) - in_y = get_index(y, h, out_h, coordinate_transformation_mode) - in_x = get_index(x, w, out_w, coordinate_transformation_mode) + in_z = get_index(z, d, out_d, coordinate_transformation_mode, rounding_method) + in_y = get_index(y, h, out_h, coordinate_transformation_mode, rounding_method) + in_x = get_index(x, w, out_w, coordinate_transformation_mode, rounding_method) out[z, y, x] = arr[in_z, in_y, in_x] return out @@ -166,7 +172,11 @@ def _get_patch(zint, yint, xint): def resize3d_ncdhw( - data, scale, method="nearest_neighbor", coordinate_transformation_mode="align_corners" + data, + scale, + method="nearest_neighbor", + coordinate_transformation_mode="align_corners", + rounding_method="", ): """reference kernel for 3D image resizing""" ishape = data.shape @@ -185,7 +195,7 @@ def resize3d_ncdhw( for c in range(oshape[1]): if method == "nearest_neighbor": output_np[b, c, :, :, :] = resize3d_nearest( - data[b, c, :, :, :], scale, coordinate_transformation_mode + data[b, c, :, :, :], scale, coordinate_transformation_mode, rounding_method ) elif method == "linear": output_np[b, c, :, :, :] = resize3d_linear( @@ -207,6 +217,7 @@ def resize1d_python( layout="NCW", method="nearest_neighbor", coordinate_transformation_mode="align_corners", + rounding_method="", ): """Python version of 3D scaling using nearest neighbour""" @@ -214,7 +225,9 @@ def resize1d_python( data = data.transpose([0, 2, 1]) data = np.expand_dims(data, axis=[2, 3]) - output_np = resize3d_ncdhw(data, (1, 1) + scale, method, coordinate_transformation_mode) + output_np = resize3d_ncdhw( + data, (1, 1) + scale, method, coordinate_transformation_mode, rounding_method + ) output_np = np.squeeze(output_np, axis=2) output_np = np.squeeze(output_np, axis=2) @@ -230,6 +243,7 @@ def resize2d_python( layout="NCHW", method="nearest_neighbor", coordinate_transformation_mode="align_corners", + rounding_method="", ): """Python version of scaling using nearest neighbour""" @@ -244,7 +258,9 @@ def resize2d_python( ) data = np.expand_dims(data, axis=2) - output_np = resize3d_ncdhw(data, (1,) + scale, method, coordinate_transformation_mode) + output_np = resize3d_ncdhw( + data, (1,) + scale, method, coordinate_transformation_mode, rounding_method + ) output_np = np.squeeze(output_np, axis=2) if layout == "NHWC": @@ -262,13 +278,14 @@ def resize3d_python( layout="NCDHW", method="nearest_neighbor", coordinate_transformation_mode="align_corners", + rounding_method="", ): """Python version of 3D scaling using nearest neighbour""" if layout == "NDHWC": data = data.transpose([0, 4, 1, 2, 3]) - output_np = resize3d_ncdhw(data, scale, method, coordinate_transformation_mode) + output_np = resize3d_ncdhw(data, scale, method, coordinate_transformation_mode, rounding_method) if layout == "NDHWC": output_np = output_np.transpose([0, 2, 3, 4, 1]) diff --git a/tests/python/topi/test_topi_resize2d.py b/tests/python/topi/test_topi_resize2d.py new file mode 100644 index 000000000000..47ad4fa06ad5 --- /dev/null +++ b/tests/python/topi/test_topi_resize2d.py @@ -0,0 +1,153 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +"""Test code for upsampling""" +import numpy as np +import tvm +from tvm import te +from tvm import topi +import tvm.testing +import tvm.topi.testing + + +def verify_resize2d( + batch, + in_channel, + in_height, + in_width, + size, + layout="NCHW", + method="linear", + coordinate_transformation_mode="half_pixel", + rounding_method="", +): + if layout == "NCHW": + A = te.placeholder((batch, in_channel, in_height, in_width), name="A") + dtype = A.dtype + out_shape = (batch, in_channel, *size) + a_np = np.random.uniform(size=(batch, in_channel, in_height, in_width)).astype(dtype) + elif layout == "NHWC": + A = te.placeholder((batch, in_height, in_width, in_channel), name="A") + dtype = A.dtype + out_shape = ( + batch, + *size, + in_channel, + ) + a_np = np.random.uniform(size=(batch, in_height, in_width, in_channel)).astype(dtype) + else: + raise NotImplementedError("Layout not supported {} ".format(layout)) + + B = topi.image.resize2d( + A, [0, 0, -1, -1], size, layout, method, coordinate_transformation_mode, rounding_method + ) + + b_np = tvm.topi.testing.resize2d_python( + a_np, + (size[0] / in_height, size[1] / in_width), + layout, + method, + coordinate_transformation_mode, + rounding_method, + ) + + def check_target(target, dev): + print("Running on target: %s" % target) + with tvm.target.Target(target): + s = tvm.topi.testing.get_injective_schedule(target)(B) + a = tvm.nd.array(a_np, dev) + b = tvm.nd.array(np.zeros(out_shape, dtype=dtype), dev) + f = tvm.build(s, [A, B], target) + f(a, b) + + tvm.testing.assert_allclose(b.numpy(), b_np, rtol=1e-5, atol=1e-5) + + for target, dev in tvm.testing.enabled_targets(): + check_target(target, dev) + + +@tvm.testing.uses_gpu +def test_image_resize2d(): + # nearest_neighbor - NCHW + verify_resize2d( + 8, + 16, + 32, + 32, + (64, 64), + method="nearest_neighbor", + coordinate_transformation_mode="asymmetric", + rounding_method="floor", + ) + verify_resize2d( + 8, + 16, + 32, + 32, + (64, 64), + method="nearest_neighbor", + coordinate_transformation_mode="asymmetric", + rounding_method="round", + ) + verify_resize2d( + 8, + 16, + 32, + 32, + (64, 64), + method="nearest_neighbor", + coordinate_transformation_mode="asymmetric", + rounding_method="ceil", + ) + + # nearest_neighbor - NHWC + verify_resize2d( + 8, + 16, + 32, + 32, + (64, 64), + layout="NHWC", + method="nearest_neighbor", + coordinate_transformation_mode="asymmetric", + rounding_method="floor", + ) + verify_resize2d( + 8, + 16, + 32, + 32, + (64, 64), + layout="NHWC", + method="nearest_neighbor", + coordinate_transformation_mode="asymmetric", + rounding_method="round", + ) + verify_resize2d( + 8, + 16, + 32, + 32, + (64, 64), + layout="NHWC", + method="nearest_neighbor", + coordinate_transformation_mode="asymmetric", + rounding_method="ceil", + ) + + +if __name__ == "__main__": + test_image_resize2d()