diff --git a/python/tvm/relay/frontend/onnx.py b/python/tvm/relay/frontend/onnx.py index bc44431df3eb..952f6675c874 100644 --- a/python/tvm/relay/frontend/onnx.py +++ b/python/tvm/relay/frontend/onnx.py @@ -937,7 +937,10 @@ def _impl_v9(cls, inputs, attr, params): else: assert len(scales) == 4 attr['layout'] = 'NCHW' - attr['align_corners'] = True + if method == 'nearest_neighbor': + attr['align_corners'] = False + else: + attr['align_corners'] = True op_name = 'upsampling' return AttrCvt(op_name)(inputs, attr) diff --git a/python/tvm/relay/frontend/pytorch.py b/python/tvm/relay/frontend/pytorch.py index 235cec0f096d..afa2c21eb9d9 100644 --- a/python/tvm/relay/frontend/pytorch.py +++ b/python/tvm/relay/frontend/pytorch.py @@ -1536,7 +1536,9 @@ def _impl(inputs, input_types): else: align_corners = False - if align_corners: + if method == "nearest_neighbor": + coord_trans = "asymmetric" + elif align_corners: coord_trans = "align_corners" else: coord_trans = "half_pixel" @@ -1581,7 +1583,9 @@ def _impl(inputs, input_types): else: align_corners = False - if align_corners: + if method == "nearest_neighbor": + coord_trans = "asymmetric" + elif align_corners: coord_trans = "align_corners" else: coord_trans = "half_pixel" diff --git a/python/tvm/topi/image/resize.py b/python/tvm/topi/image/resize.py index aab3009bd922..25258925aa37 100644 --- a/python/tvm/topi/image/resize.py +++ b/python/tvm/topi/image/resize.py @@ -529,8 +529,11 @@ def resize(data, size, layout="NCHW", method="bilinear", or [batch, in_height*scale, in_width*scale, channel] or 5-D with shape [batch, channel-major, in_height*scale, in_width*scale, channel-minor] """ - method = method.lower() + if method == "nearest_neighbor" and coordinate_transformation_mode != "asymmetric": + raise ValueError('Topi Resize does not support the combination of method %s ' \ + 'and coordinate_transformation_mode %s' % + (method, coordinate_transformation_mode)) if layout == 'NHWC': in_n, in_h, in_w, in_c = data.shape if output_shape is None: diff --git a/tests/python/relay/dyn/test_dynamic_op_level5.py b/tests/python/relay/dyn/test_dynamic_op_level5.py index f0095a1f03c9..8dcfd1fd5778 100644 --- a/tests/python/relay/dyn/test_dynamic_op_level5.py +++ b/tests/python/relay/dyn/test_dynamic_op_level5.py @@ -49,7 +49,11 @@ def verify_resize(dshape, scale, method, layout): ref_res = tvm.topi.testing.upsampling_python(x_data, (scale, scale), layout) x = relay.var("x", relay.TensorType(dshape, "float32")) size_var = relay.var("size", relay.TensorType((2,), "int64")) - z = relay.image.resize(x, size_var, layout, method, "align_corners") + + coord_trans = "asymmetric" if method == "nearest_neighbor" else "align_corners" + z = relay.image.resize(x, size_var, layout, method, + coordinate_transformation_mode=coord_trans) + zz = run_infer_type(z) func = relay.Function([x, size_var], z) @@ -60,9 +64,11 @@ def verify_resize(dshape, scale, method, layout): intrp = relay.create_executor(kind, mod=mod, ctx=ctx, target=target) op_res = intrp.evaluate()(x_data, size) tvm.testing.assert_allclose(op_res.asnumpy(), ref_res, rtol=1e-4, atol=1e-6) + for method in ["bilinear", "nearest_neighbor"]: for layout in ["NCHW", "NHWC"]: verify_resize((1, 4, 4, 4), 2, method, layout) + verify_resize((2, 8, 17, 20), 7, method, layout) if __name__ == "__main__": test_resize_infer_type() diff --git a/tests/python/relay/test_op_level5.py b/tests/python/relay/test_op_level5.py index 70678031156d..254bab5e1692 100644 --- a/tests/python/relay/test_op_level5.py +++ b/tests/python/relay/test_op_level5.py @@ -41,19 +41,21 @@ def test_resize_infer_type(): assert zz.checked_type == relay.TensorType((n, c, 100, 200), "int8") def test_resize(): - def verify_resize(dshape, scale, method, layout): + def verify_resize(dshape, scale, method, layout, coord_trans): if layout == "NHWC": size = (dshape[1] * scale, dshape[2] * scale) else: size = (dshape[2] * scale, dshape[3] * scale) x_data = np.random.uniform(size=dshape).astype("float32") + if method == "bilinear": - ref_res = tvm.topi.testing.bilinear_resize_python(x_data, size, layout) + ref_res = tvm.topi.testing.bilinear_resize_python(x_data, size, layout, coord_trans) else: ref_res = tvm.topi.testing.upsampling_python(x_data, (scale, scale), layout) x = relay.var("x", relay.TensorType(dshape, "float32")) - z = relay.image.resize(x, size, layout, method, "align_corners") + z = relay.image.resize(x, size, layout, method, + coordinate_transformation_mode=coord_trans) assert "size=" in z.astext() zz = run_infer_type(z) assert zz.checked_type == relay.TensorType(ref_res.shape, "float32") @@ -63,10 +65,13 @@ def verify_resize(dshape, scale, method, layout): for kind in ["graph", "debug"]: intrp = relay.create_executor(kind, ctx=ctx, target=target) op_res = intrp.evaluate(func)(x_data) - tvm.testing.assert_allclose(op_res.asnumpy(), ref_res, rtol=1e-4, atol=1e-6) - for method in ["bilinear", "nearest_neighbor"]: - for layout in ["NHWC", "NCHW"]: - verify_resize((1, 4, 4, 4), 2, method, layout) + tvm.testing.assert_allclose(op_res.asnumpy(), ref_res, rtol=1e-4, atol=1e-5) + + for layout in ["NHWC", "NCHW"]: + verify_resize((1, 4, 4, 4), 2, "bilinear", layout, "align_corners") + verify_resize((2, 8, 17, 20), 3, "bilinear", layout, "half_pixel") + verify_resize((2, 8, 17, 20), 3, "bilinear", layout, "asymmetric") + verify_resize((3, 4, 5, 6), 5, "nearest_neighbor", layout, "asymmetric") def test_resize3d_infer_type(): n, c, d, h, w = te.size_var("n"), te.size_var("c"), te.size_var("d"), te.size_var("h"), te.size_var("w") diff --git a/tests/python/relay/test_pass_dynamic_to_static.py b/tests/python/relay/test_pass_dynamic_to_static.py index c61f169d53e0..a53b027c6451 100644 --- a/tests/python/relay/test_pass_dynamic_to_static.py +++ b/tests/python/relay/test_pass_dynamic_to_static.py @@ -251,7 +251,9 @@ def verify_resize(shape, scale, method, layout): x = relay.var("x", relay.TensorType(shape, "float32")) size_var = relay.const(np.array(size).astype("float32")) - z = relay.image.resize(x, size_var, layout, method, "align_corners") + coord_trans = "asymmetric" if method == "nearest_neighbor" else "align_corners" + z = relay.image.resize(x, size_var, layout, method, + coordinate_transformation_mode=coord_trans) func = run_infer_type(relay.Function([x], z)) func2 = run_opt_pass(run_opt_pass(func, transform.DynamicToStatic()), diff --git a/tests/python/topi/python/test_topi_image.py b/tests/python/topi/python/test_topi_image.py index 8d0092901c5c..7fce69d2300c 100644 --- a/tests/python/topi/python/test_topi_image.py +++ b/tests/python/topi/python/test_topi_image.py @@ -81,6 +81,9 @@ def test_resize(): # half_pixel verify_resize(4, 16, 16, 16, 32, 32, 'NCHW', "half_pixel", method="bilinear") verify_resize(4, 16, 16, 16, 32, 32, 'NHWC', "half_pixel", method="bilinear") + # Bilinear + Fractional + verify_resize(4, 16, 32, 32, 50, 50, 'NCHW', "asymmetric", method="bilinear") + verify_resize(4, 16, 32, 32, 50, 50, 'NHWC', "asymmetric", method="bilinear") def verify_resize3d(batch, in_channel, in_depth, in_height, in_width, out_depth, out_height, out_width,