Caffe2 - C++ API
A deep learning, cross platform ML framework
sequence_ops.h
1 #ifndef CAFFE2_OPERATORS_SEQUENCE_OPS_H_
2 #define CAFFE2_OPERATORS_SEQUENCE_OPS_H_
3 
4 #include "caffe2/core/operator.h"
5 #include "caffe2/core/tensor.h"
6 #include "caffe2/utils/math.h"
7 
8 namespace caffe2 {
9 
10 template <class Context>
11 class GatherPaddingOp final : public Operator<Context> {
12  public:
13  USE_OPERATOR_CONTEXT_FUNCTIONS;
14  GatherPaddingOp(const OperatorDef& operator_def, Workspace* ws)
15  : Operator<Context>(operator_def, ws),
16  startPaddingWidth_(
17  OperatorBase::GetSingleArgument<int>("padding_width", 1)),
18  endPaddingWidth_(
19  OperatorBase::GetSingleArgument<int>("end_padding_width", -1)) {
20  CAFFE_ENFORCE_GE(startPaddingWidth_, 0);
21  if (endPaddingWidth_ < 0) {
22  endPaddingWidth_ = startPaddingWidth_;
23  }
24  }
25 
26  bool RunOnDevice() override {
27  if (startPaddingWidth_ == 0 && endPaddingWidth_ == 0) {
28  Output(0)->Resize(std::vector<TIndex>(0));
29  Output(0)->template mutable_data<TIndex>();
30  if (OutputSize() == 2) {
31  Output(1)->Resize(std::vector<TIndex>(0));
32  Output(1)->template mutable_data<TIndex>();
33  }
34  return true;
35  }
37  this, Input(0));
38  }
39 
40  template <typename T>
41  bool DoRunWithType() {
42  const auto& in = Input(0);
43  CAFFE_ENFORCE_GE(in.ndim(), 1);
44  const int32_t outer_size = in.dims()[0];
45  const auto block_size = in.size_from_dim(1);
46  const auto pad_width = startPaddingWidth_ + endPaddingWidth_;
47 
48  // if no lengths is provided, assume it is a single full-span entry
49  const int32_t* lengths_ptr = &outer_size;
50  int64_t lengths_size = 1;
51  if (InputSize() > 1) {
52  const auto& lengths = Input(1);
53  lengths_ptr = lengths.template data<int32_t>();
54  lengths_size = lengths.size();
55  }
56  std::vector<TIndex> padShape(in.dims().begin() + 1, in.dims().end());
57  // output will contain accumulator over paddings
58  Output(0)->Resize(padShape);
59  T* padding_start_ptr = Output(0)->template mutable_data<T>();
60  math::Set<T, Context>(block_size, 0.0, padding_start_ptr, &context_);
61 
62  // if no end_padding is provided, assume it's the same as start_padding
63  T* padding_end_ptr = padding_start_ptr;
64  if (OutputSize() == 2) {
65  Output(1)->Resize(padShape);
66  padding_end_ptr = Output(1)->template mutable_data<T>();
67  math::Set<T, Context>(block_size, 0.0, padding_end_ptr, &context_);
68  }
69  GatherPadding<T>(
70  outer_size,
71  lengths_size,
72  block_size,
73  pad_width,
74  in.template data<T>(),
75  lengths_ptr,
76  padding_start_ptr,
77  padding_end_ptr);
78  return true;
79  }
80 
81  private:
82  template <typename T>
83  void GatherPadding(
84  const int outer_size,
85  const int lengths_size,
86  const int block_size,
87  const int pad_width,
88  const T* in_ptr,
89  const int* lengths_ptr,
90  T* padding_start_ptr,
91  T* padding_end_ptr);
92 
93  int startPaddingWidth_;
94  int endPaddingWidth_;
95  // Scratch space required by the CUDA version
96  Tensor<Context> lengths_prefix_sum_buffer_;
97  Tensor<Context> lengths_prefix_sum_;
98 };
99 
100 template <class Context>
101 class RemovePaddingOp final : public Operator<Context> {
102  public:
103  USE_OPERATOR_CONTEXT_FUNCTIONS;
104  RemovePaddingOp(const OperatorDef& operator_def, Workspace* ws)
105  : Operator<Context>(operator_def, ws),
106  startPaddingWidth_(
107  OperatorBase::GetSingleArgument<int>("padding_width", 1)),
108  endPaddingWidth_(
109  OperatorBase::GetSingleArgument<int>("end_padding_width", -1)) {
110  CAFFE_ENFORCE_GE(startPaddingWidth_, 0);
111  if (endPaddingWidth_ < 0) {
112  endPaddingWidth_ = startPaddingWidth_;
113  }
114  }
115 
116  bool RunOnDevice() override {
117  if (startPaddingWidth_ == 0 && endPaddingWidth_ == 0) {
118  Output(0)->CopyFrom(Input(0), &context_);
119  if (OutputSize() == 2) {
120  Output(1)->CopyFrom(Input(1), &context_);
121  }
122  return true;
123  }
125  this, Input(0));
126  }
127 
128  template <typename T>
129  bool DoRunWithType();
130 
131  private:
132  int startPaddingWidth_;
133  int endPaddingWidth_;
134 
135  // Scratch space required by the CUDA version
136  Tensor<Context> lengths_prefix_sum_buffer_;
137  Tensor<Context> lengths_prefix_sum_;
138 };
139 
140 template <class Context>
141 class AddPaddingOp final : public Operator<Context> {
142  public:
143  USE_OPERATOR_CONTEXT_FUNCTIONS;
144  AddPaddingOp(const OperatorDef& operator_def, Workspace* ws)
145  : Operator<Context>(operator_def, ws),
146  startPaddingWidth_(
147  OperatorBase::GetSingleArgument<int>("padding_width", 1)),
148  endPaddingWidth_(
149  OperatorBase::GetSingleArgument<int>("end_padding_width", -1)) {
150  CAFFE_ENFORCE_GE(startPaddingWidth_, 0);
151  if (endPaddingWidth_ < 0) {
152  endPaddingWidth_ = startPaddingWidth_;
153  }
154  }
155 
156  bool RunOnDevice() override {
157  if (startPaddingWidth_ == 0 && endPaddingWidth_ == 0) {
158  Output(0)->CopyFrom(Input(0), &context_);
159  if (OutputSize() == 2) {
160  Output(1)->CopyFrom(Input(1), &context_);
161  }
162  return true;
163  }
165  this, Input(0));
166  }
167 
168  template <typename T>
169  bool DoRunWithType() {
170  const auto& in = Input(0);
171  CAFFE_ENFORCE_GE(in.ndim(), 1);
172  const int32_t outer_size = in.dims()[0];
173  const auto block_size = in.size_from_dim(1);
174 
175  // if no lengths is provided, assume it is a single full-span entry
176  const int32_t* lengths_ptr = nullptr;
177  int32_t lengths_size = 1;
178  if (InputSize() > 1) {
179  const auto& lengths = Input(1);
180  lengths_ptr = lengths.template data<int32_t>();
181  lengths_size = lengths.size();
182  }
183 
184  // fetch paddings
185  // input_size == 2 : pad with zeros
186  // input_size == 3 : start and end paddings are the same
187  // input_size == 4 : different start and end paddings
188  const T* padding_start_ptr = nullptr;
189  const T* padding_end_ptr = nullptr;
190  if (InputSize() >= 3) {
191  auto& padding_start = Input(2);
192  CAFFE_ENFORCE_EQ(block_size, padding_start.size());
193  padding_start_ptr = padding_start.template data<T>();
194  }
195  if (InputSize() == 4) {
196  auto& padding_end = Input(3);
197  CAFFE_ENFORCE_EQ(block_size, padding_end.size());
198  padding_end_ptr = padding_end.template data<T>();
199  } else {
200  padding_end_ptr = padding_start_ptr;
201  }
202 
203  auto* out = Output(0);
204  {
205  auto out_dims = in.dims();
206  out_dims[0] += (startPaddingWidth_ + endPaddingWidth_) * lengths_size;
207  out->Resize(std::move(out_dims));
208  }
209  const auto* in_ptr = in.template data<T>();
210  auto* out_ptr = out->template mutable_data<T>();
211 
212  return MakePadding<T>(
213  in_ptr,
214  out_ptr,
215  lengths_ptr,
216  lengths_size,
217  outer_size,
218  padding_start_ptr,
219  padding_end_ptr,
220  block_size);
221  }
222 
223  private:
224  template <typename T>
225  bool MakePadding(
226  const T* in_ptr,
227  T* out_ptr,
228  const int32_t* lengths_ptr,
229  int32_t lengths_size,
230  int32_t outer_size,
231  const T* padding_start_ptr,
232  const T* padding_end_ptr,
233  int64_t block_size);
234 
235  int startPaddingWidth_;
236  int endPaddingWidth_;
237 
238  // Scratch space required by the CUDA version
239  Tensor<Context> lengths_prefix_sum_buffer_;
240  Tensor<Context> lengths_prefix_sum_;
241 };
242 
243 template <class Context>
244 class PadEmptySamplesOp : public Operator<Context> {
245  public:
246  USE_OPERATOR_CONTEXT_FUNCTIONS;
247  PadEmptySamplesOp(const OperatorDef& operator_def, Workspace* ws)
248  : Operator<Context>(operator_def, ws) {}
249 
250  bool RunOnDevice() override;
251 };
252 
253 } // namespace caffe2
254 
255 #endif // CAFFE2_OPERATORS_SEQUENCE_OPS_H_
Tensor is the basic class in Caffe2 that stores a contiguous memory with its shape information...
Definition: tensor.h:93
Workspace is a class that holds all the related objects created during runtime: (1) all blobs...
Definition: workspace.h:47
A global dictionary that holds information about what Caffe2 modules have been loaded in the current ...