1 #ifndef CAFFE2_OPERATORS_TILE_OP_H_ 2 #define CAFFE2_OPERATORS_TILE_OP_H_ 9 #include "caffe2/core/common_omp.h" 10 #include "caffe2/core/context.h" 11 #include "caffe2/core/logging.h" 12 #include "caffe2/core/operator.h" 13 #include "caffe2/utils/eigen_utils.h" 14 #include "caffe2/utils/math.h" 19 template <
class Context>
22 USE_OPERATOR_CONTEXT_FUNCTIONS;
24 template <
class... Args>
25 explicit TileOp(Args&&... args)
27 OP_SINGLE_ARG(std::int32_t,
"tiles", tiles_, 1),
28 OP_SINGLE_ARG(std::int32_t,
"axis", axis_, 0) {}
30 bool RunOnDevice()
override {
37 bool DoRunWithType() {
38 if (InputSize() > 1) {
46 "Input `tiles` should be a vector of size 1.");
47 tiles_ = GetArgFromTensor(
Input(1));
53 if (
Input(1).
template IsType<std::int64_t>()) {
57 if (InputSize() > 2) {
60 "Input `axis` should be a vector of size 1.");
61 axis_ = GetArgFromTensor(
Input(2));
65 "Argument `axis` is missing and was not specified as input.");
70 "Argument `tiles` is missing and was not specified as input.");
73 "Argument `axis` is missing and was not specified as input.");
76 const auto& X =
Input(0);
78 const int axis = X.canonical_axis_index(axis_);
81 std::vector<std::int64_t> Y_dims = X.sizes().vec();
82 Y_dims[axis] *= tiles_;
86 const int outer_size = X.size_to_dim(axis);
88 const int inner_size = X.size_from_dim(axis);
90 const T* X_data = X.template data<T>();
91 T* Y_data = Y->template mutable_data<T>();
92 return DoTile<T>(outer_size, inner_size, X_data, Y_data);
96 std::int32_t GetArgFromTensor(
const Tensor& tensor) {
98 tensor.IsType<std::int32_t>() || tensor.IsType<std::int64_t>());
99 std::int32_t val = -1;
100 if (tensor.IsType<std::int32_t>()) {
101 context_.template CopyToCPU<std::int32_t>(
102 1, tensor.data<std::int32_t>(), &val);
103 }
else if (tensor.IsType<std::int64_t>()) {
104 std::int64_t val_int64;
105 context_.template CopyToCPU<std::int64_t>(
106 1, tensor.data<std::int64_t>(), &val_int64);
107 val =
static_cast<std::int32_t
>(val_int64);
112 template <
typename T>
113 bool DoTile(
const int outer_size,
const int inner_size,
const T* X,
T* Y) {
114 if (inner_size == 1) {
115 EigenArrayMap<T> Y_arr(Y, tiles_, outer_size);
116 for (
int i = 0; i < outer_size; ++i) {
120 ConstEigenArrayMap<T> X_arr(X, inner_size, outer_size);
121 for (
int i = 0; i < outer_size; ++i) {
122 EigenArrayMap<T>(Y + i * tiles_ * inner_size, inner_size, tiles_)
123 .colwise() = X_arr.col(i);
133 template <
class Context>
136 USE_OPERATOR_CONTEXT_FUNCTIONS;
138 template <
class... Args>
141 OP_SINGLE_ARG(std::int32_t,
"tiles", tiles_, 1),
142 OP_SINGLE_ARG(std::int32_t,
"axis", axis_, 0) {}
144 bool RunOnDevice()
override {
147 call(
this,
Input(0));
150 template <
typename T>
152 if (InputSize() > 1) {
160 "Input `tiles` should be a vector of size 1.");
161 tiles_ = GetArgFromTensor(
Input(1));
162 if (InputSize() > 2) {
165 "Input `axis` should be a vector of size 1.");
166 axis_ = GetArgFromTensor(
Input(2));
170 "Argument `axis` is missing and was not specified as input.");
175 "Argument `tiles` is missing and was not specified as input.");
178 "Argument `axis` is missing and was not specified as input.");
181 const auto& dY =
Input(0);
182 auto* dX = Output(0);
183 const int axis = dY.canonical_axis_index(axis_);
186 std::vector<std::int64_t> X_dims = dY.sizes().vec();
187 CAFFE_ENFORCE_EQ(X_dims[axis] % tiles_, 0);
188 X_dims[axis] /= tiles_;
192 const int outer_size = dX->size_to_dim(axis);
194 const int inner_size = dX->size_from_dim(axis);
206 const T* dY_data = dY.template data<T>();
207 T* dX_data = dX->template mutable_data<T>();
208 return DoTileGradient<T>(outer_size, inner_size, dY_data, dX_data);
212 std::int32_t GetArgFromTensor(
const Tensor& tensor) {
214 tensor.IsType<std::int32_t>() || tensor.IsType<std::int64_t>());
215 std::int32_t val = -1;
216 if (tensor.IsType<std::int32_t>()) {
217 context_.template CopyToCPU<std::int32_t>(
218 1, tensor.data<std::int32_t>(), &val);
219 }
else if (tensor.IsType<std::int64_t>()) {
220 std::int64_t val_int64;
221 context_.template CopyToCPU<std::int64_t>(
222 1, tensor.data<std::int64_t>(), &val_int64);
223 val =
static_cast<std::int32_t
>(val_int64);
228 template <
typename T>
230 const int outer_size,
231 const int inner_size,
234 if (inner_size == 1) {
235 const std::array<int, 2> dY_dims = {outer_size, tiles_};
236 const std::array<int, 2> dX_dims = {outer_size, 1};
237 math::ReduceSum<T, Context>(
238 2, dY_dims.data(), dX_dims.data(),
T(1), dY, dX, &context_);
240 math::CopyMatrix<T, Context>(
248 for (
int i = 0; i < outer_size; ++i) {
249 const T* dY_ptr = dY + i * tiles_ * inner_size;
250 T* dX_ptr = dX + i * inner_size;
251 for (
int j = 1; j < tiles_; ++j) {
252 math::Add<T, Context>(
253 inner_size, dX_ptr, dY_ptr + j * inner_size, dX_ptr, &context_);
268 #endif // CAFFE2_OPERATORS_TILE_OP_H_
const Tensor & Input(int idx, DeviceType type=Context::GetDeviceType())
Retrieve a non-owning reference to the input at position 'idx' for this operator. ...
A global dictionary that holds information about what Caffe2 modules have been loaded in the current ...
bool HasArgument(const string &name) const
Checks if the operator has an argument of the given name.