diff --git a/paddle/operators/activation_op.cc b/paddle/operators/activation_op.cc index f77e1c572e33533ac672e3d476a7e6dad122031f..1e1d3cf7f7634e2e5a433025f175202bd6c4b40e 100644 --- a/paddle/operators/activation_op.cc +++ b/paddle/operators/activation_op.cc @@ -132,6 +132,17 @@ class SquareOpMaker : public framework::OpProtoAndCheckerMaker { } }; +class SoftsignOpMaker : public framework::OpProtoAndCheckerMaker { + public: + SoftsignOpMaker(framework::OpProto *proto, + framework::OpAttrChecker *op_checker) + : OpProtoAndCheckerMaker(proto, op_checker) { + AddInput("X", "Input of Softsign operator"); + AddOutput("Y", "Output of Softsign operator"); + AddComment("Softsign activation operator, softsign(x) = x / (1 + |x|)"); + } +}; + template class BReluOpMaker : public framework::OpProtoAndCheckerMaker { public: @@ -277,6 +288,15 @@ REGISTER_OP_CPU_KERNEL( square_grad, ops::ActivationGradKernel>); +REGISTER_OP(softsign, ops::ActivationOp, ops::SoftsignOpMaker, softsign_grad, + ops::ActivationOpGrad); +REGISTER_OP_CPU_KERNEL(softsign, + ops::ActivationKernel>); +REGISTER_OP_CPU_KERNEL( + softsign_grad, ops::ActivationGradKernel>); + REGISTER_OP(brelu, ops::ActivationOp, ops::BReluOpMaker, brelu_grad, ops::ActivationOpGrad); REGISTER_OP_CPU_KERNEL(brelu, diff --git a/paddle/operators/activation_op.cu b/paddle/operators/activation_op.cu index feed1302b292a546f88fa35457c86aa2cfdaa307..56886d8b1b93a19e9a01798ef79e89f9b5d6fca1 100644 --- a/paddle/operators/activation_op.cu +++ b/paddle/operators/activation_op.cu @@ -80,6 +80,13 @@ REGISTER_OP_GPU_KERNEL( square_grad, ops::ActivationGradKernel>); +REGISTER_OP_GPU_KERNEL(softsign, + ops::ActivationKernel>); +REGISTER_OP_GPU_KERNEL( + softsign_grad, ops::ActivationGradKernel>); + REGISTER_OP_GPU_KERNEL(brelu, ops::BReluKernel); REGISTER_OP_GPU_KERNEL(brelu_grad, diff --git a/paddle/operators/activation_op.h b/paddle/operators/activation_op.h index e400992ae29686d81a5ea32f9c50e05424246707..b9f52e1af3958b247e4854389cb467e2fce25e27 100644 --- a/paddle/operators/activation_op.h +++ b/paddle/operators/activation_op.h @@ -201,6 +201,26 @@ struct SquareGradFunctor { } }; +// 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: diff --git a/python/paddle/v2/framework/tests/test_activation_op.py b/python/paddle/v2/framework/tests/test_activation_op.py index 8f6d2be17758b7f6604d2db74fe466fb30695bd5..c44eb849063592fbda417ec1516d195dd4358612 100644 --- a/python/paddle/v2/framework/tests/test_activation_op.py +++ b/python/paddle/v2/framework/tests/test_activation_op.py @@ -219,5 +219,22 @@ class TestSTanh(OpTest): self.check_grad(['X'], 'Y', max_relative_error=0.007) +class TestSoftsign(OpTest): + def setUp(self): + self.op_type = "softsign" + self.inputs = { + 'X': np.random.uniform(-1, 1, [11, 17]).astype("float32") + } + self.outputs = { + 'Y': np.divide(self.inputs['X'], 1 + np.abs(self.inputs['X'])) + } + + def test_check_output(self): + self.check_output() + + def test_check_grad(self): + self.check_grad(['X'], 'Y', max_relative_error=0.007) + + if __name__ == "__main__": unittest.main()