def hybrid_forward(self, F, x, gt_box=None, gt_label=None, m_rpn_box=None):
        """Forward Faster-RCNN network.

        The behavior during training and inference is different.

        Parameters
        ----------
        x : mxnet.nd.NDArray or mxnet.symbol
            The network input tensor.
        gt_box : type, only required during training
            The ground-truth bbox tensor with shape (B, N, 4).
        gt_label : type, only required during training
            The ground-truth label tensor with shape (B, 1, 4).

        Returns
        -------
        (ids, scores, bboxes)
            During inference, returns final class id, confidence scores, bounding
            boxes.

        """

        def _split(x, axis, num_outputs, squeeze_axis):
            x = F.split(
                x, axis=axis, num_outputs=num_outputs, squeeze_axis=squeeze_axis
            )
            if isinstance(x, list):
                return x
            else:
                return [x]

        if m_rpn_box is not None:
            manual_rpn_box = True
        else:
            manual_rpn_box = False
        feat = self.features(x)
        if not isinstance(feat, (list, tuple)):
            feat = [feat]

        # RPN proposals
        if autograd.is_training():
            if manual_rpn_box:
                rpn_box = m_rpn_box
                self.nms_thresh = 1
            else:
                (
                    rpn_score,
                    rpn_box,
                    raw_rpn_score,
                    raw_rpn_box,
                    anchors,
                ) = self.rpn(F.zeros_like(x), *feat)
                rpn_box, samples, matches = self.sampler(
                    rpn_box, rpn_score, gt_box
                )
        else:
            if manual_rpn_box:
                rpn_box = m_rpn_box
                self.nms_thresh = 1
            else:
                _, rpn_box = self.rpn(F.zeros_like(x), *feat)

        # create batchid for roi
        if not manual_rpn_box:
            num_roi = (
                self._num_sample
                if autograd.is_training()
                else self._rpn_test_post_nms
            )
            batch_size = self._batch_size if autograd.is_training() else 1
        else:
            num_roi = m_rpn_box.shape[1]
            batch_size = rpn_box.shape[0]

        with autograd.pause():
            roi_batchid = F.arange(0, batch_size)
            roi_batchid = F.repeat(roi_batchid, num_roi)
            # remove batch dim because ROIPooling require 2d input
            rpn_roi = F.concat(
                *[roi_batchid.reshape((-1, 1)), rpn_box.reshape((-1, 4))],
                dim=-1
            )
            rpn_roi = F.stop_gradient(rpn_roi)

        if self.num_stages > 1:
            # using FPN
            pooled_feat = self._pyramid_roi_feats(
                F,
                feat,
                rpn_roi,
                self._roi_size,
                self._strides,
                roi_mode=self._roi_mode,
            )
        else:
            # ROI features
            if self._roi_mode == "pool":
                pooled_feat = F.ROIPooling(
                    feat[0], rpn_roi, self._roi_size, 1.0 / self._strides
                )
            elif self._roi_mode == "align":
                pooled_feat = F.contrib.ROIAlign(
                    feat[0],
                    rpn_roi,
                    self._roi_size,
                    1.0 / self._strides,
                    sample_ratio=2,
                )
            else:
                raise ValueError("Invalid roi mode: {}".format(self._roi_mode))

        # RCNN prediction
        if self.top_features is not None:
            top_feat = self.top_features(pooled_feat)
        else:
            top_feat = pooled_feat
        if self.box_features is None:
            box_feat = F.contrib.AdaptiveAvgPooling2D(top_feat, output_size=1)
        else:
            box_feat = self.box_features(top_feat)
        cls_pred = self.class_predictor(box_feat)
        # cls_pred (B * N, C) -> (B, N, C)
        cls_pred = cls_pred.reshape((batch_size, num_roi, self.num_class + 1))
        if manual_rpn_box:
            spatial_feat = top_feat.mean(axis=1).reshape(
                (-4, rpn_box.shape[0], rpn_box.shape[1], -3)
            )
            cls_ids, scores = self.cls_decoder(F.softmax(cls_pred, axis=-1))
            cls_ids = cls_ids.transpose((0, 2, 1)).reshape((0, 0, 0, 1))
            scores = scores.transpose((0, 2, 1)).reshape((0, 0, 0, 1))
            cls_ids = _split(
                cls_ids, axis=0, num_outputs=batch_size, squeeze_axis=True
            )
            scores = _split(
                scores, axis=0, num_outputs=batch_size, squeeze_axis=True
            )
            return cls_ids, scores, rpn_box, spatial_feat

        # no need to convert bounding boxes in training, just return
        if autograd.is_training():
            (
                cls_targets,
                box_targets,
                box_masks,
                indices,
            ) = self._target_generator(
                rpn_box, samples, matches, gt_label, gt_box
            )
            box_feat = F.reshape(box_feat.expand_dims(0), (batch_size, -1, 0))
            box_pred = self.box_predictor(
                F.concat(
                    *[
                        F.take(
                            F.slice_axis(
                                box_feat, axis=0, begin=i, end=i + 1
                            ).squeeze(),
                            F.slice_axis(
                                indices, axis=0, begin=i, end=i + 1
                            ).squeeze(),
                        )
                        for i in range(batch_size)
                    ],
                    dim=0
                )
            )
            # box_pred (B * N, C * 4) -> (B, N, C, 4)
            box_pred = box_pred.reshape((batch_size, -1, self.num_class, 4))
            if self._additional_output:
                return (
                    cls_pred,
                    box_pred,
                    rpn_box,
                    samples,
                    matches,
                    raw_rpn_score,
                    raw_rpn_box,
                    anchors,
                    cls_targets,
                    box_targets,
                    box_masks,
                    top_feat,
                    indices,
                )
            return (
                cls_pred,
                box_pred,
                rpn_box,
                samples,
                matches,
                raw_rpn_score,
                raw_rpn_box,
                anchors,
                cls_targets,
                box_targets,
                box_masks,
                indices,
            )

        box_pred = self.box_predictor(box_feat)
        # box_pred (B * N, C * 4) -> (B, N, C, 4)
        box_pred = box_pred.reshape((batch_size, num_roi, self.num_class, 4))
        # cls_ids (B, N, C), scores (B, N, C)
        cls_ids, scores = self.cls_decoder(F.softmax(cls_pred, axis=-1))
        # cls_ids, scores (B, N, C) -> (B, C, N) -> (B, C, N, 1)
        cls_ids = cls_ids.transpose((0, 2, 1)).reshape((0, 0, 0, 1))
        scores = scores.transpose((0, 2, 1)).reshape((0, 0, 0, 1))
        # box_pred (B, N, C, 4) -> (B, C, N, 4)
        box_pred = box_pred.transpose((0, 2, 1, 3))

        # rpn_boxes (B, N, 4) -> B * (1, N, 4)
        rpn_boxes = _split(
            rpn_box, axis=0, num_outputs=batch_size, squeeze_axis=False
        )
        # cls_ids, scores (B, C, N, 1) -> B * (C, N, 1)
        cls_ids = _split(
            cls_ids, axis=0, num_outputs=batch_size, squeeze_axis=True
        )
        scores = _split(
            scores, axis=0, num_outputs=batch_size, squeeze_axis=True
        )
        # box_preds (B, C, N, 4) -> B * (C, N, 4)
        box_preds = _split(
            box_pred, axis=0, num_outputs=batch_size, squeeze_axis=True
        )

        # per batch predict, nms, each class has topk outputs
        results = []
        # add feat index
        if self._additional_output:
            sizes = scores[0].shape[0:2]
            # ind = mx.nd.array(list(range(sizes[1])))
            ind = mx.nd.linspace(0, 999, 1000)
            ind = mx.nd.repeat(ind, repeats=sizes[0])
            ind = (
                ind.reshape(sizes[1], sizes[0])
                .transpose((1, 0))
                .expand_dims(axis=2)
            )
        for rpn_box, cls_id, score, box_pred in zip(
            rpn_boxes, cls_ids, scores, box_preds
        ):
            # box_pred (C, N, 4) rpn_box (1, N, 4) -> bbox (C, N, 4)
            bbox = self.box_decoder(box_pred, rpn_box)
            if self._additional_output:
                # res (C, N, 7)
                res = F.concat(*[cls_id, score, bbox, ind], dim=-1)
            else:
                # res (C, N, 6)
                res = F.concat(*[cls_id, score, bbox], dim=-1)
            if self.force_nms:
                # res (1, C*N, 6), to allow cross-catogory suppression
                res = res.reshape((1, -1, 0))
            # res (C, self.nms_topk, 6)
            res = F.contrib.box_nms(
                res,
                overlap_thresh=self.nms_thresh,
                topk=self.nms_topk,
                valid_thresh=0.001,
                id_index=0,
                score_index=1,
                coord_start=2,
                force_suppress=self.force_nms,
            )
            # res (C * self.nms_topk, 6)
            res = res.reshape((-3, 0))
            results.append(res)

        # result B * (C * topk, 6) -> (B, C * topk, 6)
        result = F.stack(*results, axis=0)
        ids = F.slice_axis(result, axis=-1, begin=0, end=1)
        scores = F.slice_axis(result, axis=-1, begin=1, end=2)
        bboxes = F.slice_axis(result, axis=-1, begin=2, end=6)
        if self._additional_output:
            feat_ind = F.slice_axis(result, axis=-1, begin=6, end=7)
            spatial_feat = (
                top_feat.mean(axis=1).expand_dims(0).reshape(batch_size, 0, -1)
            )
            return ids, scores, bboxes, feat, feat_ind, spatial_feat
        return ids, scores, bboxes
Forward Faster-RCNN network.

        The behavior during training and inference is different.

        Parameters
        ----------
        x : mxnet.nd.NDArray or mxnet.symbol
            The network input tensor.
        gt_box : type, only required during training
            The ground-truth bbox tensor with shape (B, N, 4).
        gt_label : type, only required during training
            The ground-truth label tensor with shape (B, 1, 4).

        Returns
        -------
        (ids, scores, bboxes)
            During inference, returns final class id, confidence scores, bounding
            boxes.

        
examples/mxnet/scenegraph/model/faster_rcnn.py