:nosearch: .. _op_ai_onnx_GridSample-20: GridSample - version 20 ======================= This page documents version **20** of operator **GridSample**. See :doc:`GridSample` for the latest version (since version 22). - **Domain**: ``ai.onnx`` - **Since 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 ``X`` and output ``Y`` types 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** .. code-block:: text Node: GridSample(X, Grid) -> (Y) Attributes: mode = "linear" padding_mode = "zeros" .. code-block:: text 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** .. code-block:: text Node: GridSample(X, Grid) -> (Y) Attributes: mode = "linear" align_corners = 1 .. code-block:: text 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** .. code-block:: text Node: GridSample(X, Grid) -> (Y) Attributes: mode = "cubic" .. code-block:: text 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** .. code-block:: text Node: GridSample(X, Grid) -> (Y) Attributes: mode = "cubic" .. code-block:: text 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** .. code-block:: text Node: GridSample(X, Grid) -> (Y) Attributes: mode = "cubic" align_corners = 1 .. code-block:: text 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** .. code-block:: text Node: GridSample(X, Grid) -> (Y) Attributes: mode = "linear" .. code-block:: text 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** .. code-block:: text Node: GridSample(X, Grid) -> (Y) Attributes: mode = "linear" .. code-block:: text 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** .. code-block:: text Node: GridSample(X, Grid) -> (Y) Attributes: mode = "linear" align_corners = 1 .. code-block:: text 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** .. code-block:: text Node: GridSample(X, Grid) -> (Y) Attributes: padding_mode = "border" .. code-block:: text 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** .. code-block:: text Node: GridSample(X, Grid) -> (Y) Attributes: mode = "nearest" .. code-block:: text 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** .. code-block:: text Node: GridSample(X, Grid) -> (Y) Attributes: mode = "nearest" .. code-block:: text 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** .. code-block:: text Node: GridSample(X, Grid) -> (Y) Attributes: mode = "nearest" align_corners = 1 .. code-block:: text 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** .. code-block:: text Node: GridSample(X, Grid) -> (Y) Attributes: padding_mode = "reflection" .. code-block:: text 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** .. code-block:: text Node: GridSample(X, Grid) -> (Y) Attributes: mode = "linear" .. code-block:: text 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** .. code-block:: text Node: GridSample(X, Grid) -> (Y) Attributes: mode = "linear" align_corners = 1 .. code-block:: text 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** .. code-block:: text Node: GridSample(X, Grid) -> (Y) Attributes: mode = "nearest" .. code-block:: text 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** .. code-block:: text Node: GridSample(X, Grid) -> (Y) Attributes: mode = "nearest" align_corners = 1 .. code-block:: text 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** .. code-block:: text Node: GridSample(X, Grid) -> (Y) Attributes: padding_mode = "zeros" .. code-block:: text 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) .. code-block:: diff --- 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).