This is an automated email from the ASF dual-hosted git repository.

andrewzhaoluo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tvm.git


The following commit(s) were added to refs/heads/main by this push:
     new 7827fffe5c [Relay][Frontend][ONNX] Add GridSample operator (#13163)
7827fffe5c is described below

commit 7827fffe5c98fef213706bc296b97d96bb9f5019
Author: Ehsan M. Kermani <[email protected]>
AuthorDate: Mon Oct 24 09:55:00 2022 -0700

    [Relay][Frontend][ONNX] Add GridSample operator (#13163)
    
    * [Relay][Frontend][ONNX] Add GridSample operator
    
    * Skip the flaky gridsample nearest test on cuda
    
    * Remove the flaky skip case
    
    Co-authored-by: Ehsan M. Kermani <[email protected]>
---
 python/tvm/relay/frontend/onnx.py          | 18 ++++++++++++++++++
 python/tvm/relay/op/image/image.py         |  2 +-
 python/tvm/topi/image/grid_sample.py       | 18 +++++++++---------
 src/relay/op/image/grid_sample.cc          |  2 +-
 tests/python/frontend/onnx/test_forward.py | 12 ++++--------
 5 files changed, 33 insertions(+), 19 deletions(-)

diff --git a/python/tvm/relay/frontend/onnx.py 
b/python/tvm/relay/frontend/onnx.py
index ff7d5655e0..743e39296c 100644
--- a/python/tvm/relay/frontend/onnx.py
+++ b/python/tvm/relay/frontend/onnx.py
@@ -4815,6 +4815,23 @@ class Trilu(OnnxOpConverter):
         return _op.trilu(data, k, upper)
 
 
+class GridSample(OnnxOpConverter):
+    """Operator converter for GridSample"""
+
+    @classmethod
+    def _impl_v16(cls, inputs, attr, params):
+        grid = inputs[1]
+        # onnx grid is of shape (N, H, W, 2) which should be transposed to (N, 
2, H, W) for relay
+        grid = _op.transform.transpose(grid, axes=(0, 3, 1, 2))
+        method: str = attr.get("mode", b"bilinear").decode("utf-8")
+        padding_mode: str = attr.get("padding_mode", b"zeros").decode("utf-8")
+        # onnx default is 0 which should be changed to False in relay
+        align_corners = attr.get("align_corners", 0) != 0
+        return _op.image.grid_sample(
+            inputs[0], grid, method, padding_mode=padding_mode, 
align_corners=align_corners
+        )
+
+
 class RandomNormal(OnnxOpConverter):
     """Operator converter for random_normal"""
 
@@ -5494,6 +5511,7 @@ def _get_convert_map(opset):
         "Unique": Unique.get_converter(opset),
         "Einsum": Einsum.get_converter(opset),
         "Trilu": Trilu.get_converter(opset),
+        "GridSample": GridSample.get_converter(opset),
         # defs/control_flow
         "Loop": Loop.get_converter(opset),
         "If": If.get_converter(opset),
diff --git a/python/tvm/relay/op/image/image.py 
b/python/tvm/relay/op/image/image.py
index b5886300cb..5a17532dd0 100644
--- a/python/tvm/relay/op/image/image.py
+++ b/python/tvm/relay/op/image/image.py
@@ -477,7 +477,7 @@ def grid_sample(
 
     The left-top corner (-1, -1) and right-bottom corner (1, 1) in grid will 
be map to
     (0, 0) and (h - 1, w - 1) of data if align_corners is "True", or
-    (-0.5, -0.5) and (h + 0.5, w + 0.5) of data if align_corners is "False".
+    (-0.5, -0.5) and (h - 0.5, w - 0.5) of data if align_corners is "False".
 
     The shape of the output will be
     4-D (data.shape[0], data.shape[1], grid.shape[2], grid.shape[3]), or
diff --git a/python/tvm/topi/image/grid_sample.py 
b/python/tvm/topi/image/grid_sample.py
index 705df8db7b..7110870229 100644
--- a/python/tvm/topi/image/grid_sample.py
+++ b/python/tvm/topi/image/grid_sample.py
@@ -81,7 +81,7 @@ def _grid_sample_2d(
 
     The left-top corner (-1, -1) and right-bottom corner (1, 1) in grid will 
be map to
     (0, 0) and (h - 1, w - 1) of data if align_corners is "True", or
-    (-0.5, -0.5) and (h + 0.5, w + 0.5) of data if align_corners is "False".
+    (-0.5, -0.5) and (h - 0.5, w - 0.5) of data if align_corners is "False".
 
     The shape of the output will be (data.shape[0], data.shape[1], 
grid.shape[2], grid.shape[3]).
 
@@ -200,13 +200,13 @@ def _grid_sample_2d(
 
     def _nearest_sample(n, c, h, w):
         y, x = _compute_source_index(n, h, w)
-        y_new = te.round(y).astype("int32")
-        x_new = te.round(x).astype("int32")
+        y_new = te.nearbyint(y).astype("int32")
+        x_new = te.nearbyint(x).astype("int32")
 
         return _get_pixel_value(n, c, y_new, x_new)
 
     def _bicubic_sample(n, c, h, w):
-        A = -0.75  # 0.75 is used in pytorch, it maybe different in other 
frameworks
+        A = -0.75  # -0.75 is used in pytorch, it maybe different in other 
frameworks
 
         def cubic_weight_1(fraction):
             return ((A + 2) * fraction - (A + 3)) * fraction * fraction + 1
@@ -310,7 +310,7 @@ def _grid_sample_3d(
 
     The left-top corner (-1, -1, -1) and right-bottom corner (1, 1, 1) in grid 
will be map to
     (0, 0, 0) and (d - 1, h - 1, w - 1) of data if align_corners is "True", or
-    (-0.5, -0.5, -0.5) and (d + 0.5, h + 0.5, w + 0.5) of data if 
align_corners is "False".
+    (-0.5, -0.5, -0.5) and (d - 0.5, h - 0.5, w - 0.5) of data if 
align_corners is "False".
 
     The shape of the output will be
     (data.shape[0], data.shape[1], grid.shape[2], grid.shape[3], 
grid.shape[4]).
@@ -437,9 +437,9 @@ def _grid_sample_3d(
 
     def _nearest_sample(n, c, d, h, w):
         z, y, x = _compute_source_index(n, d, h, w)
-        z_new = te.round(z).astype("int32")
-        y_new = te.round(y).astype("int32")
-        x_new = te.round(x).astype("int32")
+        z_new = te.nearbyint(z).astype("int32")
+        y_new = te.nearbyint(y).astype("int32")
+        x_new = te.nearbyint(x).astype("int32")
         return _get_pixel_value(n, c, z_new, y_new, x_new)
 
     if method == "bilinear":
@@ -474,7 +474,7 @@ def grid_sample(
 
     The left-top corner (-1, -1) and right-bottom corner (1, 1) in grid will 
be map to
     (0, 0) and (h - 1, w - 1) of data if align_corners is "True", or
-    (-0.5, -0.5) and (h + 0.5, w + 0.5) of data if align_corners is "False".
+    (-0.5, -0.5) and (h - 0.5, w - 0.5) of data if align_corners is "False".
 
     The shape of the output will be
     4-D (data.shape[0], data.shape[1], grid.shape[2], grid.shape[3]), or
diff --git a/src/relay/op/image/grid_sample.cc 
b/src/relay/op/image/grid_sample.cc
index 689a71ebc5..46b9714aee 100644
--- a/src/relay/op/image/grid_sample.cc
+++ b/src/relay/op/image/grid_sample.cc
@@ -177,7 +177,7 @@ inner pixel value if padding_mode is "reflection".
 
 The left-top corner (-1, -1) and right-bottom corner (1, 1) in grid will be 
map to
 (0, 0) and (h - 1, w - 1) of data if align_corners is "True", or
-(-0.5, -0.5) and (h + 0.5, w + 0.5) of data if align_corners is "False".
+(-0.5, -0.5) and (h - 0.5, w - 0.5) of data if align_corners is "False".
 
 The shape of the output will be
 4-D (data.shape[0], data.shape[1], grid.shape[2], grid.shape[3]), or
diff --git a/tests/python/frontend/onnx/test_forward.py 
b/tests/python/frontend/onnx/test_forward.py
index 3a714af3a7..684a33fbce 100644
--- a/tests/python/frontend/onnx/test_forward.py
+++ b/tests/python/frontend/onnx/test_forward.py
@@ -5274,14 +5274,6 @@ unsupported_onnx_tests = [
     "test_dropout_default_mask",
     "test_dropout_default_mask_ratio",
     "test_dropout_default_ratio",
-    "test_gridsample",
-    "test_gridsample_aligncorners_true",
-    "test_gridsample_bicubic",
-    "test_gridsample_bilinear",
-    "test_gridsample_border_padding",
-    "test_gridsample_nearest",
-    "test_gridsample_reflection_padding",
-    "test_gridsample_zeros_padding",
     "test_gru_batchwise",
     "test_hammingwindow",
     "test_hammingwindow_expanded",
@@ -5419,6 +5411,10 @@ def test_onnx_nodes(target, dev, onnx_test):
         # in accuracy depending on implementation
         atol = 1e-4
 
+    if "bicubic" in test_dir:
+        # satisfies onnx precision for bicubic interpolation
+        atol = 1e-4
+
     onnx_model = onnx.load(test_dir + "/model.onnx")
     inputs = []
     outputs = []

Reply via email to