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 = []