test_conv3d_op.py 31.7 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
from __future__ import print_function

C
chengduoZH 已提交
17 18
import unittest
import numpy as np
19

20
import paddle.fluid.core as core
21
from op_test import OpTest
L
liym27 已提交
22
import paddle.fluid as fluid
H
hong 已提交
23
import paddle
C
chengduoZH 已提交
24 25


L
liym27 已提交
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
def conv3d_forward_naive(input,
                         filter,
                         group,
                         conv_param,
                         padding_algorithm='EXPLICIT',
                         data_format="NCDHW"):

    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 ["NCDHW", "NDHWC"]:
        raise ValueError("Unknown Attr(data_format): '%s' ."
                         "It can only be 'NCDHW' or 'NDHWC'." %
                         str(data_format))

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

47
    in_n, in_c, in_d, in_h, in_w = input.shape
L
liym27 已提交
48 49 50 51

    f_n, f_c, f_d, f_h, f_w = filter.shape
    out_n = in_n
    out_c = f_n
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
56

C
chengduoZH 已提交
57 58 59
    stride, pad, dilation = conv_param['stride'], conv_param['pad'], conv_param[
        'dilations']

L
liym27 已提交
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
    # 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)
            pad_sum = np.max((
                (out_size - 1) * stride_size + filter_size - input_size, 0))
            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:5]
    if padding_algorithm == "VALID":
        pad = [0, 0, 0, 0, 0, 0]
    elif padding_algorithm == "SAME":
        dilation = [1, 1, 1]
79
        input_data_shape = input.shape[2:5]
L
liym27 已提交
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
        pad = _get_padding_with_SAME(input_data_shape, ksize, stride)

    pad_d_0, pad_d_1 = pad[0], pad[0]
    pad_h_0, pad_h_1 = pad[1], pad[1]
    pad_w_0, pad_w_1 = pad[2], pad[2]
    if len(pad) == 6:
        pad_d_0, pad_d_1 = pad[0], pad[1]
        pad_h_0, pad_h_1 = pad[2], pad[3]
        pad_w_0, pad_w_1 = pad[4], pad[5]

    out_d = 1 + (in_d + pad_d_0 + pad_d_1 - (dilation[0] *
                                             (f_d - 1) + 1)) // stride[0]
    out_h = 1 + (in_h + pad_h_0 + pad_h_1 - (dilation[1] *
                                             (f_h - 1) + 1)) // stride[1]
    out_w = 1 + (in_w + pad_w_0 + pad_w_1 - (dilation[2] *
                                             (f_w - 1) + 1)) // stride[2]
C
chengduoZH 已提交
96

97 98
    out = np.zeros((in_n, out_c, out_d, out_h, out_w))

C
chengduoZH 已提交
99 100 101 102
    d_bolck_d = (dilation[0] * (f_d - 1) + 1)
    d_bolck_h = (dilation[1] * (f_h - 1) + 1)
    d_bolck_w = (dilation[2] * (f_w - 1) + 1)

L
liym27 已提交
103 104
    input_pad = np.pad(input, ((0, 0), (0, 0), (pad_d_0, pad_d_1),
                               (pad_h_0, pad_h_1), (pad_w_0, pad_w_1)),
105 106
                       mode='constant',
                       constant_values=0)
C
chengduoZH 已提交
107

L
liym27 已提交
108
    filter_dilation = np.zeros((f_n, f_c, d_bolck_d, d_bolck_h, d_bolck_w))
C
chengduoZH 已提交
109 110 111
    filter_dilation[:, :, 0:d_bolck_d:dilation[0], 0:d_bolck_h:dilation[1], 0:
                    d_bolck_w:dilation[2]] = filter

112 113 114 115 116 117
    for d in range(out_d):
        for i in range(out_h):
            for j in range(out_w):
                for g in range(group):
                    input_pad_masked = \
                        input_pad[:, g * f_c:(g + 1) * f_c,
C
chengduoZH 已提交
118 119 120 121
                        d * stride[0]:d * stride[0] + d_bolck_d,
                        i * stride[1]:i * stride[1] + d_bolck_h,
                        j * stride[2]:j * stride[2] + d_bolck_w]

L
liym27 已提交
122 123
                    f_sub = filter_dilation[g * sub_f_n:(g + 1) *
                                            sub_f_n, :, :, :, :]
124 125 126
                    for k in range(sub_out_c):
                        out[:, g * sub_out_c + k, d, i, j] = \
                            np.sum(input_pad_masked * f_sub[k, :, :, :, :],
C
chengduoZH 已提交
127
                                   axis=(1, 2, 3, 4))
L
liym27 已提交
128 129
    if channel_last:
        out = np.transpose(out, [0, 2, 3, 4, 1])
130 131 132
    return out


L
liym27 已提交
133 134 135 136 137 138
def create_test_cudnn_class(parent):
    @unittest.skipIf(not core.is_compiled_with_cuda(),
                     "core is not compiled with CUDA")
    class TestCUDNNCase(parent):
        def init_kernel_type(self):
            self.use_cudnn = True
139 140
            self.dtype = np.float32 if core.is_compiled_with_rocm(
            ) else np.float64
L
liym27 已提交
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174

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


def create_test_padding_SAME_class(parent):
    class TestPaddingSMAECase(parent):
        def init_paddings(self):
            self.pad = [0, 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):
    class TestPaddingVALIDCase(parent):
        def init_paddings(self):
            self.pad = [1, 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):
    @unittest.skipIf(not core.is_compiled_with_cuda(),
                     "core is not compiled with CUDA")
    class TestCUDNNPaddingSMAECase(parent):
        def init_kernel_type(self):
            self.use_cudnn = True
175 176
            self.dtype = np.float32 if core.is_compiled_with_rocm(
            ) else np.float64
L
liym27 已提交
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192

        def init_paddings(self):
            self.pad = [1, 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):
    @unittest.skipIf(not core.is_compiled_with_cuda(),
                     "core is not compiled with CUDA")
    class TestCUDNNPaddingVALIDCase(parent):
        def init_kernel_type(self):
            self.use_cudnn = True
193 194
            self.dtype = np.float32 if core.is_compiled_with_rocm(
            ) else np.float64
L
liym27 已提交
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219

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

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


def create_test_channel_last_class(parent):
    class TestChannelLastCase(parent):
        def init_data_format(self):
            self.data_format = "NDHWC"

        def init_test_case_2(self):
            N, C, D, H, W = self.input_size
            self.input_size = [N, D, 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):
220 221
    @unittest.skipIf(not core.is_compiled_with_cuda(),
                     "core is not compiled with CUDA")
L
liym27 已提交
222 223 224
    class TestCudnnChannelLastCase(parent):
        def init_kernel_type(self):
            self.use_cudnn = True
225 226
            self.dtype = np.float32 if core.is_compiled_with_rocm(
            ) else np.float64
L
liym27 已提交
227 228 229 230 231 232 233 234 235 236 237 238 239

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

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

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


C
cnn 已提交
240
class TestConv3DOp(OpTest):
C
chengduoZH 已提交
241
    def setUp(self):
K
Kexin Zhao 已提交
242
        self.op_type = "conv3d"
243
        self.use_cudnn = False
244 245
        self.use_mkldnn = False
        self.data_format = "AnyLayout"
246
        self.dtype = np.float64
K
Kexin Zhao 已提交
247
        self.init_kernel_type()
248
        self.init_group()
C
chengduoZH 已提交
249
        self.init_dilation()
250 251
        self.init_test_case()

C
chengduoZH 已提交
252 253 254
        conv3d_param = {
            'stride': self.stride,
            'pad': self.pad,
255
            'dilations': self.dilations
C
chengduoZH 已提交
256
        }
K
Kexin Zhao 已提交
257 258 259

        input = np.random.random(self.input_size).astype(self.dtype)
        filter = np.random.random(self.filter_size).astype(self.dtype)
L
liym27 已提交
260 261 262 263 264
        output = conv3d_forward_naive(
            input,
            filter,
            self.groups,
            conv3d_param, ).astype(self.dtype)
C
chengduoZH 已提交
265

K
Kexin Zhao 已提交
266 267 268 269
        self.inputs = {
            'Input': OpTest.np_dtype_to_fluid_dtype(input),
            'Filter': OpTest.np_dtype_to_fluid_dtype(filter)
        }
C
chengduoZH 已提交
270
        self.attrs = {
271 272
            'strides': self.stride,
            'paddings': self.pad,
C
chengduoZH 已提交
273
            'groups': self.groups,
K
Kexin Zhao 已提交
274
            'dilations': self.dilations,
275 276 277
            'use_cudnn': self.use_cudnn,
            'use_mkldnn': self.use_mkldnn,
            'data_format': self.data_format
C
chengduoZH 已提交
278 279 280
        }
        self.outputs = {'Output': output}

281
    def has_cudnn(self):
282 283
        return core.is_compiled_with_cuda() and self.use_cudnn

C
chengduoZH 已提交
284
    def test_check_output(self):
285
        # TODO(wangzhongpu): support mkldnn op in dygraph mode
286
        place = core.CUDAPlace(0) if self.has_cudnn() else core.CPUPlace()
287 288
        self.check_output_with_place(
            place, atol=1e-5, check_dygraph=(self.use_mkldnn == False))
C
chengduoZH 已提交
289 290

    def test_check_grad(self):
K
Kexin Zhao 已提交
291 292
        if self.dtype == np.float16:
            return
293
        place = core.CUDAPlace(0) if self.has_cudnn() else core.CPUPlace()
294
        # TODO(wangzhongpu): support mkldnn op in dygraph mode
295
        self.check_grad_with_place(
296 297 298 299
            place, {'Input', 'Filter'},
            'Output',
            max_relative_error=0.03,
            check_dygraph=(self.use_mkldnn == False))
C
chengduoZH 已提交
300

C
chengduoZH 已提交
301
    def test_check_grad_no_filter(self):
K
Kexin Zhao 已提交
302 303
        if self.dtype == np.float16:
            return
304
        place = core.CUDAPlace(0) if self.has_cudnn() else core.CPUPlace()
305
        # TODO(wangzhongpu): support mkldnn op in dygraph mode
306 307 308 309
        self.check_grad_with_place(
            place, ['Input'],
            'Output',
            max_relative_error=0.03,
310 311
            no_grad_set=set(['Filter']),
            check_dygraph=(self.use_mkldnn == False))
C
chengduoZH 已提交
312 313

    def test_check_grad_no_input(self):
K
Kexin Zhao 已提交
314 315
        if self.dtype == np.float16:
            return
316
        place = core.CUDAPlace(0) if self.has_cudnn() else core.CPUPlace()
317
        # TODO(wangzhongpu): support mkldnn op in dygraph mode
318
        self.check_grad_with_place(
319
            place, ['Filter'],
320 321
            'Output',
            max_relative_error=0.03,
322 323
            no_grad_set=set(['Input']),
            check_dygraph=(self.use_mkldnn == False))
C
chengduoZH 已提交
324

325 326 327
    def init_test_case(self):
        self.pad = [0, 0, 0]
        self.stride = [1, 1, 1]
C
chengduoZH 已提交
328
        self.input_size = [2, 3, 4, 4, 4]  # NCDHW
329
        assert np.mod(self.input_size[1], self.groups) == 0
M
minqiyang 已提交
330
        f_c = self.input_size[1] // self.groups
331 332
        self.filter_size = [6, f_c, 3, 3, 3]

L
liym27 已提交
333 334 335
    def init_test_case_2(self):
        pass

C
chengduoZH 已提交
336 337 338
    def init_dilation(self):
        self.dilations = [1, 1, 1]

339
    def init_group(self):
C
chengduoZH 已提交
340 341
        self.groups = 1

K
Kexin Zhao 已提交
342 343
    def init_kernel_type(self):
        pass
344

C
chengduoZH 已提交
345

C
cnn 已提交
346
class TestCase1(TestConv3DOp):
C
chengduoZH 已提交
347 348 349
    def init_test_case(self):
        self.pad = [1, 1, 1]
        self.stride = [1, 1, 1]
C
chengduoZH 已提交
350
        self.input_size = [2, 3, 4, 4, 4]  # NCDHW
C
chengduoZH 已提交
351
        assert np.mod(self.input_size[1], self.groups) == 0
M
minqiyang 已提交
352
        f_c = self.input_size[1] // self.groups
C
chengduoZH 已提交
353 354 355
        self.filter_size = [6, f_c, 3, 3, 3]


C
cnn 已提交
356
class TestWithGroup1(TestConv3DOp):
C
chengduoZH 已提交
357 358
    def init_group(self):
        self.groups = 3
C
chengduoZH 已提交
359 360


C
chengduoZH 已提交
361
class TestWithGroup2(TestCase1):
362
    def init_group(self):
C
chengduoZH 已提交
363 364
        self.groups = 3

365

C
cnn 已提交
366
class TestWith1x1(TestConv3DOp):
C
chengduoZH 已提交
367 368 369
    def init_test_case(self):
        self.pad = [0, 0, 0]
        self.stride = [1, 1, 1]
L
liym27 已提交
370
        self.input_size = [2, 3, 4, 4, 4]
C
chengduoZH 已提交
371
        assert np.mod(self.input_size[1], self.groups) == 0
M
minqiyang 已提交
372
        f_c = self.input_size[1] // self.groups
Z
zhupengyang 已提交
373
        self.filter_size = [120, f_c, 1, 1, 1]
C
chengduoZH 已提交
374 375 376

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

C
chengduoZH 已提交
378 379 380
    def init_group(self):
        self.groups = 3

C
chengduoZH 已提交
381

C
cnn 已提交
382
class TestWithInput1x1Filter1x1(TestConv3DOp):
383 384 385
    def init_test_case(self):
        self.pad = [0, 0, 0]
        self.stride = [1, 1, 1]
Z
zhupengyang 已提交
386
        self.input_size = [40, 3, 1, 1, 1]
387
        assert np.mod(self.input_size[1], self.groups) == 0
M
minqiyang 已提交
388
        f_c = self.input_size[1] // self.groups
Z
zhupengyang 已提交
389
        self.filter_size = [120, f_c, 1, 1, 1]
390 391 392 393 394 395 396 397

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

    def init_group(self):
        self.groups = 3


C
cnn 已提交
398
class TestWithDilation(TestConv3DOp):
C
chengduoZH 已提交
399 400 401
    def init_test_case(self):
        self.pad = [0, 0, 0]
        self.stride = [1, 1, 1]
L
liym27 已提交
402
        self.input_size = [2, 3, 6, 6, 6]
C
chengduoZH 已提交
403
        assert np.mod(self.input_size[1], self.groups) == 0
M
minqiyang 已提交
404
        f_c = self.input_size[1] // self.groups
Z
zhupengyang 已提交
405
        self.filter_size = [24, f_c, 2, 2, 2]
C
chengduoZH 已提交
406 407 408 409 410 411

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

    def init_group(self):
        self.groups = 3
C
chengduoZH 已提交
412

C
chengduoZH 已提交
413

C
cnn 已提交
414
#---------------- Conv3DCUDNN ----------------
L
liym27 已提交
415 416


417 418
@unittest.skipIf(not core.is_compiled_with_cuda(),
                 "core is not compiled with CUDA")
C
cnn 已提交
419
class TestCUDNN(TestConv3DOp):
K
Kexin Zhao 已提交
420
    def init_kernel_type(self):
421
        self.use_cudnn = True
422
        self.dtype = np.float32 if core.is_compiled_with_rocm() else np.float64
K
Kexin Zhao 已提交
423 424


425 426
@unittest.skipIf(not core.is_compiled_with_cuda(),
                 "core is not compiled with CUDA")
C
cnn 已提交
427
class TestFP16CUDNN(TestConv3DOp):
K
Kexin Zhao 已提交
428 429 430 431 432 433 434 435 436
    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)
武毅 已提交
437 438


439 440
@unittest.skipIf(not core.is_compiled_with_cuda(),
                 "core is not compiled with CUDA")
441
class TestWithGroup1CUDNN(TestWithGroup1):
K
Kexin Zhao 已提交
442
    def init_kernel_type(self):
443
        self.use_cudnn = True
444
        self.dtype = np.float32 if core.is_compiled_with_rocm() else np.float64
K
Kexin Zhao 已提交
445 446


447 448
@unittest.skipIf(not core.is_compiled_with_cuda(),
                 "core is not compiled with CUDA")
K
Kexin Zhao 已提交
449 450 451 452 453 454 455 456 457 458
class TestFP16WithGroup1CUDNN(TestWithGroup1):
    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)
武毅 已提交
459 460


461 462
@unittest.skipIf(not core.is_compiled_with_cuda(),
                 "core is not compiled with CUDA")
463
class TestWithGroup2CUDNN(TestWithGroup2):
K
Kexin Zhao 已提交
464
    def init_kernel_type(self):
465
        self.use_cudnn = True
466
        self.dtype = np.float32 if core.is_compiled_with_rocm() else np.float64
K
Kexin Zhao 已提交
467 468


469 470
@unittest.skipIf(not core.is_compiled_with_cuda(),
                 "core is not compiled with CUDA")
K
Kexin Zhao 已提交
471 472 473 474 475 476 477 478 479 480
class TestFP16WithGroup2CUDNN(TestWithGroup2):
    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)
武毅 已提交
481 482


483 484
@unittest.skipIf(not core.is_compiled_with_cuda(),
                 "core is not compiled with CUDA")
485
class TestWith1x1CUDNN(TestWith1x1):
K
Kexin Zhao 已提交
486
    def init_kernel_type(self):
487
        self.use_cudnn = True
488
        self.dtype = np.float32 if core.is_compiled_with_rocm() else np.float64
K
Kexin Zhao 已提交
489 490


491 492
@unittest.skipIf(not core.is_compiled_with_cuda(),
                 "core is not compiled with CUDA")
K
Kexin Zhao 已提交
493 494 495 496 497 498 499 500 501 502
class TestFP16With1x1CUDNN(TestWith1x1):
    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)
武毅 已提交
503 504


505 506
@unittest.skipIf(not core.is_compiled_with_cuda(),
                 "core is not compiled with CUDA")
507
class TestWithInput1x1Filter1x1CUDNN(TestWithInput1x1Filter1x1):
K
Kexin Zhao 已提交
508
    def init_kernel_type(self):
509
        self.use_cudnn = True
510
        self.dtype = np.float32 if core.is_compiled_with_rocm() else np.float64
K
Kexin Zhao 已提交
511 512


513 514
@unittest.skipIf(not core.is_compiled_with_cuda(),
                 "core is not compiled with CUDA")
K
Kexin Zhao 已提交
515 516 517 518 519 520 521 522 523 524
class TestFP16WithInput1x1Filter1x1CUDNN(TestWithInput1x1Filter1x1):
    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)
525 526


527 528 529 530
class TestCUDNNExhaustiveSearch(TestCUDNN):
    def init_kernel_type(self):
        self.use_cudnn = True
        self.exhaustive_search = True
531
        self.dtype = np.float32 if core.is_compiled_with_rocm() else np.float64
532 533


L
liym27 已提交
534 535 536
# ---- test asymmetric padding ----


C
cnn 已提交
537
class TestConv3DOp_2(OpTest):
L
liym27 已提交
538 539 540 541 542
    def setUp(self):
        self.op_type = "conv3d"
        self.use_cudnn = False
        self.use_mkldnn = False
        self.data_format = "NCDHW"
543
        self.dtype = np.float64
L
liym27 已提交
544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609
        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()

        conv3d_param = {
            'stride': self.stride,
            'pad': self.pad,
            'dilations': self.dilations
        }

        input = np.random.random(self.input_size).astype(self.dtype)
        filter = np.random.random(self.filter_size).astype(self.dtype)
        output = conv3d_forward_naive(input, filter, self.groups, conv3d_param,
                                      self.padding_algorithm,
                                      self.data_format).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
        }
        self.outputs = {'Output': output}

    def has_cudnn(self):
        return core.is_compiled_with_cuda() and self.use_cudnn

    def test_check_output(self):
        place = core.CUDAPlace(0) if self.has_cudnn() else core.CPUPlace()
        self.check_output_with_place(place, atol=1e-5)

    def test_check_grad(self):
        if self.dtype == np.float16:
            return
        place = core.CUDAPlace(0) if self.has_cudnn() else core.CPUPlace()
        self.check_grad_with_place(
            place, {'Input', 'Filter'}, 'Output', max_relative_error=0.03)

    def test_check_grad_no_filter(self):
        if self.dtype == np.float16:
            return
        place = core.CUDAPlace(0) if self.has_cudnn() else core.CPUPlace()
        self.check_grad_with_place(
            place, ['Input'],
            'Output',
            max_relative_error=0.03,
            no_grad_set=set(['Filter']))

    def test_check_grad_no_input(self):
        if self.dtype == np.float16:
            return
        place = core.CUDAPlace(0) if self.has_cudnn() else core.CPUPlace()
        self.check_grad_with_place(
610
            place, ['Filter'],
L
liym27 已提交
611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641
            'Output',
            max_relative_error=0.03,
            no_grad_set=set(['Input']))

    def init_test_case(self):
        self.stride = [1, 1, 1]
        self.input_size = [2, 3, 4, 4, 4]  # NCDHW
        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, 3]

    def init_test_case_2(self):
        pass

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

    def init_group(self):
        self.groups = 1

    def init_kernel_type(self):
        pass

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

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


C
cnn 已提交
642
class TestConv3DOp_AsyPadding(TestConv3DOp_2):
643 644 645 646 647 648 649
    def init_test_case(self):
        self.stride = [1, 1, 2]
        self.input_size = [2, 3, 4, 4, 4]  # NCDHW
        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, 3]

L
liym27 已提交
650 651 652 653 654
    def init_paddings(self):
        self.pad = [1, 0, 1, 0, 0, 2]
        self.padding_algorithm = "EXPLICIT"


C
cnn 已提交
655
class TestConv3DOp_DiffDataInDiffDim(TestConv3DOp_2):
656 657 658 659 660 661 662 663 664 665 666 667
    def init_test_case(self):
        self.stride = [1, 1, 2]
        self.input_size = [2, 3, 4, 5, 5]  # NCDHW
        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, 4, 3]

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


C
cnn 已提交
668 669 670
create_test_padding_SAME_class(TestConv3DOp_DiffDataInDiffDim)
create_test_padding_VALID_class(TestConv3DOp_DiffDataInDiffDim)
create_test_channel_last_class(TestConv3DOp_DiffDataInDiffDim)
671 672


C
cnn 已提交
673
class TestCase1_AsyPadding(TestConv3DOp_2):
L
liym27 已提交
674 675 676 677 678 679 680 681 682 683 684 685
    def init_test_case(self):
        self.stride = [1, 1, 1]
        self.input_size = [2, 3, 4, 4, 4]  # NCDHW
        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, 3]

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


C
cnn 已提交
686
class TestWithGroup1_AsyPadding(TestConv3DOp_2):
L
liym27 已提交
687 688 689 690 691 692 693 694
    def init_group(self):
        self.groups = 3

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


C
cnn 已提交
695
class TestWithGroup2_AsyPadding(TestConv3DOp_2):
L
liym27 已提交
696 697 698 699 700 701 702 703 704 705 706 707 708 709 710
    def init_test_case(self):
        self.stride = [1, 1, 1]
        self.input_size = [2, 3, 4, 4, 4]  # NCDHW
        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, 3]

    def init_group(self):
        self.groups = 3

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


C
cnn 已提交
711
class TestWith1x1_AsyPadding(TestConv3DOp_2):
L
liym27 已提交
712 713 714 715 716
    def init_test_case(self):
        self.stride = [1, 1, 1]
        self.input_size = [2, 3, 4, 4, 4]
        assert np.mod(self.input_size[1], self.groups) == 0
        f_c = self.input_size[1] // self.groups
Z
zhupengyang 已提交
717
        self.filter_size = [120, f_c, 1, 1, 1]
L
liym27 已提交
718 719 720 721 722 723 724 725 726 727 728 729

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

    def init_group(self):
        self.groups = 3

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


C
cnn 已提交
730
class TestWithDilation_AsyPadding(TestConv3DOp_2):
L
liym27 已提交
731 732 733 734 735
    def init_test_case(self):
        self.stride = [1, 1, 1]
        self.input_size = [2, 3, 6, 6, 6]
        assert np.mod(self.input_size[1], self.groups) == 0
        f_c = self.input_size[1] // self.groups
Z
zhupengyang 已提交
736
        self.filter_size = [24, f_c, 2, 2, 2]
L
liym27 已提交
737 738 739 740 741 742 743 744 745 746 747 748

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

    def init_group(self):
        self.groups = 3

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


C
cnn 已提交
749
create_test_cudnn_class(TestConv3DOp_AsyPadding)
L
liym27 已提交
750 751 752 753 754
create_test_cudnn_class(TestWithGroup1_AsyPadding)
create_test_cudnn_class(TestWithGroup2_AsyPadding)
create_test_cudnn_class(TestWith1x1_AsyPadding)
create_test_cudnn_class(TestWithDilation_AsyPadding)

C
cnn 已提交
755
create_test_padding_SAME_class(TestConv3DOp_AsyPadding)
L
liym27 已提交
756 757 758
create_test_padding_SAME_class(TestWithGroup1_AsyPadding)
create_test_padding_SAME_class(TestWith1x1_AsyPadding)

C
cnn 已提交
759
create_test_padding_VALID_class(TestConv3DOp_AsyPadding)
L
liym27 已提交
760 761 762
create_test_padding_VALID_class(TestWithGroup1_AsyPadding)
create_test_padding_VALID_class(TestWith1x1_AsyPadding)

C
cnn 已提交
763
create_test_cudnn_padding_SAME_class(TestConv3DOp_AsyPadding)
L
liym27 已提交
764 765 766
create_test_cudnn_padding_SAME_class(TestWithGroup1_AsyPadding)
create_test_cudnn_padding_SAME_class(TestWith1x1_AsyPadding)

C
cnn 已提交
767
create_test_cudnn_padding_VALID_class(TestConv3DOp_AsyPadding)
L
liym27 已提交
768 769 770
create_test_cudnn_padding_VALID_class(TestWithGroup1_AsyPadding)
create_test_cudnn_padding_VALID_class(TestWith1x1_AsyPadding)

C
cnn 已提交
771
create_test_channel_last_class(TestConv3DOp_AsyPadding)
L
liym27 已提交
772 773 774
create_test_channel_last_class(TestWithGroup1_AsyPadding)
create_test_channel_last_class(TestWith1x1_AsyPadding)

C
cnn 已提交
775
create_test_channel_last_class(TestConv3DOp_AsyPadding)
L
liym27 已提交
776 777 778
create_test_channel_last_class(TestWithGroup1_AsyPadding)
create_test_channel_last_class(TestWith1x1_AsyPadding)

C
cnn 已提交
779
create_test_cudnn_channel_last_class(TestConv3DOp_AsyPadding)
L
liym27 已提交
780 781 782
create_test_cudnn_channel_last_class(TestWithGroup1_AsyPadding)
create_test_cudnn_channel_last_class(TestWith1x1_AsyPadding)

C
cnn 已提交
783
create_test_cudnn_channel_last_class(TestConv3DOp_AsyPadding)
L
liym27 已提交
784 785 786
create_test_cudnn_channel_last_class(TestWithGroup1_AsyPadding)
create_test_cudnn_channel_last_class(TestWith1x1_AsyPadding)

武毅 已提交
787 788
# FIXME(typhoonzero): find a way to determine if
# using cudnn > 6 in python
789
# class TestWithDilationCUDNN(TestWithDilation):
武毅 已提交
790
#     def init_op_type(self):
791
#         self.op_type = "conv3d"
武毅 已提交
792

L
liym27 已提交
793 794

# --------- test python API ---------------
C
cnn 已提交
795
class TestConv3DAPI(unittest.TestCase):
L
liym27 已提交
796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870
    def test_api(self):

        input_NDHWC = fluid.layers.data(
            name="input_NDHWC",
            shape=[2, 5, 5, 5, 3],
            append_batch_size=False,
            dtype="float32")

        input_NCDHW = fluid.layers.data(
            name="input_NCDHW",
            shape=[2, 3, 5, 5, 3],
            append_batch_size=False,
            dtype="float32")

        fluid.layers.conv3d(
            input=input_NDHWC,
            num_filters=3,
            filter_size=[3, 3, 3],
            stride=[1, 1, 1],
            padding=0,
            dilation=[1, 1, 1],
            groups=1,
            data_format="NCDHW")

        fluid.layers.conv3d(
            input=input_NCDHW,
            num_filters=3,
            filter_size=[3, 3, 3],
            stride=[1, 1, 1],
            padding=[1, 2, 1, 0, 1, 0],
            dilation=[1, 1, 1],
            groups=1,
            data_format="NCDHW")

        fluid.layers.conv3d(
            input=input_NCDHW,
            num_filters=3,
            filter_size=[3, 3, 3],
            stride=[1, 1, 1],
            padding=[[0, 0], [0, 0], [1, 1], [1, 1], [1, 1]],
            dilation=[1, 1, 1],
            groups=1,
            data_format="NCDHW")

        fluid.layers.conv3d(
            input=input_NDHWC,
            num_filters=3,
            filter_size=[3, 3, 3],
            stride=[1, 1, 1],
            padding=[[0, 0], [1, 1], [1, 1], [1, 1], [0, 0]],
            dilation=[1, 1, 1],
            groups=1,
            data_format="NDHWC")

        fluid.layers.conv3d(
            input=input_NCDHW,
            num_filters=3,
            filter_size=[3, 3, 3],
            stride=[1, 1, 1],
            padding="SAME",
            dilation=[1, 1, 1],
            groups=1,
            data_format="NCDHW")

        fluid.layers.conv3d(
            input=input_NCDHW,
            num_filters=3,
            filter_size=[3, 3, 3],
            stride=[1, 1, 1],
            padding="VALID",
            dilation=[1, 1, 1],
            groups=1,
            data_format="NCDHW")


C
cnn 已提交
871
class TestConv3DAPI_Error(unittest.TestCase):
L
liym27 已提交
872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987
    def test_api(self):
        input = fluid.layers.data(
            name="input",
            shape=[2, 5, 5, 5, 4],
            append_batch_size=False,
            dtype="float32")

        # ValueError: cudnn
        def run_1():
            fluid.layers.conv3d(
                input=input,
                num_filters=3,
                filter_size=3,
                stride=1,
                padding=0,
                dilation=1,
                groups=1,
                use_cudnn=[0],
                data_format="NCDHW")

        self.assertRaises(ValueError, run_1)

        # ValueError: data_format
        def run_2():
            fluid.layers.conv3d(
                input=input,
                num_filters=3,
                filter_size=[3, 3, 3],
                stride=[1, 1, 1],
                padding=0,
                dilation=[1, 1, 1],
                groups=1,
                use_cudnn=False,
                data_format="NCHWC")

        self.assertRaises(ValueError, run_2)

        # ValueError: padding
        def run_3():
            fluid.layers.conv3d(
                input=input,
                num_filters=3,
                filter_size=3,
                stride=1,
                padding="SAMEE",
                dilation=1,
                groups=1,
                use_cudnn=False,
                data_format="NCDHW")

        self.assertRaises(ValueError, run_3)

        def run_4():
            fluid.layers.conv3d(
                input=input,
                num_filters=3,
                filter_size=3,
                stride=1,
                padding=[[0, 1], [0, 0], [0, 1], [0, 1], [0, 1]],
                dilation=1,
                groups=1,
                use_cudnn=False,
                data_format="NCDHW")

        self.assertRaises(ValueError, run_4)

        def run_5():
            fluid.layers.conv3d(
                input=input,
                num_filters=3,
                filter_size=0,
                stride=0,
                padding=[[0, 1], [0, 1], [0, 1], [0, 1], [0, 1]],
                dilation=1,
                groups=1,
                use_cudnn=False,
                data_format="NDHWC")

        self.assertRaises(ValueError, run_5)

        # ValueError: channel dimmention
        x = fluid.layers.data(
            name="x",
            shape=[2, 5, 5, 5, -1],
            append_batch_size=False,
            dtype="float32")

        def run_6():
            fluid.layers.conv3d(
                input=x,
                num_filters=3,
                filter_size=3,
                stride=1,
                padding=0,
                dilation=1,
                groups=1,
                use_cudnn=False,
                data_format="NDHWC")

        self.assertRaises(ValueError, run_6)

        # ValueError: groups
        def run_7():
            fluid.layers.conv3d(
                input=input,
                num_filters=3,
                filter_size=3,
                stride=1,
                padding=0,
                dilation=1,
                groups=3,
                use_cudnn=False,
                data_format="NDHWC")

        self.assertRaises(ValueError, run_7)

988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002
        # ValueError: filter num
        def run_8():
            fluid.layers.conv3d(
                input=input,
                num_filters=0,
                filter_size=0,
                stride=0,
                padding=0,
                dilation=0,
                groups=1,
                use_cudnn=False,
                data_format="NDHWC")

        self.assertRaises(ValueError, run_8)

L
liym27 已提交
1003

C
chengduoZH 已提交
1004
if __name__ == '__main__':
H
hong 已提交
1005
    paddle.enable_static()
C
chengduoZH 已提交
1006
    unittest.main()