diff --git a/python/paddle/fluid/tests/unittests/test_deform_conv2d.py b/python/paddle/fluid/tests/unittests/test_deform_conv2d.py index dc57e87f94022e2598c4ed2f2fce0b37d7f817a7..508fc1705218a0da72d1fb5213f4663852e08c3f 100644 --- a/python/paddle/fluid/tests/unittests/test_deform_conv2d.py +++ b/python/paddle/fluid/tests/unittests/test_deform_conv2d.py @@ -32,6 +32,7 @@ class TestDeformConv2D(TestCase): self.padding = [0, 0] self.stride = [1, 1] self.dilation = [1, 1] + self.deformable_groups = 1 self.groups = 1 self.no_bias = True @@ -67,11 +68,11 @@ class TestDeformConv2D(TestCase): self.input_shape = (self.batch_size, self.in_channels ) + self.spatial_shape - self.offset_shape = (self.batch_size, 2 * filter_shape[0] * - filter_shape[1]) + out_shape + self.offset_shape = (self.batch_size, self.deformable_groups * 2 * + filter_shape[0] * filter_shape[1]) + out_shape - self.mask_shape = (self.batch_size, filter_shape[0] * filter_shape[1] - ) + out_shape + self.mask_shape = (self.batch_size, self.deformable_groups * + filter_shape[0] * filter_shape[1]) + out_shape self.input = np.random.uniform(-1, 1, self.input_shape).astype(self.dtype) @@ -89,12 +90,12 @@ class TestDeformConv2D(TestCase): x = paddle.static.data( "input", (-1, self.in_channels, -1, -1), dtype=self.dtype) offset = paddle.static.data( - "offset", - (-1, 2 * self.filter_shape[0] * self.filter_shape[1], -1, -1), + "offset", (-1, self.deformable_groups * 2 * + self.filter_shape[0] * self.filter_shape[1], -1, -1), dtype=self.dtype) mask = paddle.static.data( - "mask", - (-1, self.filter_shape[0] * self.filter_shape[1], -1, -1), + "mask", (-1, self.deformable_groups * self.filter_shape[0] * + self.filter_shape[1], -1, -1), dtype=self.dtype) y_v1 = paddle.fluid.layers.deformable_conv( @@ -107,7 +108,7 @@ class TestDeformConv2D(TestCase): padding=self.padding, dilation=self.dilation, groups=self.groups, - deformable_groups=1, + deformable_groups=self.deformable_groups, im2col_step=1, param_attr=I.Assign(self.weight), bias_attr=False if self.no_bias else I.Assign(self.bias), @@ -123,7 +124,7 @@ class TestDeformConv2D(TestCase): padding=self.padding, dilation=self.dilation, groups=self.groups, - deformable_groups=1, + deformable_groups=self.deformable_groups, im2col_step=1, param_attr=I.Assign(self.weight), bias_attr=False if self.no_bias else I.Assign(self.bias)) @@ -154,6 +155,7 @@ class TestDeformConv2D(TestCase): stride=self.stride, padding=self.padding, dilation=self.dilation, + deformable_groups=self.deformable_groups, groups=self.groups, weight_attr=I.Assign(self.weight), bias_attr=False if self.no_bias else I.Assign(self.bias)) @@ -194,6 +196,7 @@ class TestDeformConv2DFunctional(TestCase): self.padding = [0, 0] self.stride = [1, 1] self.dilation = [1, 1] + self.deformable_groups = 1 self.groups = 1 self.no_bias = True @@ -229,11 +232,11 @@ class TestDeformConv2DFunctional(TestCase): self.input_shape = (self.batch_size, self.in_channels ) + self.spatial_shape - self.offset_shape = (self.batch_size, 2 * filter_shape[0] * - filter_shape[1]) + out_shape + self.offset_shape = (self.batch_size, self.deformable_groups * 2 * + filter_shape[0] * filter_shape[1]) + out_shape - self.mask_shape = (self.batch_size, filter_shape[0] * filter_shape[1] - ) + out_shape + self.mask_shape = (self.batch_size, self.deformable_groups * + filter_shape[0] * filter_shape[1]) + out_shape self.input = np.random.uniform(-1, 1, self.input_shape).astype(self.dtype) @@ -251,12 +254,12 @@ class TestDeformConv2DFunctional(TestCase): x = paddle.static.data( "input", (-1, self.in_channels, -1, -1), dtype=self.dtype) offset = paddle.static.data( - "offset", - (-1, 2 * self.filter_shape[0] * self.filter_shape[1], -1, -1), + "offset", (-1, self.deformable_groups * 2 * + self.filter_shape[0] * self.filter_shape[1], -1, -1), dtype=self.dtype) mask = paddle.static.data( - "mask", - (-1, self.filter_shape[0] * self.filter_shape[1], -1, -1), + "mask", (-1, self.deformable_groups * self.filter_shape[0] * + self.filter_shape[1], -1, -1), dtype=self.dtype) y_v1 = paddle.fluid.layers.deformable_conv( @@ -269,7 +272,7 @@ class TestDeformConv2DFunctional(TestCase): padding=self.padding, dilation=self.dilation, groups=self.groups, - deformable_groups=1, + deformable_groups=self.deformable_groups, im2col_step=1, param_attr=I.Assign(self.weight), bias_attr=False if self.no_bias else I.Assign(self.bias), @@ -285,7 +288,7 @@ class TestDeformConv2DFunctional(TestCase): padding=self.padding, dilation=self.dilation, groups=self.groups, - deformable_groups=1, + deformable_groups=self.deformable_groups, im2col_step=1, param_attr=I.Assign(self.weight), bias_attr=False if self.no_bias else I.Assign(self.bias)) @@ -317,6 +320,7 @@ class TestDeformConv2DFunctional(TestCase): stride=self.stride, padding=self.padding, dilation=self.dilation, + deformable_groups=self.deformable_groups, groups=self.groups, ) y_v2 = paddle.vision.ops.deform_conv2d( @@ -328,6 +332,7 @@ class TestDeformConv2DFunctional(TestCase): stride=self.stride, padding=self.padding, dilation=self.dilation, + deformable_groups=self.deformable_groups, groups=self.groups, ) out_v1 = y_v1.numpy() @@ -343,12 +348,12 @@ class TestDeformConv2DFunctional(TestCase): x = paddle.static.data( "input", (-1, self.in_channels, -1, -1), dtype=self.dtype) offset = paddle.static.data( - "offset", - (-1, 2 * self.filter_shape[0] * self.filter_shape[1], -1, -1), + "offset", (-1, self.deformable_groups * 2 * + self.filter_shape[0] * self.filter_shape[1], -1, -1), dtype=self.dtype) mask = paddle.static.data( - "mask", - (-1, self.filter_shape[0] * self.filter_shape[1], -1, -1), + "mask", (-1, self.deformable_groups * self.filter_shape[0] * + self.filter_shape[1], -1, -1), dtype=self.dtype) weight = paddle.static.data( @@ -365,6 +370,7 @@ class TestDeformConv2DFunctional(TestCase): stride=self.stride, padding=self.padding, dilation=self.dilation, + deformable_groups=self.deformable_groups, groups=self.groups, ) y_v2 = paddle.vision.ops.deform_conv2d( @@ -376,6 +382,7 @@ class TestDeformConv2DFunctional(TestCase): stride=self.stride, padding=self.padding, dilation=self.dilation, + deformable_groups=self.deformable_groups, groups=self.groups, ) exe = paddle.static.Executor(self.place) @@ -421,6 +428,7 @@ class TestDeformConv2DWithPadding(TestDeformConv2D): self.padding = [2, 2] self.stride = [1, 1] self.dilation = [1, 1] + self.deformable_groups = 1 self.groups = 1 self.no_bias = True @@ -433,6 +441,7 @@ class TestDeformConv2DWithBias(TestDeformConv2D): self.padding = [2, 2] self.stride = [1, 1] self.dilation = [1, 1] + self.deformable_groups = 1 self.groups = 1 self.no_bias = False @@ -445,6 +454,7 @@ class TestDeformConv2DWithAsynPadding(TestDeformConv2D): self.padding = [1, 2] self.stride = [1, 1] self.dilation = [1, 1] + self.deformable_groups = 1 self.groups = 1 self.no_bias = False @@ -457,6 +467,7 @@ class TestDeformConv2DWithDilation(TestDeformConv2D): self.padding = [1, 1] self.stride = [1, 1] self.dilation = [3, 3] + self.deformable_groups = 1 self.groups = 1 self.no_bias = False @@ -469,6 +480,20 @@ class TestDeformConv2DWithStride(TestDeformConv2D): self.padding = [1, 1] self.stride = [2, 2] self.dilation = [1, 1] + self.deformable_groups = 1 + self.groups = 1 + self.no_bias = False + + +class TestDeformConv2DWithDeformable_Groups(TestDeformConv2D): + def setUp(self): + self.in_channels = 5 + self.out_channels = 5 + self.kernel_size = [3, 3] + self.padding = [1, 1] + self.stride = [1, 1] + self.dilation = [1, 1] + self.deformable_groups = 5 self.groups = 1 self.no_bias = False @@ -481,6 +506,7 @@ class TestDeformConv2DWithGroups(TestDeformConv2D): self.padding = [1, 1] self.stride = [1, 1] self.dilation = [1, 1] + self.deformable_groups = 1 self.groups = 5 self.no_bias = False @@ -494,6 +520,7 @@ class TestDeformConv2DFunctionalWithPadding(TestDeformConv2DFunctional): self.padding = [2, 2] self.stride = [1, 1] self.dilation = [1, 1] + self.deformable_groups = 1 self.groups = 1 self.no_bias = True @@ -506,6 +533,7 @@ class TestDeformConv2DFunctionalWithBias(TestDeformConv2DFunctional): self.padding = [2, 2] self.stride = [1, 1] self.dilation = [1, 1] + self.deformable_groups = 1 self.groups = 1 self.no_bias = False @@ -518,6 +546,7 @@ class TestDeformConv2DFunctionalWithAsynPadding(TestDeformConv2DFunctional): self.padding = [1, 2] self.stride = [1, 1] self.dilation = [1, 1] + self.deformable_groups = 1 self.groups = 1 self.no_bias = False @@ -530,6 +559,7 @@ class TestDeformConv2DFunctionalWithDilation(TestDeformConv2DFunctional): self.padding = [1, 1] self.stride = [1, 1] self.dilation = [3, 3] + self.deformable_groups = 1 self.groups = 1 self.no_bias = False @@ -542,6 +572,21 @@ class TestDeformConv2DFunctionalWithStride(TestDeformConv2DFunctional): self.padding = [1, 1] self.stride = [2, 2] self.dilation = [1, 1] + self.deformable_groups = 1 + self.groups = 1 + self.no_bias = False + + +class TestDeformConv2DFunctionalWithDeformable_Groups( + TestDeformConv2DFunctional): + def setUp(self): + self.in_channels = 5 + self.out_channels = 5 + self.kernel_size = [3, 3] + self.padding = [1, 1] + self.stride = [1, 1] + self.dilation = [1, 1] + self.deformable_groups = 5 self.groups = 1 self.no_bias = False @@ -554,6 +599,7 @@ class TestDeformConv2DFunctionalWithGroups(TestDeformConv2DFunctional): self.padding = [1, 1] self.stride = [1, 1] self.dilation = [1, 1] + self.deformable_groups = 1 self.groups = 5 self.no_bias = False diff --git a/python/paddle/vision/ops.py b/python/paddle/vision/ops.py index 4b4e2088708bb955d5c7811473b49baf996a4ef3..079aa086f2b3be0abb0068eb5ede98f89b304d0c 100644 --- a/python/paddle/vision/ops.py +++ b/python/paddle/vision/ops.py @@ -398,6 +398,7 @@ def deform_conv2d(x, stride=1, padding=0, dilation=1, + deformable_groups=1, groups=1, mask=None, name=None): @@ -462,6 +463,8 @@ def deform_conv2d(x, dilation (int|list|tuple, optional): The dilation size. If dilation is a tuple, it must contain two integers, (dilation_H, dilation_W). Otherwise, the dilation_H = dilation_W = dilation. Default: dilation = 1. + deformable_groups (int): The number of deformable group partitions. + Default: deformable_groups = 1. groups (int, optonal): The groups number of the deformable conv layer. According to grouped convolution in Alex Krizhevsky's Deep CNN paper: when group=2, the first half of the filters is only connected to the first half @@ -521,7 +524,8 @@ def deform_conv2d(x, if in_dygraph_mode(): attrs = ('strides', stride, 'paddings', padding, 'dilations', dilation, - 'groups', groups, 'im2col_step', 1) + 'deformable_groups', deformable_groups, 'groups', groups, + 'im2col_step', 1) if use_deform_conv2d_v1: op_type = 'deformable_conv_v1' pre_bias = getattr(core.ops, op_type)(x, offset, weight, *attrs) @@ -572,7 +576,7 @@ def deform_conv2d(x, 'paddings': padding, 'dilations': dilation, 'groups': groups, - 'deformable_groups': 1, + 'deformable_groups': deformable_groups, 'im2col_step': 1, } helper.append_op( @@ -649,6 +653,8 @@ class DeformConv2D(Layer): dilation(int|list|tuple, optional): The dilation size. If dilation is a tuple, it must contain three integers, (dilation_D, dilation_H, dilation_W). Otherwise, the dilation_D = dilation_H = dilation_W = dilation. The default value is 1. + deformable_groups (int): The number of deformable group partitions. + Default: deformable_groups = 1. groups(int, optional): The groups number of the Conv3D Layer. According to grouped convolution in Alex Krizhevsky's Deep CNN paper: when group=2, the first half of the filters is only connected to the first half @@ -726,6 +732,7 @@ class DeformConv2D(Layer): stride=1, padding=0, dilation=1, + deformable_groups=1, groups=1, weight_attr=None, bias_attr=None): @@ -733,6 +740,7 @@ class DeformConv2D(Layer): assert weight_attr is not False, "weight_attr should not be False in Conv." self._weight_attr = weight_attr self._bias_attr = bias_attr + self._deformable_groups = deformable_groups self._groups = groups self._in_channels = in_channels self._out_channels = out_channels @@ -770,6 +778,7 @@ class DeformConv2D(Layer): stride=self._stride, padding=self._padding, dilation=self._dilation, + deformable_groups=self._deformable_groups, groups=self._groups, mask=mask) return out