code: def _backward(self, inputs, grad_outputs):
      x, grid = inputs
      xp = backend.get_array_module(x)
      (gy,) = grad_outputs
  
      B, C, H, W = x.shape
      _, _, out_H, out_W = grid.shape
      grid = grid.reshape(grid.shape[:2] + (-1,))
  
      u = grid[:, 0]
      v = grid[:, 1]
  
      # Pad the image so that points locating outside of the original
      # image's size can be sampled.
      x_pad = xp.pad(
          x, ((0, 0), (0, 0), (1, 1), (1, 1)), mode="constant"
      )
  
      # Rescale coordinates from [-1, 1] to [0, width or height - 1],
      # and adjust them to the padded image.
      u = (u + 1) * (W - 1) / 2 + 1
      v = (v + 1) * (H - 1) / 2 + 1
  
      u_clipped = u.clip(0, W + 1)
      v_clipped = v.clip(0, H + 1)
  
      # indices of the 2x2 pixel neighborhood surrounding the coordinates
      u0 = xp.floor(u_clipped).astype(numpy.int32)
      u0 = u0.clip(0, W)
      u1 = u0 + 1
      v0 = xp.floor(v_clipped).astype(numpy.int32)
      v0 = v0.clip(0, H)
      v1 = v0 + 1
  
      # weights
      wu0 = u_clipped - u0
      wu1 = u1 - u_clipped
      wv0 = v_clipped - v0
      wv1 = v1 - v_clipped
      wu0 = wu0.astype(gy.dtype, copy=False)
      wu1 = wu1.astype(gy.dtype, copy=False)
      wv0 = wv0.astype(gy.dtype, copy=False)
      wv1 = wv1.astype(gy.dtype, copy=False)
  
      # --- gu, gv
      x_indexed_1 = xp.concatenate(
          [
              xp.expand_dims(x_pad[b, :, v0[b], u0[b]], axis=0)
              for b in range(B)
          ],
          axis=0,
      )
      x_indexed_2 = xp.concatenate(
          [
              xp.expand_dims(x_pad[b, :, v0[b], u1[b]], axis=0)
              for b in range(B)
          ],
          axis=0,
      )
      x_indexed_3 = xp.concatenate(
          [
              xp.expand_dims(x_pad[b, :, v1[b], u0[b]], axis=0)
              for b in range(B)
          ],
          axis=0,
      )
      x_indexed_4 = xp.concatenate(
          [
              xp.expand_dims(x_pad[b, :, v1[b], u1[b]], axis=0)
              for b in range(B)
          ],
          axis=0,
      )
  
      gu = -wv1[:, :, None] * x_indexed_1
      gu += wv1[:, :, None] * x_indexed_2
      gu -= wv0[:, :, None] * x_indexed_3
      gu += wv0[:, :, None] * x_indexed_4
  
      gv = -wu1[:, :, None] * x_indexed_1
      gv -= wu0[:, :, None] * x_indexed_2
      gv += wu1[:, :, None] * x_indexed_3
      gv += wu0[:, :, None] * x_indexed_4
  
      gu = gu.reshape(B, out_H, out_W, C).transpose(0, 3, 1, 2)
      gv = gv.reshape(B, out_H, out_W, C).transpose(0, 3, 1, 2)
  
      gu *= gy
      gv *= gy
      gu = xp.sum(gu, axis=1)
      gv = xp.sum(gv, axis=1)
      # Offsets scaling of the coordinates and clip gradients.
      u_reshaped = u.reshape(gu.shape)
      v_reshaped = v.reshape(gv.shape)
      gu = (
          gu / 2.0 * (W - 1) * (u_reshaped > 0) * (u_reshaped < (W + 1))
      )
      gv = (
          gv / 2.0 * (H - 1) * (v_reshaped > 0) * (v_reshaped < (H + 1))
      )
  
      ggrid = xp.concatenate((gu[:, None], gv[:, None]), axis=1)
  
      # --- gx
      if xp is numpy:
          scatter_add = numpy.add.at
      else:
          scatter_add = cuda.cupyx.scatter_add
      gx = xp.zeros_like(x_pad)
      gy = gy.reshape(B, C, -1)
      for b in range(B):
          scatter_add(
              gx[b],
              (slice(None), v0[b], u0[b]),
              gy[b] * wu1[b] * wv1[b],
          )
          scatter_add(
              gx[b],
              (slice(None), v0[b], u1[b]),
              gy[b] * wu0[b] * wv1[b],
          )
          scatter_add(
              gx[b],
              (slice(None), v1[b], u0[b]),
              gy[b] * wu1[b] * wv0[b],
          )
          scatter_add(
              gx[b],
              (slice(None), v1[b], u1[b]),
              gy[b] * wu0[b] * wv0[b],
          )
      gx = gx[:, :, 1:-1, 1:-1]
      return gx, ggrid
  
file_path: chainer/chainer/functions/array/spatial_transformer_sampler.py
imports: import numpy
  import chainer
  from chainer import backend
  from chainer.backends import cuda
  from chainer import function
  from chainer.utils import argument
  from chainer.utils import type_check
label_desc: Use image node_id 7 for calling the SpatialTransformerSampler obj's underlying member method code with example usage: obj._backward(inputs, grad_outputs) and returns: gx,  ggrid