#include "caffe2/operators/erf_op.h" #include "caffe2/utils/eigen_utils.h" #include #include namespace caffe2 { template <> template bool ErfGradientFunctor::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) = T(2) / sqrtf(PI) * (-X_arr.square()).exp() * dY_arr; return true; } REGISTER_CPU_OPERATOR( Erf, UnaryElementwiseOp< TensorTypes, CPUContext, ErfFunctor>); REGISTER_CPU_OPERATOR( ErfGradient, BinaryElementwiseOp< TensorTypes, CPUContext, ErfGradientFunctor>); OPERATOR_SCHEMA(Erf) .NumInputs(1) .NumOutputs(1) .IdenticalTypeAndShape() .SetDoc(R"DOC( Calculates the arcsine of the given input tensor, element-wise. )DOC") .Input(0, "input", "Input tensor") .Output( 0, "output", "The arcsine of the input tensor computed element-wise"); OPERATOR_SCHEMA(ErfGradient) .NumInputs(2) .NumOutputs(1) .IdenticalTypeAndShape(); namespace { class GetErfGradient : public GradientMakerBase { using GradientMakerBase::GradientMakerBase; std::vector GetGradientDefs() override { return SingleGradientDef( "ErfGradient", "", std::vector{I(0), GO(0)}, std::vector{GI(0)}); } }; } // namespace REGISTER_GRADIENT(Erf, GetErfGradient); } // namespace caffe2