code: def forward_cpu(self, inputs):
      self.retain_inputs((1, 2))
      self._bottom_data_shape = inputs[0].shape
  
      bottom_data, bottom_rois, bottom_roi_indices = inputs
      channel, height, width = bottom_data.shape[1:]
      if self.out_c is None:
          if channel % (self.group_size * self.group_size) != 0:
              raise ValueError(
                  "input channel must be divided by group_size * group_size:"
                  "{} % {} != 0".format(
                      channel, self.group_size * self.group_size
                  )
              )
          out_c = channel // (self.group_size * self.group_size)
      else:
          if channel != self.out_c * self.group_size * self.group_size:
              raise ValueError(
                  "input channel must be equal to "
                  "outsize[0] * group_size * group_size: {} != {}".format(
                      channel,
                      self.out_c * self.group_size * self.group_size,
                  )
              )
          out_c = self.out_c
      n_roi = bottom_rois.shape[0]
      top_data = np.empty(
          (n_roi, out_c, self.out_h, self.out_w), dtype=np.float32
      )
  
      spatial_scale = self.spatial_scale
      pooled_height = self.out_h
      pooled_width = self.out_w
      group_size = self.group_size
  
      for i in six.moves.range(top_data.size):
          n, ctop, ph, pw = np.unravel_index(i, top_data.shape)
  
          roi_batch_ind = bottom_roi_indices[n]
          roi_start_h = bottom_rois[n, 0] * spatial_scale
          roi_start_w = bottom_rois[n, 1] * spatial_scale
          roi_end_h = bottom_rois[n, 2] * spatial_scale
          roi_end_w = bottom_rois[n, 3] * spatial_scale
  
          roi_height = max(roi_end_h - roi_start_h, 0.1)
          roi_width = max(roi_end_w - roi_start_w, 0.1)
          bin_size_h = roi_height / pooled_height
          bin_size_w = roi_width / pooled_width
  
          gh = int(np.floor(ph * group_size / pooled_height))
          gw = int(np.floor(pw * group_size / pooled_width))
          gh = min(max(gh, 0), group_size - 1)
          gw = min(max(gw, 0), group_size - 1)
          c = (ctop * group_size + gh) * group_size + gw
  
          if self.sampling_ratio[0] is None:
              roi_bin_grid_h = int(np.ceil(roi_height / pooled_height))
          else:
              roi_bin_grid_h = self.sampling_ratio[0]
          if self.sampling_ratio[1] is None:
              roi_bin_grid_w = int(np.ceil(roi_width / pooled_width))
          else:
              roi_bin_grid_w = self.sampling_ratio[1]
  
          count = roi_bin_grid_h * roi_bin_grid_w
  
          output_val = 0.0
          for iy in six.moves.range(roi_bin_grid_h):
              y = (
                  roi_start_h
                  + ph * bin_size_h
                  + (iy + 0.5) * bin_size_h / roi_bin_grid_h
              )
              y, y_low, y_high = _get_bounds(y, height)
              if y is None or y_low is None or y_high is None:
                  continue
              for ix in six.moves.range(roi_bin_grid_w):
                  x = (
                      roi_start_w
                      + pw * bin_size_w
                      + (ix + 0.5) * bin_size_w / roi_bin_grid_w
                  )
  
                  x, x_low, x_high = _get_bounds(x, width)
                  if x is None or x_low is None or x_high is None:
                      continue
  
                  # bilinear interpolation {{
                  w1, w2, w3, w4 = _get_bilinear_interp_params(
                      y, x, y_low, x_low, y_high, x_high
                  )
  
                  if w1 > 0 and y_low >= 0 and x_low >= 0:
                      v1 = bottom_data[roi_batch_ind, c, y_low, x_low]
                      output_val += w1 * v1
  
                  if w2 > 0 and y_low >= 0 and x_high <= width - 1:
                      v2 = bottom_data[roi_batch_ind, c, y_low, x_high]
                      output_val += w2 * v2
  
                  if w3 > 0 and y_high <= height - 1 and x_low >= 0:
                      v3 = bottom_data[roi_batch_ind, c, y_high, x_low]
                      output_val += w3 * v3
  
                  if (
                      w4 > 0
                      and y_high <= height - 1
                      and x_high <= width - 1
                  ):
                      v4 = bottom_data[roi_batch_ind, c, y_high, x_high]
                      output_val += w4 * v4
  
                  # }}
  
          output_val /= count
          top_data[n, ctop, ph, pw] = output_val
  
      return (top_data,)
  
imports: from __future__ import division
  import numbers
  import numpy
  import six
  import chainer
  from chainer.backends import cuda
  from chainer import function
  from chainer.utils import type_check
  from chainercv.functions.ps_roi_average_pooling_2d import _outsize
label_desc: Use image node_id 3 for calling the PSROIAverageAlign2D obj's underlying member method code with example usage: obj.forward_cpu(inputs) and returns: top_data