conv_op.cc 29.6 KB
Newer Older
1
/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved.
C
chengduoZH 已提交
2

L
Luo Tao 已提交
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
C
chengduoZH 已提交
6

L
Luo Tao 已提交
7
    http://www.apache.org/licenses/LICENSE-2.0
C
chengduoZH 已提交
8

L
Luo Tao 已提交
9 10 11 12 13
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 已提交
14

Y
Yi Wang 已提交
15
#include "paddle/fluid/operators/conv_op.h"
Y
Update  
Yi Wang 已提交
16

17
#include <memory>
Y
Update  
Yi Wang 已提交
18 19 20
#include <string>
#include <vector>

21
#include "paddle/fluid/framework/op_version_registry.h"
22
#include "paddle/fluid/platform/device/gpu/gpu_dnn.h"
23

24 25 26
#ifdef PADDLE_WITH_MKLDNN
#include "paddle/fluid/platform/mkldnn_helper.h"
#endif
H
hong 已提交
27
#include "paddle/fluid/framework/infershape_utils.h"
28
#include "paddle/fluid/platform/cudnn_workspace_helper.h"
H
hong 已提交
29 30
#include "paddle/phi/infermeta/binary.h"

C
chengduoZH 已提交
31 32 33
namespace paddle {
namespace operators {

34 35
std::vector<int64_t> ConvOp::ComputeOutputShape(
    framework::InferShapeContext* ctx) const {
36 37
  OP_INOUT_CHECK(ctx->HasInput("Input"), "Input", "Input", "Conv");
  OP_INOUT_CHECK(ctx->HasInput("Filter"), "Input", "Filter", "Conv");
C
chengduoZH 已提交
38 39 40

  auto in_dims = ctx->GetInputDim("Input");
  auto filter_dims = ctx->GetInputDim("Filter");
41

C
chengduoZH 已提交
42 43
  std::vector<int> strides = ctx->Attrs().Get<std::vector<int>>("strides");
  std::vector<int> paddings = ctx->Attrs().Get<std::vector<int>>("paddings");
L
liym27 已提交
44 45
  std::string padding_algorithm =
      ctx->Attrs().Get<std::string>("padding_algorithm");
C
chengduoZH 已提交
46
  int groups = ctx->Attrs().Get<int>("groups");
C
chengduoZH 已提交
47
  std::vector<int> dilations = ctx->Attrs().Get<std::vector<int>>("dilations");
48 49 50
  int dilation_size = dilations.size();
  for (int i = 0; i < dilation_size; ++i) {
    PADDLE_ENFORCE_GT(
51 52
        dilations[i],
        0,
53 54 55 56 57
        platform::errors::InvalidArgument(
            "The dilation of Op(Conv) should be larget than 0, but received "
            "dilation is %d.",
            dilations[i]));
  }
L
liym27 已提交
58
  const std::string data_format = ctx->Attrs().Get<std::string>("data_format");
59 60 61

  // MKL-DNN Kernels are using NCHW order of dims description
  // so we ignore data_format consideration for MKL-DNN kernel
62
  const bool channel_last = (ctx->IsRunMKLDNNKernel() == false) &&
63
                            (data_format == "NHWC" || data_format == "NDHWC");
C
chengduoZH 已提交
64

65
  PADDLE_ENFORCE_EQ(
66 67
      in_dims.size() == 4 || in_dims.size() == 5,
      true,
68
      platform::errors::InvalidArgument(
69 70
          "The input of Op(Conv) should be a 4-D or 5-D Tensor. But "
          "received: input's dimension is %u, input's shape is [%s].",
71 72
          in_dims.size(),
          in_dims));
73

C
chengduoZH 已提交
74
  PADDLE_ENFORCE_EQ(
75 76
      in_dims.size(),
      filter_dims.size(),
77
      platform::errors::InvalidArgument(
78 79 80 81
          "The input's dimension and filter's dimension of "
          "Op(Conv) should be equal. But received: the input's shape is [%s], "
          "the input's dimension is %d; the filter's shape is [%s],  "
          "the filter's dimension is %d.",
82 83 84 85
          in_dims,
          in_dims.size(),
          filter_dims,
          filter_dims.size()));
86

87 88 89
  int stride_size = strides.size();
  for (int i = 0; i < stride_size; ++i) {
    PADDLE_ENFORCE_GT(
90 91
        strides[i],
        0,
92 93 94 95 96 97 98
        platform::errors::InvalidArgument(
            "The stride of Op(Conv) should be larget than 0, but received "
            "stride is %d.",
            strides[i]));
  }

  int in_sub_stride_size = in_dims.size() - stride_size;
99
  PADDLE_ENFORCE_EQ(
100 101
      in_dims.size(),
      strides.size() + 2U,
102
      platform::errors::InvalidArgument(
103 104 105 106 107
          "The difference of input's dimension and Attr(strides)'s "
          "length must be euqal to 2 for Op(Conv). "
          "But received: input's dimension is %d, input's shape is [%s]; "
          "Attr(stride)'s length is %d, Attr(stride) is [%s]; "
          "difference of input's dimention and Attr(strides)'s length = %u.",
108 109 110 111
          in_dims.size(),
          in_dims,
          strides.size(),
          phi::make_ddim(strides),
112
          in_sub_stride_size));
L
liym27 已提交
113 114 115

  const auto input_channels =
      channel_last ? in_dims[in_dims.size() - 1] : in_dims[1];
F
fengjiayi 已提交
116

117
  PADDLE_ENFORCE_EQ(
118 119
      input_channels,
      filter_dims[1] * groups,
120
      platform::errors::InvalidArgument(
121 122 123 124 125
          "The number of input's channels should be equal to filter's channels "
          "* groups for Op(Conv). But received: the input's channels is %d, "
          "the input's shape is [%s]; the filter's channels is %d, the "
          "filter's shape is [%s]; the groups is %d, the data_format is %s. "
          "The error may come from wrong data_format setting.",
126 127 128 129 130
          input_channels,
          in_dims,
          filter_dims[1],
          filter_dims,
          groups,
131
          data_format));
C
chengduoZH 已提交
132
  PADDLE_ENFORCE_EQ(
133 134
      filter_dims[0] % groups,
      0,
135
      platform::errors::InvalidArgument(
136 137 138 139
          "The number of output's channels (filter's first dimension) of "
          "Op(Conv) should be divided by groups. But received: "
          "the output channels is %d, the filter's shape is [%s], "
          "the groups is %d.",
140 141 142
          filter_dims[0],
          filter_dims,
          groups));
W
wangxinxin08 已提交
143 144 145

  if (ctx->IsRuntime()) {
    PADDLE_ENFORCE_GT(
146 147
        filter_dims[0],
        0,
W
wangxinxin08 已提交
148 149 150
        platform::errors::InvalidArgument(
            "the size of filter at axis 0 should be greater than 0"));
  }
C
chengduoZH 已提交
151

L
liym27 已提交
152 153
  framework::DDim in_data_dims;
  if (channel_last) {
154
    in_data_dims = phi::slice_ddim(in_dims, 1, in_dims.size() - 1);
L
liym27 已提交
155
  } else {
156
    in_data_dims = phi::slice_ddim(in_dims, 2, in_dims.size());
L
liym27 已提交
157
  }
158

159
  framework::DDim filter_data_dims =
160
      phi::slice_ddim(filter_dims, 2, filter_dims.size());
161

162
  std::vector<int> ksize = phi::vectorize<int>(filter_data_dims);
163 164
  UpdatePaddingAndDilation(
      &paddings, &dilations, padding_algorithm, in_data_dims, strides, ksize);
L
liym27 已提交
165 166 167 168 169

  std::vector<int64_t> output_shape({in_dims[0]});
  if (!channel_last) {
    output_shape.push_back(filter_dims[0]);
  }
170
  for (int i = 0; i < in_data_dims.size(); ++i) {
T
tink2123 已提交
171
    if ((!ctx->IsRuntime()) &&
L
liym27 已提交
172
        (in_data_dims[i] <= 0 || filter_dims[i + 2] <= 0)) {
T
tink2123 已提交
173 174
      output_shape.push_back(-1);
    } else {
175 176 177 178 179 180
      output_shape.push_back(ConvOutputSize(in_data_dims[i],
                                            filter_data_dims[i],
                                            dilations[i],
                                            paddings[2 * i],
                                            paddings[2 * i + 1],
                                            strides[i]));
T
tink2123 已提交
181
    }
C
chengduoZH 已提交
182
  }
L
liym27 已提交
183 184 185 186
  if (channel_last) {
    output_shape.push_back(filter_dims[0]);
  }

187
  return output_shape;
C
chengduoZH 已提交
188 189
}

190 191
framework::OpKernelType ConvOp::GetExpectedKernelType(
    const framework::ExecutionContext& ctx) const {
192
  auto input_data_type = OperatorWithKernel::IndicateVarDataType(ctx, "Input");
193 194
  // todo enable data layout when it's ready
  // (https://github.com/PaddlePaddle/Paddle/pull/20042)
195

196
  if (input_data_type != framework::proto::VarType::INT8 &&
197 198
      input_data_type != framework::proto::VarType::UINT8 &&
      input_data_type != framework::proto::VarType::BF16) {
199 200
    auto filter_data_type = framework::TransToProtoVarType(
        ctx.Input<phi::DenseTensor>("Filter")->dtype());
201
    PADDLE_ENFORCE_EQ(
202 203
        input_data_type,
        filter_data_type,
204 205 206 207 208 209
        platform::errors::InvalidArgument(
            "input and filter data type should be consistent, "
            "but received input data type is %s and filter type "
            "is %s",
            paddle::framework::DataTypeToString(input_data_type),
            paddle::framework::DataTypeToString(filter_data_type)));
210
  }
211 212 213

#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
  if (platform::CanCUDNNBeUsed(ctx)) {
W
wuhuanzhou 已提交
214
#if PADDLE_WITH_CUDA
215 216 217 218 219 220 221
    if (input_data_type == framework::proto::VarType::BF16) {
      PADDLE_ENFORCE_GE(
          platform::DnnVersion(),
          8100,
          platform::errors::InvalidArgument(
              "bfloat16 can only be used when CUDNN_VERSION >= 8100"));
    }
W
wuhuanzhou 已提交
222
#endif  // PADDLE_WITH_CUDA
223 224
    return framework::OpKernelType(input_data_type,
                                   ctx.GetPlace(),
225
                                   phi::DataLayout::kAnyLayout,
226 227 228 229 230 231 232 233
                                   framework::LibraryType::kCUDNN);
  }
#endif  // PADDLE_WITH_CUDA || PADDLE_WITH_HIP

#ifdef PADDLE_WITH_MKLDNN
  if (this->CanMKLDNNBeUsed(ctx, input_data_type)) {
    return framework::OpKernelType(input_data_type,
                                   ctx.GetPlace(),
234
                                   phi::DataLayout::kMKLDNN,
235
                                   framework::LibraryType::kMKLDNN);
236 237 238 239
  }
#endif

  return framework::OpKernelType(input_data_type, ctx.GetPlace());
240 241
}

242
framework::OpKernelType ConvOp::GetKernelTypeForVar(
243
    const std::string& var_name,
244
    const phi::DenseTensor& tensor,
245 246 247 248 249
    const framework::OpKernelType& expected_kernel_type) const {
#ifdef PADDLE_WITH_MKLDNN
  // Only input require reshaping, weights and
  // bias are having shape in NCHW order
  if ((var_name == "Input") &&
250 251
      (expected_kernel_type.data_layout_ == phi::DataLayout::kMKLDNN) &&
      (tensor.layout() != phi::DataLayout::kMKLDNN)) {
252 253 254
    auto attrs = Attrs();
    auto ar = paddle::framework::AttrReader(attrs);
    const std::string data_format = ar.Get<std::string>("data_format");
255
    auto dl = phi::StringToDataLayout(data_format);
256
    // Some models may have intentionally set "AnyLayout" for conv
257
    // op. Treat this as NCHW (default data_format value)
258
    if (dl != phi::DataLayout::kAnyLayout) {
259 260
      return framework::OpKernelType(
          expected_kernel_type.data_type_, tensor.place(), dl);
261 262 263
    }
  }
#endif
264 265
  return framework::OpKernelType(
      expected_kernel_type.data_type_, tensor.place(), tensor.layout());
266 267
}

Y
Yu Yang 已提交
268
void Conv2DOpMaker::Make() {
L
liym27 已提交
269 270 271 272 273 274
  AddInput("Input",
           "(Tensor) The input tensor of convolution operator. "
           "The format of input tensor is NCHW or NHWC, where N is batch size, "
           "C is the "
           "number of channels, H is the height of the feature, "
           "and W is the width of the feature.");
C
chengduoZH 已提交
275
  AddInput("Filter",
C
fix doc  
chengduoZH 已提交
276
           "(Tensor) The filter tensor of convolution operator. "
C
chengduoZH 已提交
277 278
           "The format of the filter tensor is MCHW, where M is the number of "
           "output image channels, C is the number of input image channels, "
C
fix doc  
chengduoZH 已提交
279 280
           "H is the height of the filter, and W is the width of the filter. "
           "If the groups attribute is greater than 1, C equals the number of "
C
chengduoZH 已提交
281
           "input image channels divided by the groups.");
282 283 284 285
  AddInput("Bias",
           "(Tensor) Bias to be added to each output of filter application."
           "The format of output tensor is X (one-dimensional) of size equal"
           "to the number of output channels. Only used with MKL-DNN.")
286 287
      .AsDispensable()
      .AsExtra();
288 289 290
  AddInput("ResidualData",
           "(Tensor) Tensor with residual data "
           "to which convolution output will be added."
291
           "Used with fuse_residual_connection fusion.")
292 293
      .AsDispensable()
      .AsExtra();
Y
Yihua Xu 已提交
294 295
  AddOutput("Output",
            "(Tensor) The output tensor of convolution operator. "
L
liym27 已提交
296
            "It has same data fromat and data type as the Input.");
C
chengduoZH 已提交
297 298 299 300
  AddAttr<std::vector<int>>("strides",
                            "(vector<int> default:{1, 1}), the "
                            "strides(h_stride, w_stride) of "
                            "convolution operator.")
C
chengduoZH 已提交
301
      .SetDefault({1, 1});
C
chengduoZH 已提交
302 303
  AddAttr<std::vector<int>>("paddings",
                            "(vector<int> default:{0, 0}), the "
L
liym27 已提交
304 305
                            "paddings(pad_height_top, pad_height_bottom, "
                            "pad_width_left, pad_wifth_right)  of "
C
chengduoZH 已提交
306
                            "convolution operator.")
C
chengduoZH 已提交
307
      .SetDefault({0, 0});
L
liym27 已提交
308 309 310 311 312 313
  AddAttr<std::string>(
      "padding_algorithm",
      "(string, default \"EXPLICIT\") An optional string from: \"EXPLICIT\","
      "\"SAME\",\"VALID\". Set to \"EXPLICIT\" for explicit padding. "
      "Set to \"SAME\" or \"VALID\" for algorithm of padding. ")
      .SetDefault("EXPLICIT");
C
chengduoZH 已提交
314 315
  AddAttr<int>(
      "groups",
C
chengduoZH 已提交
316
      "(int default:1), the groups number of the convolution operator. "
C
fix doc  
chengduoZH 已提交
317 318 319 320
      "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 of the input channels, while the second half of the filters "
      "is only connected to the second half of the input channels.")
C
chengduoZH 已提交
321
      .SetDefault(1);
C
chengduoZH 已提交
322
  AddAttr<std::vector<int>>("dilations",
C
chengduoZH 已提交
323 324
                            "(vector<int> default:{1, 1}), the "
                            "dilations(h_dilation, w_dilation) of "
C
chengduoZH 已提交
325
                            "convolution operator.")
C
chengduoZH 已提交
326
      .SetDefault({1, 1});
327 328 329 330 331 332
  AddAttr<std::string>(
      "data_format",
      "(string, default NCHW) Only used in "
      "An optional string from: \"NHWC\", \"NCHW\". "
      "Defaults to \"NHWC\". Specify the data format of the output data, "
      "the input will be transformed automatically. ")
L
liym27 已提交
333
      .SetDefault("NCHW");
334
  // TODO(dzhwinter): need to registered layout transform function
C
chengduoZH 已提交
335
  AddComment(R"DOC(
C
fix doc  
chengduoZH 已提交
336 337
Convolution Operator.

C
chengduoZH 已提交
338
The convolution operation calculates the output based on the input, filter
C
chengduoZH 已提交
339
and strides, paddings, dilations, groups parameters. The size of each dimension of the
C
chengduoZH 已提交
340
parameters is checked in the infer-shape.
L
liym27 已提交
341
Input(Input) and Output(Output) are in NCHW or NHWC format. Where N is batch
C
fix doc  
chengduoZH 已提交
342
size, C is the number of channels, H is the height of the feature, and W is
C
chengduoZH 已提交
343
the width of the feature.
344
Filters(Input) is MCHW format format. Where M is the number of output image channels, C is
C
chengduoZH 已提交
345 346 347 348
the number of input image channels, H is the height of the filter, and W
is the width of the filter.
Parameters(strides, paddings, dilations) are two elements. These two elements represent
height and width, respectively.
C
chengduoZH 已提交
349 350 351 352
The input(X) size and output(Out) size may be different.

Example:
  Input:
C
chengduoZH 已提交
353 354
       Input shape: $(N, C_{in}, H_{in}, W_{in})$
       Filter shape: $(C_{out}, C_{in}, H_f, W_f)$
C
chengduoZH 已提交
355
  Output:
C
chengduoZH 已提交
356 357 358
       Output shape: $(N, C_{out}, H_{out}, W_{out})$
  Where
$$
L
liym27 已提交
359 360
       H_{out}= \frac{(H_{in} + pad_height_top + pad_height_bottom - (dilations[0] * (H_f - 1) + 1))}{strides[0]}+ 1 \\
       W_{out}= \frac{(W_{in} + pad_width_left + pad_width_right - (dilations[1] * (W_f - 1) + 1))}{strides[1]}+ 1
C
chengduoZH 已提交
361
$$
C
chengduoZH 已提交
362
)DOC");
Q
qingqing01 已提交
363
  Apply();
C
chengduoZH 已提交
364 365
}

366 367 368 369 370 371 372 373 374 375 376
class DepthwiseConv2DOpMaker : public Conv2DOpMaker {
 protected:
  void Apply() override {
    AddAttr<bool>(
        "use_cudnn",
        "(bool, default false) Only used in cudnn kernel, need install cudnn")
        .SetDefault(false)
        .AsExtra();
  }
};

Y
Yu Yang 已提交
377
void Conv3DOpMaker::Make() {
C
chengduoZH 已提交
378 379
  AddInput(
      "Input",
C
fix doc  
chengduoZH 已提交
380
      "(Tensor) The input tensor of convolution operator. "
L
liym27 已提交
381 382
      "The format of input tensor is NCDHW or NDHWC. Where N is batch size, C "
      "is the "
C
fix doc  
chengduoZH 已提交
383 384 385
      "number of channels, D is the depth of the feature, H is the height of "
      "the feature, "
      "and W is the width of the feature.");
C
chengduoZH 已提交
386
  AddInput("Filter",
C
fix doc  
chengduoZH 已提交
387
           "(Tensor) The filter tensor of convolution operator. "
C
chengduoZH 已提交
388 389
           "The format of the filter tensor is MCDHW, where M is the number of "
           "output image channels, C is the number of input image channels, "
C
fix doc  
chengduoZH 已提交
390 391 392
           "D is the depth of the filter, H is the height of the filter, and W "
           "is the width of the filter."
           "If the groups attribute is greater than 1, C equals the number of "
C
chengduoZH 已提交
393
           "input image channels divided by the groups.");
394 395 396 397
  AddInput("ResidualData",
           "(Tensor) Tensor with residual data "
           "to which convolution output will be added."
           "Used with fuse_residual_connection fusion.")
398 399
      .AsDispensable()
      .AsExtra();
Y
Yihua Xu 已提交
400 401
  AddOutput("Output",
            "(Tensor) The output tensor of convolution operator."
L
liym27 已提交
402
            "It has same data fromat and data type as the Input.");
C
chengduoZH 已提交
403 404 405 406
  AddAttr<std::vector<int>>("strides",
                            "(vector<int>, default:{1, 1, 1}), the "
                            "strides(d_stride, h_stride, w_stride) of "
                            "convolution operator.")
C
chengduoZH 已提交
407
      .SetDefault({1, 1, 1});
L
liym27 已提交
408 409 410 411 412 413
  AddAttr<std::vector<int>>(
      "paddings",
      "(vector<int>, default:{0, 0, 0}), the "
      "paddings(pad_depth_front, pad_depth_back, pad_height_top, "
      "pad_height_bottom, pad_width_left, pad_width_right) of convolution "
      "operator.")
C
chengduoZH 已提交
414
      .SetDefault({0, 0, 0});
L
liym27 已提交
415 416 417 418 419 420
  AddAttr<std::string>(
      "padding_algorithm",
      "(string, default \"EXPLICIT\") An optional string from: \"EXPLICIT\","
      "\"SAME\",\"VALID\". Set to \"EXPLICIT\" for explicit padding. "
      "Set to \"SAME\" or \"VALID\" for algorithm of padding. ")
      .SetDefault("EXPLICIT");
C
chengduoZH 已提交
421 422
  AddAttr<int>(
      "groups",
C
chengduoZH 已提交
423
      "(int default:1), the groups number of the convolution operator. "
C
fix doc  
chengduoZH 已提交
424 425 426 427
      "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 of the input channels, while the second half of the filters "
      "is only connected to the second half of the input channels.")
C
chengduoZH 已提交
428
      .SetDefault(1);
C
chengduoZH 已提交
429
  AddAttr<std::vector<int>>("dilations",
C
chengduoZH 已提交
430 431
                            "(vector<int> default:{1, 1, 1}), the "
                            "dilations(d_dilation, h_dilation, w_dilation) of "
C
chengduoZH 已提交
432
                            "convolution operator.")
C
chengduoZH 已提交
433
      .SetDefault({1, 1, 1});
434 435
  AddAttr<std::string>(
      "data_format",
L
liym27 已提交
436 437 438
      "(string, default NCDHW) Only used in "
      "An optional string from: \"NDHWC\", \"NCDHW\". "
      "Defaults to \"NDHWC\". Specify the data format of the output data, "
439
      "the input will be transformed automatically. ")
L
liym27 已提交
440
      .SetDefault("NCDHW");
C
chengduoZH 已提交
441
  AddComment(R"DOC(
C
fix doc  
chengduoZH 已提交
442 443
Convolution3D Operator.

C
chengduoZH 已提交
444
The convolution operation calculates the output based on the input, filter
C
chengduoZH 已提交
445
and strides, paddings, dilations, groups parameters. The size of each dimension of the
C
chengduoZH 已提交
446
parameters is checked in the infer-shape.
L
liym27 已提交
447
Input(Input) and output(Output) are in NCDHW or NDHWC format, where N is batch
C
fix doc  
chengduoZH 已提交
448
size, C is the number of channels,D is the depth of the feature, H is the height of
C
chengduoZH 已提交
449 450 451 452 453 454
the feature, and W is the width of the feature.
Filters(Input) is MCDHW format, where M is the number of output image channels,
C is the number of input image channels, D is the depth of the filter,
H is the height of the filter, and W is the width of the filter.
Parameters(strides, paddings, dilations) are three elements. These three elements
represent depth, height and width, respectively.
C
fix doc  
chengduoZH 已提交
455 456 457 458
The input(X) size and output(Out) size may be different.

Example:
  Input:
C
chengduoZH 已提交
459 460
       Input shape: $(N, C_{in}, D_{in}, H_{in}, W_{in})$
       Filter shape: $(C_{out}, C_{in}, D_f, H_f, W_f)$
C
fix doc  
chengduoZH 已提交
461
  Output:
C
chengduoZH 已提交
462 463 464
       Output shape: $(N, C_{out}, D_{out}, H_{out}, W_{out})$
  Where
  $$
L
liym27 已提交
465 466 467
       D_{out}= \frac{(D_{in} + pad_depth_front + pad_depth_back - (dilations[0] * (D_f - 1) + 1))}{ strides[0]}+ 1 \\
       H_{out}= \frac{(H_{in} + pad_height_top + pad_height_bottom - (dilations[1] * (H_f - 1) + 1))}{ strides[1]}+ 1 \\
       W_{out}= \frac{(W_{in} + pad_width_left + pad_width_right - (dilations[2] * (W_f - 1) + 1))}{ strides[2]}+ 1
C
chengduoZH 已提交
468
  $$
C
chengduoZH 已提交
469
)DOC");
Q
qingqing01 已提交
470
  Apply();
C
chengduoZH 已提交
471 472
}

C
chengduoZH 已提交
473 474 475 476 477 478 479 480 481 482 483
void ConvOpGrad::InferShape(framework::InferShapeContext* ctx) const {
  auto in_dims = ctx->GetInputDim("Input");
  auto filter_dims = ctx->GetInputDim("Filter");
  if (ctx->HasOutput(framework::GradVarName("Input"))) {
    ctx->SetOutputDim(framework::GradVarName("Input"), in_dims);
  }
  if (ctx->HasOutput(framework::GradVarName("Filter"))) {
    ctx->SetOutputDim(framework::GradVarName("Filter"), filter_dims);
  }
}

484 485
framework::OpKernelType ConvOpGrad::GetExpectedKernelType(
    const framework::ExecutionContext& ctx) const {
M
mozga-intel 已提交
486
  // TODO(pzelazko-intel): enable MKLDNN layout when it's ready
487
  auto data_type = OperatorWithKernel::IndicateVarDataType(ctx, "Input");
M
mozga-intel 已提交
488

489
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
490
  if (platform::CanCUDNNBeUsed(ctx)) {
491 492
    return framework::OpKernelType(data_type,
                                   ctx.GetPlace(),
493
                                   phi::DataLayout::kAnyLayout,
494
                                   framework::LibraryType::kCUDNN);
C
chengduoZH 已提交
495 496
  }
#endif
497
#ifdef PADDLE_WITH_MKLDNN
498 499 500
  if (this->CanMKLDNNBeUsed(ctx, data_type)) {
    return framework::OpKernelType(data_type,
                                   ctx.GetPlace(),
501
                                   phi::DataLayout::kMKLDNN,
502
                                   framework::LibraryType::kMKLDNN);
503
  }
504
#endif
505

506
  return framework::OpKernelType(data_type, ctx.GetPlace());
507 508
}

509
framework::OpKernelType ConvOpGrad::GetKernelTypeForVar(
510
    const std::string& var_name,
511
    const phi::DenseTensor& tensor,
512 513 514 515 516 517
    const framework::OpKernelType& expected_kernel_type) const {
#ifdef PADDLE_WITH_MKLDNN
  // Only input require reshaping, weights and
  // bias are having shape in NCHW order
  if (((var_name == "Input") ||
       (var_name == framework::GradVarName("Output"))) &&
518 519
      (expected_kernel_type.data_layout_ == phi::DataLayout::kMKLDNN) &&
      (tensor.layout() != phi::DataLayout::kMKLDNN)) {
520 521 522
    auto attrs = Attrs();
    auto ar = paddle::framework::AttrReader(attrs);
    const std::string data_format = ar.Get<std::string>("data_format");
523
    auto dl = phi::StringToDataLayout(data_format);
524 525
    // Some models may have intentionally set "AnyLayout" for pool
    // op. Treat this as NCHW (default data_format value)
526
    if (dl != phi::DataLayout::kAnyLayout) {
527 528
      return framework::OpKernelType(
          expected_kernel_type.data_type_, tensor.place(), dl);
529 530 531
    }
  }
#endif
532 533
  return framework::OpKernelType(
      expected_kernel_type.data_type_, tensor.place(), tensor.layout());
534 535
}

H
hong 已提交
536 537
template <typename T>
class Conv2DGradMaker : public framework::SingleGradOpMaker<T> {
538
 public:
H
hong 已提交
539
  using framework::SingleGradOpMaker<T>::SingleGradOpMaker;
540

541
  void Apply(GradOpPtr<T> op) const override {
S
sneaxiy 已提交
542
    op->SetType(this->ForwardOpType() + "_grad");
H
hong 已提交
543 544 545
    op->SetInput("Input", this->Input("Input"));
    op->SetInput("Filter", this->Input("Filter"));
    op->SetInput(framework::GradVarName("Output"), this->OutputGrad("Output"));
546

H
hong 已提交
547 548
    op->SetOutput(framework::GradVarName("Input"), this->InputGrad("Input"));
    op->SetOutput(framework::GradVarName("Filter"), this->InputGrad("Filter"));
549 550 551 552 553

    if (this->HasInput("Bias")) {
      op->SetInput("Bias", this->Input("Bias"));
      op->SetOutput(framework::GradVarName("Bias"), this->InputGrad("Bias"));
    }
H
hong 已提交
554
    op->SetAttrMap(this->Attrs());
555
  }
S
sneaxiy 已提交
556 557
};

H
hong 已提交
558 559
template <typename T>
class Conv3DGradMaker : public framework::SingleGradOpMaker<T> {
S
sneaxiy 已提交
560
 public:
H
hong 已提交
561
  using framework::SingleGradOpMaker<T>::SingleGradOpMaker;
562

563
  void Apply(GradOpPtr<T> op) const override {
S
sneaxiy 已提交
564
    op->SetType(this->ForwardOpType() + "_grad");
H
hong 已提交
565 566 567
    op->SetInput("Input", this->Input("Input"));
    op->SetInput("Filter", this->Input("Filter"));
    op->SetInput(framework::GradVarName("Output"), this->OutputGrad("Output"));
S
sneaxiy 已提交
568

H
hong 已提交
569 570
    op->SetOutput(framework::GradVarName("Input"), this->InputGrad("Input"));
    op->SetOutput(framework::GradVarName("Filter"), this->InputGrad("Filter"));
S
sneaxiy 已提交
571

H
hong 已提交
572 573
    if (this->HasInput("ResidualData")) {
      op->SetInput("ResidualData", this->Input("ResidualData"));
S
sneaxiy 已提交
574 575
    }

H
hong 已提交
576
    op->SetAttrMap(this->Attrs());
577 578 579
  }
};

Q
qingqing01 已提交
580 581 582 583
/*
 * Inputs:  I, W, dO, ddI, ddW
 * Outputs: ddO, dW, dI
 */
H
hong 已提交
584 585
template <typename T>
class Conv2DDoubleGradMaker : public framework::SingleGradOpMaker<T> {
Q
qingqing01 已提交
586
 public:
H
hong 已提交
587
  using framework::SingleGradOpMaker<T>::SingleGradOpMaker;
Q
qingqing01 已提交
588

589
  void Apply(GradOpPtr<T> op) const override {
Q
qingqing01 已提交
590 591
    op->SetType(this->ForwardOpType() + "_grad");
    // I, W, dO, ddI, ddW
H
hong 已提交
592 593 594 595 596 597
    op->SetInput("Input", this->Input("Input"));
    op->SetInput("Filter", this->Input("Filter"));
    op->SetInput("DOutput", this->Input(framework::GradVarName("Output")));
    op->SetInput("DDInput", this->OutputGrad(framework::GradVarName("Input")));
    op->SetInput("DDFilter",
                 this->OutputGrad(framework::GradVarName("Filter")));
Q
qingqing01 已提交
598 599 600 601

    // ddO, dI, dW
    // Unlike grad op, double grad op does not use name@GRAD@GRAD
    // as key of ops' inputs and outputs.
H
hong 已提交
602 603
    auto ddx = this->OutputGrad(framework::GradVarName("Input"));
    auto ddw = this->OutputGrad(framework::GradVarName("Filter"));
604

L
lvmengsi 已提交
605
    op->SetOutput("DDOutput",
H
hong 已提交
606
                  ddx.empty()
607
                      ? this->EmptyInputGrad()
H
hong 已提交
608
                      : this->InputGrad(framework::GradVarName("Output")));
609 610 611 612 613 614
    op->SetOutput(
        "DFilter",
        ddx.empty() ? this->EmptyInputGrad() : this->InputGrad("Filter"));
    op->SetOutput(
        "DInput",
        ddw.empty() ? this->EmptyInputGrad() : this->InputGrad("Input"));
615

H
hong 已提交
616
    op->SetAttrMap(this->Attrs());
Q
qingqing01 已提交
617 618 619
  }
};

L
lvmengsi 已提交
620 621 622 623
/*
 * Inputs:  I, W, dO, ddI, ddW
 * Outputs: ddO, dW, dI
 */
H
hong 已提交
624 625
template <typename T>
class Conv3DDoubleGradMaker : public framework::SingleGradOpMaker<T> {
L
lvmengsi 已提交
626
 public:
H
hong 已提交
627
  using framework::SingleGradOpMaker<T>::SingleGradOpMaker;
L
lvmengsi 已提交
628

629
  void Apply(GradOpPtr<T> op) const override {
L
lvmengsi 已提交
630 631
    op->SetType(this->ForwardOpType() + "_grad");
    // I, W, dO, ddI, ddW
H
hong 已提交
632 633 634 635 636 637
    op->SetInput("Input", this->Input("Input"));
    op->SetInput("Filter", this->Input("Filter"));
    op->SetInput("DOutput", this->Input(framework::GradVarName("Output")));
    op->SetInput("DDInput", this->OutputGrad(framework::GradVarName("Input")));
    op->SetInput("DDFilter",
                 this->OutputGrad(framework::GradVarName("Filter")));
L
lvmengsi 已提交
638

H
hong 已提交
639 640
    auto ddx = this->OutputGrad(framework::GradVarName("Input"));
    auto ddw = this->OutputGrad(framework::GradVarName("Filter"));
L
lvmengsi 已提交
641

L
lvmengsi 已提交
642
    op->SetOutput("DDOutput",
H
hong 已提交
643
                  ddx.empty()
644
                      ? this->EmptyInputGrad()
H
hong 已提交
645
                      : this->InputGrad(framework::GradVarName("Output")));
646 647 648 649 650 651
    op->SetOutput(
        "DFilter",
        ddx.empty() ? this->EmptyInputGrad() : this->InputGrad("Filter"));
    op->SetOutput(
        "DInput",
        ddw.empty() ? this->EmptyInputGrad() : this->InputGrad("Input"));
L
lvmengsi 已提交
652

H
hong 已提交
653
    op->SetAttrMap(this->Attrs());
L
lvmengsi 已提交
654 655 656
  }
};

Q
qingqing01 已提交
657 658 659 660 661
void ConvOpDoubleGrad::InferShape(framework::InferShapeContext* ctx) const {
  auto x_dims = ctx->GetInputDim("Input");
  auto w_dims = ctx->GetInputDim("Filter");
  auto do_dims = ctx->GetInputDim("DOutput");

L
lvmengsi 已提交
662 663
  if (ctx->HasOutput("DDOutput") &&
      (ctx->HasInput("DDInput") || (ctx->HasInput("DDFilter")))) {
Q
qingqing01 已提交
664 665
    ctx->SetOutputDim("DDOutput", do_dims);
  }
666
  if (ctx->HasOutput("DFilter") && ctx->HasInput("DDInput")) {
Q
qingqing01 已提交
667 668
    ctx->SetOutputDim("DFilter", w_dims);
  }
669
  if (ctx->HasOutput("DInput") && ctx->HasInput("DDFilter")) {
Q
qingqing01 已提交
670 671 672 673 674 675 676 677 678
    ctx->SetOutputDim("DInput", x_dims);
  }
}

framework::OpKernelType ConvOpDoubleGrad::GetExpectedKernelType(
    const framework::ExecutionContext& ctx) const {
  int customized_type_value =
      framework::OpKernelType::kDefaultCustomizedTypeValue;
  framework::LibraryType library_{framework::LibraryType::kPlain};
L
liym27 已提交
679
  std::string data_format = "AnyLayout";
680
  phi::DataLayout layout_ = phi::StringToDataLayout(data_format);
Q
qingqing01 已提交
681

682
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
Q
qingqing01 已提交
683 684
  if (platform::CanCUDNNBeUsed(ctx)) {
    library_ = framework::LibraryType::kCUDNN;
L
lvmengsi 已提交
685
  }
Q
qingqing01 已提交
686
#endif
687
  auto type = framework::OpKernelType(
688 689 690 691 692
      OperatorWithKernel::IndicateVarDataType(ctx, "Input"),
      ctx.GetPlace(),
      layout_,
      library_,
      customized_type_value);
Q
qingqing01 已提交
693 694 695
  return type;
}

C
chengduoZH 已提交
696 697 698 699
}  // namespace operators
}  // namespace paddle

namespace ops = paddle::operators;
700 701 702
REGISTER_OPERATOR(conv2d,
                  ops::ConvOp,
                  ops::Conv2DOpMaker,
H
hong 已提交
703 704 705
                  ops::ConvOpInferVarType,
                  ops::Conv2DGradMaker<paddle::framework::OpDesc>,
                  ops::Conv2DGradMaker<paddle::imperative::OpBase>);
706 707
REGISTER_OPERATOR(conv2d_grad,
                  ops::ConvOpGrad,
H
hong 已提交
708 709
                  ops::Conv2DDoubleGradMaker<paddle::framework::OpDesc>,
                  ops::Conv2DDoubleGradMaker<paddle::imperative::OpBase>);
Q
qingqing01 已提交
710
REGISTER_OPERATOR(conv2d_grad_grad, ops::ConvOpDoubleGrad);
711 712

// depthwise convolution op
713 714
REGISTER_OPERATOR(depthwise_conv2d,
                  ops::ConvOp,
715
                  ops::DepthwiseConv2DOpMaker,
H
hong 已提交
716 717 718
                  ops::ConvOpInferVarType,
                  ops::Conv2DGradMaker<paddle::framework::OpDesc>,
                  ops::Conv2DGradMaker<paddle::imperative::OpBase>);
719 720
REGISTER_OPERATOR(depthwise_conv2d_grad,
                  ops::ConvOpGrad,
721 722 723
                  ops::Conv2DDoubleGradMaker<paddle::framework::OpDesc>,
                  ops::Conv2DDoubleGradMaker<paddle::imperative::OpBase>);
REGISTER_OPERATOR(depthwise_conv2d_grad_grad, ops::ConvOpDoubleGrad);
C
chengduo 已提交
724

725 726 727
REGISTER_OPERATOR(conv3d,
                  ops::ConvOp,
                  ops::Conv3DOpMaker,
H
hong 已提交
728 729 730
                  ops::ConvOpInferVarType,
                  ops::Conv3DGradMaker<paddle::framework::OpDesc>,
                  ops::Conv3DGradMaker<paddle::imperative::OpBase>);
731 732
REGISTER_OPERATOR(conv3d_grad,
                  ops::ConvOpGrad,
H
hong 已提交
733 734
                  ops::Conv3DDoubleGradMaker<paddle::framework::OpDesc>,
                  ops::Conv3DDoubleGradMaker<paddle::imperative::OpBase>);
L
lvmengsi 已提交
735
REGISTER_OPERATOR(conv3d_grad_grad, ops::ConvOpDoubleGrad);
C
chengduoZH 已提交
736

737 738
REGISTER_OP_VERSION(conv2d).AddCheckpoint(
    R"ROC(
739 740
      Upgrade conv2d, add a new attribute [use_addto].
    )ROC",
741 742 743 744 745
    paddle::framework::compatible::OpVersionDesc().NewAttr(
        "use_addto",
        "In order to support new feature (inplace addto strategy) for "
        "gradient accumulation.",
        false));
746 747 748 749 750 751 752 753 754 755 756 757

REGISTER_OP_VERSION(depthwise_conv2d)
    .AddCheckpoint(
        R"ROC(
      Upgrade depthwise_conv2d, add a new attribute [use_addto].
    )ROC",
        paddle::framework::compatible::OpVersionDesc().NewAttr(
            "use_addto",
            "In order to support new feature (inplace addto strategy) for "
            "gradient accumulation.",
            false));

758 759
REGISTER_OP_VERSION(conv3d).AddCheckpoint(
    R"ROC(
760 761
      Upgrade conv3d, add a new attribute [use_addto].
    )ROC",
762 763 764 765 766
    paddle::framework::compatible::OpVersionDesc().NewAttr(
        "use_addto",
        "In order to support new feature (inplace addto strategy) for "
        "gradient accumulation.",
        false));