/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #pragma once #include "paddle/framework/eigen.h" #include "paddle/framework/op_registry.h" namespace paddle { namespace operators { template class ActivationKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& context) const override { auto* X = context.Input("X"); auto* Y = context.Output("Y"); Y->mutable_data(context.GetPlace()); auto x = framework::EigenVector::Flatten(*X); auto y = framework::EigenVector::Flatten(*Y); auto place = context.GetEigenDevice(); Functor functor; functor(place, x, y); } }; template class ActivationGradKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& context) const override { auto* X = context.Input("X"); auto* Y = context.Input("Y"); auto* dY = context.Input(framework::GradVarName("Y")); auto* dX = context.Output(framework::GradVarName("X")); dX->mutable_data(context.GetPlace()); auto dy = framework::EigenVector::Flatten(*dY); auto x = framework::EigenVector::Flatten(*X); auto y = framework::EigenVector::Flatten(*Y); auto dx = framework::EigenVector::Flatten(*dX); auto place = context.GetEigenDevice(); Functor functor; functor(place, x, y, dy, dx); } }; // sigmoid(x) = 1 / (1 + exp(-x)) template struct SigmoidFunctor { template void operator()(Device d, X x, Y y) { y.device(d) = static_cast(1) / (static_cast(1) + (-x).exp()); } }; template struct SigmoidGradFunctor { template void operator()(Device d, X x, Y y, dY dy, dX dx) { dx.device(d) = dy * y * (static_cast(1) - y); } }; // exp(x) = e^x struct ExpFunctor { template void operator()(Device d, X x, Y y) { y.device(d) = x.exp(); } }; struct ExpGradFunctor { template void operator()(Device d, X x, Y y, dY dy, dX dx) { dx.device(d) = dy * y; } }; // relu(x) = max(x, 0) template struct ReluFunctor { template void operator()(Device d, X x, Y y) { y.device(d) = x.cwiseMax(static_cast(0)); } }; template struct ReluGradFunctor { template void operator()(Device d, X x, Y y, dY dy, dX dx) { dx.device(d) = dy * (x > static_cast(0)).template cast(); } }; // tanh(x) = (exp(x) - exp(-x)) / (exp(x) + exp(-x)) struct TanhFunctor { template void operator()(Device d, X x, Y y) { y.device(d) = x.tanh(); } }; template struct TanhGradFunctor { template void operator()(Device d, X x, Y y, dY dy, dX dx) { dx.device(d) = dy * (static_cast(1) - y * y); } }; // sqrt(x) = x^(1/2) struct SqrtFunctor { template void operator()(Device d, X x, Y y) { y.device(d) = x.sqrt(); } }; template struct SqrtGradFunctor { template void operator()(Device d, X x, Y y, dY dy, dX dx) { const Y y_conj = Eigen::numext::conj(y); dx.device(d) = static_cast(0.5) * dy / y_conj; } }; // abs(x) = |x| struct AbsFunctor { template void operator()(Device d, X x, Y y) { y.device(d) = x.abs(); } }; struct AbsGradFunctor { template void operator()(Device d, X x, Y y, dY dy, dX dx) { dx.device(d) = dy * x.sign(); } }; // reciprocal(x) = 1 / x template struct ReciprocalFunctor { template void operator()(Device d, X x, Y y) { y.device(d) = static_cast(1) / x; } }; template struct ReciprocalGradFunctor { template void operator()(Device d, X x, Y y, dY dy, dX dx) { dx.device(d) = dy * static_cast(-1) * y * y; } }; // log(x) = natural logarithm of x struct LogFunctor { template void operator()(Device d, X x, Y y) { y.device(d) = x.log(); } }; template struct LogGradFunctor { template void operator()(Device d, X x, Y y, dY dy, dX dx) { dx.device(d) = dy * (static_cast(1) / x); } }; // square(x) = x^2 struct SquareFunctor { template void operator()(Device d, X x, Y y) { y.device(d) = x.square(); } }; template struct SquareGradFunctor { template void operator()(Device d, X x, Y y, dY dy, dX dx) { dx.device(d) = dy * static_cast(2) * x; } }; // softsign(x) = x / (1 + |x|) template struct SoftsignFunctor { template void operator()(Device d, X x, Y y) { y.device(d) = x / (static_cast(1) + x.abs()); } }; // d(softsign(x))/dx = 1 / (1 + |x|)^2 // Taken from https://en.wikipedia.org/wiki/Activation_function template struct SoftsignGradFunctor { template void operator()(Device d, X x, Y y, dY dy, dX dx) { dx.device(d) = dy * (static_cast(1) / (static_cast(1) + x.abs()).square()); } }; template class BReluKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& context) const override { auto* X = context.Input("X"); auto* Y = context.Output("Y"); auto t_min = static_cast(context.Attr("t_min")); auto t_max = static_cast(context.Attr("t_max")); Y->mutable_data(context.GetPlace()); auto x = framework::EigenVector::Flatten(*X); auto y = framework::EigenVector::Flatten(*Y); auto place = context.GetEigenDevice(); y.device(place) = x.cwiseMax(t_min).cwiseMin(t_max); } }; template class BReluGradKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& context) const override { auto* X = context.Input("X"); auto* dY = context.Input(framework::GradVarName("Y")); auto* dX = context.Output(framework::GradVarName("X")); auto t_min = static_cast(context.Attr("t_min")); auto t_max = static_cast(context.Attr("t_max")); dX->mutable_data(context.GetPlace()); auto dy = framework::EigenVector::Flatten(*dY); auto x = framework::EigenVector::Flatten(*X); auto dx = framework::EigenVector::Flatten(*dX); auto place = context.GetEigenDevice(); dx.device(place) = dy * ((x > t_min) * (x < t_max)).template cast(); } }; template class SoftReluKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& context) const override { auto* X = context.Input("X"); auto* Y = context.Output("Y"); auto threshold = static_cast(context.Attr("threshold")); Y->mutable_data(context.GetPlace()); auto x = framework::EigenVector::Flatten(*X); auto y = framework::EigenVector::Flatten(*Y); auto place = context.GetEigenDevice(); auto temp = x.cwiseMax(-threshold).cwiseMin(threshold).eval(); y.device(place) = (static_cast(1) + temp.exp()).log(); } }; template class SoftReluGradKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& context) const override { auto* X = context.Input("X"); auto* Y = context.Input("Y"); auto* dY = context.Input(framework::GradVarName("Y")); auto* dX = context.Output(framework::GradVarName("X")); auto threshold = static_cast(context.Attr("threshold")); dX->mutable_data(context.GetPlace()); auto x = framework::EigenVector::Flatten(*X); auto y = framework::EigenVector::Flatten(*Y); auto dy = framework::EigenVector::Flatten(*dY); auto dx = framework::EigenVector::Flatten(*dX); auto place = context.GetEigenDevice(); auto temp = ((x > -threshold) * (x < threshold)).template cast().eval(); dx.device(place) = dy * (static_cast(1) - (-y).exp()) * temp; } }; template class PowKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& context) const override { auto* X = context.Input("X"); auto* Y = context.Output("Y"); auto factor = static_cast(context.Attr("factor")); Y->mutable_data(context.GetPlace()); auto x = framework::EigenVector::Flatten(*X); auto y = framework::EigenVector::Flatten(*Y); auto place = context.GetEigenDevice(); y.device(place) = x.pow(factor); } }; template class PowGradKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& context) const override { auto* X = context.Input("X"); auto* dY = context.Input(framework::GradVarName("Y")); auto* dX = context.Output(framework::GradVarName("X")); auto factor = static_cast(context.Attr("factor")); dX->mutable_data(context.GetPlace()); auto dy = framework::EigenVector::Flatten(*dY); auto x = framework::EigenVector::Flatten(*X); auto dx = framework::EigenVector::Flatten(*dX); auto place = context.GetEigenDevice(); dx.device(place) = dy * factor * x.pow(factor - static_cast(1)); } }; template class STanhKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& context) const override { auto* X = context.Input("X"); auto* Y = context.Output("Y"); auto scale_a = static_cast(context.Attr("scale_a")); auto scale_b = static_cast(context.Attr("scale_b")); Y->mutable_data(context.GetPlace()); auto x = framework::EigenVector::Flatten(*X); auto y = framework::EigenVector::Flatten(*Y); auto place = context.GetEigenDevice(); y.device(place) = scale_b * (scale_a * x).tanh(); } }; template class STanhGradKernel : public framework::OpKernel { public: void Compute(const framework::ExecutionContext& context) const override { auto* X = context.Input("X"); auto* dY = context.Input(framework::GradVarName("Y")); auto* dX = context.Output(framework::GradVarName("X")); auto scale_a = static_cast(context.Attr("scale_a")); auto scale_b = static_cast(context.Attr("scale_b")); dX->mutable_data(context.GetPlace()); auto dy = framework::EigenVector::Flatten(*dY); auto x = framework::EigenVector::Flatten(*X); auto dx = framework::EigenVector::Flatten(*dX); auto place = context.GetEigenDevice(); auto temp = (scale_a * x).tanh() * (scale_a * x).tanh(); dx.device(place) = dy * scale_a * scale_b * (static_cast(1) - temp); } }; } // namespace operators } // namespace paddle