test_conv3d_op.py 34.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.

C
chengduoZH 已提交
15 16
import unittest
import numpy as np
17

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


L
liym27 已提交
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
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])

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

    f_n, f_c, f_d, f_h, f_w = filter.shape
    out_n = in_n
    out_c = f_n
50 51
    assert f_c * group == in_c
    assert np.mod(out_c, group) == 0
M
minqiyang 已提交
52
    sub_out_c = out_c // group
L
liym27 已提交
53
    sub_f_n = f_n // group
54

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

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

95 96
    out = np.zeros((in_n, out_c, out_d, out_h, out_w))

C
chengduoZH 已提交
97 98 99 100
    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 已提交
101 102
    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)),
103 104
                       mode='constant',
                       constant_values=0)
C
chengduoZH 已提交
105

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

110 111 112 113 114 115
    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 已提交
116 117 118 119
                        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 已提交
120 121
                    f_sub = filter_dilation[g * sub_f_n:(g + 1) *
                                            sub_f_n, :, :, :, :]
122 123 124
                    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 已提交
125
                                   axis=(1, 2, 3, 4))
L
liym27 已提交
126 127
    if channel_last:
        out = np.transpose(out, [0, 2, 3, 4, 1])
128 129 130
    return out


L
liym27 已提交
131
def create_test_cudnn_class(parent):
132

L
liym27 已提交
133 134 135
    @unittest.skipIf(not core.is_compiled_with_cuda(),
                     "core is not compiled with CUDA")
    class TestCUDNNCase(parent):
136

L
liym27 已提交
137 138
        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

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


def create_test_padding_SAME_class(parent):
148

L
liym27 已提交
149
    class TestPaddingSMAECase(parent):
150

L
liym27 已提交
151 152 153 154 155 156 157 158 159 160
        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):
161

L
liym27 已提交
162
    class TestPaddingVALIDCase(parent):
163

L
liym27 已提交
164 165 166 167 168 169 170 171 172 173
        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):
174

L
liym27 已提交
175 176 177
    @unittest.skipIf(not core.is_compiled_with_cuda(),
                     "core is not compiled with CUDA")
    class TestCUDNNPaddingSMAECase(parent):
178

L
liym27 已提交
179 180
        def init_kernel_type(self):
            self.use_cudnn = True
181 182
            self.dtype = np.float32 if core.is_compiled_with_rocm(
            ) else np.float64
L
liym27 已提交
183 184 185 186 187 188 189 190 191 192 193

        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):
194

L
liym27 已提交
195 196 197
    @unittest.skipIf(not core.is_compiled_with_cuda(),
                     "core is not compiled with CUDA")
    class TestCUDNNPaddingVALIDCase(parent):
198

L
liym27 已提交
199 200
        def init_kernel_type(self):
            self.use_cudnn = True
201 202
            self.dtype = np.float32 if core.is_compiled_with_rocm(
            ) else np.float64
L
liym27 已提交
203 204 205 206 207 208 209 210 211 212 213

        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):
214

L
liym27 已提交
215
    class TestChannelLastCase(parent):
216

L
liym27 已提交
217 218 219 220 221 222 223 224 225 226 227 228 229
        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):
230

231 232
    @unittest.skipIf(not core.is_compiled_with_cuda(),
                     "core is not compiled with CUDA")
L
liym27 已提交
233
    class TestCudnnChannelLastCase(parent):
234

L
liym27 已提交
235 236
        def init_kernel_type(self):
            self.use_cudnn = True
237 238
            self.dtype = np.float32 if core.is_compiled_with_rocm(
            ) else np.float64
L
liym27 已提交
239 240 241 242 243 244 245 246 247 248 249 250 251

        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 已提交
252
class TestConv3DOp(OpTest):
253

C
chengduoZH 已提交
254
    def setUp(self):
K
Kexin Zhao 已提交
255
        self.op_type = "conv3d"
256
        self.use_cudnn = False
257 258
        self.use_mkldnn = False
        self.data_format = "AnyLayout"
259
        self.dtype = np.float64
K
Kexin Zhao 已提交
260
        self.init_kernel_type()
261
        self.init_group()
C
chengduoZH 已提交
262
        self.init_dilation()
263 264
        self.init_test_case()

C
chengduoZH 已提交
265 266 267
        conv3d_param = {
            'stride': self.stride,
            'pad': self.pad,
268
            'dilations': self.dilations
C
chengduoZH 已提交
269
        }
K
Kexin Zhao 已提交
270 271 272

        input = np.random.random(self.input_size).astype(self.dtype)
        filter = np.random.random(self.filter_size).astype(self.dtype)
L
liym27 已提交
273 274 275 276
        output = conv3d_forward_naive(
            input,
            filter,
            self.groups,
277 278
            conv3d_param,
        ).astype(self.dtype)
C
chengduoZH 已提交
279

K
Kexin Zhao 已提交
280 281 282 283
        self.inputs = {
            'Input': OpTest.np_dtype_to_fluid_dtype(input),
            'Filter': OpTest.np_dtype_to_fluid_dtype(filter)
        }
C
chengduoZH 已提交
284
        self.attrs = {
285 286
            'strides': self.stride,
            'paddings': self.pad,
C
chengduoZH 已提交
287
            'groups': self.groups,
K
Kexin Zhao 已提交
288
            'dilations': self.dilations,
289 290 291
            'use_cudnn': self.use_cudnn,
            'use_mkldnn': self.use_mkldnn,
            'data_format': self.data_format
C
chengduoZH 已提交
292 293 294
        }
        self.outputs = {'Output': output}

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

C
chengduoZH 已提交
298
    def test_check_output(self):
299
        # TODO(wangzhongpu): support mkldnn op in dygraph mode
300
        place = core.CUDAPlace(0) if self.has_cudnn() else core.CPUPlace()
301 302 303
        self.check_output_with_place(place,
                                     atol=1e-5,
                                     check_dygraph=(self.use_mkldnn == False))
C
chengduoZH 已提交
304 305

    def test_check_grad(self):
K
Kexin Zhao 已提交
306 307
        if self.dtype == np.float16:
            return
308
        place = core.CUDAPlace(0) if self.has_cudnn() else core.CPUPlace()
309
        # TODO(wangzhongpu): support mkldnn op in dygraph mode
310 311 312 313
        self.check_grad_with_place(place, {'Input', 'Filter'},
                                   'Output',
                                   max_relative_error=0.03,
                                   check_dygraph=(self.use_mkldnn == False))
C
chengduoZH 已提交
314

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

    def test_check_grad_no_input(self):
K
Kexin Zhao 已提交
327 328
        if self.dtype == np.float16:
            return
329
        place = core.CUDAPlace(0) if self.has_cudnn() else core.CPUPlace()
330
        # TODO(wangzhongpu): support mkldnn op in dygraph mode
331 332 333 334 335
        self.check_grad_with_place(place, ['Filter'],
                                   'Output',
                                   max_relative_error=0.03,
                                   no_grad_set=set(['Input']),
                                   check_dygraph=(self.use_mkldnn == False))
C
chengduoZH 已提交
336

337 338 339
    def init_test_case(self):
        self.pad = [0, 0, 0]
        self.stride = [1, 1, 1]
C
chengduoZH 已提交
340
        self.input_size = [2, 3, 4, 4, 4]  # NCDHW
341
        assert np.mod(self.input_size[1], self.groups) == 0
M
minqiyang 已提交
342
        f_c = self.input_size[1] // self.groups
343 344
        self.filter_size = [6, f_c, 3, 3, 3]

L
liym27 已提交
345 346 347
    def init_test_case_2(self):
        pass

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

351
    def init_group(self):
C
chengduoZH 已提交
352 353
        self.groups = 1

K
Kexin Zhao 已提交
354 355
    def init_kernel_type(self):
        pass
356

C
chengduoZH 已提交
357

C
cnn 已提交
358
class TestCase1(TestConv3DOp):
359

C
chengduoZH 已提交
360 361 362
    def init_test_case(self):
        self.pad = [1, 1, 1]
        self.stride = [1, 1, 1]
C
chengduoZH 已提交
363
        self.input_size = [2, 3, 4, 4, 4]  # NCDHW
C
chengduoZH 已提交
364
        assert np.mod(self.input_size[1], self.groups) == 0
M
minqiyang 已提交
365
        f_c = self.input_size[1] // self.groups
C
chengduoZH 已提交
366 367 368
        self.filter_size = [6, f_c, 3, 3, 3]


C
cnn 已提交
369
class TestWithGroup1(TestConv3DOp):
370

C
chengduoZH 已提交
371 372
    def init_group(self):
        self.groups = 3
C
chengduoZH 已提交
373 374


C
chengduoZH 已提交
375
class TestWithGroup2(TestCase1):
376

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

380

C
cnn 已提交
381
class TestWith1x1(TestConv3DOp):
382

C
chengduoZH 已提交
383 384 385
    def init_test_case(self):
        self.pad = [0, 0, 0]
        self.stride = [1, 1, 1]
L
liym27 已提交
386
        self.input_size = [2, 3, 4, 4, 4]
C
chengduoZH 已提交
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]
C
chengduoZH 已提交
390 391 392

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

C
chengduoZH 已提交
394 395 396
    def init_group(self):
        self.groups = 3

C
chengduoZH 已提交
397

C
cnn 已提交
398
class TestWithInput1x1Filter1x1(TestConv3DOp):
399

400 401 402
    def init_test_case(self):
        self.pad = [0, 0, 0]
        self.stride = [1, 1, 1]
Z
zhupengyang 已提交
403
        self.input_size = [40, 3, 1, 1, 1]
404
        assert np.mod(self.input_size[1], self.groups) == 0
M
minqiyang 已提交
405
        f_c = self.input_size[1] // self.groups
Z
zhupengyang 已提交
406
        self.filter_size = [120, f_c, 1, 1, 1]
407 408 409 410 411 412 413 414

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

    def init_group(self):
        self.groups = 3


C
cnn 已提交
415
class TestWithDilation(TestConv3DOp):
416

C
chengduoZH 已提交
417 418 419
    def init_test_case(self):
        self.pad = [0, 0, 0]
        self.stride = [1, 1, 1]
L
liym27 已提交
420
        self.input_size = [2, 3, 6, 6, 6]
C
chengduoZH 已提交
421
        assert np.mod(self.input_size[1], self.groups) == 0
M
minqiyang 已提交
422
        f_c = self.input_size[1] // self.groups
Z
zhupengyang 已提交
423
        self.filter_size = [24, f_c, 2, 2, 2]
C
chengduoZH 已提交
424 425 426 427 428 429

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

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

C
chengduoZH 已提交
431

C
cnn 已提交
432
#---------------- Conv3DCUDNN ----------------
L
liym27 已提交
433 434


435 436
@unittest.skipIf(not core.is_compiled_with_cuda(),
                 "core is not compiled with CUDA")
C
cnn 已提交
437
class TestCUDNN(TestConv3DOp):
438

K
Kexin Zhao 已提交
439
    def init_kernel_type(self):
440
        self.use_cudnn = True
441
        self.dtype = np.float32 if core.is_compiled_with_rocm() else np.float64
K
Kexin Zhao 已提交
442 443


444 445
@unittest.skipIf(not core.is_compiled_with_cuda(),
                 "core is not compiled with CUDA")
C
cnn 已提交
446
class TestFP16CUDNN(TestConv3DOp):
447

K
Kexin Zhao 已提交
448 449 450 451 452 453 454 455 456
    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)
武毅 已提交
457 458


459 460
@unittest.skipIf(not core.is_compiled_with_cuda(),
                 "core is not compiled with CUDA")
461
class TestWithGroup1CUDNN(TestWithGroup1):
462

K
Kexin Zhao 已提交
463
    def init_kernel_type(self):
464
        self.use_cudnn = True
465
        self.dtype = np.float32 if core.is_compiled_with_rocm() else np.float64
K
Kexin Zhao 已提交
466 467


468 469
@unittest.skipIf(not core.is_compiled_with_cuda(),
                 "core is not compiled with CUDA")
K
Kexin Zhao 已提交
470
class TestFP16WithGroup1CUDNN(TestWithGroup1):
471

K
Kexin Zhao 已提交
472 473 474 475 476 477 478 479 480
    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 TestWithGroup2CUDNN(TestWithGroup2):
486

K
Kexin Zhao 已提交
487
    def init_kernel_type(self):
488
        self.use_cudnn = True
489
        self.dtype = np.float32 if core.is_compiled_with_rocm() else np.float64
K
Kexin Zhao 已提交
490 491


492 493
@unittest.skipIf(not core.is_compiled_with_cuda(),
                 "core is not compiled with CUDA")
K
Kexin Zhao 已提交
494
class TestFP16WithGroup2CUDNN(TestWithGroup2):
495

K
Kexin Zhao 已提交
496 497 498 499 500 501 502 503 504
    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)
武毅 已提交
505 506


507 508
@unittest.skipIf(not core.is_compiled_with_cuda(),
                 "core is not compiled with CUDA")
509
class TestWith1x1CUDNN(TestWith1x1):
510

K
Kexin Zhao 已提交
511
    def init_kernel_type(self):
512
        self.use_cudnn = True
513
        self.dtype = np.float32 if core.is_compiled_with_rocm() else np.float64
K
Kexin Zhao 已提交
514 515


516 517
@unittest.skipIf(not core.is_compiled_with_cuda(),
                 "core is not compiled with CUDA")
K
Kexin Zhao 已提交
518
class TestFP16With1x1CUDNN(TestWith1x1):
519

K
Kexin Zhao 已提交
520 521 522 523 524 525 526 527 528
    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)
武毅 已提交
529 530


531 532
@unittest.skipIf(not core.is_compiled_with_cuda(),
                 "core is not compiled with CUDA")
533
class TestWithInput1x1Filter1x1CUDNN(TestWithInput1x1Filter1x1):
534

K
Kexin Zhao 已提交
535
    def init_kernel_type(self):
536
        self.use_cudnn = True
537
        self.dtype = np.float32 if core.is_compiled_with_rocm() else np.float64
K
Kexin Zhao 已提交
538 539


540 541
@unittest.skipIf(not core.is_compiled_with_cuda(),
                 "core is not compiled with CUDA")
K
Kexin Zhao 已提交
542
class TestFP16WithInput1x1Filter1x1CUDNN(TestWithInput1x1Filter1x1):
543

K
Kexin Zhao 已提交
544 545 546 547 548 549 550 551 552
    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)
553 554


555
class TestCUDNNExhaustiveSearch(TestCUDNN):
556

557 558 559
    def init_kernel_type(self):
        self.use_cudnn = True
        self.exhaustive_search = True
560
        self.dtype = np.float32 if core.is_compiled_with_rocm() else np.float64
561 562


L
liym27 已提交
563 564 565
# ---- test asymmetric padding ----


C
cnn 已提交
566
class TestConv3DOp_2(OpTest):
567

L
liym27 已提交
568 569 570 571 572
    def setUp(self):
        self.op_type = "conv3d"
        self.use_cudnn = False
        self.use_mkldnn = False
        self.data_format = "NCDHW"
573
        self.dtype = np.float64
L
liym27 已提交
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 610 611 612 613 614 615 616 617 618 619 620 621
        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()
622 623 624
        self.check_grad_with_place(place, {'Input', 'Filter'},
                                   'Output',
                                   max_relative_error=0.03)
L
liym27 已提交
625 626 627 628 629

    def test_check_grad_no_filter(self):
        if self.dtype == np.float16:
            return
        place = core.CUDAPlace(0) if self.has_cudnn() else core.CPUPlace()
630 631 632 633
        self.check_grad_with_place(place, ['Input'],
                                   'Output',
                                   max_relative_error=0.03,
                                   no_grad_set=set(['Filter']))
L
liym27 已提交
634 635 636 637 638

    def test_check_grad_no_input(self):
        if self.dtype == np.float16:
            return
        place = core.CUDAPlace(0) if self.has_cudnn() else core.CPUPlace()
639 640 641 642
        self.check_grad_with_place(place, ['Filter'],
                                   'Output',
                                   max_relative_error=0.03,
                                   no_grad_set=set(['Input']))
L
liym27 已提交
643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670

    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 已提交
671
class TestConv3DOp_AsyPadding(TestConv3DOp_2):
672

673 674 675 676 677 678 679
    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 已提交
680 681 682 683 684
    def init_paddings(self):
        self.pad = [1, 0, 1, 0, 0, 2]
        self.padding_algorithm = "EXPLICIT"


C
cnn 已提交
685
class TestConv3DOp_DiffDataInDiffDim(TestConv3DOp_2):
686

687 688 689 690 691 692 693 694 695 696 697 698
    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 已提交
699 700 701
create_test_padding_SAME_class(TestConv3DOp_DiffDataInDiffDim)
create_test_padding_VALID_class(TestConv3DOp_DiffDataInDiffDim)
create_test_channel_last_class(TestConv3DOp_DiffDataInDiffDim)
702 703


C
cnn 已提交
704
class TestCase1_AsyPadding(TestConv3DOp_2):
705

L
liym27 已提交
706 707 708 709 710 711 712 713 714 715 716 717
    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 已提交
718
class TestWithGroup1_AsyPadding(TestConv3DOp_2):
719

L
liym27 已提交
720 721 722 723 724 725 726 727
    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 已提交
728
class TestWithGroup2_AsyPadding(TestConv3DOp_2):
729

L
liym27 已提交
730 731 732 733 734 735 736 737 738 739 740 741 742 743 744
    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 已提交
745
class TestWith1x1_AsyPadding(TestConv3DOp_2):
746

L
liym27 已提交
747 748 749 750 751
    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 已提交
752
        self.filter_size = [120, f_c, 1, 1, 1]
L
liym27 已提交
753 754 755 756 757 758 759 760 761 762 763 764

    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 已提交
765
class TestWithDilation_AsyPadding(TestConv3DOp_2):
766

L
liym27 已提交
767 768 769 770 771
    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 已提交
772
        self.filter_size = [24, f_c, 2, 2, 2]
L
liym27 已提交
773 774 775 776 777 778 779 780 781 782 783 784

    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 已提交
785
create_test_cudnn_class(TestConv3DOp_AsyPadding)
L
liym27 已提交
786 787 788 789 790
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 已提交
791
create_test_padding_SAME_class(TestConv3DOp_AsyPadding)
L
liym27 已提交
792 793 794
create_test_padding_SAME_class(TestWithGroup1_AsyPadding)
create_test_padding_SAME_class(TestWith1x1_AsyPadding)

C
cnn 已提交
795
create_test_padding_VALID_class(TestConv3DOp_AsyPadding)
L
liym27 已提交
796 797 798
create_test_padding_VALID_class(TestWithGroup1_AsyPadding)
create_test_padding_VALID_class(TestWith1x1_AsyPadding)

C
cnn 已提交
799
create_test_cudnn_padding_SAME_class(TestConv3DOp_AsyPadding)
L
liym27 已提交
800 801 802
create_test_cudnn_padding_SAME_class(TestWithGroup1_AsyPadding)
create_test_cudnn_padding_SAME_class(TestWith1x1_AsyPadding)

C
cnn 已提交
803
create_test_cudnn_padding_VALID_class(TestConv3DOp_AsyPadding)
L
liym27 已提交
804 805 806
create_test_cudnn_padding_VALID_class(TestWithGroup1_AsyPadding)
create_test_cudnn_padding_VALID_class(TestWith1x1_AsyPadding)

C
cnn 已提交
807
create_test_channel_last_class(TestConv3DOp_AsyPadding)
L
liym27 已提交
808 809 810
create_test_channel_last_class(TestWithGroup1_AsyPadding)
create_test_channel_last_class(TestWith1x1_AsyPadding)

C
cnn 已提交
811
create_test_channel_last_class(TestConv3DOp_AsyPadding)
L
liym27 已提交
812 813 814
create_test_channel_last_class(TestWithGroup1_AsyPadding)
create_test_channel_last_class(TestWith1x1_AsyPadding)

C
cnn 已提交
815
create_test_cudnn_channel_last_class(TestConv3DOp_AsyPadding)
L
liym27 已提交
816 817 818
create_test_cudnn_channel_last_class(TestWithGroup1_AsyPadding)
create_test_cudnn_channel_last_class(TestWith1x1_AsyPadding)

C
cnn 已提交
819
create_test_cudnn_channel_last_class(TestConv3DOp_AsyPadding)
L
liym27 已提交
820 821 822
create_test_cudnn_channel_last_class(TestWithGroup1_AsyPadding)
create_test_cudnn_channel_last_class(TestWith1x1_AsyPadding)

武毅 已提交
823 824
# FIXME(typhoonzero): find a way to determine if
# using cudnn > 6 in python
825
# class TestWithDilationCUDNN(TestWithDilation):
武毅 已提交
826
#     def init_op_type(self):
827
#         self.op_type = "conv3d"
武毅 已提交
828

L
liym27 已提交
829 830

# --------- test python API ---------------
C
cnn 已提交
831
class TestConv3DAPI(unittest.TestCase):
832

L
liym27 已提交
833 834
    def test_api(self):

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 871 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
        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")
L
liym27 已提交
898 899


C
cnn 已提交
900
class TestConv3DAPI_Error(unittest.TestCase):
901

L
liym27 已提交
902
    def test_api(self):
903 904 905 906
        input = fluid.layers.data(name="input",
                                  shape=[2, 5, 5, 5, 4],
                                  append_batch_size=False,
                                  dtype="float32")
L
liym27 已提交
907 908 909

        # ValueError: cudnn
        def run_1():
910 911 912 913 914 915 916 917 918
            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")
L
liym27 已提交
919 920 921 922 923

        self.assertRaises(ValueError, run_1)

        # ValueError: data_format
        def run_2():
924 925 926 927 928 929 930 931 932
            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")
L
liym27 已提交
933 934 935 936 937

        self.assertRaises(ValueError, run_2)

        # ValueError: padding
        def run_3():
938 939 940 941 942 943 944 945 946
            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")
L
liym27 已提交
947 948 949 950

        self.assertRaises(ValueError, run_3)

        def run_4():
951 952 953 954 955 956 957 958 959 960
            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")
L
liym27 已提交
961 962 963 964

        self.assertRaises(ValueError, run_4)

        def run_5():
965 966 967 968 969 970 971 972 973 974
            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")
L
liym27 已提交
975 976 977 978

        self.assertRaises(ValueError, run_5)

        # ValueError: channel dimmention
979 980 981 982
        x = fluid.layers.data(name="x",
                              shape=[2, 5, 5, 5, -1],
                              append_batch_size=False,
                              dtype="float32")
L
liym27 已提交
983 984

        def run_6():
985 986 987 988 989 990 991 992 993
            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")
L
liym27 已提交
994 995 996 997 998

        self.assertRaises(ValueError, run_6)

        # ValueError: groups
        def run_7():
999 1000 1001 1002 1003 1004 1005 1006 1007
            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")
L
liym27 已提交
1008 1009 1010

        self.assertRaises(ValueError, run_7)

1011 1012
        # ValueError: filter num
        def run_8():
1013 1014 1015 1016 1017 1018 1019 1020 1021
            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")
1022 1023 1024

        self.assertRaises(ValueError, run_8)

L
liym27 已提交
1025

C
chengduoZH 已提交
1026
if __name__ == '__main__':
H
hong 已提交
1027
    paddle.enable_static()
C
chengduoZH 已提交
1028
    unittest.main()