Caffe2 - C++ API
A deep learning, cross platform ML framework
conv_transpose_unpool_op_base.h
1 
17 #ifndef CAFFE2_OPERATORS_CONV_TRANSPOSE_UNPOOL_OP_BASE_H_
18 #define CAFFE2_OPERATORS_CONV_TRANSPOSE_UNPOOL_OP_BASE_H_
19 
20 #include "caffe2/core/context.h"
21 #include "caffe2/core/logging.h"
22 #include "caffe2/core/operator.h"
23 #include "caffe2/operators/conv_op_shared.h"
24 #include "caffe2/operators/conv_pool_op_base.h"
25 #include "caffe2/proto/caffe2_legacy.pb.h"
26 #include "caffe2/utils/math.h"
27 
28 CAFFE2_DECLARE_bool(caffe2_force_shared_col_buffer);
29 
30 namespace caffe2 {
31 
32 template <class Context>
33 class ConvTransposeUnpoolBase : public Operator<Context> {
34  public:
35  USE_OPERATOR_CONTEXT_FUNCTIONS;
36  ConvTransposeUnpoolBase(const OperatorDef& operator_def, Workspace* ws)
37  : Operator<Context>(operator_def, ws),
38  legacy_pad_(
39  static_cast<LegacyPadding>(OperatorBase::GetSingleArgument<int>(
40  "legacy_pad",
41  LegacyPadding::NOTSET))),
42  kernel_(OperatorBase::GetRepeatedArgument<int>("kernels")),
43  stride_(OperatorBase::GetRepeatedArgument<int>("strides")),
44  pads_(OperatorBase::GetRepeatedArgument<int>("pads")),
45  adj_(OperatorBase::GetRepeatedArgument<int>("adjs")),
46  order_(StringToStorageOrder(
47  OperatorBase::GetSingleArgument<string>("order", "NCHW"))),
48  shared_buffer_(
49  OperatorBase::GetSingleArgument<int>("shared_buffer", 0)),
50  ws_(ws) {
51  // For the padding, they should either be the legacy padding strategy
52  // (VALID or SAME), or an explicit, non-negative value.
53  if (legacy_pad_ == LegacyPadding::VALID ||
54  legacy_pad_ == LegacyPadding::SAME) {
55  CAFFE_ENFORCE(
57  "If you use legacy padding VALID or SAME, you should not specify "
58  "any specific padding values.");
59  }
60  // Get old arguments values.
61  if (OperatorBase::HasArgument("kernel")) {
62  kernel_.resize(2, OperatorBase::GetSingleArgument<int>("kernel", 0));
63  } else if (
64  OperatorBase::HasArgument("kernel_h") &&
65  OperatorBase::HasArgument("kernel_w")) {
66  kernel_.push_back(OperatorBase::GetSingleArgument<int>("kernel_h", 0));
67  kernel_.push_back(OperatorBase::GetSingleArgument<int>("kernel_w", 0));
68  }
69 
70  if (OperatorBase::HasArgument("stride")) {
71  stride_.resize(2, OperatorBase::GetSingleArgument<int>("stride", 0));
72  } else if (
73  OperatorBase::HasArgument("stride_h") &&
74  OperatorBase::HasArgument("stride_w")) {
75  stride_.push_back(OperatorBase::GetSingleArgument<int>("stride_h", 0));
76  stride_.push_back(OperatorBase::GetSingleArgument<int>("stride_w", 0));
77  }
78 
79  if (OperatorBase::HasArgument("adj")) {
80  adj_.resize(2, OperatorBase::GetSingleArgument<int>("adj", 0));
81  } else if (
82  OperatorBase::HasArgument("adj_h") &&
83  OperatorBase::HasArgument("adj_w")) {
84  adj_.push_back(OperatorBase::GetSingleArgument<int>("adj_h", 0));
85  adj_.push_back(OperatorBase::GetSingleArgument<int>("adj_w", 0));
86  }
87 
88  if (OperatorBase::HasArgument("pad")) {
89  CAFFE_ENFORCE(
90  legacy_pad_ != LegacyPadding::VALID &&
91  legacy_pad_ != LegacyPadding::SAME,
92  "If you use legacy padding VALID or SAME, you should not specify "
93  "any specific padding values.");
94  pads_.resize(4, OperatorBase::GetSingleArgument<int>("pad", 0));
95  } else if (
96  OperatorBase::HasArgument("pad_t") &&
97  OperatorBase::HasArgument("pad_l") &&
98  OperatorBase::HasArgument("pad_b") &&
99  OperatorBase::HasArgument("pad_r")) {
100  CAFFE_ENFORCE(
101  legacy_pad_ != LegacyPadding::VALID &&
102  legacy_pad_ != LegacyPadding::SAME,
103  "If you use legacy padding VALID or SAME, you should not specify "
104  "any specific padding values.");
105  pads_.push_back(OperatorBase::GetSingleArgument<int>("pad_t", 0));
106  pads_.push_back(OperatorBase::GetSingleArgument<int>("pad_l", 0));
107  pads_.push_back(OperatorBase::GetSingleArgument<int>("pad_b", 0));
108  pads_.push_back(OperatorBase::GetSingleArgument<int>("pad_r", 0));
109  }
110 
111  // Fill default values.
112  if (kernel_.size() == 0) {
113  kernel_.assign({0, 0});
114  }
115 
116  if (stride_.size() == 0) {
117  stride_.resize(kernel_.size(), 1);
118  }
119 
120  if (pads_.size() == 0) {
121  pads_.resize(kernel_.size() * 2, 0);
122  }
123 
124  if (adj_.size() == 0) {
125  adj_.resize(kernel_.size(), 0);
126  }
127 
128  CAFFE_ENFORCE_EQ(stride_.size(), kernel_.size());
129  CAFFE_ENFORCE_EQ(adj_.size(), kernel_.size());
130 
131  if (legacy_pad_ != LegacyPadding::VALID &&
132  legacy_pad_ != LegacyPadding::SAME) {
133  CAFFE_ENFORCE_EQ(pads_.size(), 2 * kernel_.size());
134  }
135 
136  for (int dim = 0; dim < kernel_.size(); ++dim) {
137  CAFFE_ENFORCE_GT(kernel_[dim], 0);
138  CAFFE_ENFORCE_GT(stride_[dim], 0);
139  CAFFE_ENFORCE_GE(adj_[dim], 0);
140  CAFFE_ENFORCE_LE(adj_[dim], stride_[dim]);
141  }
142 
143  // Create shared buffer mutex in the constructor
144  // to avoid race-condition in DAGNet.
145  if (FLAGS_caffe2_force_shared_col_buffer || shared_buffer_) {
146  createSharedBuffer<Context>(ws_);
147  }
148  }
149  // Sets the output size. The output channel is manually specified.
150  void SetOutputSize(
151  const Tensor<Context>& input,
152  Tensor<Context>* output,
153  int output_channel) {
154  CAFFE_ENFORCE(4 == input.ndim());
155  CAFFE_ENFORCE(input.size() > 0);
156  int N = input.dim32(0);
157  bool channel_first = false; // initialized to suppress compiler warning.
158  int H = 0, W = 0; // initialized to suppress compiler warning.
159  int M = 0;
160  switch (order_) {
161  case StorageOrder::NHWC:
162  channel_first = false;
163  H = input.dim32(1);
164  W = input.dim32(2);
165  M = input.dim32(3);
166  break;
167  case StorageOrder::NCHW:
168  channel_first = true;
169  M = input.dim32(1);
170  H = input.dim32(2);
171  W = input.dim32(3);
172  break;
173  default:
174  LOG(FATAL) << "Unknown Storage order: " << order_;
175  }
176  int output_height = 0, output_width = 0;
177  ComputeSizeAndPad(
178  H,
179  stride_[0],
180  kernel_[0],
181  adj_[0],
182  &pads_[0],
183  &pads_[2],
184  &output_height);
185  ComputeSizeAndPad(
186  W,
187  stride_[1],
188  kernel_[1],
189  adj_[1],
190  &pads_[1],
191  &pads_[3],
192  &output_width);
193  if (channel_first) {
194  output->Resize(N, output_channel, output_height, output_width);
195  } else {
196  output->Resize(N, output_height, output_width, output_channel);
197  }
198  VLOG(2) << "In: N " << N << " M " << M << " H " << H << " W " << W;
199  VLOG(2) << "Out: output_channel " << output_channel << " H "
200  << output_height << " W " << output_width;
201  }
202 
203  bool RunOnDevice() override {
204  switch (order_) {
205  case StorageOrder::NHWC:
206  return RunOnDeviceWithOrderNHWC();
207  case StorageOrder::NCHW:
208  return RunOnDeviceWithOrderNCHW();
209  default:
210  LOG(FATAL) << "Unknown storage order: " << order_;
211  }
212  // To suppress old compiler warnings
213  return true;
214  }
215 
216  virtual bool RunOnDeviceWithOrderNCHW() {
217  CAFFE_THROW("Not implemented");
218  }
219 
220  virtual bool RunOnDeviceWithOrderNHWC() {
221  CAFFE_THROW("Not implemented");
222  }
223 
224  virtual ~ConvTransposeUnpoolBase() {}
225 
226  private:
227  LegacyPadding legacy_pad_;
228  int pad_;
229 
230  protected:
231  vector<int> kernel_;
232  vector<int> stride_;
233  vector<int> pads_;
234  vector<int> adj_;
235  StorageOrder order_;
236  bool shared_buffer_;
237  Workspace* ws_;
238 
239  // Accessors for 2D conv params.
240 
241  inline int pad_t() const {
242  return pads_[0];
243  }
244 
245  inline int pad_l() const {
246  return pads_[1];
247  }
248 
249  inline int pad_b() const {
250  return pads_[2];
251  }
252 
253  inline int pad_r() const {
254  return pads_[3];
255  }
256 
257  inline int kernel_h() const {
258  return kernel_[0];
259  }
260 
261  inline int kernel_w() const {
262  return kernel_[1];
263  }
264 
265  inline int stride_h() const {
266  return stride_[0];
267  }
268 
269  inline int stride_w() const {
270  return stride_[1];
271  }
272 
273  inline int adj_h() const {
274  return adj_[0];
275  }
276 
277  inline int adj_w() const {
278  return adj_[1];
279  }
280 
281  inline void ComputeSizeAndPad(
282  const int in_size,
283  const int stride,
284  const int kernel,
285  const int adj,
286  int* pad_head,
287  int* pad_tail,
288  int* out_size) {
289  switch (legacy_pad_) {
290  case LegacyPadding::NOTSET:
291  CAFFE_ENFORCE(*pad_head >= 0);
292  CAFFE_ENFORCE(*pad_tail >= 0);
293  *out_size =
294  (in_size - 1) * stride + kernel + adj - *pad_head - *pad_tail;
295  break;
296  // We handle cases of LegacyPadding::VALID and LegacyPadding::SAME
297  // the same way
298  case LegacyPadding::VALID:
299  case LegacyPadding::SAME:
300  *pad_head = 0;
301  *pad_tail = 0;
302  *out_size = (in_size - 1) * stride + kernel + adj;
303  break;
304  case LegacyPadding::CAFFE_LEGACY_POOLING:
305  LOG(FATAL) << "CAFFE_LEGACY_POOLING is no longer supported.";
306  break;
307  }
308  }
309 };
310 
311 #define USE_CONV_TRANSPOSE_UNPOOL_BASE_FUNCTIONS(Context) \
312  USE_OPERATOR_FUNCTIONS(Context); \
313  using ConvTransposeUnpoolBase<Context>::kernel_; \
314  using ConvTransposeUnpoolBase<Context>::stride_; \
315  using ConvTransposeUnpoolBase<Context>::pads_; \
316  using ConvTransposeUnpoolBase<Context>::adj_; \
317  using ConvTransposeUnpoolBase<Context>::order_; \
318  using ConvTransposeUnpoolBase<Context>::shared_buffer_; \
319  using ConvTransposeUnpoolBase<Context>::ws_
320 
321 } // namespace caffe2
322 
323 #endif // CAFFE2_OPERATORS_CONV_TRANSPOSE_UNPOOL_OP_BASE_H_
Tensor is the basic class in Caffe2 that stores a contiguous memory with its shape information...
Definition: tensor.h:109
int dim32(const int i) const
Returns the i-th dimension of the tensor in int.
Definition: tensor.h:673
TIndex size() const
Returns the size (i.e.
Definition: tensor.h:609
Workspace is a class that holds all the related objects created during runtime: (1) all blobs...
Definition: workspace.h:63
void Resize(Ts...dim_source)
Resizes a tensor.
Definition: tensor.h:304
Copyright (c) 2016-present, Facebook, Inc.
bool HasArgument(const string &name) const
Checks if the operator has an argument of the given name.
Definition: operator.h:52
int ndim() const
Returns the number of dimensions of the data.
Definition: tensor.h:605