Caffe2 - C++ API
A deep learning, cross platform ML framework
expand_op.h
1 #ifndef CAFFE2_OPERATORS_EXPAND_OP_H_
2 #define CAFFE2_OPERATORS_EXPAND_OP_H_
3 
4 #include <vector>
5 
6 #include "caffe2/core/context.h"
7 #include "caffe2/core/operator.h"
8 #include "caffe2/core/types.h"
9 #include "caffe2/utils/math.h"
10 
11 namespace caffe2 {
12 
13 template <typename InputTypes, class Context>
14 class ExpandOp final : public Operator<Context> {
15  public:
16  USE_OPERATOR_CONTEXT_FUNCTIONS;
17 
18  template <class... Args>
19  explicit ExpandOp(Args&&... args)
20  : Operator<Context>(std::forward<Args>(args)...) {}
21 
22  bool RunOnDevice() override {
23  return DispatchHelper<InputTypes>::call(this, Input(0));
24  }
25  template <typename T>
26  bool DoRunWithType() {
27  const auto& X = Input(0);
28  const auto& Y_shape_tensor = Input(1);
29  std::vector<int64_t> shape_dims(Y_shape_tensor.numel());
30  context_.template CopyToCPU<int64_t>(
31  Y_shape_tensor.numel(),
32  Y_shape_tensor.template data<int64_t>(),
33  shape_dims.data());
34 
35  const int ndim = shape_dims.size();
36  const std::vector<int> X_dims(X.sizes().cbegin(), X.sizes().cend());
37  std::vector<int> Y_dims;
38  Y_dims.reserve(std::max(ndim, X.dim()));
39  // ndim, X.ndim() might equal to 0
40  for (int i = ndim - 1, j = X.dim() - 1; i >= 0 || j >= 0; --i, --j) {
41  const int shape_x = (j >= 0 ? X_dims[j] : 1);
42  // In PyTorch expand treats -1 as a special value to indicate
43  // preserving the size of that dimension.
44  const int shape_y = ((i >= 0 && shape_dims[i] > 0) ? shape_dims[i] : 1);
45 
46  CAFFE_ENFORCE(
47  shape_x == 1 || shape_y == 1 || shape_x == shape_y,
48  "Dimensions format invalid.");
49  Y_dims.push_back(std::max(shape_x, shape_y));
50  }
51  std::reverse(Y_dims.begin(), Y_dims.end());
52  // TODO: remove when the function in math are changed to use vector<int64_t>
53  std::vector<int64_t> Y_dims_int64;
54  std::copy(Y_dims.begin(), Y_dims.end(), std::back_inserter(Y_dims_int64));
55  auto* Y = Output(0, Y_dims_int64, at::dtype<T>());
56  math::Broadcast<T, Context>(
57  X_dims.size(),
58  X_dims.data(),
59  Y_dims.size(),
60  Y_dims.data(),
61  T(1),
62  X.template data<T>(),
63  Y->template mutable_data<T>(),
64  &context_);
65  return true;
66  }
67 
68 };
69 
70 template <typename InputTypes, class Context>
71 class ExpandGradientOp final : public Operator<Context> {
72  public:
73  USE_OPERATOR_CONTEXT_FUNCTIONS;
74 
75  template <class... Args>
76  explicit ExpandGradientOp(Args&&... args)
77  : Operator<Context>(std::forward<Args>(args)...) {}
78 
79  bool RunOnDevice() override {
80  return DispatchHelper<InputTypes>::call(this, Input(0));
81  }
82 
83  template <typename T>
84  bool DoRunWithType() {
85  const auto& dY = Input(0);
86  const auto& X = Input(1);
87 
88  const int ndim = dY.dim();
89  const std::vector<int> dX_dims(X.sizes().cbegin(), X.sizes().cend());
90  const std::vector<int> dY_dims(dY.sizes().cbegin(), dY.sizes().cend());
91  auto* dX = Output(0, X.sizes(), at::dtype<T>());
92  std::vector<int> axes;
93  const int offset = ndim - X.dim();
94  for (int i = 0; i < ndim; i++) {
95  if (i < offset || dX_dims[i - offset] == 1) {
96  axes.push_back(i);
97  }
98  }
99  std::vector<int> X_dims = dY_dims;
100  for (const int axis : axes) {
101  X_dims[axis] = 1;
102  }
103  math::ReduceSum<T, Context>(
104  dY_dims.size(),
105  dY_dims.data(),
106  X_dims.data(),
107  T(1),
108  dY.template data<T>(),
109  dX->template mutable_data<T>(),
110  &context_);
111  return true;
112  }
113 };
114 
115 } // namespace caffe2
116 
117 #endif // CAFFE2_OPERATORS_REDUCE_OPS_H_
const Tensor & Input(int idx, DeviceType type=Context::GetDeviceType())
Retrieve a non-owning reference to the input at position &#39;idx&#39; for this operator. ...
Definition: operator.h:702
A global dictionary that holds information about what Caffe2 modules have been loaded in the current ...
Definition: blob.h:13