From 6b9fbcf3adebc555ec2df3936aacfc5f64a1d0b9 Mon Sep 17 00:00:00 2001 From: FDInSky <48318485+FDInSky@users.noreply.github.com> Date: Tue, 24 Dec 2019 11:08:58 +0800 Subject: [PATCH] Update iou_similarity op to support non-normalized bbox (#21671) Update iou_similarity op to support non-normalized bbox --- .../operators/detection/iou_similarity_op.cc | 5 ++- .../operators/detection/iou_similarity_op.h | 33 +++++++++++---- python/paddle/fluid/layers/detection.py | 7 ++-- .../tests/unittests/test_iou_similarity_op.py | 42 ++++++++++++++++--- 4 files changed, 71 insertions(+), 16 deletions(-) diff --git a/paddle/fluid/operators/detection/iou_similarity_op.cc b/paddle/fluid/operators/detection/iou_similarity_op.cc index b56c678099..55012556e2 100644 --- a/paddle/fluid/operators/detection/iou_similarity_op.cc +++ b/paddle/fluid/operators/detection/iou_similarity_op.cc @@ -61,7 +61,10 @@ class IOUSimilarityOpMaker : public framework::OpProtoAndCheckerMaker { "[xmin, ymin] is the left top coordinate of the box if the " "input is image feature map, and [xmax, ymax] is the right " "bottom coordinate of the box."); - + AddAttr("box_normalized", + "(bool, default true) " + "whether treat the priorbox as a noramlized box") + .SetDefault(true); AddOutput("Out", "(LoDTensor, the lod is same as input X) The output of " "iou_similarity op, a tensor with shape [N, M] " diff --git a/paddle/fluid/operators/detection/iou_similarity_op.h b/paddle/fluid/operators/detection/iou_similarity_op.h index 9f193ebc59..d8fb643298 100644 --- a/paddle/fluid/operators/detection/iou_similarity_op.h +++ b/paddle/fluid/operators/detection/iou_similarity_op.h @@ -18,16 +18,28 @@ limitations under the License. */ template inline HOSTDEVICE T IOUSimilarity(T xmin1, T ymin1, T xmax1, T ymax1, T xmin2, - T ymin2, T xmax2, T ymax2) { + T ymin2, T xmax2, T ymax2, bool normalized) { constexpr T zero = static_cast(0); - T area1 = (ymax1 - ymin1) * (xmax1 - xmin1); - T area2 = (ymax2 - ymin2) * (xmax2 - xmin2); + T area1; + T area2; + if (!normalized) { + area1 = (ymax1 - ymin1 + 1) * (xmax1 - xmin1 + 1); + area2 = (ymax2 - ymin2 + 1) * (xmax2 - xmin2 + 1); + } else { + area1 = (ymax1 - ymin1) * (xmax1 - xmin1); + area2 = (ymax2 - ymin2) * (xmax2 - xmin2); + } + T inter_xmax = xmax1 > xmax2 ? xmax2 : xmax1; T inter_ymax = ymax1 > ymax2 ? ymax2 : ymax1; T inter_xmin = xmin1 > xmin2 ? xmin1 : xmin2; T inter_ymin = ymin1 > ymin2 ? ymin1 : ymin2; T inter_height = inter_ymax - inter_ymin; T inter_width = inter_xmax - inter_xmin; + if (!normalized) { + inter_height = inter_height + 1; + inter_width = inter_width + 1; + } inter_height = inter_height > zero ? inter_height : zero; inter_width = inter_width > zero ? inter_width : zero; T inter_area = inter_width * inter_height; @@ -38,8 +50,12 @@ inline HOSTDEVICE T IOUSimilarity(T xmin1, T ymin1, T xmax1, T ymax1, T xmin2, template struct IOUSimilarityFunctor { - IOUSimilarityFunctor(const T* x, const T* y, T* z, int cols) - : x_(x), y_(y), z_(z), cols_(static_cast(cols)) {} + IOUSimilarityFunctor(const T* x, const T* y, T* z, int cols, bool normalized) + : x_(x), + y_(y), + z_(z), + cols_(static_cast(cols)), + normalized_(normalized) {} inline HOSTDEVICE void operator()(size_t tid) const { size_t row_id = tid / cols_; @@ -56,7 +72,7 @@ struct IOUSimilarityFunctor { T y_max2 = y_[col_id * 4 + 3]; T sim = IOUSimilarity(x_min1, y_min1, x_max1, y_max1, x_min2, y_min2, - x_max2, y_max2); + x_max2, y_max2, normalized_); z_[row_id * cols_ + col_id] = sim; } @@ -64,6 +80,7 @@ struct IOUSimilarityFunctor { const T* y_; T* z_; const size_t cols_; + bool normalized_; }; namespace paddle { @@ -75,12 +92,14 @@ class IOUSimilarityKernel : public framework::OpKernel { void Compute(const framework::ExecutionContext& ctx) const override { const framework::LoDTensor* in_x = ctx.Input("X"); const framework::Tensor* in_y = ctx.Input("Y"); + bool normalized = ctx.Attr("box_normalized"); framework::LoDTensor* out = ctx.Output("Out"); int x_n = in_x->dims()[0]; int y_n = in_y->dims()[0]; IOUSimilarityFunctor functor(in_x->data(), in_y->data(), - out->mutable_data(ctx.GetPlace()), y_n); + out->mutable_data(ctx.GetPlace()), y_n, + normalized); platform::ForRange for_range( static_cast(ctx.device_context()), x_n * y_n); diff --git a/python/paddle/fluid/layers/detection.py b/python/paddle/fluid/layers/detection.py index 2397fff8b1..28a4cfc911 100644 --- a/python/paddle/fluid/layers/detection.py +++ b/python/paddle/fluid/layers/detection.py @@ -653,14 +653,15 @@ def detection_output(loc, @templatedoc() -def iou_similarity(x, y, name=None): +def iou_similarity(x, y, box_normalized=True, name=None): """ ${comment} Args: x (Variable): ${x_comment}.The data type is float32 or float64. y (Variable): ${y_comment}.The data type is float32 or float64. - + box_normalized(bool): Whether treat the priorbox as a noramlized box. + Set true by default. Returns: Variable: ${out_comment}.The data type is same with x. @@ -700,7 +701,7 @@ def iou_similarity(x, y, name=None): type="iou_similarity", inputs={"X": x, "Y": y}, - attrs={}, + attrs={"box_normalized": box_normalized}, outputs={"Out": out}) return out diff --git a/python/paddle/fluid/tests/unittests/test_iou_similarity_op.py b/python/paddle/fluid/tests/unittests/test_iou_similarity_op.py index 12d99b9cfc..6d7ffecc38 100644 --- a/python/paddle/fluid/tests/unittests/test_iou_similarity_op.py +++ b/python/paddle/fluid/tests/unittests/test_iou_similarity_op.py @@ -31,27 +31,40 @@ class TestIOUSimilarityOp(OpTest): self.boxes1 = random.rand(2, 4).astype('float32') self.boxes2 = random.rand(3, 4).astype('float32') self.output = random.rand(2, 3).astype('float32') + self.box_normalized = False + # run python iou computation + self._compute_iou() + self.inputs = {'X': self.boxes1, 'Y': self.boxes2} + self.attrs = {"box_normalized": self.box_normalized} + self.outputs = {'Out': self.output} + + def _compute_iou(self, ): for row in range(self.boxes1.shape[0]): for col in range(self.boxes2.shape[0]): xmin1, ymin1, xmax1, ymax1 = self.boxes1[row] xmin2, ymin2, xmax2, ymax2 = self.boxes2[col] - area1 = (ymax1 - ymin1) * (xmax1 - xmin1) - area2 = (ymax2 - ymin2) * (xmax2 - xmin2) + if not self.box_normalized: + area1 = (ymax1 - ymin1 + 1) * (xmax1 - xmin1 + 1) + area2 = (ymax2 - ymin2 + 1) * (xmax2 - xmin2 + 1) + else: + area1 = (ymax1 - ymin1) * (xmax1 - xmin1) + area2 = (ymax2 - ymin2) * (xmax2 - xmin2) + inter_xmax = min(xmax1, xmax2) inter_ymax = min(ymax1, ymax2) inter_xmin = max(xmin1, xmin2) inter_ymin = max(ymin1, ymin2) inter_height = inter_ymax - inter_ymin inter_width = inter_xmax - inter_xmin + if not self.box_normalized: + inter_height += 1 + inter_width += 1 inter_height = max(inter_height, 0) inter_width = max(inter_width, 0) inter_area = inter_width * inter_height union_area = area1 + area2 - inter_area sim_score = inter_area / union_area self.output[row, col] = sim_score - self.inputs = {'X': self.boxes1, 'Y': self.boxes2} - - self.outputs = {'Out': self.output} class TestIOUSimilarityOpWithLoD(TestIOUSimilarityOp): @@ -62,8 +75,27 @@ class TestIOUSimilarityOpWithLoD(TestIOUSimilarityOp): super(TestIOUSimilarityOpWithLoD, self).setUp() self.boxes1_lod = [[1, 1]] self.output_lod = [[1, 1]] + self.box_normalized = False + # run python iou computation + self._compute_iou() + self.inputs = {'X': (self.boxes1, self.boxes1_lod), 'Y': self.boxes2} + self.attrs = {"box_normalized": self.box_normalized} + self.outputs = {'Out': (self.output, self.output_lod)} + + +class TestIOUSimilarityOpWithBoxNormalized(TestIOUSimilarityOp): + def test_check_output(self): + self.check_output(check_dygraph=False) + def setUp(self): + super(TestIOUSimilarityOpWithBoxNormalized, self).setUp() + self.boxes1_lod = [[1, 1]] + self.output_lod = [[1, 1]] + self.box_normalized = True + # run python iou computation + self._compute_iou() self.inputs = {'X': (self.boxes1, self.boxes1_lod), 'Y': self.boxes2} + self.attrs = {"box_normalized": self.box_normalized} self.outputs = {'Out': (self.output, self.output_lod)} -- GitLab