#include "caffe2/operators/abs_op.h" #include "caffe2/utils/eigen_utils.h" #include #include namespace caffe2 { template <> template bool AbsGradientFunctor::Forward( const std::vector& X_dims, const std::vector& /* dY_dims */, const T* X, const T* dY, T* dX, CPUContext* /* context */) const { const int size = std::accumulate( X_dims.cbegin(), X_dims.cend(), 1, std::multiplies()); ConstEigenVectorArrayMap dY_arr(dY, size); ConstEigenVectorArrayMap X_arr(X, size); EigenVectorMap(dX, size) = (X_arr == T(0)).select(T(0), (X_arr > T(0)).select(dY_arr, -dY_arr)); return true; } REGISTER_CPU_OPERATOR( Abs, UnaryElementwiseOp, CPUContext, AbsFunctor>); REGISTER_CPU_OPERATOR( AbsGradient, BinaryElementwiseOp< TensorTypes, CPUContext, AbsGradientFunctor>); OPERATOR_SCHEMA(Abs) .NumInputs(1) .NumOutputs(1) .IdenticalTypeAndShape() .SetDoc(R"DOC( Calculates the absolute value of the given input tensor, element-wise. Github Links: - https://github.com/pytorch/pytorch/blob/master/caffe2/operators/abs_op.cc
Example **Code** ``` workspace.ResetWorkspace() op = core.CreateOperator( "Abs", ["X"], ["Y"] ) workspace.FeedBlob("X", np.random.randn(5).astype(np.float32)) print("X:", workspace.FetchBlob("X")) workspace.RunOperatorOnce(op) print("Y:", workspace.FetchBlob("Y")) ``` **Result** ``` X: [ 0.3005476 1.551666 -1.3591481 0.39191285 -0.21866608] Y: [0.3005476 1.551666 1.3591481 0.39191285 0.21866608] ```
)DOC") .Input(0, "X", "*(type: Tensor)* Input tensor.") .Output( 0, "Y", "*(type: Tensor``)* Absolute value of input element-wise.") .InheritOnnxSchema(); OPERATOR_SCHEMA(AbsGradient).NumInputs(2).NumOutputs(1).IdenticalTypeAndShape(); namespace { class GetAbsGradient : public GradientMakerBase { using GradientMakerBase::GradientMakerBase; std::vector GetGradientDefs() override { return SingleGradientDef( "AbsGradient", "", std::vector{I(0), GO(0)}, std::vector{GI(0)}); } }; } // namespace REGISTER_GRADIENT(Abs, GetAbsGradient); } // namespace caffe2