From aa2ed0dcc6e0f85e4a450acec9b13038fadd64e7 Mon Sep 17 00:00:00 2001 From: FDInSky <48318485+FDInSky@users.noreply.github.com> Date: Fri, 3 Jan 2020 10:44:09 +0800 Subject: [PATCH] fix generate_proposal_labesl op (#21793) * test=develop fix generate_proposal_labesl op --- .../detection/generate_proposal_labels_op.cc | 47 +++++----- .../test_generate_proposal_labels_op.py | 93 +++++++++++++++---- 2 files changed, 98 insertions(+), 42 deletions(-) diff --git a/paddle/fluid/operators/detection/generate_proposal_labels_op.cc b/paddle/fluid/operators/detection/generate_proposal_labels_op.cc index 668459f0a3d..b8195fbcc03 100644 --- a/paddle/fluid/operators/detection/generate_proposal_labels_op.cc +++ b/paddle/fluid/operators/detection/generate_proposal_labels_op.cc @@ -124,6 +124,7 @@ std::vector> SampleFgBgGt( // Follow the Faster RCNN's implementation for (int64_t i = 0; i < row; ++i) { const T* v = proposal_to_gt_overlaps + i * col; + T max_overlap = *std::max_element(v, v + col); if ((i < gt_num) && (crowd_data[i])) { max_overlap = -1.0; @@ -254,38 +255,40 @@ std::vector SampleRoisForOneImage( bool is_cls_agnostic) { // 1.1 map to original image auto im_scale = im_info.data()[2]; - Tensor rpn_rois_slice; - Tensor rpn_rois; - if (is_cascade_rcnn) { - // slice rpn_rois from gt_box_num refer to detectron - rpn_rois_slice = - rpn_rois_in.Slice(gt_boxes.dims()[0], rpn_rois_in.dims()[0]); - rpn_rois.mutable_data(rpn_rois_slice.dims(), context.GetPlace()); - const T* rpn_rois_in_dt = rpn_rois_slice.data(); - T* rpn_rois_dt = rpn_rois.data(); - for (int i = 0; i < rpn_rois.numel(); ++i) { - rpn_rois_dt[i] = rpn_rois_in_dt[i] / im_scale; - } - } else { - rpn_rois.mutable_data(rpn_rois_in.dims(), context.GetPlace()); - const T* rpn_rois_in_dt = rpn_rois_in.data(); - T* rpn_rois_dt = rpn_rois.data(); - for (int i = 0; i < rpn_rois.numel(); ++i) { + Tensor rpn_rois; + rpn_rois.mutable_data(rpn_rois_in.dims(), context.GetPlace()); + const T* rpn_rois_in_dt = rpn_rois_in.data(); + T* rpn_rois_dt = rpn_rois.data(); + int gt_num = gt_boxes.dims()[0] * 4; + for (int i = 0; i < rpn_rois.numel(); ++i) { + if (i < gt_num && is_cascade_rcnn) { + rpn_rois_dt[i] = rpn_rois_in_dt[i]; + } else { rpn_rois_dt[i] = rpn_rois_in_dt[i] / im_scale; } } // 1.2 compute overlaps - int proposals_num = gt_boxes.dims()[0] + rpn_rois.dims()[0]; - Tensor boxes; - boxes.mutable_data({proposals_num, kBoxDim}, context.GetPlace()); - Concat(context, gt_boxes, rpn_rois, &boxes); + int proposals_num = rpn_rois.dims()[0]; + if (!is_cascade_rcnn) { + proposals_num += gt_boxes.dims()[0]; + } Tensor proposal_to_gt_overlaps; proposal_to_gt_overlaps.mutable_data({proposals_num, gt_boxes.dims()[0]}, context.GetPlace()); - BboxOverlaps(boxes, gt_boxes, &proposal_to_gt_overlaps); + Tensor boxes; + boxes.mutable_data({proposals_num, kBoxDim}, context.GetPlace()); + if (!is_cascade_rcnn) { + Concat(context, gt_boxes, rpn_rois, &boxes); + } else { + T* boxes_dt = boxes.data(); + for (int i = 0; i < boxes.numel(); ++i) { + boxes_dt[i] = rpn_rois_dt[i]; + } + } + BboxOverlaps(boxes, gt_boxes, &proposal_to_gt_overlaps); // Generate proposal index std::vector> fg_bg_gt = SampleFgBgGt(context, &proposal_to_gt_overlaps, is_crowd, diff --git a/python/paddle/fluid/tests/unittests/test_generate_proposal_labels_op.py b/python/paddle/fluid/tests/unittests/test_generate_proposal_labels_op.py index 406c255970a..1259c82b586 100644 --- a/python/paddle/fluid/tests/unittests/test_generate_proposal_labels_op.py +++ b/python/paddle/fluid/tests/unittests/test_generate_proposal_labels_op.py @@ -25,7 +25,7 @@ from op_test import OpTest def generate_proposal_labels_in_python( rpn_rois, gt_classes, is_crowd, gt_boxes, im_info, batch_size_per_im, fg_fraction, fg_thresh, bg_thresh_hi, bg_thresh_lo, bbox_reg_weights, - class_nums, is_cls_agnostic, is_cascade_rcnn): + class_nums, use_random, is_cls_agnostic, is_cascade_rcnn): rois = [] labels_int32 = [] bbox_targets = [] @@ -36,11 +36,11 @@ def generate_proposal_labels_in_python( im_info), 'batch size of rpn_rois and ground_truth is not matched' for im_i in range(len(im_info)): - frcn_blobs = _sample_rois(rpn_rois[im_i], gt_classes[im_i], - is_crowd[im_i], gt_boxes[im_i], im_info[im_i], - batch_size_per_im, fg_fraction, fg_thresh, - bg_thresh_hi, bg_thresh_lo, bbox_reg_weights, - class_nums, is_cls_agnostic, is_cascade_rcnn) + frcn_blobs = _sample_rois( + rpn_rois[im_i], gt_classes[im_i], is_crowd[im_i], gt_boxes[im_i], + im_info[im_i], batch_size_per_im, fg_fraction, fg_thresh, + bg_thresh_hi, bg_thresh_lo, bbox_reg_weights, class_nums, + use_random, is_cls_agnostic, is_cascade_rcnn) lod.append(frcn_blobs['rois'].shape[0]) rois.append(frcn_blobs['rois']) labels_int32.append(frcn_blobs['labels_int32']) @@ -53,18 +53,19 @@ def generate_proposal_labels_in_python( def _sample_rois(rpn_rois, gt_classes, is_crowd, gt_boxes, im_info, batch_size_per_im, fg_fraction, fg_thresh, bg_thresh_hi, - bg_thresh_lo, bbox_reg_weights, class_nums, is_cls_agnostic, - is_cascade_rcnn): + bg_thresh_lo, bbox_reg_weights, class_nums, use_random, + is_cls_agnostic, is_cascade_rcnn): rois_per_image = int(batch_size_per_im) fg_rois_per_im = int(np.round(fg_fraction * rois_per_image)) # Roidb im_scale = im_info[2] inv_im_scale = 1. / im_scale - rpn_rois = rpn_rois * inv_im_scale if is_cascade_rcnn: - rpn_rois = rpn_rois[gt_boxes.shape[0]:, :] + rpn_rois = rpn_rois[len(gt_boxes):, :] + rpn_rois = rpn_rois * inv_im_scale boxes = np.vstack([gt_boxes, rpn_rois]) + gt_overlaps = np.zeros((boxes.shape[0], class_nums)) box_to_gt_ind_map = np.zeros((boxes.shape[0]), dtype=np.int32) if len(gt_boxes) > 0: @@ -83,13 +84,12 @@ def _sample_rois(rpn_rois, gt_classes, is_crowd, gt_boxes, im_info, overlapped_boxes_ind] crowd_ind = np.where(is_crowd)[0] - gt_overlaps[crowd_ind] = -1 - + gt_overlaps[crowd_ind] = -1.0 max_overlaps = gt_overlaps.max(axis=1) max_classes = gt_overlaps.argmax(axis=1) - # Cascade RCNN Decode Filter if is_cascade_rcnn: + # Cascade RCNN Decode Filter ws = boxes[:, 2] - boxes[:, 0] + 1 hs = boxes[:, 3] - boxes[:, 1] + 1 keep = np.where((ws > 0) & (hs > 0))[0] @@ -104,7 +104,7 @@ def _sample_rois(rpn_rois, gt_classes, is_crowd, gt_boxes, im_info, fg_inds = np.where(max_overlaps >= fg_thresh)[0] fg_rois_per_this_image = np.minimum(fg_rois_per_im, fg_inds.shape[0]) # Sample foreground if there are too many - if fg_inds.shape[0] > fg_rois_per_this_image: + if (fg_inds.shape[0] > fg_rois_per_this_image) and use_random: fg_inds = np.random.choice( fg_inds, size=fg_rois_per_this_image, replace=False) fg_inds = fg_inds[:fg_rois_per_this_image] @@ -115,7 +115,7 @@ def _sample_rois(rpn_rois, gt_classes, is_crowd, gt_boxes, im_info, bg_rois_per_this_image = np.minimum(bg_rois_per_this_image, bg_inds.shape[0]) # Sample background if there are too many - if bg_inds.shape[0] > bg_rois_per_this_image: + if (bg_inds.shape[0] > bg_rois_per_this_image) and use_random: bg_inds = np.random.choice( bg_inds, size=bg_rois_per_this_image, replace=False) bg_inds = bg_inds[:bg_rois_per_this_image] @@ -223,9 +223,12 @@ def _expand_bbox_targets(bbox_targets_input, class_nums, is_cls_agnostic): class TestGenerateProposalLabelsOp(OpTest): def set_data(self): + self.use_random = False + self.init_test_cascade() self.init_test_params() self.init_test_input() self.init_test_output() + self.inputs = { 'RpnRois': (self.rpn_rois[0], self.rpn_rois_lod), 'GtClasses': (self.gt_classes[0], self.gts_lod), @@ -241,7 +244,7 @@ class TestGenerateProposalLabelsOp(OpTest): 'bg_thresh_lo': self.bg_thresh_lo, 'bbox_reg_weights': self.bbox_reg_weights, 'class_nums': self.class_nums, - 'use_random': False, + 'use_random': self.use_random, 'is_cls_agnostic': self.is_cls_agnostic, 'is_cascade_rcnn': self.is_cascade_rcnn } @@ -260,6 +263,9 @@ class TestGenerateProposalLabelsOp(OpTest): self.op_type = 'generate_proposal_labels' self.set_data() + def init_test_cascade(self, ): + self.is_cascade_rcnn = False + def init_test_params(self): self.batch_size_per_im = 512 self.fg_fraction = 0.25 @@ -267,9 +273,7 @@ class TestGenerateProposalLabelsOp(OpTest): self.bg_thresh_hi = 0.5 self.bg_thresh_lo = 0.0 self.bbox_reg_weights = [0.1, 0.1, 0.2, 0.2] - #self.class_nums = 81 - self.is_cls_agnostic = False #True - self.is_cascade_rcnn = True + self.is_cls_agnostic = False self.class_nums = 2 if self.is_cls_agnostic else 81 def init_test_input(self): @@ -287,10 +291,20 @@ class TestGenerateProposalLabelsOp(OpTest): proposal_nums) ground_truth, self.gts_lod = _generate_groundtruth( images_shape, self.class_nums, gt_nums) + self.gt_classes = [gt['gt_classes'] for gt in ground_truth] self.gt_boxes = [gt['boxes'] for gt in ground_truth] self.is_crowd = [gt['is_crowd'] for gt in ground_truth] + if self.is_cascade_rcnn: + rpn_rois_new = [] + for im_i in range(len(self.im_info)): + gt_boxes = self.gt_boxes[im_i] + rpn_rois = np.vstack( + [gt_boxes, self.rpn_rois[im_i][len(gt_boxes):, :]]) + rpn_rois_new.append(rpn_rois) + self.rpn_rois = rpn_rois_new + def init_test_output(self): self.rois, self.labels_int32, self.bbox_targets, \ self.bbox_inside_weights, self.bbox_outside_weights, \ @@ -298,7 +312,7 @@ class TestGenerateProposalLabelsOp(OpTest): self.rpn_rois, self.gt_classes, self.is_crowd, self.gt_boxes, self.im_info, self.batch_size_per_im, self.fg_fraction, self.fg_thresh, self.bg_thresh_hi, self.bg_thresh_lo, - self.bbox_reg_weights, self.class_nums, + self.bbox_reg_weights, self.class_nums, self.use_random, self.is_cls_agnostic, self.is_cascade_rcnn ) self.rois = np.vstack(self.rois) @@ -309,6 +323,45 @@ class TestGenerateProposalLabelsOp(OpTest): self.bbox_outside_weights = np.vstack(self.bbox_outside_weights) +class TestCascade(TestGenerateProposalLabelsOp): + def init_test_cascade(self): + self.is_cascade_rcnn = True + + +class TestClsAgnostic(TestCascade): + def init_test_params(self): + self.batch_size_per_im = 512 + self.fg_fraction = 0.25 + self.fg_thresh = 0.5 + self.bg_thresh_hi = 0.5 + self.bg_thresh_lo = 0.0 + self.bbox_reg_weights = [0.1, 0.1, 0.2, 0.2] + self.is_cls_agnostic = True + self.class_nums = 2 if self.is_cls_agnostic else 81 + + +class TestOnlyGT(TestCascade): + def init_test_input(self): + np.random.seed(0) + gt_nums = 6 # Keep same with batch_size_per_im for unittest + proposal_nums = 6 + images_shape = [[64, 64]] + self.im_info = np.ones((len(images_shape), 3)).astype(np.float32) + for i in range(len(images_shape)): + self.im_info[i, 0] = images_shape[i][0] + self.im_info[i, 1] = images_shape[i][1] + self.im_info[i, 2] = 0.8 #scale + + ground_truth, self.gts_lod = _generate_groundtruth( + images_shape, self.class_nums, gt_nums) + + self.gt_classes = [gt['gt_classes'] for gt in ground_truth] + self.gt_boxes = [gt['boxes'] for gt in ground_truth] + self.is_crowd = [gt['is_crowd'] for gt in ground_truth] + self.rpn_rois = self.gt_boxes + self.rpn_rois_lod = self.gts_lod + + def _generate_proposals(images_shape, proposal_nums): rpn_rois = [] rpn_rois_lod = [] -- GitLab