test_box_coder_op.py 13.4 KB
Newer Older
1
#   Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
G
gaoyuan 已提交
2 3 4 5 6 7 8 9 10 11 12 13 14 15
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import unittest
16

G
gaoyuan 已提交
17
import numpy as np
W
wanghuancoder 已提交
18
from eager_op_test import OpTest
19

L
lyq 已提交
20
import paddle
G
gaoyuan 已提交
21 22


23
def box_decoder(t_box, p_box, pb_v, output_box, norm, axis=0):
24 25
    pb_w = p_box[:, 2] - p_box[:, 0] + (not norm)
    pb_h = p_box[:, 3] - p_box[:, 1] + (not norm)
26 27 28 29 30 31 32 33 34 35
    pb_x = pb_w * 0.5 + p_box[:, 0]
    pb_y = pb_h * 0.5 + p_box[:, 1]
    shape = (1, p_box.shape[0]) if axis == 0 else (p_box.shape[0], 1)

    pb_w = pb_w.reshape(shape)
    pb_h = pb_h.reshape(shape)
    pb_x = pb_x.reshape(shape)
    pb_y = pb_y.reshape(shape)

    if pb_v.ndim == 2:
36 37 38 39 40
        var_shape = (
            (1, pb_v.shape[0], pb_v.shape[1])
            if axis == 0
            else (pb_v.shape[0], 1, pb_v.shape[1])
        )
41
        pb_v = pb_v.reshape(var_shape)
42 43 44 45 46
    if pb_v.ndim == 1:
        tb_x = pb_v[0] * t_box[:, :, 0] * pb_w + pb_x
        tb_y = pb_v[1] * t_box[:, :, 1] * pb_h + pb_y
        tb_w = np.exp(pb_v[2] * t_box[:, :, 2]) * pb_w
        tb_h = np.exp(pb_v[3] * t_box[:, :, 3]) * pb_h
J
jerrywgz 已提交
47
    else:
48 49 50 51 52 53 54 55 56
        tb_x = pb_v[:, :, 0] * t_box[:, :, 0] * pb_w + pb_x
        tb_y = pb_v[:, :, 1] * t_box[:, :, 1] * pb_h + pb_y
        tb_w = np.exp(pb_v[:, :, 2] * t_box[:, :, 2]) * pb_w
        tb_h = np.exp(pb_v[:, :, 3] * t_box[:, :, 3]) * pb_h
    output_box[:, :, 0] = tb_x - tb_w / 2
    output_box[:, :, 1] = tb_y - tb_h / 2
    output_box[:, :, 2] = tb_x + tb_w / 2 - (not norm)
    output_box[:, :, 3] = tb_y + tb_h / 2 - (not norm)

G
gaoyuan 已提交
57

58
def box_encoder(t_box, p_box, pb_v, output_box, norm):
59 60
    pb_w = p_box[:, 2] - p_box[:, 0] + (not norm)
    pb_h = p_box[:, 3] - p_box[:, 1] + (not norm)
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
    pb_x = pb_w * 0.5 + p_box[:, 0]
    pb_y = pb_h * 0.5 + p_box[:, 1]
    shape = (1, p_box.shape[0])

    pb_w = pb_w.reshape(shape)
    pb_h = pb_h.reshape(shape)
    pb_x = pb_x.reshape(shape)
    pb_y = pb_y.reshape(shape)

    if pb_v.ndim == 2:
        pb_v = pb_v.reshape(1, pb_v.shape[0], pb_v.shape[1])
    tb_x = ((t_box[:, 2] + t_box[:, 0]) / 2).reshape(t_box.shape[0], 1)
    tb_y = ((t_box[:, 3] + t_box[:, 1]) / 2).reshape(t_box.shape[0], 1)
    tb_w = (t_box[:, 2] - t_box[:, 0]).reshape(t_box.shape[0], 1) + (not norm)
    tb_h = (t_box[:, 3] - t_box[:, 1]).reshape(t_box.shape[0], 1) + (not norm)
    if pb_v.ndim == 1:
        output_box[:, :, 0] = (tb_x - pb_x) / pb_w / pb_v[0]
        output_box[:, :, 1] = (tb_y - pb_y) / pb_h / pb_v[1]
        output_box[:, :, 2] = np.log(np.fabs(tb_w / pb_w)) / pb_v[2]
        output_box[:, :, 3] = np.log(np.fabs(tb_h / pb_h)) / pb_v[3]
    else:
        output_box[:, :, 0] = (tb_x - pb_x) / pb_w / pb_v[:, :, 0]
        output_box[:, :, 1] = (tb_y - pb_y) / pb_h / pb_v[:, :, 1]
        output_box[:, :, 2] = np.log(np.fabs(tb_w / pb_w)) / pb_v[:, :, 2]
        output_box[:, :, 3] = np.log(np.fabs(tb_h / pb_h)) / pb_v[:, :, 3]
G
gaoyuan 已提交
86 87


88 89 90
def batch_box_coder(p_box, pb_v, t_box, lod, code_type, norm, axis=0):
    n = t_box.shape[0]
    m = p_box.shape[0]
J
jerrywgz 已提交
91
    if code_type == "DecodeCenterSize":
92
        m = t_box.shape[1]
G
gaoyuan 已提交
93
    output_box = np.zeros((n, m, 4), dtype=np.float32)
94 95
    cur_offset = 0
    for i in range(len(lod)):
96 97 98 99 100 101 102 103 104
        if code_type == "EncodeCenterSize":
            box_encoder(
                t_box[cur_offset : (cur_offset + lod[i]), :],
                p_box,
                pb_v,
                output_box[cur_offset : (cur_offset + lod[i]), :, :],
                norm,
            )
        elif code_type == "DecodeCenterSize":
105
            box_decoder(t_box, p_box, pb_v, output_box, norm, axis)
106
        cur_offset += lod[i]
G
gaoyuan 已提交
107 108 109 110 111
    return output_box


class TestBoxCoderOp(OpTest):
    def test_check_output(self):
W
wanghuancoder 已提交
112
        self.check_output()
G
gaoyuan 已提交
113 114 115

    def setUp(self):
        self.op_type = "box_coder"
116
        self.python_api = paddle.vision.ops.box_coder
117
        lod = [[1, 1, 1, 1, 1]]
118 119 120
        prior_box = np.random.random((81, 4)).astype('float32')
        prior_box_var = np.random.random((81, 4)).astype('float32')
        target_box = np.random.random((20, 81, 4)).astype('float32')
G
gaoyuan 已提交
121
        code_type = "DecodeCenterSize"
122
        box_normalized = False
123 124 125 126 127 128 129 130
        output_box = batch_box_coder(
            prior_box,
            prior_box_var,
            target_box,
            lod[0],
            code_type,
            box_normalized,
        )
J
jerrywgz 已提交
131 132 133 134 135 136 137
        self.inputs = {
            'PriorBox': prior_box,
            'PriorBoxVar': prior_box_var,
            'TargetBox': target_box,
        }
        self.attrs = {
            'code_type': 'decode_center_size',
138
            'box_normalized': False,
J
jerrywgz 已提交
139 140 141 142
        }
        self.outputs = {'OutputBox': output_box}


143 144
class TestBoxCoderOpWithoutBoxVar(OpTest):
    def test_check_output(self):
W
wanghuancoder 已提交
145
        self.check_output()
146 147

    def setUp(self):
148
        self.python_api = paddle.vision.ops.box_coder
149 150
        self.op_type = "box_coder"
        lod = [[0, 1, 2, 3, 4, 5]]
151 152 153
        prior_box = np.random.random((81, 4)).astype('float32')
        prior_box_var = np.ones((81, 4)).astype('float32')
        target_box = np.random.random((20, 81, 4)).astype('float32')
154 155
        code_type = "DecodeCenterSize"
        box_normalized = False
156 157 158 159 160 161 162 163
        output_box = batch_box_coder(
            prior_box,
            prior_box_var,
            target_box,
            lod[0],
            code_type,
            box_normalized,
        )
164 165 166

        self.inputs = {
            'PriorBox': prior_box,
L
lyq 已提交
167
            'PriorBoxVar': prior_box_var,
168 169 170 171
            'TargetBox': target_box,
        }
        self.attrs = {
            'code_type': 'decode_center_size',
172
            'box_normalized': False,
173
        }
G
gaoyuan 已提交
174 175 176 177 178
        self.outputs = {'OutputBox': output_box}


class TestBoxCoderOpWithLoD(OpTest):
    def test_check_output(self):
W
wanghuancoder 已提交
179
        self.check_output()
G
gaoyuan 已提交
180 181

    def setUp(self):
182
        self.python_api = paddle.vision.ops.box_coder
G
gaoyuan 已提交
183
        self.op_type = "box_coder"
184 185 186 187
        lod = [[10, 20, 20]]
        prior_box = np.random.random((20, 4)).astype('float32')
        prior_box_var = np.random.random((20, 4)).astype('float32')
        target_box = np.random.random((50, 4)).astype('float32')
G
gaoyuan 已提交
188
        code_type = "EncodeCenterSize"
189
        box_normalized = True
190 191 192 193 194 195 196 197
        output_box = batch_box_coder(
            prior_box,
            prior_box_var,
            target_box,
            lod[0],
            code_type,
            box_normalized,
        )
G
gaoyuan 已提交
198 199 200 201 202 203

        self.inputs = {
            'PriorBox': prior_box,
            'PriorBoxVar': prior_box_var,
            'TargetBox': (target_box, lod),
        }
204
        self.attrs = {'code_type': 'encode_center_size', 'box_normalized': True}
G
gaoyuan 已提交
205 206 207
        self.outputs = {'OutputBox': output_box}


J
jerrywgz 已提交
208 209
class TestBoxCoderOpWithAxis(OpTest):
    def test_check_output(self):
W
wanghuancoder 已提交
210
        self.check_output()
J
jerrywgz 已提交
211 212

    def setUp(self):
213
        self.python_api = paddle.vision.ops.box_coder
J
jerrywgz 已提交
214 215
        self.op_type = "box_coder"
        lod = [[1, 1, 1, 1, 1]]
216
        prior_box = np.random.random((30, 4)).astype('float32')
217
        prior_box_var = np.random.random((30, 4)).astype('float32')
218
        target_box = np.random.random((30, 81, 4)).astype('float32')
J
jerrywgz 已提交
219 220 221
        code_type = "DecodeCenterSize"
        box_normalized = False
        axis = 1
222 223 224 225 226 227 228 229 230
        output_box = batch_box_coder(
            prior_box,
            prior_box_var,
            target_box,
            lod[0],
            code_type,
            box_normalized,
            axis,
        )
J
jerrywgz 已提交
231 232 233 234 235 236 237 238 239

        self.inputs = {
            'PriorBox': prior_box,
            'PriorBoxVar': prior_box_var,
            'TargetBox': target_box,
        }
        self.attrs = {
            'code_type': 'decode_center_size',
            'box_normalized': False,
240
            'axis': axis,
J
jerrywgz 已提交
241 242 243 244
        }
        self.outputs = {'OutputBox': output_box}


W
wanghuancoder 已提交
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
def wrapper_box_coder(
    prior_box,
    prior_box_var=None,
    target_box=None,
    code_type="encode_center_size",
    box_normalized=True,
    axis=0,
    variance=[],
):
    if isinstance(prior_box_var, paddle.Tensor):
        output_box = paddle._C_ops.box_coder(
            prior_box,
            prior_box_var,
            target_box,
            code_type,
            box_normalized,
            axis,
            [],
        )
    elif isinstance(prior_box_var, list):
        output_box = paddle._C_ops.box_coder(
            prior_box,
            None,
            target_box,
            code_type,
            box_normalized,
            axis,
            prior_box_var,
        )
    else:
        output_box = paddle._C_ops.box_coder(
            prior_box,
            None,
            target_box,
            code_type,
            box_normalized,
            axis,
            variance,
        )
    return output_box


287 288 289 290 291 292
class TestBoxCoderOpWithVariance(OpTest):
    def test_check_output(self):
        self.check_output()

    def setUp(self):
        self.op_type = "box_coder"
W
wanghuancoder 已提交
293
        self.python_api = wrapper_box_coder
294 295 296 297 298 299 300
        lod = [[1, 1, 1, 1, 1]]
        prior_box = np.random.random((30, 4)).astype('float32')
        prior_box_var = np.random.random((4)).astype('float32')
        target_box = np.random.random((30, 81, 4)).astype('float32')
        code_type = "DecodeCenterSize"
        box_normalized = False
        axis = 1
301 302 303 304 305 306 307 308 309
        output_box = batch_box_coder(
            prior_box,
            prior_box_var,
            target_box,
            lod[0],
            code_type,
            box_normalized,
            axis,
        )
310 311 312 313 314 315 316 317

        self.inputs = {
            'PriorBox': prior_box,
            'TargetBox': target_box,
        }
        self.attrs = {
            'code_type': 'decode_center_size',
            'box_normalized': False,
318
            'variance': prior_box_var.astype(np.float64).flatten(),
319
            'axis': axis,
320 321 322 323
        }
        self.outputs = {'OutputBox': output_box}


L
lyq 已提交
324 325 326 327 328 329 330 331 332
class TestBoxCoderOpWithVarianceDygraphAPI(unittest.TestCase):
    def setUp(self):
        self.lod = [[1, 1, 1, 1, 1]]
        self.prior_box = np.random.random((30, 4)).astype('float32')
        self.prior_box_var = np.random.random((4)).astype('float32')
        self.target_box = np.random.random((30, 81, 4)).astype('float32')
        self.code_type = "DecodeCenterSize"
        self.box_normalized = False
        self.axis = 1
333 334 335 336 337 338 339 340 341
        self.output_ref = batch_box_coder(
            self.prior_box,
            self.prior_box_var,
            self.target_box,
            self.lod[0],
            self.code_type,
            self.box_normalized,
            self.axis,
        )
L
lyq 已提交
342
        self.place = [paddle.CPUPlace()]
343
        if paddle.is_compiled_with_cuda():
L
lyq 已提交
344 345 346 347 348
            self.place.append(paddle.CUDAPlace(0))

    def test_dygraph_api(self):
        def run(place):
            paddle.disable_static(place)
349
            output_box = paddle.vision.ops.box_coder(
L
lyq 已提交
350 351 352 353 354
                paddle.to_tensor(self.prior_box),
                self.prior_box_var.tolist(),
                paddle.to_tensor(self.target_box),
                "decode_center_size",
                self.box_normalized,
355 356 357 358 359
                axis=self.axis,
            )
            np.testing.assert_allclose(
                np.sum(self.output_ref), np.sum(output_box.numpy()), rtol=1e-05
            )
L
lyq 已提交
360 361 362 363 364 365
            paddle.enable_static()

        for place in self.place:
            run(place)


366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
class TestBoxCoderAPI(unittest.TestCase):
    def setUp(self):
        np.random.seed(678)
        self.prior_box_np = np.random.random((80, 4)).astype('float32')
        self.prior_box_var_np = np.random.random((80, 4)).astype('float32')
        self.target_box_np = np.random.random((20, 80, 4)).astype('float32')

    def test_dygraph_with_static(self):
        paddle.enable_static()
        prior_box = paddle.static.data(
            name='prior_box', shape=[80, 4], dtype='float32'
        )
        prior_box_var = paddle.static.data(
            name='prior_box_var', shape=[80, 4], dtype='float32'
        )
        target_box = paddle.static.data(
            name='target_box', shape=[20, 80, 4], dtype='float32'
        )

        boxes = paddle.vision.ops.box_coder(
            prior_box=prior_box,
            prior_box_var=prior_box_var,
            target_box=target_box,
            code_type="decode_center_size",
            box_normalized=False,
        )

        exe = paddle.static.Executor()
        boxes_np = exe.run(
            paddle.static.default_main_program(),
            feed={
                'prior_box': self.prior_box_np,
                'prior_box_var': self.prior_box_var_np,
                'target_box': self.target_box_np,
            },
            fetch_list=[boxes],
        )

        paddle.disable_static()
        prior_box_dy = paddle.to_tensor(self.prior_box_np)
        prior_box_var_dy = paddle.to_tensor(self.prior_box_var_np)
        target_box_dy = paddle.to_tensor(self.target_box_np)

        boxes_dy = paddle.vision.ops.box_coder(
            prior_box=prior_box_dy,
            prior_box_var=prior_box_var_dy,
            target_box=target_box_dy,
            code_type="decode_center_size",
            box_normalized=False,
        )
        boxes_dy_np = boxes_dy.numpy()

        np.testing.assert_allclose(boxes_np[0], boxes_dy_np)
        paddle.enable_static()


G
gaoyuan 已提交
422
if __name__ == '__main__':
423
    paddle.enable_static()
G
gaoyuan 已提交
424
    unittest.main()