class_docstr: Assign anchors to ground-truth targets. Produces anchor classification
  labels and bounding-box regression targets.
class_docstr_tok: ["Assign","anchors","to","ground-truth","targets",".","Produces","anchor","classification","labels","and","bounding-box","regression","targets","."]
code: def forward(self, bottom, top):
      # Algorithm:
      #
      # for each (H, W) location i
      #   generate 9 anchor boxes centered on cell i
      #   apply predicted bbox deltas at cell i to each of the 9 anchors
      # filter out-of-image anchors
      # measure GT overlap
  
      assert (
          bottom[0].data.shape[0] == 1
      ), "Only single item batches are supported"
  
      # map of shape (..., H, W)
      height, width = bottom[0].data.shape[-2:]
      # GT boxes (x1, y1, x2, y2, label)
      gt_boxes = bottom[1]  # .data
      # im_info
      im_info = bottom[2]  # .data[0, :]
  
      if DEBUG:
          print("")
          print("im_size: ({}, {})".format(im_info[0], im_info[1]))
          print("scale: {}".format(im_info[2]))
          print("height, width: ({}, {})".format(height, width))
          print("rpn: gt_boxes.shape", gt_boxes.shape)
          print("rpn: gt_boxes", gt_boxes)
  
      # 1. Generate proposals from bbox deltas and shifted anchors
      shift_x = np.arange(0, width) * self._feat_stride
      shift_y = np.arange(0, height) * self._feat_stride
      shift_x, shift_y = np.meshgrid(shift_x, shift_y)
      shifts = np.vstack(
          (
              shift_x.ravel(),
              shift_y.ravel(),
              shift_x.ravel(),
              shift_y.ravel(),
          )
      ).transpose()
      # add A anchors (1, A, 4) to
      # cell K shifts (K, 1, 4) to get
      # shift anchors (K, A, 4)
      # reshape to (K*A, 4) shifted anchors
      A = self._num_anchors
      K = shifts.shape[0]
      all_anchors = self._anchors.reshape((1, A, 4)) + shifts.reshape(
          (1, K, 4)
      ).transpose((1, 0, 2))
      all_anchors = all_anchors.reshape((K * A, 4))
      total_anchors = int(K * A)
  
      # only keep anchors inside the image
      inds_inside = np.where(
          (all_anchors[:, 0] >= -self._allowed_border)
          & (all_anchors[:, 1] >= -self._allowed_border)
          & (all_anchors[:, 2] < im_info[1] + self._allowed_border)
          & (  # width
              all_anchors[:, 3] < im_info[0] + self._allowed_border
          )  # height
      )[0]
  
      if DEBUG:
          print("total_anchors", total_anchors)
          print("inds_inside", len(inds_inside))
  
      # keep only inside anchors
      anchors = all_anchors[inds_inside, :]
      if DEBUG:
          print("anchors.shape", anchors.shape)
  
      # label: 1 is positive, 0 is negative, -1 is dont care
      labels = np.empty((len(inds_inside),), dtype=np.float32)
      labels.fill(-1)
  
      # overlaps between the anchors and the gt boxes
      # overlaps (ex, gt)
      overlaps = bbox_overlaps(
          np.ascontiguousarray(anchors, dtype=np.float),
          np.ascontiguousarray(gt_boxes, dtype=np.float),
      )
      argmax_overlaps = overlaps.argmax(axis=1)
      max_overlaps = overlaps[
          np.arange(len(inds_inside)), argmax_overlaps
      ]
      gt_argmax_overlaps = overlaps.argmax(axis=0)
      gt_max_overlaps = overlaps[
          gt_argmax_overlaps, np.arange(overlaps.shape[1])
      ]
      gt_argmax_overlaps = np.where(overlaps == gt_max_overlaps)[0]
  
      if not cfg.TRAIN.RPN_CLOBBER_POSITIVES:
          # assign bg labels first so that positive labels can clobber them
          labels[max_overlaps < cfg.TRAIN.RPN_NEGATIVE_OVERLAP] = 0
  
      # fg label: for each gt, anchor with highest overlap
      labels[gt_argmax_overlaps] = 1
  
      # fg label: above threshold IOU
      labels[max_overlaps >= cfg.TRAIN.RPN_POSITIVE_OVERLAP] = 1
  
      if cfg.TRAIN.RPN_CLOBBER_POSITIVES:
          # assign bg labels last so that negative labels can clobber positives
          labels[max_overlaps < cfg.TRAIN.RPN_NEGATIVE_OVERLAP] = 0
  
      # subsample positive labels if we have too many
      num_fg = int(cfg.TRAIN.RPN_FG_FRACTION * cfg.TRAIN.RPN_BATCHSIZE)
      fg_inds = np.where(labels == 1)[0]
      if len(fg_inds) > num_fg:
          if self._determininistic_mode:
              disable_inds = fg_inds[: (len(fg_inds) - num_fg)]
          else:
              disable_inds = npr.choice(
                  fg_inds, size=(len(fg_inds) - num_fg), replace=False
              )
          labels[disable_inds] = -1
  
      # subsample negative labels if we have too many
      num_bg = cfg.TRAIN.RPN_BATCHSIZE - np.sum(labels == 1)
      bg_inds = np.where(labels == 0)[0]
      if len(bg_inds) > num_bg:
          if self._determininistic_mode:
              disable_inds = bg_inds[: (len(bg_inds) - num_bg)]
          else:
              disable_inds = npr.choice(
                  bg_inds, size=(len(bg_inds) - num_bg), replace=False
              )
          labels[disable_inds] = -1
          # print "was %s inds, disabling %s, now %s inds" % (
          # len(bg_inds), len(disable_inds), np.sum(labels == 0))
  
      bbox_targets = np.zeros((len(inds_inside), 4), dtype=np.float32)
      bbox_targets = _compute_targets(
          anchors, gt_boxes[argmax_overlaps, :]
      )
  
      bbox_inside_weights = np.zeros(
          (len(inds_inside), 4), dtype=np.float32
      )
      bbox_inside_weights[labels == 1, :] = np.array(
          cfg.TRAIN.RPN_BBOX_INSIDE_WEIGHTS
      )
  
      bbox_outside_weights = np.zeros(
          (len(inds_inside), 4), dtype=np.float32
      )
      if cfg.TRAIN.RPN_POSITIVE_WEIGHT < 0:
          # uniform weighting of examples (given non-uniform sampling)
          num_examples = np.sum(labels >= 0)
          positive_weights = np.ones((1, 4)) * 1.0 / num_examples
          negative_weights = np.ones((1, 4)) * 1.0 / num_examples
      else:
          assert (cfg.TRAIN.RPN_POSITIVE_WEIGHT > 0) & (
              cfg.TRAIN.RPN_POSITIVE_WEIGHT < 1
          )
          positive_weights = cfg.TRAIN.RPN_POSITIVE_WEIGHT / np.sum(
              labels == 1
          )
          negative_weights = (
              1.0 - cfg.TRAIN.RPN_POSITIVE_WEIGHT
          ) / np.sum(labels == 0)
      bbox_outside_weights[labels == 1, :] = positive_weights
      bbox_outside_weights[labels == 0, :] = negative_weights
  
      if DEBUG:
          self._sums += bbox_targets[labels == 1, :].sum(axis=0)
          self._squared_sums += (bbox_targets[labels == 1, :] ** 2).sum(
              axis=0
          )
          self._counts += np.sum(labels == 1)
          means = self._sums / self._counts
          stds = np.sqrt(self._squared_sums / self._counts - means**2)
          print("means:")
          print(means)
          print("stdevs:")
          print(stds)
  
      # map up to original set of anchors
      labels = _unmap(labels, total_anchors, inds_inside, fill=-1)
      bbox_targets = _unmap(
          bbox_targets, total_anchors, inds_inside, fill=0
      )
      bbox_inside_weights = _unmap(
          bbox_inside_weights, total_anchors, inds_inside, fill=0
      )
      bbox_outside_weights = _unmap(
          bbox_outside_weights, total_anchors, inds_inside, fill=0
      )
  
      if DEBUG:
          print("rpn: max max_overlap", np.max(max_overlaps))
          print("rpn: num_positive", np.sum(labels == 1))
          print("rpn: num_negative", np.sum(labels == 0))
          self._fg_sum += np.sum(labels == 1)
          self._bg_sum += np.sum(labels == 0)
          self._count += 1
          print("rpn: num_positive avg", self._fg_sum / self._count)
          print("rpn: num_negative avg", self._bg_sum / self._count)
  
      # labels
      labels = labels.reshape((1, height, width, A)).transpose(
          0, 3, 1, 2
      )
      # labels = labels.reshape((1, 1, A * height, width))
      # top[0].reshape(*labels.shape)
      # top[0].data[...] = labels
  
      # bbox_targets
      bbox_targets = bbox_targets.reshape(
          (1, height, width, A * 4)
      ).transpose(0, 3, 1, 2)
      # top[1].reshape(*bbox_targets.shape)
      # top[1].data[...] = bbox_targets
  
      # bbox_inside_weights
      bbox_inside_weights = bbox_inside_weights.reshape(
          (1, height, width, A * 4)
      ).transpose(0, 3, 1, 2)
      # assert bbox_inside_weights.shape[2] == height
      # assert bbox_inside_weights.shape[3] == width
      # top[2].reshape(*bbox_inside_weights.shape)
      # top[2].data[...] = bbox_inside_weights
  
      # bbox_outside_weights
      # bbox_outside_weights = bbox_outside_weights \
      #    .reshape((1, height, width, A * 4)).transpose(0, 3, 1, 2)
      # assert bbox_outside_weights.shape[2] == height
      # assert bbox_outside_weights.shape[3] == width
      # top[3].reshape(*bbox_outside_weights.shape)
      # top[3].data[...] = bbox_outside_weights
  
      return labels, bbox_targets, bbox_inside_weights
  
file_path: CNTK/Examples/Image/Detection/utils/caffe_layers/anchor_target_layer.py
imports: import os
  import yaml
  import numpy
  import numpy.random
  from utils.caffe_layers.default_config import cfg
  from utils.rpn.generate_anchors import generate_anchors
  from utils.rpn.bbox_transform import bbox_transform
  from utils.cython_modules.cython_bbox import bbox_overlaps
label_desc: Use image node_id 4 for calling the AnchorTargetLayer obj's underlying member method code with example usage: obj.forward(bottom, top) and returns: labels,  bbox_targets,  bbox_inside_weights