|  | #include "caffe2/operators/tanh_op.h" | 
|  |  | 
|  | #include "caffe2/utils/eigen_utils.h" | 
|  |  | 
|  | #include <algorithm> | 
|  | #include <functional> | 
|  | #include <string> | 
|  | #include <vector> | 
|  |  | 
|  | namespace caffe2 { | 
|  |  | 
|  | template <> | 
|  | template <> | 
|  | bool TanhGradientFunctor<CPUContext>::Forward<float>( | 
|  | const std::vector<int>& Y_dims, | 
|  | const std::vector<int>& /* dY_dims */, | 
|  | const float* Y, | 
|  | const float* dY, | 
|  | float* dX, | 
|  | CPUContext* /* context */) const { | 
|  | const int size = std::accumulate( | 
|  | Y_dims.cbegin(), Y_dims.cend(), 1, std::multiplies<int>()); | 
|  | ConstEigenVectorArrayMap<float> dY_arr(dY, size); | 
|  | ConstEigenVectorArrayMap<float> Y_arr(Y, size); | 
|  | EigenVectorMap<float>(dX, size) = dY_arr * (1 - Y_arr * Y_arr); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | REGISTER_CPU_OPERATOR( | 
|  | TanhGradient, | 
|  | BinaryElementwiseOp< | 
|  | TensorTypes<float>, | 
|  | CPUContext, | 
|  | TanhGradientFunctor<CPUContext>>); | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | class GetTanhGradient : public GradientMakerBase { | 
|  | using GradientMakerBase::GradientMakerBase; | 
|  | std::vector<OperatorDef> GetGradientDefs() override { | 
|  | return SingleGradientDef( | 
|  | "TanhGradient", | 
|  | "", | 
|  | std::vector<std::string>{O(0), GO(0)}, | 
|  | std::vector<std::string>{GI(0)}); | 
|  | } | 
|  | }; | 
|  |  | 
|  | } // namespace | 
|  |  | 
|  | REGISTER_GRADIENT(Tanh, GetTanhGradient); | 
|  |  | 
|  | } // namespace caffe2 |