diff --git a/converter/main.py b/converter/main.py
index 8db65514dbc14ad813f055f1bf32a7521ae50d5f..bca6e8f95613edba14217b50fbca50033c4143f2 100644
--- a/converter/main.py
+++ b/converter/main.py
@@ -123,6 +123,7 @@ class OPTYPE(IntEnum):
     # and the matrix multiplication by batches.
     BatchMatMul = (6,)
     ScatterND = (22,)
+    GridSample = (23,)
 
     # "BatchMatMulV2" did not exist in Tensorflow 1.9. It exists in
     # Tensorflow 1.15.
@@ -1004,6 +1005,37 @@ def parse_graph_node(
         myGraph[node.output[0]]["additional"]["data"] = node
         map_onnx_to_myGraph[node.output[0]] = node.output[0]
 
+    elif node.op_type == "GridSample":
+        # Currently, the official TensorFlow does not have an implementation for GridSample.
+        align_corners = getAttribute(node, "align_corners").i
+        mode = getAttribute(node, "mode").s.decode('utf-8')
+        padding_mode = getAttribute(node, "padding_mode").s.decode('utf-8')
+
+        mode_list = ["nearest", "bilinear"]
+        if not mode in mode_list:
+            quit("[ERROR] Currently, the mode of GridSample must in", mode_list, node)
+        else:
+            mode = mode_list.index(mode)
+        padding_mode_list = ["border"]
+        if not padding_mode in padding_mode_list:
+            quit("[ERROR] Currently, the padding_mode of GridSample must in",
+                 padding_mode_list, node)
+        else:
+            padding_mode = padding_mode_list.index(padding_mode)
+
+        myGraph[node.output[0]] = {}
+        myGraph[node.output[0]]["op_type"] = OPTYPE.GridSample
+        myGraph[node.output[0]]["inputs"] = [
+            map_onnx_to_myGraph[n0name],
+            map_onnx_to_myGraph[node.input[1]],
+        ]
+        myGraph[node.output[0]]["additional"] = {}
+        myGraph[node.output[0]]["additional"]["data"] = node
+        myGraph[node.output[0]]["additional"]["align_corners"] = align_corners
+        myGraph[node.output[0]]["additional"]["mode"] = mode
+        myGraph[node.output[0]]["additional"]["padding_mode"] = padding_mode
+        map_onnx_to_myGraph[node.output[0]] = node.output[0]
+
     else:
         raise Exception("[ERROR] node not supported:\n{})".format(node))
 
@@ -1272,6 +1304,23 @@ def dump_onnx(graph, my_inputs, my_outputs, output_filename, verbose=False):
                     print("#\t axis", node["additional"]["axis"])
                 f.write(struct.pack("i", int(node["additional"]["axis"])))
 
+            elif node["op_type"] == OPTYPE.GridSample:
+                if verbose:
+                    print("#\t align_corners",
+                          node["additional"]["align_corners"])
+                f.write(struct.pack(
+                    "i", int(node["additional"]["align_corners"])))
+
+                if verbose:
+                    print("#\t mode", node["additional"]["mode"])
+                f.write(struct.pack("i", int(node["additional"]["mode"])))
+
+                if verbose:
+                    print("#\t padding_mode",
+                          node["additional"]["padding_mode"])
+                f.write(struct.pack(
+                    "i", int(node["additional"]["padding_mode"])))
+
             if (
                 node["op_type"] == OPTYPE.Conv2D
                 or node["op_type"] == OPTYPE.Conv2DTranspose
@@ -1348,6 +1397,19 @@ def annotate_node(
                 if verbose > 1:
                     print("[WARNING] transpose not for NCHW handling in\n", node)
 
+            if node_annotation[node.name].to_remove:
+                # The GridSample is usually used with Transpose. Cause the optical-flow will be
+                # transposed from (N,2,H,W) to (N,H,W,2) and this operation should not be removed.
+                # Meanwhile there will not have other operations after transposed feature with
+                # shape (N,H,W,2) in PyTorch, so the code in this IF statement will not influnce
+                # other situations.
+                nexts = getNodesWithInput(node.output[0], model_onnx)
+                for n in nexts:
+                    if n.op_type == "GridSample":
+                        node_annotation[node.name].to_remove = False
+                        node_annotation[node.name].layout_onnx = "nchw"
+                        break
+
     elif node.op_type == "Reshape":
         initializer = getInitializer(node.input[1], model_onnx)
         # Case: In pytorch, Reshape is not in model_onnx.graph.initializer but in model_onnx.graph.node
diff --git a/sadl/layer.h b/sadl/layer.h
index 7bd52b569a146eb25940c6b7611dc965a8836d6e..a7ed32bf8b0f7fe3589839f2df49ceff96f10163 100644
--- a/sadl/layer.h
+++ b/sadl/layer.h
@@ -70,7 +70,8 @@ struct OperationType
     Slice              = 20,
     PReLU              = 21,
     ScatterND          = 22,
-    OperationTypeCount = 23
+    GridSample         = 23,
+    OperationTypeCount = 24
   };
 };
 
diff --git a/sadl/layer_gridsample.h b/sadl/layer_gridsample.h
new file mode 100644
index 0000000000000000000000000000000000000000..ac57280b062554d07cd6e62ab3c481633f4f9b2f
--- /dev/null
+++ b/sadl/layer_gridsample.h
@@ -0,0 +1,249 @@
+/* The copyright in this software is being made available under the BSD
+ * License, included below. This software may be subject to other third party
+ * and contributor rights, including patent rights, and no such rights are
+ * granted under this license.
+ *
+ * Copyright (c) 2010-2023, ITU/ISO/IEC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *  * Neither the name of the ITU/ISO/IEC nor the names of its contributors may
+ *    be used to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#pragma once
+#include "layer.h"
+
+namespace sadl
+{
+namespace layers
+{
+template<typename T> class GridSample : public Layer<T>
+{
+public:
+  using Layer<T>::Layer;
+  using Layer<T>::m_out;   // to avoid this->
+  using Layer<T>::m_initDone;
+
+  virtual bool apply(std::vector<Tensor<T> *> &in) override;
+  virtual bool init(const std::vector<Tensor<T> *> &in) override;
+
+protected:
+  virtual bool loadInternal(std::istream &file, Version) override;
+  void         gs_denormalize(float &x, int length);
+  void         pixel_addr_at_grid(int &addr, int H, int W, int C, int i, int j, int c);
+  void         atomic_bilinear(const Tensor<T> &X, float x, float y, int shift, int addr_out);
+  int          m_align_corners;   // 0: False, 1: True
+  int          m_mode;            // 0: "nearest", 1: "bilinear"
+  int          m_padding_mode;    // 0: "border"
+  using T2 = typename ComputationType<T>::type;
+  DUMP_MODEL_EXT;
+};
+
+template<typename T> bool GridSample<T>::loadInternal(std::istream &file, Version)
+{
+  if (!std::is_same<T, float>::value)
+  {
+    std::cerr << "[ERROR] Currently, GridSample only supports float data type." << std::endl;
+    return false;
+  }
+
+  int32_t x = 0;
+  file.read((char *) &x, sizeof(x));
+  m_align_corners = x;
+  SADL_DBG(std::cout << "  - align_corners: " << m_align_corners << std::endl);
+  file.read((char *) &x, sizeof(x));
+  m_mode = x;
+  SADL_DBG(std::cout << "  - mode: " << m_mode << std::endl);
+  file.read((char *) &x, sizeof(x));
+  m_padding_mode = x;
+  SADL_DBG(std::cout << "  - padding_mode: " << m_padding_mode << std::endl);
+  if (m_mode != 0 && m_mode != 1)
+  {
+    std::cerr << "[ERROR] invalid mode: " << m_mode << std::endl;
+    return false;
+  }
+  if (m_padding_mode != 0)
+  {
+    std::cerr << "[ERROR] invalid padding mode: " << m_padding_mode << std::endl;
+    return false;
+  }
+  return true;
+}
+
+template<typename T> bool GridSample<T>::init(const std::vector<Tensor<T> *> &in)
+{
+  if (in.size() != 2)
+    return false;
+  Dimensions dim;
+  dim.resize(4);
+  dim[0] = in[0]->dims()[0];   // N, inherit from X
+  dim[1] = in[1]->dims()[3];   // H_out, inherit from grid
+  dim[2] = in[1]->dims()[1];   // W_out, inherit from grid
+  dim[3] = in[0]->dims()[3];   // C, inherit from X
+  m_out.resize(dim);
+  m_initDone = true;
+  return true;
+}
+
+template<typename T> bool GridSample<T>::apply(std::vector<Tensor<T> *> &in)
+{
+  const Tensor<T> &X    = *in[0];   // (1,H_in,W_in,C)
+  const Tensor<T> &grid = *in[1];   // (1,W_out,2,H_out)
+  m_out.quantizer       = X.quantizer;
+  assert(X.dims()[0] == 1 && grid.dims()[0] == 1 && grid.dims()[2] == 2);
+
+  int   C                    = X.dims()[3];
+  int   H_in                 = X.dims()[1];
+  int   W_in                 = X.dims()[2];
+  int   H_out                = grid.dims()[3];
+  int   W_out                = grid.dims()[1];
+  float x_min                = (m_align_corners) ? 0 : -0.5;
+  float x_max                = (m_align_corners) ? W_in - 1 : W_in - 0.5;
+  float y_min                = (m_align_corners) ? 0 : -0.5;
+  float y_max                = (m_align_corners) ? H_in - 1 : H_in - 0.5;
+  bool  normalize_grid_flag  = !std::is_same<T, float>::value;
+  float normalize_grid_coeff = 2 << (grid.quantizer - 1);
+  int   shift                = grid.quantizer;
+
+  // Given an input X and a flow-field grid, computes the output Y using X values and pixel locations from the grid.
+  int addr_grid_x = -W_out, addr_grid_y = -W_out + H_out;
+  for (int im_j = 0; im_j < W_out; im_j++)
+  {
+    addr_grid_x += H_out;
+    addr_grid_y += H_out;
+    for (int im_i = 0; im_i < H_out; im_i++)
+    {
+      // compute pixel locations from the grid
+      float x = grid[addr_grid_x++];
+      float y = grid[addr_grid_y++];
+      if (normalize_grid_flag)
+      {
+        x = x / normalize_grid_coeff;
+        y = y / normalize_grid_coeff;
+      }
+      gs_denormalize(x, W_in);
+      gs_denormalize(y, H_in);
+      if (m_mode == 0)   // nearest
+      {
+        x = round(x);
+        y = round(y);
+      }
+      if (x < x_min || x > x_max || y < y_min || y > y_max)
+      {
+        if (m_padding_mode == 0)   // border
+        {
+          x = (x < 0) ? 0 : ((x > W_in - 1) ? W_in - 1 : x);
+          y = (y < 0) ? 0 : ((y > H_in - 1) ? H_in - 1 : y);
+        }
+      }
+      // compute the output Y using X values and pixel locations
+      int addr_out = (im_i * W_out + im_j) * C;
+      if (m_mode == 0)   // nearest
+      {
+        int addr_grid = 0;
+        pixel_addr_at_grid(addr_grid, H_in, W_in, C, int(y), int(x), 0);
+        for (int im_c = 0; im_c < C; im_c++)
+        {
+          m_out[addr_out++] = X[addr_grid];   // same data type
+          COUNTERS(X[addr_grid++]);
+        }
+      }
+      else if (m_mode == 1)   // bilinear
+      {
+        atomic_bilinear(X, x, y, shift, addr_out);
+      }
+    }
+  }
+  return true;
+}
+
+template<typename T> void GridSample<T>::gs_denormalize(float &x, int length)
+{
+  if (m_align_corners)
+  {
+    x = (x + 1) / 2.0 * (length - 1);
+  }
+  else
+  {
+    x = ((x + 1) * length - 1) / 2.0;
+  }
+}
+
+template<typename T> void GridSample<T>::pixel_addr_at_grid(int &addr, int H, int W, int C, int i, int j, int c)
+{
+  if (m_padding_mode == 0)   // border
+  {
+    i    = (i < 0) ? 0 : ((i > H - 1) ? H - 1 : i);
+    j    = (j < 0) ? 0 : ((j > W - 1) ? W - 1 : j);
+    addr = C * (W * i + j) + c;   // (0, i, j, c)
+  }
+}
+
+template<typename T> void GridSample<T>::atomic_bilinear(const Tensor<T> &X, float x, float y, int shift, int addr_out)
+{
+  int H_in = X.dims()[1];
+  int W_in = X.dims()[2];
+  int C    = X.dims()[3];
+
+  T2    num{};
+  T     coeff11{}, coeff12{}, coeff21{}, coeff22{};
+  float x1 = floor(x), y1 = floor(y), x2 = x1 + 1, y2 = y1 + 1;
+  float normalize_grid_coeff = 2 << (shift - 1);
+  if (std::is_same<T2, float>::value)
+  {
+    coeff11 = (y2 - y) * (x2 - x);   // dy2 * dx2
+    coeff12 = (y2 - y) * (x - x1);   // dy2 * dx1
+    coeff21 = (y - y1) * (x2 - x);   // dy1 * dx2
+    coeff22 = (y - y1) * (x - x1);   // dy1 * dx1
+  }
+  else
+  {
+    coeff11 = (y2 - y) * (x2 - x) * normalize_grid_coeff;
+    coeff12 = (y2 - y) * (x - x1) * normalize_grid_coeff;
+    coeff21 = (y - y1) * (x2 - x) * normalize_grid_coeff;
+    coeff22 = (y - y1) * (x - x1) * normalize_grid_coeff;
+  }
+
+  int addr_grid11 = 0, addr_grid12 = 0, addr_grid21 = 0, addr_grid22 = 0;
+  pixel_addr_at_grid(addr_grid11, H_in, W_in, C, y1, x1, 0);
+  pixel_addr_at_grid(addr_grid12, H_in, W_in, C, y1, x2, 0);
+  pixel_addr_at_grid(addr_grid21, H_in, W_in, C, y2, x1, 0);
+  pixel_addr_at_grid(addr_grid22, H_in, W_in, C, y2, x2, 0);
+  for (int im_c = 0; im_c < C; im_c++)
+  {
+    num = coeff11 * X[addr_grid11++] + coeff12 * X[addr_grid12++] + coeff21 * X[addr_grid21++] + coeff22 * X[addr_grid22++];
+    ComputationType<T>::quantize(num, shift);
+    {
+      COUNTERS_MAC(coeff11);
+      COUNTERS_MAC(coeff12);
+      COUNTERS_MAC(coeff21);
+      COUNTERS_MAC(coeff22);
+    }
+    COUNTERS(num);
+    SATURATE(num);
+    m_out[addr_out++] = static_cast<T>(num);
+  }
+}
+
+}   // namespace layers
+}   // namespace sadl
diff --git a/sadl/layers.h b/sadl/layers.h
index b08604c12eb28cc4c8e2ec6a76d9b514a91c8c67..dabfef58d4978e7b9f5773622259bb3a7544510f 100644
--- a/sadl/layers.h
+++ b/sadl/layers.h
@@ -55,6 +55,7 @@
 #include "layer_slice.h"
 #include "layer_prelu.h"
 #include "layer_scatternd.h"
+#include "layer_gridsample.h"
 
 namespace sadl
 {
@@ -92,6 +93,7 @@ inline std::string opName(const OperationType::Type op)
     DIRTYCASEPRINT(Slice);
     DIRTYCASEPRINT(PReLU);
     DIRTYCASEPRINT(ScatterND);
+    DIRTYCASEPRINT(GridSample);
   default:
     oss << "??";
     break;
diff --git a/sadl/model.h b/sadl/model.h
index 9b749521396c8a6b115def21c124f4549407ccb9..c40d67fb1b89df94dc58f24564ddb14628955d8b 100644
--- a/sadl/model.h
+++ b/sadl/model.h
@@ -171,7 +171,10 @@ template<typename T> std::unique_ptr<layers::Layer<T>> createLayer(int32_t id, l
     return std::unique_ptr<layers::Layer<T>>(new layers::PReLU<T>{ id, op });
     break;
   case layers::OperationType::ScatterND:
-    return std::unique_ptr<layers::Layer<T>>(new layers::ScatterND<T>{id, op});
+    return std::unique_ptr<layers::Layer<T>>(new layers::ScatterND<T>{ id, op });
+    break;
+  case layers::OperationType::GridSample:
+    return std::unique_ptr<layers::Layer<T>>(new layers::GridSample<T>{ id, op });
     break;
   case layers::OperationType::OperationTypeCount:
     break;   // no default on purpose
diff --git a/sample/copy.h b/sample/copy.h
index 12b546a347934c797432c44c03a6a1c75d3b3dc2..64423953af36576dea0581310cbc7143ba8cfab7 100644
--- a/sample/copy.h
+++ b/sample/copy.h
@@ -82,6 +82,11 @@ template<typename T> bool copy(const sadl::layers::Layer<float> &layer, sadl::la
     break;
   case sadl::layers::OperationType::ScatterND:
     break;
+  case sadl::layers::OperationType::GridSample:
+    dynamic_cast<sadl::layers::GridSample<T> &>(layerQ).m_align_corners = dynamic_cast<const sadl::layers::GridSample<float> &>(layer).m_align_corners;
+    dynamic_cast<sadl::layers::GridSample<T> &>(layerQ).m_mode          = dynamic_cast<const sadl::layers::GridSample<float> &>(layer).m_mode;
+    dynamic_cast<sadl::layers::GridSample<T> &>(layerQ).m_padding_mode  = dynamic_cast<const sadl::layers::GridSample<float> &>(layer).m_padding_mode;
+    break;
     // no default to get warning
   }
 
diff --git a/sample/dumper.h b/sample/dumper.h
index 826352ed5b2d120011d3eb8237ece510699395a3..d2349cf552ccebd247fb40ea5ab9eb721ff65b86 100644
--- a/sample/dumper.h
+++ b/sample/dumper.h
@@ -112,6 +112,14 @@ template<typename T> bool sadl::layers::Const<T>::dump(std::ostream &file)
   return true;
 }
 
+template<typename T> bool sadl::layers::GridSample<T>::dump(std::ostream &file)
+{
+  file.write((const char *) &m_align_corners, sizeof(m_align_corners));
+  file.write((const char *) &m_mode, sizeof(m_mode));
+  file.write((const char *) &m_padding_mode, sizeof(m_padding_mode));
+  return true;
+}
+
 template<typename T> bool sadl::layers::Layer<T>::dump(std::ostream &file)
 {
   // std::cout<<"todo? "<<opName(op_)<<std::endl;
diff --git a/sample/naive_quantization.cpp b/sample/naive_quantization.cpp
index 567a577e08c1ed6a676eeb146d6fb90ad0ecd83f..d50351664e35550aaae6a5291a0a2ebc087b60ce 100644
--- a/sample/naive_quantization.cpp
+++ b/sample/naive_quantization.cpp
@@ -72,7 +72,7 @@ bool toQuantize(sadl::layers::OperationType::Type type)
          && type != sadl::layers::OperationType::Identity && type != sadl::layers::OperationType::LeakyRelu && type != sadl::layers::OperationType::MaxPool
          && type != sadl::layers::OperationType::Relu && type != sadl::layers::OperationType::Reshape && type != sadl::layers::OperationType::Shape
          && type != sadl::layers::OperationType::Slice && type != sadl::layers::OperationType::Transpose && type != sadl::layers::OperationType::PReLU
-         && type != sadl::layers::OperationType::ScatterND;
+         && type != sadl::layers::OperationType::ScatterND && type != sadl::layers::OperationType::GridSample;
 }
 
 template<typename T> void quantizeTensor(const sadl::Tensor<float> &B, sadl::Tensor<T> &Bq)
diff --git a/utests/check.sh b/utests/check.sh
index fecee81f457b4eb13fb26c8adf009da7207245bf..adbd03eb6a668053e2fe305b471e92127033c95c 100755
--- a/utests/check.sh
+++ b/utests/check.sh
@@ -18,7 +18,7 @@ for F in $L; do
   ../utest.sh ../models/${F}.onnx --no_transpose;
 done
   
-L="conv2d_4_8x8x4_k1x1s1,1_g1_p0,0 conv2d_4_8x8x4_k1x1s1,1_g4_p0,0 conv2d_4_8x8x4_k1x1s2,1_g1_p0,0 conv2d_4_8x8x4_k1x3s1,2_g1_p0,1 conv2d_4_8x8x4_k3x1s1,1_g1_p1,0 conv2d_4_8x8x4_k3x1s1,1_g4_p1,0 conv2d_4_8x8x4_k3x3s1,1_g1_p1,1 conv2d_4_8x8x4_k3x3s2,1_g1_p1,1 conv2d_4_8x8x4_k3x3s2,2_g1_p1,1 conv2d_4_8x8x4_k5x5s1,1_g1_p2,2 conv2d_4_8x8x4_k5x5s1,1_g4_p2,2 conv2d_4_8x8x4_k5x5s2,1_g1_p2,2 conv2d_4_8x9x4_k1x1s2,1_g1_p0,0 conv2d_4_8x9x4_k3x1s1,1_g4_p1,0 conv2d_4_8x9x4_k3x3s1,1_g4_p1,1 conv2d_4_8x9x4_k3x3s2,1_g1_p1,1 conv2d_4_8x9x4_k3x3s2,2_g1_p1,1 conv2d_4_9x8x4_k1x1s1,1_g1_p0,0 conv2d_4_9x8x4_k1x1s2,1_g1_p0,0 conv2d_4_9x8x4_k1x3s1,2_g1_p0,1 conv2d_4_9x8x4_k3x1s1,1_g1_p1,0 conv2d_4_9x8x4_k3x3s1,1_g1_p1,1 conv2d_4_9x8x4_k3x3s2,1_g1_p1,1 conv2d_4_9x8x4_k3x3s2,2_g1_p1,1 conv2d_4_9x8x4_k5x5s1,1_g1_p2,2 conv2d_4_9x8x4_k5x5s2,1_g1_p2,2 conv2d_4_9x9x4_k1x3s1,2_g1_p0,1 repeated_conv slice_pytorch slice_inf_pytorch slice_chw_pytorch prelu_multiple_alpha prelu_single_alpha scatternd_c_pytorch scatternd_hwc_with_conv_pytorch";
+L="conv2d_4_8x8x4_k1x1s1,1_g1_p0,0 conv2d_4_8x8x4_k1x1s1,1_g4_p0,0 conv2d_4_8x8x4_k1x1s2,1_g1_p0,0 conv2d_4_8x8x4_k1x3s1,2_g1_p0,1 conv2d_4_8x8x4_k3x1s1,1_g1_p1,0 conv2d_4_8x8x4_k3x1s1,1_g4_p1,0 conv2d_4_8x8x4_k3x3s1,1_g1_p1,1 conv2d_4_8x8x4_k3x3s2,1_g1_p1,1 conv2d_4_8x8x4_k3x3s2,2_g1_p1,1 conv2d_4_8x8x4_k5x5s1,1_g1_p2,2 conv2d_4_8x8x4_k5x5s1,1_g4_p2,2 conv2d_4_8x8x4_k5x5s2,1_g1_p2,2 conv2d_4_8x9x4_k1x1s2,1_g1_p0,0 conv2d_4_8x9x4_k3x1s1,1_g4_p1,0 conv2d_4_8x9x4_k3x3s1,1_g4_p1,1 conv2d_4_8x9x4_k3x3s2,1_g1_p1,1 conv2d_4_8x9x4_k3x3s2,2_g1_p1,1 conv2d_4_9x8x4_k1x1s1,1_g1_p0,0 conv2d_4_9x8x4_k1x1s2,1_g1_p0,0 conv2d_4_9x8x4_k1x3s1,2_g1_p0,1 conv2d_4_9x8x4_k3x1s1,1_g1_p1,0 conv2d_4_9x8x4_k3x3s1,1_g1_p1,1 conv2d_4_9x8x4_k3x3s2,1_g1_p1,1 conv2d_4_9x8x4_k3x3s2,2_g1_p1,1 conv2d_4_9x8x4_k5x5s1,1_g1_p2,2 conv2d_4_9x8x4_k5x5s2,1_g1_p2,2 conv2d_4_9x9x4_k1x3s1,2_g1_p0,1 repeated_conv slice_pytorch slice_inf_pytorch slice_chw_pytorch prelu_multiple_alpha prelu_single_alpha scatternd_c_pytorch scatternd_hwc_with_conv_pytorch gridsample_bilinear gridsample_nearest gridsample_bilinear_conv gridsample_nearest_conv";
 for F in $L; do
   ../utest.sh ../models/${F}.onnx;
 done
diff --git a/utests/models/gridsample_bilinear.onnx b/utests/models/gridsample_bilinear.onnx
new file mode 100644
index 0000000000000000000000000000000000000000..f5d29b9d2c87b9e48e562bb813c4a13a9c91a164
--- /dev/null
+++ b/utests/models/gridsample_bilinear.onnx
@@ -0,0 +1,26 @@
+pytorch1.13.0:Ø
+n
+img
+grid_2/GridSample"
+GridSample*
+
align_corners *
+mode"bilinear *
+padding_mode"border 	torch_jitZ
+img
+
+
+
+
+Z
+grid_
+
+
+
+
+b
+2
+
+
+
+
+B
\ No newline at end of file
diff --git a/utests/models/gridsample_bilinear_conv.onnx b/utests/models/gridsample_bilinear_conv.onnx
new file mode 100644
index 0000000000000000000000000000000000000000..f74c3110f6f769b890d6ba1abedf36028d57d322
Binary files /dev/null and b/utests/models/gridsample_bilinear_conv.onnx differ
diff --git a/utests/models/gridsample_nearest.onnx b/utests/models/gridsample_nearest.onnx
new file mode 100644
index 0000000000000000000000000000000000000000..5c73e93fbb8b3c0da5f6c371171dab73caba7872
--- /dev/null
+++ b/utests/models/gridsample_nearest.onnx
@@ -0,0 +1,26 @@
+pytorch1.13.0:×
+m
+img
+grid_2/GridSample"
+GridSample*
+
align_corners *
+mode"nearest *
+padding_mode"border 	torch_jitZ
+img
+
+
+
+
+Z
+grid_
+
+
+
+
+b
+2
+
+
+
+
+B
\ No newline at end of file
diff --git a/utests/models/gridsample_nearest_conv.onnx b/utests/models/gridsample_nearest_conv.onnx
new file mode 100644
index 0000000000000000000000000000000000000000..80b629d20bafa10f568235bc76758f14bcf52130
Binary files /dev/null and b/utests/models/gridsample_nearest_conv.onnx differ