|  | #ifndef CAFFE2_OPERATORS_POW_OP_H_ | 
|  | #define CAFFE2_OPERATORS_POW_OP_H_ | 
|  |  | 
|  | #include "caffe2/core/common_omp.h" | 
|  | #include "caffe2/core/context.h" | 
|  | #include "caffe2/core/logging.h" | 
|  | #include "caffe2/core/operator.h" | 
|  | #include "caffe2/operators/elementwise_ops.h" | 
|  | #include "caffe2/operators/elementwise_ops_utils.h" | 
|  | #include "caffe2/utils/math.h" | 
|  |  | 
|  | namespace caffe2 { | 
|  |  | 
|  | template < | 
|  | typename InputTypes, | 
|  | class Context, | 
|  | class Functor, | 
|  | class TypeMap = SameTypeAsInput> | 
|  | class PowOp : public Operator<Context> { | 
|  | public: | 
|  | USE_OPERATOR_CONTEXT_FUNCTIONS; | 
|  |  | 
|  | template <class... Args> | 
|  | explicit PowOp(Args&&... args) | 
|  | : Operator<Context>(std::forward<Args>(args)...), | 
|  | OP_SINGLE_ARG(bool, "broadcast", enable_broadcast_, 0), | 
|  | OP_SINGLE_ARG(int, "axis", axis_, -1), | 
|  | OP_SINGLE_ARG(string, "axis_str", axis_str_, ""), | 
|  | OP_SINGLE_ARG(string, "order", order_, "NCHW"), | 
|  | functor_() { | 
|  | if ((InputSize() == 1) && HasArgument("exponent")) { // UnaryElementwiseOp | 
|  | exponent_ = this->template GetSingleArgument<float>( | 
|  | "exponent", 0); // based on pow_ops.h | 
|  | } else if (InputSize() == 2) { // BinaryElementwiseOp | 
|  | // Figure out the correct axis to use. | 
|  | if (enable_broadcast_) { | 
|  | if (axis_ != -1) { | 
|  | // Get axis from an explicit axis argument. | 
|  | CAFFE_ENFORCE_EQ( | 
|  | axis_str_.size(), | 
|  | 0, | 
|  | "Args axis and axis_str cannot be used simultaneously."); | 
|  | } else if (axis_str_.size()) { | 
|  | // Get the axis index semantically. | 
|  | CAFFE_ENFORCE_EQ( | 
|  | axis_str_.size(), 1, "Unsupported axis string", axis_str_); | 
|  | size_t semantic_axis_ = order_.find(axis_str_); | 
|  | CAFFE_ENFORCE_NE( | 
|  | semantic_axis_, | 
|  | string::npos, | 
|  | "Unrecognizable axis string ", | 
|  | axis_str_, | 
|  | " from order string ", | 
|  | order_); | 
|  | axis_ = semantic_axis_; | 
|  | } | 
|  | } else { | 
|  | CAFFE_ENFORCE( | 
|  | axis_ == -1 && axis_str_.size() == 0, | 
|  | "Do not specify axis or axis_str if broadcast is not enabled."); | 
|  | } | 
|  | } else { | 
|  | CAFFE_THROW( | 
|  | "Only a tensor with an argument or two input tensors are supported as input to pow operator."); | 
|  | } | 
|  | } | 
|  |  | 
|  | bool RunOnDevice() override { | 
|  | return DispatchHelper<InputTypes>::call(this, Input(0)); | 
|  | } | 
|  |  | 
|  | template <typename T> | 
|  | bool DoRunWithType() { | 
|  | if ((InputSize() == 1) && HasArgument("exponent")) { // UnaryElementwiseOp | 
|  | const auto& A = Input(0); | 
|  |  | 
|  | auto* C = | 
|  | Output(0, A.sizes(), at::dtype<typename TypeMap::template type<T>>()); | 
|  | const T* Adata = A.template data<T>(); | 
|  | auto* Cdata = | 
|  | C->template mutable_data<typename TypeMap::template type<T>>(); | 
|  | functor_.template Run<true, T, float, T>( | 
|  | A.numel(), Adata, NULL, exponent_, Cdata, &context_); | 
|  | } else if (InputSize() == 2) { // BinaryElementwiseOp | 
|  | const auto& A = Input(0); | 
|  | const auto& B = Input(1); | 
|  | CAFFE_ENFORCE( | 
|  | !IsInputOutputAlias(1, 0) || !enable_broadcast_, | 
|  | "In-place is allowed only with the first tensor when broadcasting"); | 
|  | auto* C = | 
|  | Output(0, A.sizes(), at::dtype<typename TypeMap::template type<T>>()); | 
|  | const T* Adata = A.template data<T>(); | 
|  | const T* Bdata = B.template data<T>(); | 
|  | auto* Cdata = | 
|  | C->template mutable_data<typename TypeMap::template type<T>>(); | 
|  | if (!enable_broadcast_) { | 
|  | CAFFE_ENFORCE_EQ( | 
|  | A.sizes(), | 
|  | B.sizes(), | 
|  | "Dimension mismatch - did you forget to set broadcast=1?"); | 
|  | functor_.template Run<false, T, T, T>( | 
|  | A.numel(), Adata, Bdata, 0, Cdata, &context_); | 
|  | } else if (B.numel() == 1) { | 
|  | functor_.template Run<true, T, T, T>( | 
|  | A.numel(), Adata, Bdata, 0, Cdata, &context_); | 
|  | } else { | 
|  | size_t pre, n, post; | 
|  | std::tie(pre, n, post) = | 
|  | elementwise_ops_utils::ComputeLegacyBroadcastSizes(A, B, axis_); | 
|  | if (post == 1) { | 
|  | functor_.template RunWithBroadcast<T, T, T>( | 
|  | Adata, Bdata, Cdata, pre, n, &context_); | 
|  | } else { | 
|  | functor_.template RunWithBroadcast2<T, T, T>( | 
|  | Adata, Bdata, Cdata, pre, n, post, &context_); | 
|  | } | 
|  | } | 
|  | } else { | 
|  | CAFFE_THROW( | 
|  | "Only a tensor with an argument or two input tensors are supported as input to pow operator."); | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | private: | 
|  | bool enable_broadcast_; | 
|  | int axis_; | 
|  | string axis_str_; | 
|  | string order_; | 
|  | float exponent_; | 
|  | Functor functor_; | 
|  | }; | 
|  |  | 
|  | } // namespace caffe2 | 
|  |  | 
|  | #endif // CAFFE2_OPERATORS_POW_OP_H_ |