test_conv2d_op.py 36.0 KB
Newer Older
1
#   Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
D
dzhwinter 已提交
2
#
D
dzhwinter 已提交
3 4 5
# 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
D
dzhwinter 已提交
6
#
D
dzhwinter 已提交
7
#     http://www.apache.org/licenses/LICENSE-2.0
D
dzhwinter 已提交
8
#
D
dzhwinter 已提交
9 10 11 12 13 14
# 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.

15 16
import unittest
import numpy as np
H
hong 已提交
17
import paddle
D
dzhwinter 已提交
18

19
import paddle
20
import paddle.fluid.core as core
L
liym27 已提交
21
import paddle.fluid as fluid
22 23 24
from paddle.fluid.tests.unittests.op_test import (OpTest,
                                                  convert_float_to_uint16,
                                                  get_numeric_gradient)
W
wuhuanzhou 已提交
25
from paddle.fluid.tests.unittests.testsuite import create_op
26
from paddle.fluid import Program, program_guard
27 28


L
liym27 已提交
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
def conv2d_forward_naive(input,
                         filter,
                         group,
                         conv_param,
                         padding_algorithm='EXPLICIT',
                         data_format='NCHW'):
    if padding_algorithm not in ["SAME", "VALID", "EXPLICIT"]:
        raise ValueError("Unknown Attr(padding_algorithm): '%s'. "
                         "It can only be 'SAME' or 'VALID'." %
                         str(padding_algorithm))

    if data_format not in ["NCHW", "NHWC"]:
        raise ValueError("Unknown Attr(data_format): '%s' ."
                         "It can only be 'NCHW' or 'NHWC'." % str(data_format))

    channel_last = (data_format == "NHWC")
    if channel_last:
        input = np.transpose(input, [0, 3, 1, 2])

C
chengduoZH 已提交
48
    in_n, in_c, in_h, in_w = input.shape
L
liym27 已提交
49 50 51
    f_n, f_c, f_h, f_w = filter.shape
    out_n = in_n
    out_c = f_n
C
chengduoZH 已提交
52 53
    assert f_c * group == in_c
    assert np.mod(out_c, group) == 0
M
minqiyang 已提交
54
    sub_out_c = out_c // group
L
liym27 已提交
55
    sub_f_n = f_n // group
C
chengduoZH 已提交
56

C
chengduoZH 已提交
57 58
    stride, pad, dilation = conv_param['stride'], conv_param['pad'], conv_param[
        'dilation']
L
liym27 已提交
59 60 61 62 63 64 65

    # update pad and dilation
    def _get_padding_with_SAME(input_shape, pool_size, pool_stride):
        padding = []
        for input_size, filter_size, stride_size in zip(input_shape, pool_size,
                                                        pool_stride):
            out_size = int((input_size + stride_size - 1) / stride_size)
66 67
            pad_sum = np.max(
                ((out_size - 1) * stride_size + filter_size - input_size, 0))
L
liym27 已提交
68 69 70 71 72 73 74 75 76 77 78
            pad_0 = int(pad_sum / 2)
            pad_1 = int(pad_sum - pad_0)
            padding.append(pad_0)
            padding.append(pad_1)
        return padding

    ksize = filter.shape[2:4]
    if padding_algorithm == "VALID":
        pad = [0, 0, 0, 0]
    elif padding_algorithm == "SAME":
        dilation = [1, 1]
79
        input_data_shape = input.shape[2:4]
L
liym27 已提交
80 81 82 83 84 85 86 87 88 89 90 91
        pad = _get_padding_with_SAME(input_data_shape, ksize, stride)

    pad_h_0, pad_h_1 = pad[0], pad[0]
    pad_w_0, pad_w_1 = pad[1], pad[1]
    if len(pad) == 4:
        pad_h_0, pad_h_1 = pad[0], pad[1]
        pad_w_0, pad_w_1 = pad[2], pad[3]
    out_h = 1 + (in_h + pad_h_0 + pad_h_1 - (dilation[0] *
                                             (f_h - 1) + 1)) // stride[0]
    out_w = 1 + (in_w + pad_w_0 + pad_w_1 - (dilation[1] *
                                             (f_w - 1) + 1)) // stride[1]
    out = np.zeros((out_n, out_c, out_h, out_w))
C
chengduoZH 已提交
92

武毅 已提交
93 94
    d_bolck_h = (dilation[0] * (f_h - 1) + 1)
    d_bolck_w = (dilation[1] * (f_w - 1) + 1)
C
chengduoZH 已提交
95

96 97
    input_pad = np.pad(input,
                       ((0, 0), (0, 0), (pad_h_0, pad_h_1), (pad_w_0, pad_w_1)),
C
chengduoZH 已提交
98 99
                       mode='constant',
                       constant_values=0)
C
chengduoZH 已提交
100

L
liym27 已提交
101
    filter_dilation = np.zeros((f_n, f_c, d_bolck_h, d_bolck_w))
102 103
    filter_dilation[:, :, 0:d_bolck_h:dilation[0],
                    0:d_bolck_w:dilation[1]] = filter
C
chengduoZH 已提交
104

C
chengduoZH 已提交
105 106 107
    for i in range(out_h):
        for j in range(out_w):
            for g in range(group):
C
chengduoZH 已提交
108 109
                input_pad_masked = \
                    input_pad[:, g * f_c:(g + 1) * f_c,
C
chengduoZH 已提交
110 111
                    i * stride[0]:i * stride[0] + d_bolck_h,
                    j * stride[1]:j * stride[1] + d_bolck_w]
C
chengduoZH 已提交
112

L
liym27 已提交
113 114
                f_sub = filter_dilation[g * sub_f_n:(g + 1) * sub_f_n, :, :, :]
                # sub_f_n == sub_out_c
C
chengduoZH 已提交
115
                for k in range(sub_out_c):
L
liym27 已提交
116
                    # Multiplication of Corresponding Elements, then sum all
C
chengduoZH 已提交
117 118 119
                    out[:, g * sub_out_c + k, i, j] = \
                        np.sum(input_pad_masked * f_sub[k, :, :, :],
                               axis=(1, 2, 3))
C
chengduoZH 已提交
120

L
liym27 已提交
121 122 123
    if channel_last:
        out = np.transpose(out, [0, 2, 3, 1])

124
    return out, in_n, out_h, out_w, out_c
C
chengduoZH 已提交
125 126


L
liym27 已提交
127
def create_test_cudnn_class(parent):
128

L
liym27 已提交
129 130 131
    @unittest.skipIf(not core.is_compiled_with_cuda(),
                     "core is not compiled with CUDA")
    class TestCUDNNCase(parent):
132

L
liym27 已提交
133 134
        def init_kernel_type(self):
            self.use_cudnn = True
135 136
            self.dtype = np.float32 if core.is_compiled_with_rocm(
            ) else np.float64
L
liym27 已提交
137 138 139 140 141 142 143

    cls_name = "{0}_{1}".format(parent.__name__, "CUDNN")
    TestCUDNNCase.__name__ = cls_name
    globals()[cls_name] = TestCUDNNCase


def create_test_cudnn_fp16_class(parent, grad_check=True):
144

L
liym27 已提交
145 146 147
    @unittest.skipIf(not core.is_compiled_with_cuda(),
                     "core is not compiled with CUDA")
    class TestConv2DCUDNNFp16(parent):
148

L
liym27 已提交
149 150 151 152 153 154 155 156 157 158 159 160 161
        def init_kernel_type(self):
            self.use_cudnn = True
            self.dtype = np.float16

        def test_check_output(self):
            if core.is_compiled_with_cuda():
                place = core.CUDAPlace(0)
                if core.is_float16_supported(place):
                    self.check_output_with_place(place, atol=2e-2)

        def test_check_grad_no_filter(self):
            place = core.CUDAPlace(0)
            if core.is_float16_supported(place) and grad_check:
162 163 164
                self.check_grad_with_place(place, ['Input'],
                                           'Output',
                                           no_grad_set=set(['Filter']))
L
liym27 已提交
165 166 167 168

        def test_check_grad_no_input(self):
            place = core.CUDAPlace(0)
            if core.is_float16_supported(place) and grad_check:
169 170 171
                self.check_grad_with_place(place, ['Filter'],
                                           'Output',
                                           no_grad_set=set(['Input']))
L
liym27 已提交
172 173 174 175 176 177

    cls_name = "{0}_{1}".format(parent.__name__, "CUDNNFp16")
    TestConv2DCUDNNFp16.__name__ = cls_name
    globals()[cls_name] = TestConv2DCUDNNFp16


W
wuhuanzhou 已提交
178
def create_test_cudnn_bf16_class(parent):
179

W
wuhuanzhou 已提交
180
    @unittest.skipIf(
181 182
        not core.is_compiled_with_cuda()
        or not core.is_bfloat16_supported(core.CUDAPlace(0)),
183
        "core is not compiled with CUDA and do not support bfloat16")
W
wuhuanzhou 已提交
184
    class TestConv2DCUDNNBF16(parent):
185

W
wuhuanzhou 已提交
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
        def get_numeric_grad(self, place, check_name):
            scope = core.Scope()
            self._check_grad_helper()
            op = create_op(scope, self.op_type, self.inputs, self.outputs,
                           self.attrs)
            return get_numeric_gradient(place, scope, op, self.inputs_fp32,
                                        check_name, ['Output'])

        def init_kernel_type(self):
            self.use_cudnn = True
            self.no_need_check_grad = True
            self.dtype = np.uint16

        def test_check_output(self):
            place = core.CUDAPlace(0)
            self.check_output_with_place(place, atol=1e-2)

        def test_check_grad_no_filter(self):
            place = core.CUDAPlace(0)
            numeric_grads = self.get_numeric_grad(place, 'Input')
206 207 208 209
            self.check_grad_with_place(place, ['Input'],
                                       'Output',
                                       no_grad_set=set(['Filter']),
                                       user_defined_grads=[numeric_grads])
W
wuhuanzhou 已提交
210 211 212 213

        def test_check_grad_no_input(self):
            place = core.CUDAPlace(0)
            numeric_grads = self.get_numeric_grad(place, 'Filter')
214 215 216 217
            self.check_grad_with_place(place, ['Filter'],
                                       'Output',
                                       no_grad_set=set(['Input']),
                                       user_defined_grads=[numeric_grads])
W
wuhuanzhou 已提交
218 219 220 221 222 223

    cls_name = "{0}_{1}".format(parent.__name__, "CUDNNBF16")
    TestConv2DCUDNNBF16.__name__ = cls_name
    globals()[cls_name] = TestConv2DCUDNNBF16


L
liym27 已提交
224
def create_test_channel_last_class(parent):
225

L
liym27 已提交
226
    class TestChannelLastCase(parent):
227

L
liym27 已提交
228 229 230 231 232 233 234 235 236 237 238 239 240
        def init_data_format(self):
            self.data_format = "NHWC"

        def init_test_case_2(self):
            N, C, H, W = self.input_size
            self.input_size = [N, H, W, C]

    cls_name = "{0}_{1}".format(parent.__name__, "ChannelLast")
    TestChannelLastCase.__name__ = cls_name
    globals()[cls_name] = TestChannelLastCase


def create_test_cudnn_channel_last_class(parent):
241

L
liym27 已提交
242 243 244
    @unittest.skipIf(not core.is_compiled_with_cuda(),
                     "core is not compiled with CUDA")
    class TestCudnnChannelLastCase(parent):
245

L
liym27 已提交
246 247
        def init_kernel_type(self):
            self.use_cudnn = True
248 249
            self.dtype = np.float32 if core.is_compiled_with_rocm(
            ) else np.float64
L
liym27 已提交
250 251 252 253 254 255 256 257 258 259 260 261 262

        def init_data_format(self):
            self.data_format = "NHWC"

        def init_test_case_2(self):
            N, C, H, W = self.input_size
            self.input_size = [N, H, W, C]

    cls_name = "{0}_{1}".format(parent.__name__, "CudnnChannelLast")
    TestCudnnChannelLastCase.__name__ = cls_name
    globals()[cls_name] = TestCudnnChannelLastCase


263
def create_test_cudnn_channel_last_fp16_class(parent, grad_check=True):
264

265 266 267
    @unittest.skipIf(not core.is_compiled_with_cuda(),
                     "core is not compiled with CUDA")
    class TestCudnnChannelLastFp16(parent):
268

269 270 271 272 273 274 275 276 277 278 279 280 281
        def init_kernel_type(self):
            self.use_cudnn = True
            self.dtype = np.float16

        def test_check_output(self):
            if core.is_compiled_with_cuda():
                place = core.CUDAPlace(0)
                if core.is_float16_supported(place):
                    self.check_output_with_place(place, atol=2e-2)

        def test_check_grad_no_filter(self):
            place = core.CUDAPlace(0)
            if core.is_float16_supported(place) and grad_check:
282 283 284
                self.check_grad_with_place(place, ['Input'],
                                           'Output',
                                           no_grad_set=set(['Filter']))
285 286 287 288

        def test_check_grad_no_input(self):
            place = core.CUDAPlace(0)
            if core.is_float16_supported(place) and grad_check:
289 290 291
                self.check_grad_with_place(place, ['Filter'],
                                           'Output',
                                           no_grad_set=set(['Input']))
292 293 294 295 296 297 298 299 300 301 302 303 304

        def init_data_format(self):
            self.data_format = "NHWC"

        def init_test_case_2(self):
            N, C, H, W = self.input_size
            self.input_size = [N, H, W, C]

    cls_name = "{0}_{1}".format(parent.__name__, "CudnnChannelLastFp16")
    TestCudnnChannelLastFp16.__name__ = cls_name
    globals()[cls_name] = TestCudnnChannelLastFp16


L
liym27 已提交
305
def create_test_padding_SAME_class(parent):
306

L
liym27 已提交
307
    class TestPaddingSMAECase(parent):
308

L
liym27 已提交
309 310 311 312 313 314 315 316 317 318
        def init_paddings(self):
            self.pad = [0, 0]
            self.padding_algorithm = "SAME"

    cls_name = "{0}_{1}".format(parent.__name__, "PaddingSAMEOp")
    TestPaddingSMAECase.__name__ = cls_name
    globals()[cls_name] = TestPaddingSMAECase


def create_test_padding_VALID_class(parent):
319

L
liym27 已提交
320
    class TestPaddingVALIDCase(parent):
321

L
liym27 已提交
322 323 324 325 326 327 328 329 330 331
        def init_paddings(self):
            self.pad = [1, 1]
            self.padding_algorithm = "VALID"

    cls_name = "{0}_{1}".format(parent.__name__, "PaddingVALIDOp")
    TestPaddingVALIDCase.__name__ = cls_name
    globals()[cls_name] = TestPaddingVALIDCase


def create_test_cudnn_padding_SAME_class(parent):
332

L
liym27 已提交
333 334 335
    @unittest.skipIf(not core.is_compiled_with_cuda(),
                     "core is not compiled with CUDA")
    class TestCUDNNPaddingSMAECase(parent):
336

L
liym27 已提交
337 338
        def init_kernel_type(self):
            self.use_cudnn = True
339 340
            self.dtype = np.float32 if core.is_compiled_with_rocm(
            ) else np.float64
L
liym27 已提交
341 342 343 344 345 346 347 348 349 350 351

        def init_paddings(self):
            self.pad = [1, 1]
            self.padding_algorithm = "SAME"

    cls_name = "{0}_{1}".format(parent.__name__, "CudnnPaddingSAMEOp")
    TestCUDNNPaddingSMAECase.__name__ = cls_name
    globals()[cls_name] = TestCUDNNPaddingSMAECase


def create_test_cudnn_padding_VALID_class(parent):
352

L
liym27 已提交
353 354 355
    @unittest.skipIf(not core.is_compiled_with_cuda(),
                     "core is not compiled with CUDA")
    class TestCUDNNPaddingVALIDCase(parent):
356

L
liym27 已提交
357 358
        def init_kernel_type(self):
            self.use_cudnn = True
359 360
            self.dtype = np.float32 if core.is_compiled_with_rocm(
            ) else np.float64
L
liym27 已提交
361 362 363 364 365 366 367 368 369 370

        def init_paddings(self):
            self.pad = [1, 1]
            self.padding_algorithm = "VALID"

    cls_name = "{0}_{1}".format(parent.__name__, "CudnnPaddingVALIDOp")
    TestCUDNNPaddingVALIDCase.__name__ = cls_name
    globals()[cls_name] = TestCUDNNPaddingVALIDCase


C
cnn 已提交
371
class TestConv2DOp(OpTest):
372

373
    def setUp(self):
K
Kexin Zhao 已提交
374
        self.op_type = "conv2d"
375
        self.use_cudnn = False
376
        self.exhaustive_search = False
377
        self.use_cuda = False
378
        self.use_mkldnn = False
379
        self.fuse_relu_before_depthwise_conv = False
380
        self.data_format = "AnyLayout"
381
        self.dtype = np.float64
K
Kexin Zhao 已提交
382
        self.init_kernel_type()
C
chengduoZH 已提交
383
        self.init_group()
C
chengduoZH 已提交
384
        self.init_dilation()
C
chengduoZH 已提交
385
        self.init_test_case()
C
chengduoZH 已提交
386

C
chengduoZH 已提交
387 388 389 390 391
        conv2d_param = {
            'stride': self.stride,
            'pad': self.pad,
            'dilation': self.dilations
        }
392

W
wuhuanzhou 已提交
393 394 395 396 397 398 399 400 401
        if self.is_bfloat16_op():
            input = np.random.random(self.input_size).astype(np.float32)
            filter = np.random.uniform(-1, 1,
                                       self.filter_size).astype(np.float32)
        else:
            input = np.random.random(self.input_size).astype(self.dtype)
            filter = np.random.uniform(-1, 1,
                                       self.filter_size).astype(self.dtype)

G
guomingz 已提交
402
        if not self.has_cuda():
403 404 405 406 407 408 409 410
            self.fuse_relu_before_depthwise_conv = False
        if self.fuse_relu_before_depthwise_conv:
            input = input - 0.5
            input -= (input < 0) * 0.1
            input += (input >= 0) * 0.1
            input2 = np.maximum(input, 0.0)
        else:
            input2 = input
L
liym27 已提交
411

412
        output, _, _, _, _ = conv2d_forward_naive(input2, filter, self.groups,
413
                                                  conv2d_param)
K
Kexin Zhao 已提交
414

W
wuhuanzhou 已提交
415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431
        if self.is_bfloat16_op():
            output = output.astype(np.float32)
            self.inputs = {
                'Input': convert_float_to_uint16(input),
                'Filter': convert_float_to_uint16(filter)
            }
            self.inputs_fp32 = {
                'Input': OpTest.np_dtype_to_fluid_dtype(input),
                'Filter': OpTest.np_dtype_to_fluid_dtype(filter)
            }
        else:
            output = output.astype(self.dtype)
            self.inputs = {
                'Input': OpTest.np_dtype_to_fluid_dtype(input),
                'Filter': OpTest.np_dtype_to_fluid_dtype(filter)
            }

H
hedaoyuan 已提交
432
        self.attrs = {
C
chengduoZH 已提交
433 434
            'strides': self.stride,
            'paddings': self.pad,
C
chengduoZH 已提交
435
            'groups': self.groups,
436
            'dilations': self.dilations,
437
            'use_cudnn': self.use_cudnn,
438
            'use_mkldnn': self.use_mkldnn,
439
            'data_format': self.data_format,
440 441
            'fuse_relu_before_depthwise_conv':
            self.fuse_relu_before_depthwise_conv,
442
            'exhaustive_search': self.exhaustive_search
H
hedaoyuan 已提交
443
        }
444 445
        self.outputs = {'Output': output}

G
guomingz 已提交
446
    def has_cuda(self):
447 448
        return core.is_compiled_with_cuda() and (self.use_cudnn
                                                 or self.use_cuda)
449

H
hedaoyuan 已提交
450
    def test_check_output(self):
G
guomingz 已提交
451
        place = core.CUDAPlace(0) if self.has_cuda() else core.CPUPlace()
452
        # TODO(wangzhongpu): support mkldnn op in dygraph mode
453 454 455
        self.check_output_with_place(place,
                                     atol=1e-5,
                                     check_dygraph=(self.use_mkldnn == False))
H
hedaoyuan 已提交
456

H
hedaoyuan 已提交
457
    def test_check_grad(self):
458 459
        if self.dtype == np.float16 or (hasattr(self, "no_need_check_grad")
                                        and self.no_need_check_grad == True):
K
Kexin Zhao 已提交
460
            return
G
guomingz 已提交
461
        place = core.CUDAPlace(0) if self.has_cuda() else core.CPUPlace()
462
        # TODO(wangzhongpu): support mkldnn op in dygraph mode
463 464 465 466
        self.check_grad_with_place(place, {'Input', 'Filter'},
                                   'Output',
                                   max_relative_error=0.02,
                                   check_dygraph=(self.use_mkldnn == False))
H
hedaoyuan 已提交
467

468
    def test_check_grad_no_filter(self):
469 470
        if self.dtype == np.float16 or (hasattr(self, "no_need_check_grad")
                                        and self.no_need_check_grad == True):
K
Kexin Zhao 已提交
471
            return
G
guomingz 已提交
472
        place = core.CUDAPlace(0) if self.has_cuda() else core.CPUPlace()
473
        # TODO(wangzhongpu): support mkldnn op in dygraph mode
474 475 476 477 478
        self.check_grad_with_place(place, ['Input'],
                                   'Output',
                                   max_relative_error=0.02,
                                   no_grad_set=set(['Filter']),
                                   check_dygraph=(self.use_mkldnn == False))
479 480

    def test_check_grad_no_input(self):
481 482
        if self.dtype == np.float16 or (hasattr(self, "no_need_check_grad")
                                        and self.no_need_check_grad == True):
K
Kexin Zhao 已提交
483
            return
G
guomingz 已提交
484
        place = core.CUDAPlace(0) if self.has_cuda() else core.CPUPlace()
485
        # TODO(wangzhongpu): support mkldnn op in dygraph mode
486 487 488 489
        self.check_grad_with_place(place, ['Filter'],
                                   'Output',
                                   no_grad_set=set(['Input']),
                                   check_dygraph=(self.use_mkldnn == False))
490

C
chengduoZH 已提交
491 492 493 494 495
    def init_test_case(self):
        self.pad = [0, 0]
        self.stride = [1, 1]
        self.input_size = [2, 3, 5, 5]  # NCHW
        assert np.mod(self.input_size[1], self.groups) == 0
M
minqiyang 已提交
496
        f_c = self.input_size[1] // self.groups
C
chengduoZH 已提交
497 498
        self.filter_size = [6, f_c, 3, 3]

L
liym27 已提交
499 500 501
    def init_test_case_2(self):
        pass

C
chengduoZH 已提交
502 503 504
    def init_dilation(self):
        self.dilations = [1, 1]

C
chengduoZH 已提交
505
    def init_group(self):
H
hedaoyuan 已提交
506 507
        self.groups = 1

K
Kexin Zhao 已提交
508 509
    def init_kernel_type(self):
        pass
武毅 已提交
510

H
hedaoyuan 已提交
511

C
cnn 已提交
512
class TestWithPad(TestConv2DOp):
513

C
chengduoZH 已提交
514 515 516 517 518
    def init_test_case(self):
        self.pad = [1, 1]
        self.stride = [1, 1]
        self.input_size = [2, 3, 5, 5]  # NCHW
        assert np.mod(self.input_size[1], self.groups) == 0
M
minqiyang 已提交
519
        f_c = self.input_size[1] // self.groups
C
chengduoZH 已提交
520 521 522
        self.filter_size = [6, f_c, 3, 3]


C
cnn 已提交
523
class TestWithStride(TestConv2DOp):
524

C
chengduoZH 已提交
525 526 527 528 529
    def init_test_case(self):
        self.pad = [1, 1]
        self.stride = [2, 2]
        self.input_size = [2, 3, 6, 6]  # NCHW
        assert np.mod(self.input_size[1], self.groups) == 0
M
minqiyang 已提交
530
        f_c = self.input_size[1] // self.groups
C
chengduoZH 已提交
531 532 533
        self.filter_size = [6, f_c, 3, 3]


C
cnn 已提交
534
class TestWithGroup(TestConv2DOp):
535

Z
zhupengyang 已提交
536 537 538 539 540 541 542 543
    def init_test_case(self):
        self.pad = [0, 0]
        self.stride = [1, 1]
        self.input_size = [2, 3, 5, 5]  # NCHW
        self.group = 3
        assert np.mod(self.input_size[1], self.groups) == 0
        f_c = self.input_size[1] // self.groups
        self.filter_size = [18, f_c, 3, 3]
H
hedaoyuan 已提交
544

武毅 已提交
545

C
cnn 已提交
546
class TestWith1x1(TestConv2DOp):
547

C
chengduoZH 已提交
548 549 550 551 552
    def init_test_case(self):
        self.pad = [0, 0]
        self.stride = [1, 1]
        self.input_size = [2, 3, 5, 5]  # NCHW
        assert np.mod(self.input_size[1], self.groups) == 0
M
minqiyang 已提交
553
        f_c = self.input_size[1] // self.groups
Z
zhupengyang 已提交
554
        self.filter_size = [120, f_c, 1, 1]
C
chengduoZH 已提交
555 556 557 558 559

    def init_group(self):
        self.groups = 3


C
cnn 已提交
560
class TestWithDepthWise3x3(TestConv2DOp):
561

562 563 564 565 566 567
    def init_test_case(self):
        self.pad = [1, 1]
        self.stride = [1, 1]
        self.input_size = [3, 4, 10, 10]  # NCHW
        assert np.mod(self.input_size[1], self.groups) == 0
        f_c = self.input_size[1] // self.groups
Z
zhupengyang 已提交
568
        self.filter_size = [12, f_c, 3, 3]
569 570 571 572 573 574 575 576

    def init_dilation(self):
        self.dilations = [2, 2]

    def init_group(self):
        self.groups = 4


C
cnn 已提交
577
class TestWithDepthWise5x5(TestConv2DOp):
578

579 580 581 582 583 584 585 586 587 588 589 590
    def init_test_case(self):
        self.pad = [0, 0]
        self.stride = [1, 1]
        self.input_size = [2, 4, 10, 10]  # NCHW
        assert np.mod(self.input_size[1], self.groups) == 0
        f_c = self.input_size[1] // self.groups
        self.filter_size = [8, f_c, 5, 5]

    def init_group(self):
        self.groups = 4


C
cnn 已提交
591
class TestWithDepthWise7x7(TestConv2DOp):
592

593 594 595 596 597 598 599 600 601 602 603 604
    def init_test_case(self):
        self.pad = [1, 1]
        self.stride = [2, 2]
        self.input_size = [2, 8, 10, 10]  # NCHW
        assert np.mod(self.input_size[1], self.groups) == 0
        f_c = self.input_size[1] // self.groups
        self.filter_size = [16, f_c, 7, 7]

    def init_group(self):
        self.groups = 8


C
cnn 已提交
605
class TestWithDilation(TestConv2DOp):
606

C
chengduoZH 已提交
607 608 609 610 611
    def init_test_case(self):
        self.pad = [0, 0]
        self.stride = [1, 1]
        self.input_size = [2, 3, 10, 10]  # NCHW
        assert np.mod(self.input_size[1], self.groups) == 0
M
minqiyang 已提交
612
        f_c = self.input_size[1] // self.groups
Z
zhupengyang 已提交
613
        self.filter_size = [12, f_c, 3, 3]
C
chengduoZH 已提交
614

C
chengduoZH 已提交
615 616
    def init_dilation(self):
        self.dilations = [2, 2]
C
chengduoZH 已提交
617

C
chengduoZH 已提交
618
    def init_group(self):
C
chengduoZH 已提交
619
        self.groups = 3
武毅 已提交
620

C
chengduoZH 已提交
621

C
cnn 已提交
622
class TestWithInput1x1Filter1x1(TestConv2DOp):
623

624 625 626
    def init_test_case(self):
        self.pad = [0, 0]
        self.stride = [1, 1]
Z
zhupengyang 已提交
627
        self.input_size = [100, 3, 1, 1]  # NCHW
628
        assert np.mod(self.input_size[1], self.groups) == 0
M
minqiyang 已提交
629
        f_c = self.input_size[1] // self.groups
Z
zhupengyang 已提交
630
        self.filter_size = [120, f_c, 1, 1]
631 632 633 634 635

    def init_group(self):
        self.groups = 3


H
hong 已提交
636
# #----------------Conv2DCUDNN----------------
C
chengduoZH 已提交
637

C
cnn 已提交
638
create_test_cudnn_class(TestConv2DOp)
C
chengduo 已提交
639 640 641 642 643
create_test_cudnn_class(TestWithPad)
create_test_cudnn_class(TestWithStride)
create_test_cudnn_class(TestWithGroup)
create_test_cudnn_class(TestWith1x1)
create_test_cudnn_class(TestWithInput1x1Filter1x1)
K
Kexin Zhao 已提交
644

C
cnn 已提交
645
#----------------Conv2DCUDNN fp16----------------
C
chengduo 已提交
646

C
cnn 已提交
647
create_test_cudnn_fp16_class(TestConv2DOp, grad_check=False)
C
chengduo 已提交
648 649 650 651 652
create_test_cudnn_fp16_class(TestWithPad, grad_check=False)
create_test_cudnn_fp16_class(TestWithStride, grad_check=False)
create_test_cudnn_fp16_class(TestWithGroup, grad_check=False)
create_test_cudnn_fp16_class(TestWith1x1, grad_check=False)
create_test_cudnn_fp16_class(TestWithInput1x1Filter1x1, grad_check=False)
C
chengduo 已提交
653

W
wuhuanzhou 已提交
654 655 656 657 658 659 660 661 662
#----------------Conv2DCUDNN bf16----------------

create_test_cudnn_bf16_class(TestConv2DOp)
create_test_cudnn_bf16_class(TestWithPad)
create_test_cudnn_bf16_class(TestWithStride)
create_test_cudnn_bf16_class(TestWithGroup)
create_test_cudnn_bf16_class(TestWith1x1)
create_test_cudnn_bf16_class(TestWithInput1x1Filter1x1)

663

C
cnn 已提交
664
class TestCUDNNExhaustiveSearch(TestConv2DOp):
665

666 667 668
    def init_kernel_type(self):
        self.use_cudnn = True
        self.exhaustive_search = True
669
        self.dtype = np.float32 if core.is_compiled_with_rocm() else np.float64
670 671


C
cnn 已提交
672
class TestConv2DOpError(unittest.TestCase):
673

674 675 676 677 678
    def test_errors(self):
        with program_guard(Program(), Program()):

            def test_Variable():
                # the input of conv2d must be Variable.
679 680
                x1 = fluid.create_lod_tensor(np.array([-1, 3, 5, 5]),
                                             [[1, 1, 1, 1]], fluid.CPUPlace())
681 682 683 684 685 686 687
                fluid.layers.conv2d(x1, 1, 1)

            self.assertRaises(TypeError, test_Variable)

            def test_dtype():
                # the input dtype of conv2d must be float16 or float32 or float64
                # float16 only can be set on GPU place
688 689 690
                x2 = fluid.layers.data(name='x2',
                                       shape=[3, 4, 5, 6],
                                       dtype="int32")
691 692 693 694 695
                fluid.layers.conv2d(x2, 1, 1)

            self.assertRaises(TypeError, test_dtype)


696 697
# Please Don't remove the following code.
# Currently, CI use cudnn V5.0 which not support dilation conv.
698
# class TestCUDNNWithDilation(TestWithDilation):
C
chengduoZH 已提交
699 700 701
#     def init_op_type(self):
#         self.op_type = "conv_cudnn"

L
liym27 已提交
702 703 704
# ---- test asymmetric padding ----


C
cnn 已提交
705
class TestConv2DOp_v2(OpTest):
706

L
liym27 已提交
707 708 709 710 711 712 713
    def setUp(self):
        self.op_type = "conv2d"
        self.use_cudnn = False
        self.exhaustive_search = False
        self.use_cuda = False
        self.use_mkldnn = False
        self.fuse_relu_before_depthwise_conv = False
714
        self.dtype = np.float64
L
liym27 已提交
715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739
        self.init_kernel_type()
        self.init_group()
        self.init_dilation()
        self.init_data_format()
        self.init_test_case()
        self.init_paddings()
        self.init_test_case_2()

        conv2d_param = {
            'stride': self.stride,
            'pad': self.pad,
            'dilation': self.dilations
        }

        input = np.random.random(self.input_size).astype(self.dtype)
        if not self.has_cuda():
            self.fuse_relu_before_depthwise_conv = False
        if self.fuse_relu_before_depthwise_conv:
            input = input - 0.5
            input -= (input < 0) * 0.1
            input += (input >= 0) * 0.1
            input2 = np.maximum(input, 0.0)
        else:
            input2 = input
        filter = np.random.uniform(-1, 1, self.filter_size).astype(self.dtype)
740 741 742 743
        output, _, _, _, _ = conv2d_forward_naive(input2, filter, self.groups,
                                                  conv2d_param,
                                                  self.padding_algorithm,
                                                  self.data_format)
L
liym27 已提交
744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765
        output = output.astype(self.dtype)

        self.inputs = {
            'Input': OpTest.np_dtype_to_fluid_dtype(input),
            'Filter': OpTest.np_dtype_to_fluid_dtype(filter)
        }
        self.attrs = {
            'strides': self.stride,
            'paddings': self.pad,
            'padding_algorithm': self.padding_algorithm,
            'groups': self.groups,
            'dilations': self.dilations,
            'use_cudnn': self.use_cudnn,
            'use_mkldnn': self.use_mkldnn,
            'data_format': self.data_format,
            'fuse_relu_before_depthwise_conv':
            self.fuse_relu_before_depthwise_conv,
            'exhaustive_search': self.exhaustive_search
        }
        self.outputs = {'Output': output}

    def has_cuda(self):
766 767
        return core.is_compiled_with_cuda() and (self.use_cudnn
                                                 or self.use_cuda)
L
liym27 已提交
768 769

    def test_check_output(self):
770
        # TODO(wangzhongpu): support mkldnn op in dygraph mode
L
liym27 已提交
771
        place = core.CUDAPlace(0) if self.has_cuda() else core.CPUPlace()
772 773 774
        self.check_output_with_place(place,
                                     atol=1e-5,
                                     check_dygraph=(self.use_mkldnn == False))
L
liym27 已提交
775 776

    def test_check_grad(self):
777
        # TODO(wangzhongpu): support mkldnn op in dygraph mode
L
liym27 已提交
778 779 780
        if self.dtype == np.float16:
            return
        place = core.CUDAPlace(0) if self.has_cuda() else core.CPUPlace()
781 782 783 784
        self.check_grad_with_place(place, {'Input', 'Filter'},
                                   'Output',
                                   max_relative_error=0.02,
                                   check_dygraph=(self.use_mkldnn == False))
L
liym27 已提交
785 786

    def test_check_grad_no_filter(self):
787
        # TODO(wangzhongpu): support mkldnn op in dygraph mode
L
liym27 已提交
788 789 790
        if self.dtype == np.float16:
            return
        place = core.CUDAPlace(0) if self.has_cuda() else core.CPUPlace()
791 792 793 794 795
        self.check_grad_with_place(place, ['Input'],
                                   'Output',
                                   max_relative_error=0.02,
                                   no_grad_set=set(['Filter']),
                                   check_dygraph=(self.use_mkldnn == False))
L
liym27 已提交
796 797

    def test_check_grad_no_input(self):
798
        # TODO(wangzhongpu): support mkldnn op in dygraph mode
L
liym27 已提交
799 800 801
        if self.dtype == np.float16:
            return
        place = core.CUDAPlace(0) if self.has_cuda() else core.CPUPlace()
802 803 804 805
        self.check_grad_with_place(place, ['Filter'],
                                   'Output',
                                   no_grad_set=set(['Input']),
                                   check_dygraph=(self.use_mkldnn == False))
L
liym27 已提交
806 807 808

    def init_test_case(self):
        self.pad = [0, 0]
809
        self.stride = [1, 2]
L
liym27 已提交
810 811 812
        self.input_size = [2, 3, 5, 5]  # NCHW
        assert np.mod(self.input_size[1], self.groups) == 0
        f_c = self.input_size[1] // self.groups
813
        self.filter_size = [6, f_c, 4, 3]
L
liym27 已提交
814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834

    def init_dilation(self):
        self.dilations = [1, 1]

    def init_group(self):
        self.groups = 1

    def init_kernel_type(self):
        pass

    def init_paddings(self):
        self.pad = [0, 0]
        self.padding_algorithm = "EXPLICIT"

    def init_data_format(self):
        self.data_format = "NCHW"

    def init_test_case_2(self):
        pass


C
cnn 已提交
835
class TestConv2DOp_AsyPadding(TestConv2DOp_v2):
836

L
liym27 已提交
837 838 839 840 841
    def init_paddings(self):
        self.pad = [0, 0, 1, 2]
        self.padding_algorithm = "EXPLICIT"


C
cnn 已提交
842
class TestWithPad_AsyPadding(TestConv2DOp_v2):
843

L
liym27 已提交
844 845 846 847 848 849 850 851 852 853 854 855
    def init_test_case(self):
        self.stride = [1, 1]
        self.input_size = [2, 3, 5, 5]  # NCHW
        assert np.mod(self.input_size[1], self.groups) == 0
        f_c = self.input_size[1] // self.groups
        self.filter_size = [6, f_c, 3, 3]

    def init_paddings(self):
        self.pad = [2, 1, 3, 2]
        self.padding_algorithm = "EXPLICIT"


C
cnn 已提交
856
class TestWithStride_AsyPadding(TestConv2DOp_v2):
857

L
liym27 已提交
858 859 860 861 862 863 864 865 866 867 868 869
    def init_test_case(self):
        self.stride = [2, 2]
        self.input_size = [2, 3, 6, 6]  # NCHW
        assert np.mod(self.input_size[1], self.groups) == 0
        f_c = self.input_size[1] // self.groups
        self.filter_size = [6, f_c, 3, 3]

    def init_paddings(self):
        self.pad = [2, 1, 3, 2]
        self.padding_algorithm = "EXPLICIT"


C
cnn 已提交
870
class TestWithGroup_AsyPadding(TestConv2DOp_v2):
871

Z
zhupengyang 已提交
872 873 874 875 876 877 878 879
    def init_test_case(self):
        self.pad = [0, 0]
        self.stride = [1, 2]
        self.input_size = [2, 3, 5, 5]  # NCHW
        self.group = 3
        assert np.mod(self.input_size[1], self.groups) == 0
        f_c = self.input_size[1] // self.groups
        self.filter_size = [24, f_c, 4, 3]
L
liym27 已提交
880 881


C
cnn 已提交
882
class TestWith1x1_AsyPadding(TestConv2DOp_v2):
883

L
liym27 已提交
884 885 886 887 888
    def init_test_case(self):
        self.stride = [1, 1]
        self.input_size = [2, 3, 5, 5]  # NCHW
        assert np.mod(self.input_size[1], self.groups) == 0
        f_c = self.input_size[1] // self.groups
Z
zhupengyang 已提交
889
        self.filter_size = [120, f_c, 1, 1]
L
liym27 已提交
890 891 892 893 894 895 896 897 898

    def init_group(self):
        self.groups = 3

    def init_paddings(self):
        self.pad = [2, 2, 4, 0]
        self.padding_algorithm = "EXPLICIT"


C
cnn 已提交
899
class TestWithDepthWise3x3_AsyPadding(TestConv2DOp_v2):
900

L
liym27 已提交
901 902 903 904 905
    def init_test_case(self):
        self.stride = [1, 1]
        self.input_size = [3, 4, 10, 10]  # NCHW
        assert np.mod(self.input_size[1], self.groups) == 0
        f_c = self.input_size[1] // self.groups
Z
zhupengyang 已提交
906
        self.filter_size = [16, f_c, 3, 3]
L
liym27 已提交
907 908 909 910 911 912 913 914 915 916 917 918

    def init_dilation(self):
        self.dilations = [2, 2]

    def init_group(self):
        self.groups = 4

    def init_paddings(self):
        self.pad = [1, 3, 2, 1]
        self.padding_algorithm = "EXPLICIT"


C
cnn 已提交
919
class TestWithDepthWise5x5_AsyPadding(TestConv2DOp_v2):
920

L
liym27 已提交
921 922 923 924 925 926 927 928 929 930 931 932 933 934 935
    def init_test_case(self):
        self.stride = [1, 1]
        self.input_size = [2, 4, 10, 10]  # NCHW
        assert np.mod(self.input_size[1], self.groups) == 0
        f_c = self.input_size[1] // self.groups
        self.filter_size = [8, f_c, 5, 5]

    def init_group(self):
        self.groups = 4

    def init_paddings(self):
        self.pad = [0, 1, 1, 0]
        self.padding_algorithm = "EXPLICIT"


C
cnn 已提交
936
class TestWithDepthWise7x7_AsyPadding(TestConv2DOp_v2):
937

L
liym27 已提交
938 939 940 941 942 943 944 945 946 947 948 949 950 951 952
    def init_test_case(self):
        self.stride = [2, 2]
        self.input_size = [2, 8, 10, 10]  # NCHW
        assert np.mod(self.input_size[1], self.groups) == 0
        f_c = self.input_size[1] // self.groups
        self.filter_size = [16, f_c, 7, 7]

    def init_group(self):
        self.groups = 8

    def init_paddings(self):
        self.pad = [1, 3, 4, 1]
        self.padding_algorithm = "EXPLICIT"


C
cnn 已提交
953
class TestWithDilation_AsyPadding(TestConv2DOp_v2):
954

L
liym27 已提交
955 956 957 958 959
    def init_test_case(self):
        self.stride = [1, 1]
        self.input_size = [2, 3, 10, 10]  # NCHW
        assert np.mod(self.input_size[1], self.groups) == 0
        f_c = self.input_size[1] // self.groups
Z
zhupengyang 已提交
960
        self.filter_size = [24, f_c, 3, 3]
L
liym27 已提交
961 962 963 964 965 966 967 968 969 970 971 972

    def init_dilation(self):
        self.dilations = [2, 2]

    def init_group(self):
        self.groups = 3

    def init_paddings(self):
        self.pad = [0, 1, 3, 0]
        self.padding_algorithm = "EXPLICIT"


C
cnn 已提交
973
class TestWithInput1x1Filter1x1_AsyPadding(TestConv2DOp_v2):
974

L
liym27 已提交
975 976
    def init_test_case(self):
        self.stride = [1, 1]
Z
zhupengyang 已提交
977
        self.input_size = [40, 3, 1, 1]  # NCHW
L
liym27 已提交
978 979
        assert np.mod(self.input_size[1], self.groups) == 0
        f_c = self.input_size[1] // self.groups
Z
zhupengyang 已提交
980
        self.filter_size = [120, f_c, 1, 1]
L
liym27 已提交
981 982 983 984 985 986 987 988 989

    def init_group(self):
        self.groups = 3

    def init_paddings(self):
        self.pad = [0, 3, 4, 0]
        self.padding_algorithm = "EXPLICIT"


C
cnn 已提交
990
create_test_cudnn_class(TestConv2DOp_AsyPadding)
L
liym27 已提交
991 992 993 994 995 996 997
create_test_cudnn_class(TestWithPad_AsyPadding)
create_test_cudnn_class(TestWithStride_AsyPadding)
create_test_cudnn_class(TestWithGroup_AsyPadding)
create_test_cudnn_class(TestWith1x1_AsyPadding)
create_test_cudnn_class(TestWithInput1x1Filter1x1_AsyPadding)

#---------- test SAME VALID -----------
C
cnn 已提交
998
create_test_padding_SAME_class(TestConv2DOp_AsyPadding)
L
liym27 已提交
999 1000 1001 1002 1003
create_test_padding_SAME_class(TestWithPad_AsyPadding)
create_test_padding_SAME_class(TestWithStride_AsyPadding)
create_test_padding_SAME_class(TestWithGroup_AsyPadding)
create_test_padding_SAME_class(TestWithInput1x1Filter1x1_AsyPadding)

C
cnn 已提交
1004
create_test_padding_VALID_class(TestConv2DOp_AsyPadding)
L
liym27 已提交
1005 1006 1007 1008 1009
create_test_padding_VALID_class(TestWithPad_AsyPadding)
create_test_padding_VALID_class(TestWithStride_AsyPadding)
create_test_padding_VALID_class(TestWithGroup_AsyPadding)
create_test_padding_VALID_class(TestWithInput1x1Filter1x1_AsyPadding)

C
cnn 已提交
1010
create_test_cudnn_padding_SAME_class(TestConv2DOp_AsyPadding)
L
liym27 已提交
1011 1012 1013 1014 1015
create_test_cudnn_padding_SAME_class(TestWithPad_AsyPadding)
create_test_cudnn_padding_SAME_class(TestWithStride_AsyPadding)
create_test_cudnn_padding_SAME_class(TestWithGroup_AsyPadding)
create_test_cudnn_padding_SAME_class(TestWithInput1x1Filter1x1_AsyPadding)

C
cnn 已提交
1016
create_test_cudnn_padding_VALID_class(TestConv2DOp_AsyPadding)
L
liym27 已提交
1017 1018 1019 1020 1021 1022
create_test_cudnn_padding_VALID_class(TestWithPad_AsyPadding)
create_test_cudnn_padding_VALID_class(TestWithStride_AsyPadding)
create_test_cudnn_padding_VALID_class(TestWithGroup_AsyPadding)
create_test_cudnn_padding_VALID_class(TestWithInput1x1Filter1x1_AsyPadding)

# ------------ test channel last ---------
C
cnn 已提交
1023
create_test_channel_last_class(TestConv2DOp_AsyPadding)
L
liym27 已提交
1024 1025 1026 1027 1028
create_test_channel_last_class(TestWithPad_AsyPadding)
create_test_channel_last_class(TestWithGroup_AsyPadding)
create_test_channel_last_class(TestWith1x1_AsyPadding)
create_test_channel_last_class(TestWithInput1x1Filter1x1_AsyPadding)

C
cnn 已提交
1029
create_test_cudnn_channel_last_class(TestConv2DOp_AsyPadding)
L
liym27 已提交
1030 1031 1032 1033 1034
create_test_cudnn_channel_last_class(TestWithPad_AsyPadding)
create_test_cudnn_channel_last_class(TestWithStride_AsyPadding)
create_test_cudnn_channel_last_class(TestWithGroup_AsyPadding)
create_test_cudnn_channel_last_class(TestWithDilation_AsyPadding)

1035 1036 1037 1038 1039 1040 1041 1042 1043 1044
create_test_cudnn_channel_last_fp16_class(TestConv2DOp_AsyPadding,
                                          grad_check=False)
create_test_cudnn_channel_last_fp16_class(TestWithPad_AsyPadding,
                                          grad_check=False)
create_test_cudnn_channel_last_fp16_class(TestWithStride_AsyPadding,
                                          grad_check=False)
create_test_cudnn_channel_last_fp16_class(TestWithGroup_AsyPadding,
                                          grad_check=False)
create_test_cudnn_channel_last_fp16_class(TestWithDilation_AsyPadding,
                                          grad_check=False)
1045

1046
if __name__ == '__main__':
H
hong 已提交
1047
    paddle.enable_static()
1048
    unittest.main()