class_docstr: ROI average align over a set of 2d planes.
class_docstr_tok: ["ROI","average","align","over","a","set","of","2d","planes","."]
code: def forward_gpu(self, inputs):
      self.retain_inputs((1, 2))
      self._bottom_data_shape = inputs[0].shape
  
      bottom_data, bottom_rois, bottom_roi_indices = inputs
      channels, height, width = bottom_data.shape[1:]
      n_rois = bottom_rois.shape[0]
      top_data = cuda.cupy.empty(
          (n_rois, channels, self.outh, self.outw),
          dtype=bottom_data.dtype,
      )
      if self.sampling_ratio[0] is None:
          sampling_ratio_h = 0
      else:
          sampling_ratio_h = self.sampling_ratio[0]
      if self.sampling_ratio[1] is None:
          sampling_ratio_w = 0
      else:
          sampling_ratio_w = self.sampling_ratio[1]
      cuda.elementwise(
          """
              raw T bottom_data, T spatial_scale, int32 channels,
              int32 height, int32 width, int32 pooled_height, int32 pooled_width,
              int32 sampling_ratio_h, int32 sampling_ratio_w,
              raw T bottom_rois, raw int32 bottom_roi_indices
              """,
          "T top_data",
          """
              int pw = i % pooled_width;
              int ph = (i / pooled_width) % pooled_height;
              int c = (i / pooled_width / pooled_height) % channels;
              int n = i / pooled_width / pooled_height / channels;
  
              int roi_batch_ind = bottom_roi_indices[n];
  
              T roi_start_h = bottom_rois[n * 4 + 0] * spatial_scale;
              T roi_start_w = bottom_rois[n * 4 + 1] * spatial_scale;
              T roi_end_h = bottom_rois[n * 4 + 2] * spatial_scale;
              T roi_end_w = bottom_rois[n * 4 + 3] * spatial_scale;
  
              // Force malformed ROIs to be 1x1
              T roi_height = max(roi_end_h - roi_start_h, (T)1.);
              T roi_width = max(roi_end_w - roi_start_w, (T)1.);
              T bin_size_h = static_cast<T>(roi_height)
                              / static_cast<T>(pooled_height);
              T bin_size_w = static_cast<T>(roi_width)
                              / static_cast<T>(pooled_width);
  
              int bottom_data_offset =
                  (roi_batch_ind * channels + c) * height * width;
  
              // We use roi_bin_grid to sample the grid and mimic integral
              int roi_bin_grid_h = (sampling_ratio_h > 0)
                  ? sampling_ratio_h
                  : ceil(roi_height / pooled_height);  // e.g. = 2
              int roi_bin_grid_w = (sampling_ratio_w > 0)
                  ? sampling_ratio_w
                  : ceil(roi_width / pooled_width);
  
              // We do average (integral) pooling inside a bin
              T count = roi_bin_grid_h * roi_bin_grid_w;  // e.g. = 4
  
              T output_val = 0.;
              for (int iy = 0; iy < roi_bin_grid_h; iy++)  // e.g. iy = 0, 1
              {
                  T y = roi_start_h + ph * bin_size_h +
                      static_cast<T>(iy + .5f) * bin_size_h /
                          static_cast<T>(roi_bin_grid_h);  // e.g. 0.5, 1.5
                  int y_low, y_high;
                  bool y_ret = get_bounds(y, height, y_low, y_high);
                  if (!y_ret) continue;
                  for (int ix = 0; ix < roi_bin_grid_w; ix++) {
                      T x = roi_start_w + pw * bin_size_w +
                          static_cast<T>(ix + .5f) * bin_size_w /
                              static_cast<T>(roi_bin_grid_w);
  
                      int x_low, x_high;
                      bool x_ret = get_bounds(x, width, x_low, x_high);
                      if (!x_ret) continue;
                      // bilinear_interpolation_gradient {{
                      T w1, w2, w3, w4;
                      get_bilinear_interp_params(
                          y, x, y_low, x_low, y_high, x_high, w1, w2, w3, w4);
  
                      if (w1 > 0 && y_low >= 0 && x_low >= 0) {
                          T v1 = bottom_data[
                              bottom_data_offset + y_low * width + x_low];
                          output_val += w1 * v1;
                      }
                      if (w2 > 0 && y_low >= 0 && x_high <= width - 1) {
                          T v2 = bottom_data[
                              bottom_data_offset + y_low * width + x_high];
                          output_val += w2 * v2;
                      }
                      if (w3 > 0 && y_high <= height - 1 && x_low >= 0) {
                          T v3 = bottom_data[
                              bottom_data_offset + y_high * width + x_low];
                          output_val += w3 * v3;
                      }
                      if (w4 > 0 && y_high <= height - 1 &&
                              x_high <= width - 1) {
                          T v4 = bottom_data[
                              bottom_data_offset + y_high * width + x_high];
                          output_val += w4 * v4;
                      }
  
                      // }}
                  }
              }
              output_val /= count;
  
              top_data = output_val;
              """,
          "roi_average_align_2d_fwd",
          preamble=_GET_BILINEAR_INTERP_KERNEL,
      )(
          bottom_data,
          self.spatial_scale,
          channels,
          height,
          width,
          self.outh,
          self.outw,
          sampling_ratio_h,
          sampling_ratio_w,
          bottom_rois,
          bottom_roi_indices,
          top_data,
      )
  
      return (top_data,)
  
imports: import numbers
  import numpy
  import six
  import chainer
  from chainer.backends import cuda
  from chainer import function
  from chainer import utils
  from chainer.utils import type_check
label_desc: Use image node_id 4 for calling the ROIAverageAlign2D obj's underlying member method code with example usage: obj.forward_gpu(inputs) and returns: top_data