test_deform_conv2d.py 21.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
#
# 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 paddle
import paddle.nn.initializer as I
import numpy as np
import unittest
19
from paddle.fluid.framework import _test_eager_guard
20 21 22 23 24
from unittest import TestCase


class TestDeformConv2D(TestCase):
    batch_size = 4
25
    spatial_shape = (5, 5)
26 27 28
    dtype = "float32"

    def setUp(self):
29
        self.in_channels = 2
30 31 32 33 34
        self.out_channels = 5
        self.kernel_size = [3, 3]
        self.padding = [0, 0]
        self.stride = [1, 1]
        self.dilation = [1, 1]
35
        self.deformable_groups = 1
36 37 38 39
        self.groups = 1
        self.no_bias = True

    def prepare(self):
40 41
        np.random.seed(1)
        paddle.seed(1)
42
        if isinstance(self.kernel_size, int):
43
            filter_shape = (self.kernel_size,) * 2
44 45 46 47 48
        else:
            filter_shape = tuple(self.kernel_size)
        self.filter_shape = filter_shape

        self.weight = np.random.uniform(
49 50 51 52
            -1,
            1,
            (self.out_channels, self.in_channels // self.groups) + filter_shape,
        ).astype(self.dtype)
53
        if not self.no_bias:
54 55 56
            self.bias = np.random.uniform(-1, 1, (self.out_channels,)).astype(
                self.dtype
            )
57

58 59 60 61 62 63
        def out_size(
            in_size, pad_size, dilation_size, kernel_size, stride_size
        ):
            return (
                in_size + 2 * pad_size - (dilation_size * (kernel_size - 1) + 1)
            ) / stride_size + 1
64 65

        out_h = int(
66 67 68 69 70 71 72 73
            out_size(
                self.spatial_shape[0],
                self.padding[0],
                self.dilation[0],
                self.kernel_size[0],
                self.stride[0],
            )
        )
74
        out_w = int(
75 76 77 78 79 80 81 82
            out_size(
                self.spatial_shape[1],
                self.padding[1],
                self.dilation[1],
                self.kernel_size[1],
                self.stride[1],
            )
        )
83 84
        out_shape = (out_h, out_w)

85 86 87 88
        self.input_shape = (
            self.batch_size,
            self.in_channels,
        ) + self.spatial_shape
89

90 91 92 93
        self.offset_shape = (
            self.batch_size,
            self.deformable_groups * 2 * filter_shape[0] * filter_shape[1],
        ) + out_shape
94

95 96 97 98
        self.mask_shape = (
            self.batch_size,
            self.deformable_groups * filter_shape[0] * filter_shape[1],
        ) + out_shape
99

100 101 102
        self.input = np.random.uniform(-1, 1, self.input_shape).astype(
            self.dtype
        )
103

104 105 106
        self.offset = np.random.uniform(-1, 1, self.offset_shape).astype(
            self.dtype
        )
107 108 109 110 111 112 113 114

        self.mask = np.random.uniform(-1, 1, self.mask_shape).astype(self.dtype)

    def static_graph_case_dcn(self):
        main = paddle.static.Program()
        start = paddle.static.Program()
        paddle.enable_static()
        with paddle.static.program_guard(main, start):
115 116 117
            x = paddle.static.data(
                "input", (-1, self.in_channels, -1, -1), dtype=self.dtype
            )
118
            offset = paddle.static.data(
119 120 121 122 123 124 125 126 127 128 129 130
                "offset",
                (
                    -1,
                    self.deformable_groups
                    * 2
                    * self.filter_shape[0]
                    * self.filter_shape[1],
                    -1,
                    -1,
                ),
                dtype=self.dtype,
            )
131
            mask = paddle.static.data(
132 133 134 135 136 137 138 139 140 141 142
                "mask",
                (
                    -1,
                    self.deformable_groups
                    * self.filter_shape[0]
                    * self.filter_shape[1],
                    -1,
                    -1,
                ),
                dtype=self.dtype,
            )
143

144
            y_v1 = paddle.static.nn.common.deformable_conv(
145 146 147 148 149 150 151 152 153
                input=x,
                offset=offset,
                mask=None,
                num_filters=self.out_channels,
                filter_size=self.filter_shape,
                stride=self.stride,
                padding=self.padding,
                dilation=self.dilation,
                groups=self.groups,
154
                deformable_groups=self.deformable_groups,
155 156 157
                im2col_step=1,
                param_attr=I.Assign(self.weight),
                bias_attr=False if self.no_bias else I.Assign(self.bias),
158 159
                modulated=False,
            )
160

161
            y_v2 = paddle.static.nn.common.deformable_conv(
162 163 164 165 166 167 168 169 170
                input=x,
                offset=offset,
                mask=mask,
                num_filters=self.out_channels,
                filter_size=self.filter_shape,
                stride=self.stride,
                padding=self.padding,
                dilation=self.dilation,
                groups=self.groups,
171
                deformable_groups=self.deformable_groups,
172 173
                im2col_step=1,
                param_attr=I.Assign(self.weight),
174 175
                bias_attr=False if self.no_bias else I.Assign(self.bias),
            )
176 177 178

        exe = paddle.static.Executor(self.place)
        exe.run(start)
179 180 181 182 183 184 185 186 187
        out_v1, out_v2 = exe.run(
            main,
            feed={
                "input": self.input,
                "offset": self.offset,
                "mask": self.mask,
            },
            fetch_list=[y_v1, y_v2],
        )
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
        return out_v1, out_v2

    def dygraph_case_dcn(self):
        paddle.disable_static()
        x = paddle.to_tensor(self.input)
        offset = paddle.to_tensor(self.offset)
        mask = paddle.to_tensor(self.mask)

        bias = None if self.no_bias else paddle.to_tensor(self.bias)

        deform_conv2d = paddle.vision.ops.DeformConv2D(
            in_channels=self.in_channels,
            out_channels=self.out_channels,
            kernel_size=self.kernel_size,
            stride=self.stride,
            padding=self.padding,
            dilation=self.dilation,
205
            deformable_groups=self.deformable_groups,
206 207
            groups=self.groups,
            weight_attr=I.Assign(self.weight),
208 209
            bias_attr=False if self.no_bias else I.Assign(self.bias),
        )
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233

        y_v1 = deform_conv2d(x, offset)
        y_v2 = deform_conv2d(x, offset, mask)

        out_v1 = y_v1.numpy()
        out_v2 = y_v2.numpy()

        return out_v1, out_v2

    def _test_identity(self):
        self.prepare()
        static_dcn_v1, static_dcn_v2 = self.static_graph_case_dcn()
        dy_dcn_v1, dy_dcn_v2 = self.dygraph_case_dcn()
        np.testing.assert_array_almost_equal(static_dcn_v1, dy_dcn_v1)
        np.testing.assert_array_almost_equal(static_dcn_v2, dy_dcn_v2)

    def test_identity(self):
        self.place = paddle.CPUPlace()
        self._test_identity()

        if paddle.is_compiled_with_cuda():
            self.place = paddle.CUDAPlace(0)
            self._test_identity()

234 235 236 237
    def test_identity_with_eager_guard(self):
        with _test_eager_guard():
            self.test_identity()

238 239 240

class TestDeformConv2DFunctional(TestCase):
    batch_size = 4
241
    spatial_shape = (5, 5)
242 243 244
    dtype = "float32"

    def setUp(self):
245
        self.in_channels = 2
246 247 248 249 250
        self.out_channels = 5
        self.kernel_size = [3, 3]
        self.padding = [0, 0]
        self.stride = [1, 1]
        self.dilation = [1, 1]
251
        self.deformable_groups = 1
252 253 254 255
        self.groups = 1
        self.no_bias = True

    def prepare(self):
256 257
        np.random.seed(1)
        paddle.seed(1)
258
        if isinstance(self.kernel_size, int):
259
            filter_shape = (self.kernel_size,) * 2
260 261 262 263 264
        else:
            filter_shape = tuple(self.kernel_size)
        self.filter_shape = filter_shape

        self.weight = np.random.uniform(
265 266 267 268
            -1,
            1,
            (self.out_channels, self.in_channels // self.groups) + filter_shape,
        ).astype(self.dtype)
269
        if not self.no_bias:
270 271 272
            self.bias = np.random.uniform(-1, 1, (self.out_channels,)).astype(
                self.dtype
            )
273

274 275 276 277 278 279
        def out_size(
            in_size, pad_size, dilation_size, kernel_size, stride_size
        ):
            return (
                in_size + 2 * pad_size - (dilation_size * (kernel_size - 1) + 1)
            ) / stride_size + 1
280 281

        out_h = int(
282 283 284 285 286 287 288 289
            out_size(
                self.spatial_shape[0],
                self.padding[0],
                self.dilation[0],
                self.kernel_size[0],
                self.stride[0],
            )
        )
290
        out_w = int(
291 292 293 294 295 296 297 298
            out_size(
                self.spatial_shape[1],
                self.padding[1],
                self.dilation[1],
                self.kernel_size[1],
                self.stride[1],
            )
        )
299 300
        out_shape = (out_h, out_w)

301 302 303 304
        self.input_shape = (
            self.batch_size,
            self.in_channels,
        ) + self.spatial_shape
305

306 307 308 309
        self.offset_shape = (
            self.batch_size,
            self.deformable_groups * 2 * filter_shape[0] * filter_shape[1],
        ) + out_shape
310

311 312 313 314
        self.mask_shape = (
            self.batch_size,
            self.deformable_groups * filter_shape[0] * filter_shape[1],
        ) + out_shape
315

316 317 318
        self.input = np.random.uniform(-1, 1, self.input_shape).astype(
            self.dtype
        )
319

320 321 322
        self.offset = np.random.uniform(-1, 1, self.offset_shape).astype(
            self.dtype
        )
323 324 325 326 327 328 329 330

        self.mask = np.random.uniform(-1, 1, self.mask_shape).astype(self.dtype)

    def static_graph_case_dcn(self):
        main = paddle.static.Program()
        start = paddle.static.Program()
        paddle.enable_static()
        with paddle.static.program_guard(main, start):
331 332 333
            x = paddle.static.data(
                "input", (-1, self.in_channels, -1, -1), dtype=self.dtype
            )
334
            offset = paddle.static.data(
335 336 337 338 339 340 341 342 343 344 345 346
                "offset",
                (
                    -1,
                    self.deformable_groups
                    * 2
                    * self.filter_shape[0]
                    * self.filter_shape[1],
                    -1,
                    -1,
                ),
                dtype=self.dtype,
            )
347
            mask = paddle.static.data(
348 349 350 351 352 353 354 355 356 357 358
                "mask",
                (
                    -1,
                    self.deformable_groups
                    * self.filter_shape[0]
                    * self.filter_shape[1],
                    -1,
                    -1,
                ),
                dtype=self.dtype,
            )
359

360
            y_v1 = paddle.static.nn.common.deformable_conv(
361 362 363 364 365 366 367 368 369
                input=x,
                offset=offset,
                mask=None,
                num_filters=self.out_channels,
                filter_size=self.filter_shape,
                stride=self.stride,
                padding=self.padding,
                dilation=self.dilation,
                groups=self.groups,
370
                deformable_groups=self.deformable_groups,
371 372 373
                im2col_step=1,
                param_attr=I.Assign(self.weight),
                bias_attr=False if self.no_bias else I.Assign(self.bias),
374 375
                modulated=False,
            )
376

377
            y_v2 = paddle.static.nn.common.deformable_conv(
378 379 380 381 382 383 384 385 386
                input=x,
                offset=offset,
                mask=mask,
                num_filters=self.out_channels,
                filter_size=self.filter_shape,
                stride=self.stride,
                padding=self.padding,
                dilation=self.dilation,
                groups=self.groups,
387
                deformable_groups=self.deformable_groups,
388 389
                im2col_step=1,
                param_attr=I.Assign(self.weight),
390 391
                bias_attr=False if self.no_bias else I.Assign(self.bias),
            )
392 393 394

        exe = paddle.static.Executor(self.place)
        exe.run(start)
395 396 397 398 399 400 401 402 403
        out_v1, out_v2 = exe.run(
            main,
            feed={
                "input": self.input,
                "offset": self.offset,
                "mask": self.mask,
            },
            fetch_list=[y_v1, y_v2],
        )
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
        return out_v1, out_v2

    def dygraph_case_dcn(self):
        paddle.disable_static()
        x = paddle.to_tensor(self.input)
        offset = paddle.to_tensor(self.offset)
        mask = paddle.to_tensor(self.mask)
        weight = paddle.to_tensor(self.weight)
        bias = None if self.no_bias else paddle.to_tensor(self.bias)

        y_v1 = paddle.vision.ops.deform_conv2d(
            x=x,
            offset=offset,
            weight=weight,
            bias=bias,
            stride=self.stride,
            padding=self.padding,
            dilation=self.dilation,
422
            deformable_groups=self.deformable_groups,
423 424
            groups=self.groups,
        )
425 426 427 428 429 430 431 432 433 434

        y_v2 = paddle.vision.ops.deform_conv2d(
            x=x,
            offset=offset,
            mask=mask,
            weight=weight,
            bias=bias,
            stride=self.stride,
            padding=self.padding,
            dilation=self.dilation,
435
            deformable_groups=self.deformable_groups,
436 437
            groups=self.groups,
        )
438 439 440 441 442 443 444 445 446 447 448

        out_v1 = y_v1.numpy()
        out_v2 = y_v2.numpy()

        return out_v1, out_v2

    def new_api_static_graph_case_dcn(self):
        main = paddle.static.Program()
        start = paddle.static.Program()
        paddle.enable_static()
        with paddle.static.program_guard(main, start):
449 450 451
            x = paddle.static.data(
                "input", (-1, self.in_channels, -1, -1), dtype=self.dtype
            )
452
            offset = paddle.static.data(
453 454 455 456 457 458 459 460 461 462 463 464
                "offset",
                (
                    -1,
                    self.deformable_groups
                    * 2
                    * self.filter_shape[0]
                    * self.filter_shape[1],
                    -1,
                    -1,
                ),
                dtype=self.dtype,
            )
465
            mask = paddle.static.data(
466 467 468 469 470 471 472 473 474 475 476
                "mask",
                (
                    -1,
                    self.deformable_groups
                    * self.filter_shape[0]
                    * self.filter_shape[1],
                    -1,
                    -1,
                ),
                dtype=self.dtype,
            )
477

478 479 480
            weight = paddle.static.data(
                "weight", list(self.weight.shape), dtype=self.dtype
            )
481 482 483 484 485 486 487 488 489 490 491 492

            if not self.no_bias:
                bias = paddle.static.data("bias", [-1], dtype=self.dtype)

            y_v1 = paddle.vision.ops.deform_conv2d(
                x=x,
                offset=offset,
                weight=weight,
                bias=None if self.no_bias else bias,
                stride=self.stride,
                padding=self.padding,
                dilation=self.dilation,
493
                deformable_groups=self.deformable_groups,
494 495
                groups=self.groups,
            )
496 497 498 499 500 501 502 503 504 505

            y_v2 = paddle.vision.ops.deform_conv2d(
                x=x,
                offset=offset,
                mask=mask,
                weight=weight,
                bias=None if self.no_bias else bias,
                stride=self.stride,
                padding=self.padding,
                dilation=self.dilation,
506
                deformable_groups=self.deformable_groups,
507 508
                groups=self.groups,
            )
509 510 511 512 513 514 515

        exe = paddle.static.Executor(self.place)
        exe.run(start)
        feed_dict = {
            "input": self.input,
            "offset": self.offset,
            "mask": self.mask,
516
            "weight": self.weight,
517 518 519 520 521 522 523 524 525 526 527
        }
        if not self.no_bias:
            feed_dict["bias"] = self.bias

        out_v1, out_v2 = exe.run(main, feed=feed_dict, fetch_list=[y_v1, y_v2])
        return out_v1, out_v2

    def _test_identity(self):
        self.prepare()
        static_dcn_v1, static_dcn_v2 = self.static_graph_case_dcn()
        dy_dcn_v1, dy_dcn_v2 = self.dygraph_case_dcn()
528 529 530 531
        (
            new_static_dcn_v1,
            new_static_dcn_v2,
        ) = self.new_api_static_graph_case_dcn()
532 533 534 535 536 537 538 539 540 541 542 543 544
        np.testing.assert_array_almost_equal(static_dcn_v1, dy_dcn_v1)
        np.testing.assert_array_almost_equal(static_dcn_v2, dy_dcn_v2)
        np.testing.assert_array_almost_equal(static_dcn_v1, new_static_dcn_v1)
        np.testing.assert_array_almost_equal(static_dcn_v2, new_static_dcn_v2)

    def test_identity(self):
        self.place = paddle.CPUPlace()
        self._test_identity()

        if paddle.is_compiled_with_cuda():
            self.place = paddle.CUDAPlace(0)
            self._test_identity()

545 546 547 548
    def test_identity_with_eager_guard(self):
        with _test_eager_guard():
            self.test_identity()

549 550 551 552 553 554 555 556 557 558

# testcases for DeformConv2D
class TestDeformConv2DWithPadding(TestDeformConv2D):
    def setUp(self):
        self.in_channels = 3
        self.out_channels = 5
        self.kernel_size = [3, 3]
        self.padding = [2, 2]
        self.stride = [1, 1]
        self.dilation = [1, 1]
559
        self.deformable_groups = 1
560 561 562 563 564 565 566 567 568 569 570 571
        self.groups = 1
        self.no_bias = True


class TestDeformConv2DWithBias(TestDeformConv2D):
    def setUp(self):
        self.in_channels = 3
        self.out_channels = 5
        self.kernel_size = [3, 3]
        self.padding = [2, 2]
        self.stride = [1, 1]
        self.dilation = [1, 1]
572
        self.deformable_groups = 1
573 574 575 576 577 578 579 580 581 582 583 584
        self.groups = 1
        self.no_bias = False


class TestDeformConv2DWithAsynPadding(TestDeformConv2D):
    def setUp(self):
        self.in_channels = 3
        self.out_channels = 5
        self.kernel_size = [3, 3]
        self.padding = [1, 2]
        self.stride = [1, 1]
        self.dilation = [1, 1]
585
        self.deformable_groups = 1
586 587 588 589 590 591 592 593 594 595 596 597
        self.groups = 1
        self.no_bias = False


class TestDeformConv2DWithDilation(TestDeformConv2D):
    def setUp(self):
        self.in_channels = 3
        self.out_channels = 5
        self.kernel_size = [3, 3]
        self.padding = [1, 1]
        self.stride = [1, 1]
        self.dilation = [3, 3]
598
        self.deformable_groups = 1
599 600 601 602 603 604 605 606 607 608 609 610
        self.groups = 1
        self.no_bias = False


class TestDeformConv2DWithStride(TestDeformConv2D):
    def setUp(self):
        self.in_channels = 3
        self.out_channels = 5
        self.kernel_size = [3, 3]
        self.padding = [1, 1]
        self.stride = [2, 2]
        self.dilation = [1, 1]
611 612 613 614 615 616 617 618 619 620 621 622 623 624
        self.deformable_groups = 1
        self.groups = 1
        self.no_bias = False


class TestDeformConv2DWithDeformable_Groups(TestDeformConv2D):
    def setUp(self):
        self.in_channels = 5
        self.out_channels = 5
        self.kernel_size = [3, 3]
        self.padding = [1, 1]
        self.stride = [1, 1]
        self.dilation = [1, 1]
        self.deformable_groups = 5
625 626 627 628 629 630 631 632 633 634 635 636
        self.groups = 1
        self.no_bias = False


class TestDeformConv2DWithGroups(TestDeformConv2D):
    def setUp(self):
        self.in_channels = 5
        self.out_channels = 5
        self.kernel_size = [3, 3]
        self.padding = [1, 1]
        self.stride = [1, 1]
        self.dilation = [1, 1]
637
        self.deformable_groups = 1
638 639 640 641 642 643 644 645 646 647 648 649 650
        self.groups = 5
        self.no_bias = False


# testcases for deform_conv2d
class TestDeformConv2DFunctionalWithPadding(TestDeformConv2DFunctional):
    def setUp(self):
        self.in_channels = 3
        self.out_channels = 5
        self.kernel_size = [3, 3]
        self.padding = [2, 2]
        self.stride = [1, 1]
        self.dilation = [1, 1]
651
        self.deformable_groups = 1
652 653 654 655 656 657 658 659 660 661 662 663
        self.groups = 1
        self.no_bias = True


class TestDeformConv2DFunctionalWithBias(TestDeformConv2DFunctional):
    def setUp(self):
        self.in_channels = 3
        self.out_channels = 5
        self.kernel_size = [3, 3]
        self.padding = [2, 2]
        self.stride = [1, 1]
        self.dilation = [1, 1]
664
        self.deformable_groups = 1
665 666 667 668 669 670 671 672 673 674 675 676
        self.groups = 1
        self.no_bias = False


class TestDeformConv2DFunctionalWithAsynPadding(TestDeformConv2DFunctional):
    def setUp(self):
        self.in_channels = 3
        self.out_channels = 5
        self.kernel_size = [3, 3]
        self.padding = [1, 2]
        self.stride = [1, 1]
        self.dilation = [1, 1]
677
        self.deformable_groups = 1
678 679 680 681 682 683 684 685 686 687 688 689
        self.groups = 1
        self.no_bias = False


class TestDeformConv2DFunctionalWithDilation(TestDeformConv2DFunctional):
    def setUp(self):
        self.in_channels = 3
        self.out_channels = 5
        self.kernel_size = [3, 3]
        self.padding = [1, 1]
        self.stride = [1, 1]
        self.dilation = [3, 3]
690
        self.deformable_groups = 1
691 692 693 694 695 696 697 698 699 700 701 702
        self.groups = 1
        self.no_bias = False


class TestDeformConv2DFunctionalWithStride(TestDeformConv2DFunctional):
    def setUp(self):
        self.in_channels = 3
        self.out_channels = 5
        self.kernel_size = [3, 3]
        self.padding = [1, 1]
        self.stride = [2, 2]
        self.dilation = [1, 1]
703 704 705 706 707
        self.deformable_groups = 1
        self.groups = 1
        self.no_bias = False


708 709 710
class TestDeformConv2DFunctionalWithDeformable_Groups(
    TestDeformConv2DFunctional
):
711 712 713 714 715 716 717 718
    def setUp(self):
        self.in_channels = 5
        self.out_channels = 5
        self.kernel_size = [3, 3]
        self.padding = [1, 1]
        self.stride = [1, 1]
        self.dilation = [1, 1]
        self.deformable_groups = 5
719 720 721 722 723 724 725 726 727 728 729 730
        self.groups = 1
        self.no_bias = False


class TestDeformConv2DFunctionalWithGroups(TestDeformConv2DFunctional):
    def setUp(self):
        self.in_channels = 5
        self.out_channels = 5
        self.kernel_size = [3, 3]
        self.padding = [1, 1]
        self.stride = [1, 1]
        self.dilation = [1, 1]
731
        self.deformable_groups = 1
732 733 734 735 736 737
        self.groups = 5
        self.no_bias = False


if __name__ == "__main__":
    unittest.main()