conv_op.h 8.0 KB
Newer Older
1
/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved.
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

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. */

#pragma once

L
liym27 已提交
17
#include <algorithm>
Q
qingqing01 已提交
18
#include <string>
Q
qingqing01 已提交
19
#include <unordered_map>
20
#include <vector>
21

Y
Yi Wang 已提交
22 23
#include "paddle/fluid/framework/eigen.h"
#include "paddle/fluid/framework/op_registry.h"
F
Feiyu Chan 已提交
24
#include "paddle/fluid/operators/layout_utils.h"
25
#include "paddle/phi/kernels/funcs/blas/blas.h"
26
#include "paddle/phi/kernels/funcs/im2col.h"
27
#include "paddle/phi/kernels/funcs/vol2col.h"
28 29 30 31

namespace paddle {
namespace operators {

32
using Tensor = phi::DenseTensor;
33

武毅 已提交
34 35
// Base convolution operator definations for other conv
// like operators to reuse the implementation.
36 37
inline int ConvOutputSize(
    int input_size, int filter_size, int dilation, int padding, int stride) {
C
chengduoZH 已提交
38
  const int dkernel = dilation * (filter_size - 1) + 1;
C
chengduoZH 已提交
39
  int output_size = (input_size + 2 * padding - dkernel) / stride + 1;
L
liym27 已提交
40
  PADDLE_ENFORCE_GT(
41 42
      output_size,
      0,
43 44
      platform::errors::InvalidArgument(
          "The output's size is expected to be greater than 0. "
45
          "But received: output's size is %d. The output's size is computed by "
46 47 48
          "((input_size + 2 * padding - (dilation * (filter_size - 1) + 1)) / "
          "stride + 1), where input_size is %d, padding is %d, "
          "filter_size is %d, dilation is %d, stride is %d.",
49 50 51 52 53 54
          output_size,
          input_size,
          padding,
          filter_size,
          dilation,
          stride));
C
chengduoZH 已提交
55

武毅 已提交
56 57
  return output_size;
}
L
liym27 已提交
58

59 60 61 62 63 64
inline int ConvOutputSize(int input_size,
                          int filter_size,
                          int dilation,
                          int padding_1,
                          int padding_2,
                          int stride) {
L
liym27 已提交
65 66
  const int dkernel = dilation * (filter_size - 1) + 1;
  int output_size = (input_size + padding_1 + padding_2 - dkernel) / stride + 1;
67
  PADDLE_ENFORCE_GT(
68 69
      output_size,
      0,
70 71
      platform::errors::InvalidArgument(
          "The output's size is expected to be greater than 0. "
72
          "But received: output's size is %d. The output's size is computed by "
73 74 75
          "((input_size + padding_1 + padding_2 - (dilation * (filter_size - "
          "1) + 1)) / stride + 1), where input_size is %d, padding is "
          "(%d, %d), filter_size is %d, dilation is %d, stride is %d.",
76 77 78 79 80 81
          output_size,
          input_size,
          padding_1,
          padding_2,
          filter_size,
          dilation,
82
          stride));
L
liym27 已提交
83 84 85

  return output_size;
}
86 87 88 89

template <typename T = int>
inline void UpdatePaddingAndDilation(std::vector<T>* paddings,
                                     std::vector<T>* dilation,
L
liym27 已提交
90 91
                                     const std::string padding_algorithm,
                                     const framework::DDim data_dims,
92 93
                                     const std::vector<T>& strides,
                                     const std::vector<T>& ksize) {
L
liym27 已提交
94
  // set padding size == data_dims.size() * 2
95
  auto data_shape = phi::vectorize<T>(data_dims);
96 97
  if (static_cast<int>(paddings->size()) == data_dims.size()) {
    for (int i = 0; i < data_dims.size(); ++i) {
98
      T copy_pad = *(paddings->begin() + 2 * i);
L
liym27 已提交
99 100 101 102
      paddings->insert(paddings->begin() + 2 * i + 1, copy_pad);
    }
  } else {
    PADDLE_ENFORCE_EQ(
103 104
        data_dims.size() * 2,
        paddings->size(),
105 106 107
        platform::errors::InvalidArgument(
            "Attribute padding's size should be the same or twice as the "
            "input's dimension. "
108
            "But received: padding's size is %d, padding is [%s]; input's "
109
            "dimension is %d, input's shape is [%s].",
110 111 112
            paddings->size(),
            phi::make_ddim(*paddings),
            data_dims.size(),
113
            data_dims));
L
liym27 已提交
114 115
  }

116
  // when padding_algorithm is "VALID" or "SAME"
L
liym27 已提交
117
  if (padding_algorithm == "SAME") {
118
    for (int i = 0; i < data_dims.size(); ++i) {
119 120
      T out_size = (data_dims[i] + strides[i] - 1) / strides[i];
      T pad_sum =
121 122
          std::max((out_size - 1) * strides[i] + ksize[i] - data_shape[i],
                   static_cast<T>(0));
123 124
      T pad_0 = pad_sum / 2;
      T pad_1 = pad_sum - pad_0;
L
liym27 已提交
125 126 127 128 129 130 131 132 133 134 135 136 137 138
      *(paddings->begin() + i * 2) = pad_0;
      *(paddings->begin() + i * 2 + 1) = pad_1;

      // dilation
      *(dilation->begin() + i) = 1;
    }

  } else if (padding_algorithm == "VALID") {
    for (auto it = paddings->begin(); it != paddings->end(); it++) {
      *it = 0;
    }
  }
}

139 140 141 142
inline bool IsExpand(const std::vector<int64_t>& filter_dim,
                     const std::vector<int>& strides,
                     const std::vector<int>& paddings,
                     const std::vector<int>& dilations) {
C
chengduoZH 已提交
143 144
  bool filter_1 = true, strides_1 = true, padding_0 = true, dilation_1 = true;
  for (size_t j = 0; j < strides.size(); ++j) {
C
chengduoZH 已提交
145
    filter_1 = filter_1 && (static_cast<int>(filter_dim[j + 2]) == 1);
C
chengduoZH 已提交
146 147 148
    strides_1 = strides_1 && (strides[j] == 1);
    padding_0 = padding_0 && (paddings[j] == 0);
    dilation_1 = dilation_1 && (dilations[j] == 1);
C
chengduoZH 已提交
149
  }
L
liym27 已提交
150 151 152 153 154
  if (paddings.size() != strides.size()) {
    for (size_t j = 0; j < paddings.size(); ++j) {
      padding_0 = padding_0 && (paddings[j] == 0);
    }
  }
C
chengduoZH 已提交
155
  return !(filter_1 && strides_1 && padding_0 && dilation_1);
C
chengduoZH 已提交
156
}
武毅 已提交
157 158 159 160 161

// Define Op classes in .h file so that other conv
// operator implementations can reuse the code.
class Conv2DOpMaker : public framework::OpProtoAndCheckerMaker {
 public:
Q
qingqing01 已提交
162 163 164 165
  void Make() final;

 protected:
  virtual void Apply() {}
武毅 已提交
166 167
};

C
chengduoZH 已提交
168 169
class Conv3DOpMaker : public framework::OpProtoAndCheckerMaker {
 public:
Q
qingqing01 已提交
170 171 172 173 174 175 176 177
  void Make() final;

 protected:
  virtual void Apply() {}
};

class ConvOpInferVarType : public framework::PassInDtypeAndVarTypeToOutput {
 protected:
178
  std::unordered_map<std::string, std::string>& GetInputOutputWithSameType()
Q
qingqing01 已提交
179
      const override {
180
    static std::unordered_map<std::string, std::string> m{
Q
qingqing01 已提交
181
        {"Input", /*->*/ "Output"}};
182
    return m;
Q
qingqing01 已提交
183
  }
C
chengduoZH 已提交
184 185 186
};

class ConvOp : public framework::OperatorWithKernel {
武毅 已提交
187 188
 public:
  using framework::OperatorWithKernel::OperatorWithKernel;
189 190 191 192
  void InferShape(framework::InferShapeContext* ctx) const override {
    std::vector<int64_t> output_shape = ComputeOutputShape(ctx);

    OP_INOUT_CHECK(ctx->HasOutput("Output"), "Output", "Output", "Conv");
193
    ctx->SetOutputDim("Output", phi::make_ddim(output_shape));
194 195
    ctx->ShareLoD("Input", "Output");
  }
196 197

 protected:
198 199 200
  std::vector<int64_t> ComputeOutputShape(
      framework::InferShapeContext* ctx) const;

201 202
  framework::OpKernelType GetExpectedKernelType(
      const framework::ExecutionContext& ctx) const override;
203 204

  framework::OpKernelType GetKernelTypeForVar(
205
      const std::string& var_name,
206
      const phi::DenseTensor& tensor,
207
      const framework::OpKernelType& expected_kernel_type) const override;
武毅 已提交
208 209
};

C
chengduoZH 已提交
210
class ConvOpGrad : public framework::OperatorWithKernel {
武毅 已提交
211 212 213
 public:
  using framework::OperatorWithKernel::OperatorWithKernel;
  void InferShape(framework::InferShapeContext* ctx) const override;
214

Q
qingqing01 已提交
215 216 217
 protected:
  framework::OpKernelType GetExpectedKernelType(
      const framework::ExecutionContext& ctx) const override;
218 219

  framework::OpKernelType GetKernelTypeForVar(
220
      const std::string& var_name,
221
      const phi::DenseTensor& tensor,
222
      const framework::OpKernelType& expected_kernel_type) const override;
Q
qingqing01 已提交
223 224 225 226 227 228 229
};

class ConvOpDoubleGrad : public framework::OperatorWithKernel {
 public:
  using framework::OperatorWithKernel::OperatorWithKernel;
  void InferShape(framework::InferShapeContext* ctx) const override;

230 231 232
 protected:
  framework::OpKernelType GetExpectedKernelType(
      const framework::ExecutionContext& ctx) const override;
武毅 已提交
233 234
};

235 236
}  // namespace operators
}  // namespace paddle