conv_op.h 7.9 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 {

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

武毅 已提交
54 55
  return output_size;
}
L
liym27 已提交
56

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

  return output_size;
}
84 85 86 87

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

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

137 138 139 140
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 已提交
141 142
  bool filter_1 = true, strides_1 = true, padding_0 = true, dilation_1 = true;
  for (size_t j = 0; j < strides.size(); ++j) {
C
chengduoZH 已提交
143
    filter_1 = filter_1 && (static_cast<int>(filter_dim[j + 2]) == 1);
C
chengduoZH 已提交
144 145 146
    strides_1 = strides_1 && (strides[j] == 1);
    padding_0 = padding_0 && (paddings[j] == 0);
    dilation_1 = dilation_1 && (dilations[j] == 1);
C
chengduoZH 已提交
147
  }
L
liym27 已提交
148 149 150 151 152
  if (paddings.size() != strides.size()) {
    for (size_t j = 0; j < paddings.size(); ++j) {
      padding_0 = padding_0 && (paddings[j] == 0);
    }
  }
C
chengduoZH 已提交
153
  return !(filter_1 && strides_1 && padding_0 && dilation_1);
C
chengduoZH 已提交
154
}
武毅 已提交
155 156 157 158 159

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

 protected:
  virtual void Apply() {}
武毅 已提交
164 165
};

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

 protected:
  virtual void Apply() {}
};

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

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

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

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

199
  phi::KernelKey GetExpectedKernelType(
200
      const framework::ExecutionContext& ctx) const override;
201

202
  phi::KernelKey GetKernelTypeForVar(
203
      const std::string& var_name,
204
      const phi::DenseTensor& tensor,
205
      const phi::KernelKey& expected_kernel_type) const override;
武毅 已提交
206 207
};

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

Q
qingqing01 已提交
213
 protected:
214
  phi::KernelKey GetExpectedKernelType(
Q
qingqing01 已提交
215
      const framework::ExecutionContext& ctx) const override;
216

217
  phi::KernelKey GetKernelTypeForVar(
218
      const std::string& var_name,
219
      const phi::DenseTensor& tensor,
220
      const phi::KernelKey& expected_kernel_type) const override;
Q
qingqing01 已提交
221 222 223 224 225 226 227
};

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

228
 protected:
229
  phi::KernelKey GetExpectedKernelType(
230
      const framework::ExecutionContext& ctx) const override;
武毅 已提交
231 232
};

233 234
}  // namespace operators
}  // namespace paddle