GridSample - version 20#
This page documents version 20 of operator GridSample. See GridSample for the latest version (since version 22).
Domain:
ai.onnxSince version: 20
Given an input X and a flow-field grid, computes the output Y using X values and pixel locations from the grid.
For spatial input X with shape (N, C, H, W), the grid will have shape (N, H_out, W_out, 2),
the output Y will have shape (N, C, H_out, W_out). For volumetric input X with shape (N, C, D, H, W),
the grid will have shape (N, D_out, H_out, W_out, 3), the output Y will have shape (N, C, D_out, H_out, W_out).
More generally, for an input X of rank r+2 with shape (N, C, d1, d2, …, dr),
the grid will have shape (N, D1_out, D2_out, …, Dr_out, r), the output Y will have shape (N, C, D1_out, D2_out, …, Dr_out).
The tensor X contains values at centers of square pixels (voxels, etc) locations such as (n, c, d1_in, d2_in, …, dr_in).
The (n, d1_out, d2_out, …, dr_out, :) values from the tensor grid are the normalized positions for interpolating the values
at the (n, c, d1_out, d2_out, …, dr_out) locations from the output tensor Y using a specified interpolation method (the mode)
and a padding mode (for grid positions falling outside the 2-dimensional image).
For example, the values in grid[n, h_out, w_out, :] are size-2 vectors specifying normalized positions in the 2-dimensional space of X.
They are used to interpolate output values of Y[n, c, h_out, w_out].
The GridSample operator is often used in doing grid generator and sampler in the Spatial Transformer Networks. See also in torch.nn.functional.grid_sample.
Inputs
X (T1): Input tensor of rank r+2 that has shape (N, C, D1, D2, …, Dr), where N is the batch size, C is the number of channels, D1, D2, …, Dr are the spatial dimensions.
grid (T2): Input offset of shape (N, D1_out, D2_out, …, Dr_out, r), where D1_out, D2_out, …, Dr_out are the spatial dimensions of the grid and output, and r is the number of spatial dimensions. Grid specifies the sampling locations normalized by the input spatial dimensions. Therefore, it should have most values in the range of [-1, 1]. If the grid has values outside the range of [-1, 1], the corresponding outputs will be handled as defined by padding_mode. Following computer vision convention, the coordinates in the length-r location vector are listed from the innermost tensor dimension to the outermost, the opposite of regular tensor indexing.
Outputs
Y (T1): Output tensor of rank r+2 that has shape (N, C, D1_out, D2_out, …, Dr_out) of the sampled values. For integer input types, intermediate values are computed as floating point and cast to integer at the end.
Attributes
align_corners (int): If align_corners=1, the extrema (-1 and 1) are considered as referring to the center points of the input’s corner pixels (voxels, etc.). If align_corners=0, they are instead considered as referring to the corner points of the input’s corner pixels (voxels, etc.), making the sampling more resolution agnostic.
mode (string): Three interpolation modes: linear (default), nearest and cubic. The “linear” mode includes linear and N-linear interpolation modes depending on the number of spatial dimensions of the input tensor (i.e. linear for 1 spatial dimension, bilinear for 2 spatial dimensions, etc.). The “cubic” mode also includes N-cubic interpolation modes following the same rules. The “nearest” mode rounds to the nearest even index when the sampling point falls halfway between two indices.
padding_mode (string): Support padding modes for outside grid values:
zeros``(default), ``border,reflection. zeros: use 0 for out-of-bound grid locations, border: use border values for out-of-bound grid locations, reflection: use values at locations reflected by the border for out-of-bound grid locations. If index 0 represents the margin pixel, the reflected value at index -1 will be the same as the value at index 1. For location far away from the border, it will keep being reflected until becoming in bound. If pixel location x = -3.5 reflects by border -1 and becomes x’ = 1.5, then reflects by border 1 and becomes x’’ = 0.5.
Type Constraints
T1: Constrain input
Xand outputYtypes to all tensor types. Allowed types: tensor(bool), tensor(complex128), tensor(complex64), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(string), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8).T2: Constrain grid types to float tensors. Allowed types: tensor(double), tensor(float), tensor(float16).
Examples#
test_gridsample
Node:
GridSample(X, Grid) -> (Y)
Attributes:
mode = "linear"
padding_mode = "zeros"
Inputs:
X: shape=(1, 1, 4, 4), dtype=float32
[[[[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.],
[12., 13., 14., 15.]]]]
Grid: shape=(1, 6, 6, 2), dtype=float32
[[[[-1. , -1. ],
[-0.6, -1. ],
[-0.2, -1. ],
[ 0.2, -1. ],
[ 0.6, -1. ],
[ 1. , -1. ]],
[[-1. , -0.6],
[-0.6, -0.6],
[-0.2, -0.6],
[ 0.2, -0.6],
[ 0.6, -0.6],
[ 1. , -0.6]],
[[-1. , -0.2],
[-0.6, -0.2],
[-0.2, -0.2],
[ 0.2, -0.2],
[ 0.6, -0.2],
[ 1. , -0.2]],
[[-1. , 0.2],
[-0.6, 0.2],
[-0.2, 0.2],
[ 0.2, 0.2],
[ 0.6, 0.2],
[ 1. , 0.2]],
[[-1. , 0.6],
[-0.6, 0.6],
[-0.2, 0.6],
[ 0.2, 0.6],
[ 0.6, 0.6],
[ 1. , 0.6]],
[[-1. , 1. ],
[-0.6, 1. ],
[-0.2, 1. ],
[ 0.2, 1. ],
[ 0.6, 1. ],
[ 1. , 1. ]]]]
Outputs:
Y: shape=(1, 1, 6, 6), dtype=float32
[[[[ 0. , 0.14999998, 0.55 , 0.95 , 1.35 ,
0.75 ],
[ 0.5999999 , 1.4999998 , 2.2999997 , 3.1 , 3.8999999 ,
2.1 ],
[ 2.2 , 4.7 , 5.5 , 6.3 , 7.1 ,
3.7 ],
[ 3.8 , 7.9 , 8.7 , 9.5 , 10.3 ,
5.3 ],
[ 5.4 , 11.1 , 11.900001 , 12.7 , 13.5 ,
6.9 ],
[ 3. , 6.15 , 6.55 , 6.95 , 7.35 ,
3.75 ]]]]
test_gridsample_aligncorners_true
Node:
GridSample(X, Grid) -> (Y)
Attributes:
mode = "linear"
align_corners = 1
Inputs:
X: shape=(1, 1, 3, 2), dtype=float32
[[[[0., 1.],
[2., 3.],
[4., 5.]]]]
Grid: shape=(1, 2, 4, 2), dtype=float32
[[[[-1. , -1. ],
[-0.5, -0.5],
[-0.2, -0.2],
[ 0. , 0. ]],
[[ 0. , 0. ],
[-0.2, -0.2],
[ 0.5, 0.5],
[ 1. , 1. ]]]]
Outputs:
Y: shape=(1, 1, 2, 4), dtype=float32
[[[[0. , 1.25, 2. , 2.5 ],
[2.5 , 2. , 3.75, 5. ]]]]
test_gridsample_bicubic
Node:
GridSample(X, Grid) -> (Y)
Attributes:
mode = "cubic"
Inputs:
X: shape=(1, 1, 3, 2), dtype=float32
[[[[0., 1.],
[2., 3.],
[4., 5.]]]]
Grid: shape=(1, 2, 4, 2), dtype=float32
[[[[-1. , -1. ],
[-0.5, -0.5],
[-0.2, -0.2],
[ 0. , 0. ]],
[[ 0. , 0. ],
[-0.2, -0.2],
[ 0.5, 0.5],
[ 1. , 1. ]]]]
Outputs:
Y: shape=(1, 1, 2, 4), dtype=float32
[[[[-0.140625 , 0.3828125, 1.7555516, 2.96875 ],
[ 2.96875 , 1.7555516, 5.1445312, 1.390625 ]]]]
test_gridsample_bicubic_align_corners_0_additional_1
Node:
GridSample(X, Grid) -> (Y)
Attributes:
mode = "cubic"
Inputs:
X: shape=(1, 1, 3, 2), dtype=float32
[[[[0., 1.],
[2., 3.],
[4., 5.]]]]
Grid: shape=(1, 2, 4, 2), dtype=float32
[[[[-1. , -0.8],
[-0.6, -0.5],
[-0.1, -0.2],
[ 0.7, 0. ]],
[[ 0. , 0.4],
[ 0.2, -0.2],
[-0.3, 0.5],
[-1. , 1. ]]]]
Outputs:
Y: shape=(1, 1, 2, 4), dtype=float32
[[[[-0.17325 , 0.28426462, 1.923105 , 2.568 ],
[ 5.170375 , 2.2844129 , 4.7448435 , 1.046875 ]]]]
test_gridsample_bicubic_align_corners_1_additional_1
Node:
GridSample(X, Grid) -> (Y)
Attributes:
mode = "cubic"
align_corners = 1
Inputs:
X: shape=(1, 1, 3, 2), dtype=float32
[[[[0., 1.],
[2., 3.],
[4., 5.]]]]
Grid: shape=(1, 2, 4, 2), dtype=float32
[[[[-1. , -0.8],
[-0.6, -0.5],
[-0.1, -0.2],
[ 0.7, 0. ]],
[[ 0. , 0.4],
[ 0.2, -0.2],
[-0.3, 0.5],
[-1. , 1. ]]]]
Outputs:
Y: shape=(1, 1, 2, 4), dtype=float32
[[[[0.304 , 1.12875 , 2.26627 , 3.1448438],
[4.5315 , 2.45536 , 4.599819 , 4. ]]]]
test_gridsample_bilinear
Node:
GridSample(X, Grid) -> (Y)
Attributes:
mode = "linear"
Inputs:
X: shape=(1, 1, 3, 2), dtype=float32
[[[[0., 1.],
[2., 3.],
[4., 5.]]]]
Grid: shape=(1, 2, 4, 2), dtype=float32
[[[[-1. , -1. ],
[-0.5, -0.5],
[-0.2, -0.2],
[ 0. , 0. ]],
[[ 0. , 0. ],
[-0.2, -0.2],
[ 0.5, 0.5],
[ 1. , 1. ]]]]
Outputs:
Y: shape=(1, 1, 2, 4), dtype=float32
[[[[0. , 0.5 , 1.7 , 2.5 ],
[2.5 , 1.7 , 4.5 , 1.25]]]]
test_gridsample_bilinear_align_corners_0_additional_1
Node:
GridSample(X, Grid) -> (Y)
Attributes:
mode = "linear"
Inputs:
X: shape=(1, 1, 3, 2), dtype=float32
[[[[0., 1.],
[2., 3.],
[4., 5.]]]]
Grid: shape=(1, 2, 4, 2), dtype=float32
[[[[-1. , -0.8],
[-0.6, -0.5],
[-0.1, -0.2],
[ 0.7, 0. ]],
[[ 0. , 0.4],
[ 0.2, -0.2],
[-0.3, 0.5],
[-1. , 1. ]]]]
Outputs:
Y: shape=(1, 1, 2, 4), dtype=float32
[[[[0. , 0.45, 1.8 , 2.4 ],
[3.7 , 2.1 , 3.7 , 1. ]]]]
test_gridsample_bilinear_align_corners_1_additional_1
Node:
GridSample(X, Grid) -> (Y)
Attributes:
mode = "linear"
align_corners = 1
Inputs:
X: shape=(1, 1, 3, 2), dtype=float32
[[[[0., 1.],
[2., 3.],
[4., 5.]]]]
Grid: shape=(1, 2, 4, 2), dtype=float32
[[[[-1. , -0.8],
[-0.6, -0.5],
[-0.1, -0.2],
[ 0.7, 0. ]],
[[ 0. , 0.4],
[ 0.2, -0.2],
[-0.3, 0.5],
[-1. , 1. ]]]]
Outputs:
Y: shape=(1, 1, 2, 4), dtype=float32
[[[[0.39999998, 1.2 , 2.05 , 2.85 ],
[3.3 , 2.2 , 3.35 , 4. ]]]]
test_gridsample_border_padding
Node:
GridSample(X, Grid) -> (Y)
Attributes:
padding_mode = "border"
Inputs:
X: shape=(1, 1, 3, 2), dtype=float32
[[[[0., 1.],
[2., 3.],
[4., 5.]]]]
Grid: shape=(1, 2, 4, 2), dtype=float32
[[[[-10. , -10. ],
[ -5. , -5. ],
[ -0.2, -0.2],
[ 10. , 10. ]],
[[ 10. , 10. ],
[ -0.2, -0.2],
[ 5. , 5. ],
[ 10. , 10. ]]]]
Outputs:
Y: shape=(1, 1, 2, 4), dtype=float32
[[[[0. , 0. , 1.7, 5. ],
[5. , 1.7, 5. , 5. ]]]]
test_gridsample_nearest
Node:
GridSample(X, Grid) -> (Y)
Attributes:
mode = "nearest"
Inputs:
X: shape=(1, 1, 3, 2), dtype=float32
[[[[0., 1.],
[2., 3.],
[4., 5.]]]]
Grid: shape=(1, 2, 4, 2), dtype=float32
[[[[-1. , -1. ],
[-0.5, -0.5],
[-0.2, -0.2],
[ 0. , 0. ]],
[[ 0. , 0. ],
[-0.2, -0.2],
[ 0.5, 0.5],
[ 1. , 1. ]]]]
Outputs:
Y: shape=(1, 1, 2, 4), dtype=float32
[[[[0., 0., 2., 2.],
[2., 2., 5., 0.]]]]
test_gridsample_nearest_align_corners_0_additional_1
Node:
GridSample(X, Grid) -> (Y)
Attributes:
mode = "nearest"
Inputs:
X: shape=(1, 1, 3, 2), dtype=float32
[[[[0., 1.],
[2., 3.],
[4., 5.]]]]
Grid: shape=(1, 2, 4, 2), dtype=float32
[[[[-1. , -0.8],
[-0.6, -0.5],
[-0.1, -0.2],
[ 0.7, 0. ]],
[[ 0. , 0.4],
[ 0.2, -0.2],
[-0.3, 0.5],
[-1. , 1. ]]]]
Outputs:
Y: shape=(1, 1, 2, 4), dtype=float32
[[[[0., 0., 2., 3.],
[4., 3., 4., 4.]]]]
test_gridsample_nearest_align_corners_1_additional_1
Node:
GridSample(X, Grid) -> (Y)
Attributes:
mode = "nearest"
align_corners = 1
Inputs:
X: shape=(1, 1, 3, 2), dtype=float32
[[[[0., 1.],
[2., 3.],
[4., 5.]]]]
Grid: shape=(1, 2, 4, 2), dtype=float32
[[[[-1. , -0.8],
[-0.6, -0.5],
[-0.1, -0.2],
[ 0.7, 0. ]],
[[ 0. , 0.4],
[ 0.2, -0.2],
[-0.3, 0.5],
[-1. , 1. ]]]]
Outputs:
Y: shape=(1, 1, 2, 4), dtype=float32
[[[[0., 0., 2., 3.],
[2., 3., 4., 4.]]]]
test_gridsample_reflection_padding
Node:
GridSample(X, Grid) -> (Y)
Attributes:
padding_mode = "reflection"
Inputs:
X: shape=(1, 1, 3, 2), dtype=float32
[[[[0., 1.],
[2., 3.],
[4., 5.]]]]
Grid: shape=(1, 2, 4, 2), dtype=float32
[[[[-10. , -10. ],
[ -5. , -5. ],
[ -0.2, -0.2],
[ 10. , 10. ]],
[[ 10. , 10. ],
[ -0.2, -0.2],
[ 5. , 5. ],
[ 10. , 10. ]]]]
Outputs:
Y: shape=(1, 1, 2, 4), dtype=float32
[[[[2.5, 0. , 1.7, 2.5],
[2.5, 1.7, 5. , 2.5]]]]
test_gridsample_volumetric_bilinear_align_corners_0
Node:
GridSample(X, Grid) -> (Y)
Attributes:
mode = "linear"
Inputs:
X: shape=(1, 1, 3, 2, 2), dtype=float32
[[[[[ 1., 2.],
[ 3., 4.]],
[[ 5., 6.],
[ 7., 8.]],
[[ 9., 10.],
[11., 12.]]]]]
Grid: shape=(1, 2, 4, 2, 3), dtype=float32
[[[[[-1. , -1. , -1. ],
[-1. , -0.5, 0.3]],
[[-0.5, -0.5, -0.5],
[ 1. , -0.6, -1. ]],
[[-0.2, -0.2, -0.2],
[ 0.4, 0.2, 0.6]],
[[ 0. , 0. , 0. ],
[-1. , 0. , 0. ]]],
[[[ 0. , 0. , 0. ],
[-1. , 1. , 0. ]],
[[-0.2, -0.2, -0.2],
[ 1. , 0.4, -0.2]],
[[ 0.5, 0.5, 0.5],
[-1. , -0.8, 0.8]],
[[ 1. , 1. , 1. ],
[ 0.4, 0.6, -0.3]]]]]
Outputs:
Y: shape=(1, 1, 2, 4, 2), dtype=float32
[[[[[ 0.125 , 3.4 ],
[ 2. , 0.45 ],
[ 4.7 , 10.900001],
[ 6.5 , 3. ]],
[[ 6.5 , 1.75 ],
[ 4.7 , 3.3 ],
[11. , 2.52 ],
[ 1.5 , 5.49 ]]]]]
test_gridsample_volumetric_bilinear_align_corners_1
Node:
GridSample(X, Grid) -> (Y)
Attributes:
mode = "linear"
align_corners = 1
Inputs:
X: shape=(1, 1, 3, 2, 2), dtype=float32
[[[[[ 1., 2.],
[ 3., 4.]],
[[ 5., 6.],
[ 7., 8.]],
[[ 9., 10.],
[11., 12.]]]]]
Grid: shape=(1, 2, 4, 2, 3), dtype=float32
[[[[[-1. , -1. , -1. ],
[-1. , -0.5, 0.3]],
[[-0.5, -0.5, -0.5],
[ 1. , -0.6, -1. ]],
[[-0.2, -0.2, -0.2],
[ 0.4, 0.2, 0.6]],
[[ 0. , 0. , 0. ],
[-1. , 0. , 0. ]]],
[[[ 0. , 0. , 0. ],
[-1. , 1. , 0. ]],
[[-0.2, -0.2, -0.2],
[ 1. , 0.4, -0.2]],
[[ 0.5, 0.5, 0.5],
[-1. , -0.8, 0.8]],
[[ 1. , 1. , 1. ],
[ 0.4, 0.6, -0.3]]]]]
Outputs:
Y: shape=(1, 1, 2, 4, 2), dtype=float32
[[[[[ 1. , 6.7 ],
[ 3.75, 2.4 ],
[ 5.4 , 9.3 ],
[ 6.5 , 6. ]],
[[ 6.5 , 7. ],
[ 5.4 , 6.6 ],
[ 9.25, 8.4 ],
[12. , 6.1 ]]]]]
test_gridsample_volumetric_nearest_align_corners_0
Node:
GridSample(X, Grid) -> (Y)
Attributes:
mode = "nearest"
Inputs:
X: shape=(1, 1, 3, 2, 2), dtype=float32
[[[[[ 1., 2.],
[ 3., 4.]],
[[ 5., 6.],
[ 7., 8.]],
[[ 9., 10.],
[11., 12.]]]]]
Grid: shape=(1, 2, 4, 2, 3), dtype=float32
[[[[[-1. , -1. , -1. ],
[-1. , -0.5, 0.3]],
[[-0.5, -0.5, -0.5],
[ 1. , -0.6, -1. ]],
[[-0.2, -0.2, -0.2],
[ 0.4, 0.2, 0.6]],
[[ 0. , 0. , 0. ],
[-1. , 0. , 0. ]]],
[[[ 0. , 0. , 0. ],
[-1. , 1. , 0. ]],
[[-0.2, -0.2, -0.2],
[ 1. , 0.4, -0.2]],
[[ 0.5, 0.5, 0.5],
[-1. , -0.8, 0.8]],
[[ 1. , 1. , 1. ],
[ 0.4, 0.6, -0.3]]]]]
Outputs:
Y: shape=(1, 1, 2, 4, 2), dtype=float32
[[[[[ 1., 5.],
[ 1., 0.],
[ 5., 12.],
[ 5., 5.]],
[[ 5., 0.],
[ 5., 0.],
[12., 9.],
[ 0., 8.]]]]]
test_gridsample_volumetric_nearest_align_corners_1
Node:
GridSample(X, Grid) -> (Y)
Attributes:
mode = "nearest"
align_corners = 1
Inputs:
X: shape=(1, 1, 3, 2, 2), dtype=float32
[[[[[ 1., 2.],
[ 3., 4.]],
[[ 5., 6.],
[ 7., 8.]],
[[ 9., 10.],
[11., 12.]]]]]
Grid: shape=(1, 2, 4, 2, 3), dtype=float32
[[[[[-1. , -1. , -1. ],
[-1. , -0.5, 0.3]],
[[-0.5, -0.5, -0.5],
[ 1. , -0.6, -1. ]],
[[-0.2, -0.2, -0.2],
[ 0.4, 0.2, 0.6]],
[[ 0. , 0. , 0. ],
[-1. , 0. , 0. ]]],
[[[ 0. , 0. , 0. ],
[-1. , 1. , 0. ]],
[[-0.2, -0.2, -0.2],
[ 1. , 0.4, -0.2]],
[[ 0.5, 0.5, 0.5],
[-1. , -0.8, 0.8]],
[[ 1. , 1. , 1. ],
[ 0.4, 0.6, -0.3]]]]]
Outputs:
Y: shape=(1, 1, 2, 4, 2), dtype=float32
[[[[[ 1., 5.],
[ 1., 2.],
[ 5., 12.],
[ 5., 5.]],
[[ 5., 7.],
[ 5., 8.],
[12., 9.],
[12., 8.]]]]]
test_gridsample_zeros_padding
Node:
GridSample(X, Grid) -> (Y)
Attributes:
padding_mode = "zeros"
Inputs:
X: shape=(1, 1, 3, 2), dtype=float32
[[[[0., 1.],
[2., 3.],
[4., 5.]]]]
Grid: shape=(1, 2, 4, 2), dtype=float32
[[[[-10. , -10. ],
[ -5. , -5. ],
[ -0.2, -0.2],
[ 10. , 10. ]],
[[ 10. , 10. ],
[ -0.2, -0.2],
[ 5. , 5. ],
[ 10. , 10. ]]]]
Outputs:
Y: shape=(1, 1, 2, 4), dtype=float32
[[[[0. , 0. , 1.7, 0. ],
[0. , 1.7, 0. , 0. ]]]]
Differences with previous version (16)#
SchemaDiff: GridSample (domain 'ai.onnx')
old version: 16
new version: 20
breaking: yes
Breaking reasons:
attribute ‘mode’ (changed): default value changed bilinear -> linear
Attributes:
[BREAKING] changed ‘mode’: default value changed bilinear -> linear
Documentation:
line similarity: 0.24 (+15/-10 lines)
--- GridSample v16
+++ GridSample v20
@@ -1,14 +1,19 @@
-Given an input `X` and a flow-field `grid`, computes the output `Y` using `X` values and pixel locations from `grid`.
-Currently, only spatial (4-D) inputs are supported. For input `X` with shape (N, C, H, W) and `grid` with shape (N, H_out, W_out, 2),
-the output `Y` will have shape (N, C, H_out, W_out).
+Given an input `X` and a flow-field `grid`, computes the output `Y` using `X` values and pixel locations from the `grid`.
+For spatial input `X` with shape (N, C, H, W), the `grid` will have shape (N, H_out, W_out, 2),
+the output `Y` will have shape (N, C, H_out, W_out). For volumetric input `X` with shape (N, C, D, H, W),
+the `grid` will have shape (N, D_out, H_out, W_out, 3), the output `Y` will have shape (N, C, D_out, H_out, W_out).
+More generally, for an input `X` of rank r+2 with shape (N, C, d1, d2, ..., dr),
+the `grid` will have shape (N, D1_out, D2_out, ..., Dr_out, r), the output `Y` will have shape (N, C, D1_out, D2_out, ..., Dr_out).
-The tensor `X` contains values at centers of square pixels in a H by W 2-dimensional image.
-The tensor `grid` describes normalized positions where the output `Y` is to be computed
-using a specified interpolation method (the mode) and a padding mode (for grid positions falling outside the 2-dimensional image).
+The tensor `X` contains values at centers of square pixels (voxels, etc) locations such as (n, c, d1_in, d2_in, ..., dr_in).
+The (n, d1_out, d2_out, ..., dr_out, :) values from the tensor `grid` are the normalized positions for interpolating the values
+at the (n, c, d1_out, d2_out, ..., dr_out) locations from the output tensor `Y` using a specified interpolation method (the mode)
+and a padding mode (for `grid` positions falling outside the 2-dimensional image).
-Elements in `grid[N, H_out, W_out]` are size-2 vectors specifying positions in the 2-dimensional space of `X`.
-They are used to interpolate output values of `Y[N, C, H_out, W_out]`.
+For example, the values in `grid[n, h_out, w_out, :]` are size-2 vectors specifying normalized positions in the 2-dimensional space of `X`.
+They are used to interpolate output values of `Y[n, c, h_out, w_out]`.
-The GridSample operator is often used in doing grid generator and sampler in the [Spatial Transformer Networks](https://arxiv.org/abs/1506.02025).
-See also in [torch.nn.functional.grid_sample](https://pytorch.org/docs/master/generated/torch.nn.functional.grid_sample.html#torch-nn-functional-grid-sample).
+The GridSample operator is often used in doing grid generator and sampler in the
+[Spatial Transformer Networks](https://arxiv.org/abs/1506.02025).
+See also in [torch.nn.functional.grid_sample](https://pytorch.org/docs/stable/generated/torch.nn.functional.grid_sample.html).