conv.py 48.3 KB
Newer Older
Z
zhunaipan 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
# Copyright 2020 Huawei Technologies Co., Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ============================================================================
"""conv"""
16

L
liuxiao93 已提交
17
import numpy as np
Z
zhunaipan 已提交
18 19
from mindspore import log as logger
from mindspore.ops import operations as P
L
liuxiao93 已提交
20
from mindspore.ops.primitive import constexpr
Z
zhunaipan 已提交
21 22
from mindspore.common.parameter import Parameter
from mindspore.common.initializer import initializer
L
liuxiao93 已提交
23
from mindspore.common.tensor import Tensor
24
from mindspore._checkparam import ParamValidator as validator, Rel
J
jiangjinsheng 已提交
25
from mindspore._checkparam import Validator
J
jiangjinsheng 已提交
26
from mindspore._checkparam import check_bool, twice, check_int_positive
Z
zhunaipan 已提交
27 28 29
from mindspore._extends import cell_attr_register
from ..cell import Cell

J
jiangjinsheng 已提交
30
__all__ = ['Conv2d', 'Conv2dTranspose', 'DepthwiseConv2d', 'Conv1d', 'Conv1dTranspose']
Z
zhunaipan 已提交
31

32

Z
zhunaipan 已提交
33 34 35 36
class _Conv(Cell):
    """
    Applies a N-D convolution over an input signal composed of several input planes.
    """
37

Z
zhunaipan 已提交
38 39 40 41 42 43 44 45 46 47 48
    def __init__(self,
                 in_channels,
                 out_channels,
                 kernel_size,
                 stride,
                 pad_mode,
                 padding,
                 dilation,
                 group,
                 has_bias,
                 weight_init,
J
jinyaohui 已提交
49 50
                 bias_init,
                 transposed=False):
Z
zhunaipan 已提交
51 52 53 54
        super(_Conv, self).__init__()
        self.in_channels = check_int_positive(in_channels)
        self.out_channels = check_int_positive(out_channels)
        self.kernel_size = kernel_size
55
        self.stride = stride
Z
zhunaipan 已提交
56
        self.pad_mode = pad_mode
C
chenzomi 已提交
57 58
        self.weight_init = weight_init
        self.bias_init = bias_init
J
jiangjinsheng 已提交
59 60 61 62 63 64 65 66 67 68
        if isinstance(padding, int):
            Validator.check_integer('padding', padding, 0, Rel.GE, self.cls_name)
            self.padding = padding
        elif isinstance(padding, tuple):
            for pad in padding:
                Validator.check_integer('padding item', pad, 0, Rel.GE, self.cls_name)
            self.padding = padding
        else:
            raise TypeError("padding type must be int/tuple(int) cannot be {}!".format(type(padding)))

69
        self.dilation = dilation
Z
zhunaipan 已提交
70 71
        self.group = check_int_positive(group)
        self.has_bias = has_bias
72
        if (not isinstance(kernel_size[0], int)) or (not isinstance(kernel_size[1], int)) or \
73 74
                isinstance(kernel_size[0], bool) or isinstance(kernel_size[1], bool) or \
                kernel_size[0] < 1 or kernel_size[1] < 1:
Z
zhunaipan 已提交
75 76
            raise ValueError("Attr 'kernel_size' of 'Conv2D' Op passed "
                             + str(self.kernel_size) + ", should be a int or tuple and equal to or greater than 1.")
77
        if (not isinstance(stride[0], int)) or (not isinstance(stride[1], int)) or \
78
                isinstance(stride[0], bool) or isinstance(stride[1], bool) or stride[0] < 1 or stride[1] < 1:
79 80 81
            raise ValueError("Attr 'stride' of 'Conv2D' Op passed "
                             + str(self.stride) + ", should be a int or tuple and equal to or greater than 1.")
        if (not isinstance(dilation[0], int)) or (not isinstance(dilation[1], int)) or \
82
                isinstance(dilation[0], bool) or isinstance(dilation[1], bool) or dilation[0] < 1 or dilation[1] < 1:
83
            raise ValueError("Attr 'dilation' of 'Conv2D' Op passed "
84
                             + str(self.dilation) + ", should be a int or tuple and equal to or greater than 1.")
Z
zhunaipan 已提交
85 86 87 88 89 90
        if in_channels % group != 0:
            raise ValueError("Attr 'in_channels' of 'Conv2D' Op must be divisible by "
                             "attr 'group' of 'Conv2D' Op.")
        if out_channels % group != 0:
            raise ValueError("Attr 'out_channels' of 'Conv2D' Op must be divisible by "
                             "attr 'group' of 'Conv2D' Op.")
J
jinyaohui 已提交
91 92 93 94
        if transposed:
            shape = [in_channels, out_channels // group, *kernel_size]
        else:
            shape = [out_channels, in_channels // group, *kernel_size]
C
chenzomi 已提交
95
        self.weight = Parameter(initializer(self.weight_init, shape), name='weight')
Z
zhunaipan 已提交
96 97

        if check_bool(has_bias):
C
chenzomi 已提交
98
            self.bias = Parameter(initializer(self.bias_init, [out_channels]), name='bias')
Z
zhunaipan 已提交
99
        else:
C
chenzomi 已提交
100
            if self.bias_init != 'zeros':
Z
zhunaipan 已提交
101 102 103 104 105 106 107 108 109 110 111 112 113
                logger.warning("Value of 'has_bias' is False, value of 'bias_init' will be ignored.")
            self.bias = None

    def construct(self, *inputs):
        """Must be overridden by all subclasses."""
        raise NotImplementedError


class Conv2d(_Conv):
    r"""
    2D convolution layer.

    Applies a 2D convolution over an input tensor which is typically of shape :math:`(N, C_{in}, H_{in}, W_{in})`,
S
simson 已提交
114 115
    where :math:`N` is batch size, :math:`C_{in}` is channel number, and :math:`H_{in}, W_{in})` are height and width.
    For each batch of shape :math:`(C_{in}, H_{in}, W_{in})`, the formula is defined as:
Z
zhunaipan 已提交
116 117 118 119 120

    .. math::

        out_j = \sum_{i=0}^{C_{in} - 1} ccor(W_{ij}, X_i) + b_j,

S
simson 已提交
121
    where :math:`ccor` is the cross-correlation operator, :math:`C_{in}` is the input channel number, :math:`j` ranges
122
    from :math:`0` to :math:`C_{out} - 1`, :math:`W_{ij}` corresponds to the :math:`i`-th channel of the :math:`j`-th
Z
zhunaipan 已提交
123 124
    filter and :math:`out_{j}` corresponds to the :math:`j`-th channel of the output. :math:`W_{ij}` is a slice
    of kernel and it has shape :math:`(\text{ks_h}, \text{ks_w})`, where :math:`\text{ks_h}` and
125
    :math:`\text{ks_w}` are the height and width of the convolution kernel. The full kernel has shape
Z
zhunaipan 已提交
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
    :math:`(C_{out}, C_{in} // \text{group}, \text{ks_h}, \text{ks_w})`, where group is the group number
    to split the input in the channel dimension.

    If the 'pad_mode' is set to be "valid", the output height and width will be
    :math:`\left \lfloor{1 + \frac{H_{in} + 2 \times \text{padding} - \text{ks_h} -
    (\text{ks_h} - 1) \times (\text{dilation} - 1) }{\text{stride}}} \right \rfloor` and
    :math:`\left \lfloor{1 + \frac{W_{in} + 2 \times \text{padding} - \text{ks_w} -
    (\text{ks_w} - 1) \times (\text{dilation} - 1) }{\text{stride}}} \right \rfloor` respectively.

    The first introduction can be found in paper `Gradient Based Learning Applied to Document Recognition
    <http://vision.stanford.edu/cs598_spring07/papers/Lecun98.pdf>`_.

    Args:
        in_channels (int): The number of input channel :math:`C_{in}`.
        out_channels (int): The number of output channel :math:`C_{out}`.
141
        kernel_size (Union[int, tuple[int]]): The data type is int or a tuple of 2 integers. Specifies the height
142
            and width of the 2D convolution window. Single int means the value is for both the height and the width of
Z
zhunaipan 已提交
143 144
            the kernel. A tuple of 2 ints means the first value is for the height and the other is for the
            width of the kernel.
145 146 147
        stride (Union[int, tuple[int]]): The distance of kernel moving, an int number that represents
            the height and width of movement are both strides, or a tuple of two int numbers that
            represent height and width of movement respectively. Default: 1.
Z
zhunaipan 已提交
148 149 150
        pad_mode (str): Specifies padding mode. The optional values are
            "same", "valid", "pad". Default: "same".

151 152 153
            - same: Adopts the way of completion. The height and width of the output will be the same as
              the input. The total number of padding will be calculated in horizontal and vertical
              directions and evenly distributed to top and bottom, left and right if possible. Otherwise, the
Z
zhunaipan 已提交
154 155 156
              last extra padding will be done from the bottom and the right side. If this mode is set, `padding`
              must be 0.

157
            - valid: Adopts the way of discarding. The possible largest height and width of output will be returned
Z
zhunaipan 已提交
158 159 160 161 162 163
              without padding. Extra pixels will be discarded. If this mode is set, `padding`
              must be 0.

            - pad: Implicit paddings on both sides of the input. The number of `padding` will be padded to the input
              Tensor borders. `padding` should be greater than or equal to 0.

J
jiangjinsheng 已提交
164
        padding (Union[int, tuple[int]]): Implicit paddings on both sides of the input. If `padding` is one integer,
S
simson 已提交
165 166
                    the paddings of top, bottom, left and right are the same, equal to padding. If `padding` is a tuple
                    with four integers, the paddings of top, bottom, left and right will be equal to padding[0],
167
                    padding[1], padding[2], and padding[3] accordingly. Default: 0.
168
        dilation (Union[int, tuple[int]]): The data type is int or a tuple of 2 integers. Specifies the dilation rate
169 170 171 172
                                      to use for dilated convolution. If set to be :math:`k > 1`, there will
                                      be :math:`k - 1` pixels skipped for each sampling location. Its value should
                                      be greater or equal to 1 and bounded by the height and width of the
                                      input. Default: 1.
Z
zhunaipan 已提交
173 174 175 176
        group (int): Split filter into groups, `in_ channels` and `out_channels` should be
            divisible by the number of groups. Default: 1.
        has_bias (bool): Specifies whether the layer uses a bias vector. Default: False.
        weight_init (Union[Tensor, str, Initializer, numbers.Number]): Initializer for the convolution kernel.
177
            It can be a Tensor, a string, an Initializer or a number. When a string is specified,
Z
zhunaipan 已提交
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
            values from 'TruncatedNormal', 'Normal', 'Uniform', 'HeUniform' and 'XavierUniform' distributions as well
            as constant 'One' and 'Zero' distributions are possible. Alias 'xavier_uniform', 'he_uniform', 'ones'
            and 'zeros' are acceptable. Uppercase and lowercase are both acceptable. Refer to the values of
            Initializer for more details. Default: 'normal'.
        bias_init (Union[Tensor, str, Initializer, numbers.Number]): Initializer for the bias vector. Possible
            Initializer and string are the same as 'weight_init'. Refer to the values of
            Initializer for more details. Default: 'zeros'.

    Inputs:
        - **input** (Tensor) - Tensor of shape :math:`(N, C_{in}, H_{in}, W_{in})`.

    Outputs:
        Tensor of shape :math:`(N, C_{out}, H_{out}, W_{out})`.

    Examples:
        >>> net = nn.Conv2d(120, 240, 4, has_bias=False, weight_init='normal')
Z
zhongligeng 已提交
194
        >>> input = Tensor(np.ones([1, 120, 1024, 640]), mindspore.float32)
195
        >>> net(input).shape
高东海's avatar
高东海 已提交
196
        (1, 240, 1024, 640)
Z
zhunaipan 已提交
197
    """
198

Z
zhunaipan 已提交
199 200 201 202 203 204 205 206 207 208 209 210 211 212
    @cell_attr_register
    def __init__(self,
                 in_channels,
                 out_channels,
                 kernel_size,
                 stride=1,
                 pad_mode='same',
                 padding=0,
                 dilation=1,
                 group=1,
                 has_bias=False,
                 weight_init='normal',
                 bias_init='zeros'):
        kernel_size = twice(kernel_size)
213 214
        stride = twice(stride)
        dilation = twice(dilation)
Z
zhunaipan 已提交
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
        super(Conv2d, self).__init__(
            in_channels,
            out_channels,
            kernel_size,
            stride,
            pad_mode,
            padding,
            dilation,
            group,
            has_bias,
            weight_init,
            bias_init)
        self.conv2d = P.Conv2D(out_channel=self.out_channels,
                               kernel_size=self.kernel_size,
                               mode=1,
                               pad_mode=self.pad_mode,
                               pad=self.padding,
                               stride=self.stride,
                               dilation=self.dilation,
                               group=self.group)
        self.bias_add = P.BiasAdd()
        if pad_mode not in ('valid', 'same', 'pad'):
            raise ValueError('Attr \'pad_mode\' of \'Conv2d\' Op passed '
                             + str(pad_mode) + ', should be one of values in \'valid\', \'same\', \'pad\'.')

    def construct(self, x):
        output = self.conv2d(x, self.weight)
        if self.has_bias:
            output = self.bias_add(output, self.bias)
        return output

    def extend_repr(self):
        s = 'input_channels={}, output_channels={}, kernel_size={},' \
            'stride={},  pad_mode={}, padding={}, dilation={}, ' \
            'group={}, has_bias={},' \
            'weight_init={}, bias_init={}'.format(
                self.in_channels,
                self.out_channels,
                self.kernel_size,
                self.stride,
                self.pad_mode,
                self.padding,
                self.dilation,
                self.group,
                self.has_bias,
C
chenzomi 已提交
260 261
                self.weight_init,
                self.bias_init)
Z
zhunaipan 已提交
262 263 264
        return s


L
liuxiao93 已提交
265 266 267 268 269
@constexpr
def _check_input_3d(input_shape):
    if len(input_shape) != 3:
        raise ValueError(f"Input should be 3d, but got shape {input_shape}")

270

J
jiangjinsheng 已提交
271 272 273 274 275 276 277 278 279 280 281 282
class Conv1d(_Conv):
    r"""
    1D convolution layer.

    Applies a 1D convolution over an input tensor which is typically of shape :math:`(N, C_{in}, W_{in})`,
    where :math:`N` is batch size and :math:`C_{in}` is channel number. For each batch of shape
    :math:`(C_{in}, W_{in})`, the formula is defined as:

    .. math::

        out_j = \sum_{i=0}^{C_{in} - 1} ccor(W_{ij}, X_i) + b_j,

283 284
    where :math:`ccor` is the cross correlation operator, :math:`C_{in}` is the input channel number, :math:`j` ranges
    from :math:`0` to :math:`C_{out} - 1`, :math:`W_{ij}` corresponds to the :math:`i`-th channel of the :math:`j`-th
J
jiangjinsheng 已提交
285
    filter and :math:`out_{j}` corresponds to the :math:`j`-th channel of the output. :math:`W_{ij}` is a slice
286
    of kernel and it has shape :math:`(\text{ks_w})`, where :math:`\text{ks_w}` is the width of the convolution kernel.
J
jiangjinsheng 已提交
287 288 289 290 291 292 293
    The full kernel has shape :math:`(C_{out}, C_{in} // \text{group}, \text{ks_w})`, where group is the group number
    to split the input in the channel dimension.

    If the 'pad_mode' is set to be "valid", the output width will be
    :math:`\left \lfloor{1 + \frac{W_{in} + 2 \times \text{padding} - \text{ks_w} -
    (\text{ks_w} - 1) \times (\text{dilation} - 1) }{\text{stride}}} \right \rfloor` respectively.

294 295
    The first introduction of convolution layer can be found in paper `Gradient Based Learning Applied to Document
    Recognition <http://vision.stanford.edu/cs598_spring07/papers/Lecun98.pdf>`_.
J
jiangjinsheng 已提交
296 297 298 299 300 301 302 303 304 305 306

    Args:
        in_channels (int): The number of input channel :math:`C_{in}`.
        out_channels (int): The number of output channel :math:`C_{out}`.
        kernel_size (int): The data type is int. Specifies the
            width of the 1D convolution window.
        stride (int): The distance of kernel moving, an int number that represents
            the width of movement. Default: 1.
        pad_mode (str): Specifies padding mode. The optional values are
            "same", "valid", "pad". Default: "same".

307 308
            - same: Adopts the way of completion. The output width will be the same as the input.
              The total number of padding will be calculated in the horizontal
J
jiangjinsheng 已提交
309 310 311 312
              direction and evenly distributed to left and right if possible. Otherwise, the
              last extra padding will be done from the bottom and the right side. If this mode is set, `padding`
              must be 0.

313
            - valid: Adopts the way of discarding. The possible largest width of the output will be returned
J
jiangjinsheng 已提交
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
              without padding. Extra pixels will be discarded. If this mode is set, `padding`
              must be 0.

            - pad: Implicit paddings on both sides of the input. The number of `padding` will be padded to the input
              Tensor borders. `padding` should be greater than or equal to 0.

        padding (int): Implicit paddings on both sides of the input. Default: 0.
        dilation (int): The data type is int. Specifies the dilation rate
                                      to use for dilated convolution. If set to be :math:`k > 1`, there will
                                      be :math:`k - 1` pixels skipped for each sampling location. Its value should
                                      be greater or equal to 1 and bounded by the height and width of the
                                      input. Default: 1.
        group (int): Split filter into groups, `in_ channels` and `out_channels` should be
            divisible by the number of groups. Default: 1.
        has_bias (bool): Specifies whether the layer uses a bias vector. Default: False.
329 330
        weight_init (Union[Tensor, str, Initializer, numbers.Number]): An initializer for the convolution kernel.
            It can be a Tensor, a string, an Initializer or a number. When a string is specified,
J
jiangjinsheng 已提交
331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350
            values from 'TruncatedNormal', 'Normal', 'Uniform', 'HeUniform' and 'XavierUniform' distributions as well
            as constant 'One' and 'Zero' distributions are possible. Alias 'xavier_uniform', 'he_uniform', 'ones'
            and 'zeros' are acceptable. Uppercase and lowercase are both acceptable. Refer to the values of
            Initializer for more details. Default: 'normal'.
        bias_init (Union[Tensor, str, Initializer, numbers.Number]): Initializer for the bias vector. Possible
            Initializer and string are the same as 'weight_init'. Refer to the values of
            Initializer for more details. Default: 'zeros'.

    Inputs:
        - **input** (Tensor) - Tensor of shape :math:`(N, C_{in}, W_{in})`.

    Outputs:
        Tensor of shape :math:`(N, C_{out}, W_{out})`.

    Examples:
        >>> net = nn.Conv1d(120, 240, 4, has_bias=False, weight_init='normal')
        >>> input = Tensor(np.ones([1, 120, 640]), mindspore.float32)
        >>> net(input).shape
        (1, 240, 640)
    """
351

J
jiangjinsheng 已提交
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376
    @cell_attr_register
    def __init__(self,
                 in_channels,
                 out_channels,
                 kernel_size,
                 stride=1,
                 pad_mode='same',
                 padding=0,
                 dilation=1,
                 group=1,
                 has_bias=False,
                 weight_init='normal',
                 bias_init='zeros'):

        Validator.check_value_type("kernel_size", kernel_size, [int], self.cls_name)
        Validator.check_value_type("stride", stride, [int], self.cls_name)
        Validator.check_value_type("padding", padding, [int], self.cls_name)
        Validator.check_value_type("dilation", dilation, [int], self.cls_name)
        Validator.check_integer('kernel_size', kernel_size, 1, Rel.GE, self.cls_name)
        Validator.check_integer('stride', stride, 1, Rel.GE, self.cls_name)
        Validator.check_integer('padding', padding, 0, Rel.GE, self.cls_name)
        Validator.check_integer('dilation', dilation, 1, Rel.GE, self.cls_name)
        kernel_size = (1, kernel_size)
        stride = (1, stride)
        dilation = (1, dilation)
L
liuxiao93 已提交
377 378 379 380 381 382 383 384 385
        get_shape = P.Shape()
        get_dtype = P.DType()
        if isinstance(weight_init, Tensor):
            weight_init_shape = get_shape(weight_init)
            Validator.check_integer('weight_init_shape', len(weight_init_shape), 3, Rel.EQ, self.cls_name)
            weight_init_dtype = get_dtype(weight_init)
            weight_init_value = weight_init.asnumpy()
            weight_init_value = np.expand_dims(weight_init_value, 2)
            weight_init = Tensor(weight_init_value, weight_init_dtype)
J
jiangjinsheng 已提交
386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417

        super(Conv1d, self).__init__(
            in_channels,
            out_channels,
            kernel_size,
            stride,
            pad_mode,
            padding,
            dilation,
            group,
            has_bias,
            weight_init,
            bias_init)
        self.padding = (0, 0, padding, padding)
        self.conv2d = P.Conv2D(out_channel=self.out_channels,
                               kernel_size=self.kernel_size,
                               mode=1,
                               pad_mode=self.pad_mode,
                               pad=self.padding,
                               stride=self.stride,
                               dilation=self.dilation,
                               group=self.group)
        self.bias_add = P.BiasAdd()
        if pad_mode not in ('valid', 'same', 'pad'):
            raise ValueError('Attr \'pad_mode\' of \'Conv1d\' Op passed '
                             + str(pad_mode) + ', should be one of values in \'valid\', \'same\', \'pad\'.')
        self.expand_dims = P.ExpandDims()
        self.squeeze = P.Squeeze(2)
        self.shape = P.Shape()

    def construct(self, x):
        x_shape = self.shape(x)
L
liuxiao93 已提交
418 419
        _check_input_3d(x_shape)
        x = self.expand_dims(x, 2)
J
jiangjinsheng 已提交
420 421 422
        output = self.conv2d(x, self.weight)
        if self.has_bias:
            output = self.bias_add(output, self.bias)
L
liuxiao93 已提交
423 424

        output = self.squeeze(output)
J
jiangjinsheng 已提交
425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440
        return output

    def extend_repr(self):
        s = 'input_channels={}, output_channels={}, kernel_size={},' \
            'stride={},  pad_mode={}, padding={}, dilation={}, ' \
            'group={}, has_bias={},' \
            'weight_init={}, bias_init={}'.format(
                self.in_channels,
                self.out_channels,
                self.kernel_size,
                self.stride,
                self.pad_mode,
                self.padding,
                self.dilation,
                self.group,
                self.has_bias,
C
chenzomi 已提交
441 442
                self.weight_init,
                self.bias_init)
J
jiangjinsheng 已提交
443 444 445
        return s


Z
zhunaipan 已提交
446 447 448 449
class Conv2dTranspose(_Conv):
    r"""
    2D transposed convolution layer.

450 451
    Compute a 2D transposed convolution, which is also known as a deconvolution
    (although it is not an actual deconvolution).
Z
zhunaipan 已提交
452 453 454 455 456 457

    Input is typically of shape :math:`(N, C, H, W)`, where :math:`N` is batch size and :math:`C` is channel number.

    Args:
        in_channels (int): The number of channels in the input space.
        out_channels (int): The number of channels in the output space.
458
        kernel_size (Union[int, tuple]): int or a tuple of 2 integers, which specifies the  height
459
            and width of the 2D convolution window. Single int means the value is for both the height and the width of
Z
zhunaipan 已提交
460 461
            the kernel. A tuple of 2 ints means the first value is for the height and the other is for the
            width of the kernel.
462 463
        stride (Union[int, tuple[int]]): The distance of kernel moving, an int number that represents
            the height and width of movement are both strides, or a tuple of two int numbers that
L
lihongkang 已提交
464 465
            represent height and width of movement respectively. Its value should be equal to or greater than 1.
            Default: 1.
Z
zhunaipan 已提交
466 467 468 469 470 471 472 473
        pad_mode (str): Select the mode of the pad. The optional values are
            "pad", "same", "valid". Default: "same".

            - pad: Implicit paddings on both sides of the input.

            - same: Adopted the way of completion.

            - valid: Adopted the way of discarding.
J
jiangjinsheng 已提交
474
        padding (Union[int, tuple[int]]): Implicit paddings on both sides of the input. If `padding` is one integer,
S
simson 已提交
475 476
                    the paddings of top, bottom, left and right are the same, equal to padding. If `padding` is a tuple
                    with four integers, the paddings of top, bottom, left and right will be equal to padding[0],
477 478
                    padding[1], padding[2], and padding[3] accordingly. Default: 0.
        dilation (Union[int, tuple[int]]): The data type is int or a tuple of 2 integers. Specifies the dilation rate
479 480
                                      to use for dilated convolution. If set to be :math:`k > 1`, there will
                                      be :math:`k - 1` pixels skipped for each sampling location. Its value should
481
                                      be greater than or equal to 1 and bounded by the height and width of the
482
                                      input. Default: 1.
Z
zhunaipan 已提交
483
        group (int): Split filter into groups, `in_channels` and `out_channels` should be
484
            divisible by the number of groups. This does not support for Davinci devices when group > 1. Default: 1.
Z
zhunaipan 已提交
485 486
        has_bias (bool): Specifies whether the layer uses a bias vector. Default: False.
        weight_init (Union[Tensor, str, Initializer, numbers.Number]): Initializer for the convolution kernel.
487
            It can be a Tensor, a string, an Initializer or a number. When a string is specified,
Z
zhunaipan 已提交
488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503
            values from 'TruncatedNormal', 'Normal', 'Uniform', 'HeUniform' and 'XavierUniform' distributions as well
            as constant 'One' and 'Zero' distributions are possible. Alias 'xavier_uniform', 'he_uniform', 'ones'
            and 'zeros' are acceptable. Uppercase and lowercase are both acceptable. Refer to the values of
            Initializer for more details. Default: 'normal'.
        bias_init (Union[Tensor, str, Initializer, numbers.Number]): Initializer for the bias vector. Possible
            Initializer and string are the same as 'weight_init'. Refer to the values of
            Initializer for more details. Default: 'zeros'.

    Inputs:
        - **input** (Tensor) - Tensor of shape :math:`(N, C_{in}, H_{in}, W_{in})`.

    Outputs:
        Tensor of shape :math:`(N, C_{out}, H_{out}, W_{out})`.

    Examples:
        >>> net = nn.Conv2dTranspose(3, 64, 4, has_bias=False, weight_init='normal')
Z
zhongligeng 已提交
504
        >>> input = Tensor(np.ones([1, 3, 16, 50]), mindspore.float32)
Z
zhunaipan 已提交
505 506
        >>> net(input)
        """
507

Z
zhunaipan 已提交
508 509 510 511 512 513 514 515 516 517 518 519 520
    def __init__(self,
                 in_channels,
                 out_channels,
                 kernel_size,
                 stride=1,
                 pad_mode='same',
                 padding=0,
                 dilation=1,
                 group=1,
                 has_bias=False,
                 weight_init='normal',
                 bias_init='zeros'):
        kernel_size = twice(kernel_size)
521 522
        stride = twice(stride)
        dilation = twice(dilation)
J
jiangjinsheng 已提交
523 524 525
        Validator.check_value_type('padding', padding, (int, tuple), self.cls_name)
        if isinstance(padding, tuple):
            Validator.check_integer('padding size', len(padding), 4, Rel.EQ, self.cls_name)
Z
zhunaipan 已提交
526 527 528 529 530
        # out_channels and in_channels swap.
        # cause Conv2DBackpropInput's out_channel refers to Conv2D's out_channel,
        # then Conv2dTranspose's out_channel refers to Conv2DBackpropInput's in_channel.
        super(Conv2dTranspose, self).__init__(
            in_channels,
J
jinyaohui 已提交
531
            out_channels,
Z
zhunaipan 已提交
532 533 534 535 536 537 538 539
            kernel_size,
            stride,
            pad_mode,
            padding,
            dilation,
            group,
            has_bias,
            weight_init,
J
jinyaohui 已提交
540 541
            bias_init,
            transposed=True)
Z
zhunaipan 已提交
542 543

        self.in_channels = in_channels
J
jinyaohui 已提交
544
        self.out_channels = out_channels
Z
zhunaipan 已提交
545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564
        self.shape = P.Shape()
        if pad_mode not in ('valid', 'same', 'pad'):
            raise ValueError('Attr \'pad_mode\' of \'Conv2dTranspose\' Op passed '
                             + str(pad_mode) + ', should be one of values in \'valid\', \'same\', \'pad\'.')
        self.is_valid = self.pad_mode == 'valid'
        self.is_same = self.pad_mode == 'same'
        self.is_pad = self.pad_mode == 'pad'
        if check_bool(has_bias):
            self.bias = Parameter(initializer(bias_init, [out_channels]), name='bias')

        # cause Conv2DBackpropInput's out_channel refers to Conv2D's out_channel.
        self.conv2d_transpose = P.Conv2DBackpropInput(out_channel=in_channels,
                                                      kernel_size=kernel_size,
                                                      mode=1,
                                                      pad_mode=pad_mode,
                                                      pad=padding,
                                                      stride=stride,
                                                      dilation=dilation,
                                                      group=group)
        self.bias_add = P.BiasAdd()
J
jiangjinsheng 已提交
565 566 567 568
        if isinstance(self.padding, int):
            self.padding_top, self.padding_bottom, self.padding_left, self.padding_right = (self.padding,) * 4
        else:
            self.padding_top, self.padding_bottom, self.padding_left, self.padding_right = self.padding
Z
zhunaipan 已提交
569 570 571 572 573

    def set_strategy(self, strategy):
        self.conv2d_transpose.set_strategy(strategy)
        return self

J
jiangjinsheng 已提交
574
    def _deconv_output_length(self, input_length, filter_size, stride_size, dilation_size, padding):
Z
zhunaipan 已提交
575 576
        """Calculate the width and height of output."""
        length = 0
577
        filter_size = filter_size + (filter_size - 1) * (dilation_size - 1)
Z
zhunaipan 已提交
578
        if self.is_valid:
579 580
            if filter_size - stride_size > 0:
                length = input_length * stride_size + filter_size - stride_size
Z
zhunaipan 已提交
581
            else:
582
                length = input_length * stride_size
Z
zhunaipan 已提交
583
        elif self.is_same:
584
            length = input_length * stride_size
Z
zhunaipan 已提交
585
        elif self.is_pad:
J
jiangjinsheng 已提交
586
            length = input_length * stride_size - padding + filter_size - stride_size
Z
zhunaipan 已提交
587 588 589 590 591

        return length

    def construct(self, x):
        n, _, h, w = self.shape(x)
J
jiangjinsheng 已提交
592 593 594 595
        h_out = self._deconv_output_length(h, self.kernel_size[0], self.stride[0], self.dilation[0],
                                           self.padding_top + self.padding_bottom)
        w_out = self._deconv_output_length(w, self.kernel_size[1], self.stride[1], self.dilation[1],
                                           self.padding_left + self.padding_right)
Z
zhunaipan 已提交
596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613
        if self.has_bias:
            return self.bias_add(self.conv2d_transpose(x, self.weight, (n, self.out_channels, h_out, w_out)),
                                 self.bias)
        return self.conv2d_transpose(x, self.weight, (n, self.out_channels, h_out, w_out))

    def extend_repr(self):
        s = 'input_channels={}, output_channels={}, kernel_size={},' \
            'stride={},  pad_mode={}, padding={}, dilation={}, ' \
            'group={}, has_bias={},' \
            'weight_init={}, bias_init={}'.format(self.in_channels,
                                                  self.out_channels,
                                                  self.kernel_size,
                                                  self.stride,
                                                  self.pad_mode,
                                                  self.padding,
                                                  self.dilation,
                                                  self.group,
                                                  self.has_bias,
C
chenzomi 已提交
614 615
                                                  self.weight_init,
                                                  self.bias_init)
Z
zhunaipan 已提交
616
        return s
617 618


J
jiangjinsheng 已提交
619 620 621 622
class Conv1dTranspose(_Conv):
    r"""
    1D transposed convolution layer.

623 624
    Compute a 1D transposed convolution, which is also known as a deconvolution
    (although it is not an actual deconvolution).
J
jiangjinsheng 已提交
625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 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 671

    Input is typically of shape :math:`(N, C, W)`, where :math:`N` is batch size and :math:`C` is channel number.

    Args:
        in_channels (int): The number of channels in the input space.
        out_channels (int): The number of channels in the output space.
        kernel_size (int): int, which specifies the width of the 1D convolution window.
        stride (int): The distance of kernel moving, an int number that represents
            the width of movement. Default: 1.
        pad_mode (str): Select the mode of the pad. The optional values are
            "pad", "same", "valid". Default: "same".

            - pad: Implicit paddings on both sides of the input.

            - same: Adopted the way of completion.

            - valid: Adopted the way of discarding.
        padding (int): Implicit paddings on both sides of the input. Default: 0.
        dilation (int): The data type is int. Specifies the dilation rate
                                      to use for dilated convolution. If set to be :math:`k > 1`, there will
                                      be :math:`k - 1` pixels skipped for each sampling location. Its value should
                                      be greater or equal to 1 and bounded by the width of the
                                      input. Default: 1.
        group (int): Split filter into groups, `in_channels` and `out_channels` should be
            divisible by the number of groups. This is not support for Davinci devices when group > 1. Default: 1.
        has_bias (bool): Specifies whether the layer uses a bias vector. Default: False.
        weight_init (Union[Tensor, str, Initializer, numbers.Number]): Initializer for the convolution kernel.
            It can be a Tensor, a string, an Initializer or a numbers.Number. When a string is specified,
            values from 'TruncatedNormal', 'Normal', 'Uniform', 'HeUniform' and 'XavierUniform' distributions as well
            as constant 'One' and 'Zero' distributions are possible. Alias 'xavier_uniform', 'he_uniform', 'ones'
            and 'zeros' are acceptable. Uppercase and lowercase are both acceptable. Refer to the values of
            Initializer for more details. Default: 'normal'.
        bias_init (Union[Tensor, str, Initializer, numbers.Number]): Initializer for the bias vector. Possible
            Initializer and string are the same as 'weight_init'. Refer to the values of
            Initializer for more details. Default: 'zeros'.

    Inputs:
        - **input** (Tensor) - Tensor of shape :math:`(N, C_{in}, W_{in})`.

    Outputs:
        Tensor of shape :math:`(N, C_{out}, W_{out})`.

    Examples:
        >>> net = nn.Conv1dTranspose(3, 64, 4, has_bias=False, weight_init='normal')
        >>> input = Tensor(np.ones([1, 3, 50]), mindspore.float32)
        >>> net(input)
    """
672

J
jiangjinsheng 已提交
673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695
    def __init__(self,
                 in_channels,
                 out_channels,
                 kernel_size,
                 stride=1,
                 pad_mode='same',
                 padding=0,
                 dilation=1,
                 group=1,
                 has_bias=False,
                 weight_init='normal',
                 bias_init='zeros'):
        Validator.check_value_type("kernel_size", kernel_size, [int], self.cls_name)
        Validator.check_value_type("stride", stride, [int], self.cls_name)
        Validator.check_value_type("padding", padding, [int], self.cls_name)
        Validator.check_value_type("dilation", dilation, [int], self.cls_name)
        Validator.check_integer('kernel_size', kernel_size, 1, Rel.GE, self.cls_name)
        Validator.check_integer('stride', stride, 1, Rel.GE, self.cls_name)
        Validator.check_integer('padding', padding, 0, Rel.GE, self.cls_name)
        Validator.check_integer('dilation', dilation, 1, Rel.GE, self.cls_name)
        kernel_size = (1, kernel_size)
        stride = (1, stride)
        dilation = (1, dilation)
L
liuxiao93 已提交
696 697 698 699 700 701 702 703 704
        get_shape = P.Shape()
        get_dtype = P.DType()
        if isinstance(weight_init, Tensor):
            weight_init_shape = get_shape(weight_init)
            Validator.check_integer('weight_init_shape', len(weight_init_shape), 3, Rel.EQ, self.cls_name)
            weight_init_dtype = get_dtype(weight_init)
            weight_init_value = weight_init.asnumpy()
            weight_init_value = np.expand_dims(weight_init_value, 2)
            weight_init = Tensor(weight_init_value, weight_init_dtype)
J
jiangjinsheng 已提交
705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768
        # out_channels and in_channels swap.
        # cause Conv2DBackpropInput's out_channel refers to Conv2D's out_channel,
        # then Conv1dTranspose's out_channel refers to Conv2DBackpropInput's in_channel.
        super(Conv1dTranspose, self).__init__(
            in_channels,
            out_channels,
            kernel_size,
            stride,
            pad_mode,
            padding,
            dilation,
            group,
            has_bias,
            weight_init,
            bias_init,
            transposed=True)
        self.padding = (0, 0, padding, padding)
        self.in_channels = in_channels
        self.out_channels = out_channels
        self.shape = P.Shape()
        if pad_mode not in ('valid', 'same', 'pad'):
            raise ValueError('Attr \'pad_mode\' of \'Conv1dTranspose\' Op passed '
                             + str(pad_mode) + ', should be one of values in \'valid\', \'same\', \'pad\'.')
        self.is_valid = self.pad_mode == 'valid'
        self.is_same = self.pad_mode == 'same'
        self.is_pad = self.pad_mode == 'pad'
        if check_bool(has_bias):
            self.bias = Parameter(initializer(bias_init, [out_channels]), name='bias')

        # cause Conv2DBackpropInput's out_channel refers to Conv2D's out_channel.
        self.conv2d_transpose = P.Conv2DBackpropInput(out_channel=in_channels,
                                                      kernel_size=kernel_size,
                                                      mode=1,
                                                      pad_mode=pad_mode,
                                                      pad=self.padding,
                                                      stride=stride,
                                                      dilation=dilation,
                                                      group=group)
        self.bias_add = P.BiasAdd()
        self.expand_dims = P.ExpandDims()
        self.squeeze = P.Squeeze(2)

    def set_strategy(self, strategy):
        self.conv2d_transpose.set_strategy(strategy)
        return self

    def _deconv_output_length(self, input_length, filter_size, stride_size, dilation_size, padding):
        """Calculate the width and height of output."""
        length = 0
        filter_size = filter_size + (filter_size - 1) * (dilation_size - 1)
        if self.is_valid:
            if filter_size - stride_size > 0:
                length = input_length * stride_size + filter_size - stride_size
            else:
                length = input_length * stride_size
        elif self.is_same:
            length = input_length * stride_size
        elif self.is_pad:
            length = input_length * stride_size - padding + filter_size - stride_size

        return length

    def construct(self, x):
        x_shape = self.shape(x)
L
liuxiao93 已提交
769 770
        _check_input_3d(x_shape)
        x = self.expand_dims(x, 2)
J
jiangjinsheng 已提交
771 772 773 774 775 776 777 778

        n, _, h, w = self.shape(x)

        h_out = self._deconv_output_length(h, self.kernel_size[0], self.stride[0], self.dilation[0],
                                           self.padding[0] + self.padding[1])
        w_out = self._deconv_output_length(w, self.kernel_size[1], self.stride[1], self.dilation[1],
                                           self.padding[2] + self.padding[3])
        output = self.conv2d_transpose(x, self.weight, (n, self.out_channels, h_out, w_out))
J
jiangjinsheng 已提交
779 780 781
        if self.has_bias:
            output = self.bias_add(output, self.bias)

L
liuxiao93 已提交
782
        output = self.squeeze(output)
J
jiangjinsheng 已提交
783 784 785 786 787 788 789 790 791 792 793 794 795 796 797
        return output

    def extend_repr(self):
        s = 'input_channels={}, output_channels={}, kernel_size={},' \
            'stride={},  pad_mode={}, padding={}, dilation={}, ' \
            'group={}, has_bias={},' \
            'weight_init={}, bias_init={}'.format(self.in_channels,
                                                  self.out_channels,
                                                  self.kernel_size,
                                                  self.stride,
                                                  self.pad_mode,
                                                  self.padding,
                                                  self.dilation,
                                                  self.group,
                                                  self.has_bias,
C
chenzomi 已提交
798 799
                                                  self.weight_init,
                                                  self.bias_init)
J
jiangjinsheng 已提交
800 801 802
        return s


803 804 805 806 807 808 809 810 811 812 813 814
class DepthwiseConv2d(Cell):
    r"""
    2D depthwise convolution layer.

    Applies a 2D depthwise convolution over an input tensor which is typically of shape:
    math:`(N, C_{in}, H_{in}, W_{in})`, where :math:`N` is batch size and :math:`C_{in}` is channel number.
    For each batch of shape:math:`(C_{in}, H_{in}, W_{in})`, the formula is defined as:

    .. math::

        out_j = \sum_{i=0}^{C_{in} - 1} ccor(W_{ij}, X_i) + b_j,

815 816
    where :math:`ccor` is the cross correlation operator, :math:`C_{in}` is the input channel number, :math:`j` ranges
    from :math:`0` to :math:`C_{out} - 1`, :math:`W_{ij}` corresponds to the :math:`i`-th channel of the :math:`j`-th
817 818
    filter and :math:`out_{j}` corresponds to the :math:`j`-th channel of the output. :math:`W_{ij}` is a slice
    of kernel and it has shape :math:`(\text{ks_h}, \text{ks_w})`, where :math:`\text{ks_h}` and
819
    :math:`\text{ks_w}` are the height and width of the convolution kernel. The full kernel has shape
820 821
    :math:`(C_{out}, C_{in} // \text{group}, \text{ks_h}, \text{ks_w})`, where group is the group number
    to split the input in the channel dimension.
822 823 824 825 826 827 828 829 830 831 832 833 834

    If the 'pad_mode' is set to be "valid", the output height and width will be
    :math:`\left \lfloor{1 + \frac{H_{in} + 2 \times \text{padding} - \text{ks_h} -
    (\text{ks_h} - 1) \times (\text{dilation} - 1) }{\text{stride}}} \right \rfloor` and
    :math:`\left \lfloor{1 + \frac{W_{in} + 2 \times \text{padding} - \text{ks_w} -
    (\text{ks_w} - 1) \times (\text{dilation} - 1) }{\text{stride}}} \right \rfloor` respectively.

    The first introduction can be found in paper `Gradient Based Learning Applied to Document Recognition
    <http://vision.stanford.edu/cs598_spring07/papers/Lecun98.pdf>`_.

    Args:
        in_channels (int): The number of input channel :math:`C_{in}`.
        out_channels (int): The number of output channel :math:`C_{out}`.
835
        kernel_size (Union[int, tuple[int]]): The data type is int or a tuple of 2 integers. Specifies the height
836
            and width of the 2D convolution window. Single int means the value is for both the height and the width of
837 838 839 840 841 842 843 844
            the kernel. A tuple of 2 ints means the first value is for the height and the other is for the
            width of the kernel.
        stride (Union[int, tuple[int]]): The distance of kernel moving, an int number that represents
            the height and width of movement are both strides, or a tuple of two int numbers that
            represent height and width of movement respectively. Default: 1.
        pad_mode (str): Specifies padding mode. The optional values are
            "same", "valid", "pad". Default: "same".

845 846 847
            - same: Adopts the way of completion. The height and width of the output will be the same as
              the input. The total number of padding will be calculated in horizontal and vertical
              directions and evenly distributed to top and bottom, left and right if possible. Otherwise, the
848 849 850
              last extra padding will be done from the bottom and the right side. If this mode is set, `padding`
              must be 0.

851
            - valid: Adopts the way of discarding. The possible largest height and width of output will be returned
852 853 854 855 856 857
              without padding. Extra pixels will be discarded. If this mode is set, `padding`
              must be 0.

            - pad: Implicit paddings on both sides of the input. The number of `padding` will be padded to the input
              Tensor borders. `padding` should be greater than or equal to 0.

858
        padding (Union[int, tuple[int]]): Implicit paddings on both sides of the input. If `padding` is one integer,
S
simson 已提交
859 860
            the paddings of top, bottom, left and right are the same, equal to padding. If `padding` is a tuple
            with four integers, the paddings of top, bottom, left and right will be equal to padding[0],
861
            padding[1], padding[2], and padding[3] accordingly. Default: 0.
862
        dilation (Union[int, tuple[int]]): The data type is int or a tuple of 2 integers. Specifies the dilation rate
863 864
                                      to use for dilated convolution. If set to be :math:`k > 1`, there will
                                      be :math:`k - 1` pixels skipped for each sampling location. Its value should
865
                                      be greater than or equal to 1 and bounded by the height and width of the
866
                                      input. Default: 1.
867
        group (int): Split filter into groups, `in_ channels` and `out_channels` should be
868
            divisible by the number of groups. If 'group' is None, it will be set as the value of 'in_channels'
869 870
        has_bias (bool): Specifies whether the layer uses a bias vector. Default: False.
        weight_init (Union[Tensor, str, Initializer, numbers.Number]): Initializer for the convolution kernel.
871
            It can be a Tensor, a string, an Initializer or a number. When a string is specified,
872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891
            values from 'TruncatedNormal', 'Normal', 'Uniform', 'HeUniform' and 'XavierUniform' distributions as well
            as constant 'One' and 'Zero' distributions are possible. Alias 'xavier_uniform', 'he_uniform', 'ones'
            and 'zeros' are acceptable. Uppercase and lowercase are both acceptable. Refer to the values of
            Initializer for more details. Default: 'normal'.
        bias_init (Union[Tensor, str, Initializer, numbers.Number]): Initializer for the bias vector. Possible
            Initializer and string are the same as 'weight_init'. Refer to the values of
            Initializer for more details. Default: 'zeros'.

    Inputs:
        - **input** (Tensor) - Tensor of shape :math:`(N, C_{in}, H_{in}, W_{in})`.

    Outputs:
        Tensor of shape :math:`(N, C_{out}, H_{out}, W_{out})`.

    Examples:
        >>> net = nn.DepthwiseConv2d(120, 240, 4, has_bias=False, weight_init='normal')
        >>> input = Tensor(np.ones([1, 120, 1024, 640]), mindspore.float32)
        >>> net(input).shape
        (1, 240, 1024, 640)
    """
892

893 894 895 896
    def __init__(self,
                 in_channels,
                 out_channels,
                 kernel_size,
897
                 group,
898 899 900 901 902 903 904 905 906 907 908 909 910
                 stride=1,
                 pad_mode='same',
                 padding=0,
                 dilation=1,
                 has_bias=False,
                 weight_init='normal',
                 bias_init='zeros'):
        super(DepthwiseConv2d, self).__init__()
        self.kernel_size = twice(kernel_size)
        self.stride = twice(stride)
        self.dilation = twice(dilation)
        self.in_channels = check_int_positive(in_channels)
        self.out_channels = check_int_positive(out_channels)
911 912
        if group is None:
            group = in_channels
913 914 915
        validator.check_integer('group', group, in_channels, Rel.EQ)
        validator.check_integer('group', group, out_channels, Rel.EQ)
        validator.check_integer('group', group, 1, Rel.GE)
916 917
        self.pad_mode = pad_mode
        self.dilation = dilation
918
        self.group = group
919
        self.has_bias = has_bias
920 921
        self.weight_init = weight_init
        self.bias_init = bias_init
922 923 924 925
        Validator.check_value_type('padding', padding, (int, tuple), self.cls_name)
        if isinstance(padding, tuple):
            Validator.check_integer('padding size', len(padding), 4, Rel.EQ, self.cls_name)
        self.padding = padding
926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949
        self.conv = P.DepthwiseConv2dNative(channel_multiplier=1,
                                            kernel_size=self.kernel_size,
                                            pad_mode=self.pad_mode,
                                            pad=self.padding,
                                            stride=self.stride,
                                            dilation=self.dilation)
        self.bias_add = P.BiasAdd()
        weight_shape = [1, in_channels, *self.kernel_size]
        self.weight = Parameter(initializer(weight_init, weight_shape), name='weight')
        if check_bool(has_bias):
            self.bias = Parameter(initializer(bias_init, [out_channels]), name='bias')
        else:
            if bias_init != 'zeros':
                logger.warning("value of `has_bias` is False, value of `bias_init` will be ignore.")
            self.bias = None

    def construct(self, x):
        out = self.conv(x, self.weight)
        if self.has_bias:
            out = self.bias_add(out, self.bias)
        return out

    def extend_repr(self):
        s = 'input_channels={}, output_channels={}, kernel_size={}, stride={}, ' \
950
            'pad_mode={}, padding={}, dilation={}, group={}, ' \
951 952
            'has_bias={}, weight_init={}, bias_init={}'.format(
                self.in_channels, self.out_channels, self.kernel_size, self.stride,
953
                self.pad_mode, self.padding, self.dilation, self.group,
954 955 956 957 958
                self.has_bias, self.weight_init, self.bias_init)

        if self.has_bias:
            s += ', bias={}'.format(self.bias)
        return s