From 1a26f5a548d9631a8e3e6ba2880087637307a616 Mon Sep 17 00:00:00 2001 From: Abhinav Arora Date: Fri, 27 Oct 2017 10:51:54 -0700 Subject: [PATCH] Adding the Sign Op for L1 Weight Decay Regularization (#5138) --- paddle/operators/sign_op.cc | 70 +++++++++++++++++++ paddle/operators/sign_op.cu | 18 +++++ paddle/operators/sign_op.h | 38 ++++++++++ .../paddle/v2/framework/tests/test_sign_op.py | 22 ++++++ 4 files changed, 148 insertions(+) create mode 100644 paddle/operators/sign_op.cc create mode 100644 paddle/operators/sign_op.cu create mode 100644 paddle/operators/sign_op.h create mode 100644 python/paddle/v2/framework/tests/test_sign_op.py diff --git a/paddle/operators/sign_op.cc b/paddle/operators/sign_op.cc new file mode 100644 index 00000000000..1b2f879d6d3 --- /dev/null +++ b/paddle/operators/sign_op.cc @@ -0,0 +1,70 @@ +/* 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. */ + +#include "paddle/operators/sign_op.h" + +namespace paddle { +namespace operators { + +class SignOp : public framework::OperatorWithKernel { + public: + using framework::OperatorWithKernel::OperatorWithKernel; + + void InferShape(framework::InferShapeContext *ctx) const override { + PADDLE_ENFORCE(ctx->HasInput("X"), + "Input(X) of SignOp should not be null."); + PADDLE_ENFORCE(ctx->HasOutput("Out"), + "Output(Out) of SignOp should not be null."); + ctx->SetOutputDim("Out", ctx->GetInputDim("X")); + ctx->ShareLoD("X", /*->*/ "Out"); + } +}; + +template +class SignOpMaker : public framework::OpProtoAndCheckerMaker { + public: + SignOpMaker(framework::OpProto *proto, framework::OpAttrChecker *op_checker) + : OpProtoAndCheckerMaker(proto, op_checker) { + AddInput("X", "(Tensor) Input tensor of sign operator."); + AddOutput("Out", "(Tensor) Output tensor of sign operator."); + AddComment(R"DOC(Sign operator + +The equation is: Out = X.sign() +)DOC"); + } +}; + +class SignGradMaker : public framework::SingleGradOpDescMaker { + public: + using framework::SingleGradOpDescMaker::SingleGradOpDescMaker; + + std::unique_ptr Apply() const override { + auto *grad_op = new framework::OpDescBind(); + grad_op->SetType("scale"); + grad_op->SetInput("X", OutputGrad("Out")); + grad_op->SetOutput("Out", InputGrad("X")); + grad_op->SetAttr("scale", 0.0f); + return std::unique_ptr(grad_op); + } +}; + +} // namespace operators +} // namespace paddle + +namespace ops = paddle::operators; + +REGISTER_OPERATOR(sign, ops::SignOp, ops::SignOpMaker, + ops::SignGradMaker); +REGISTER_OP_CPU_KERNEL(sign, + ops::SignKernel); diff --git a/paddle/operators/sign_op.cu b/paddle/operators/sign_op.cu new file mode 100644 index 00000000000..4d0638cb97d --- /dev/null +++ b/paddle/operators/sign_op.cu @@ -0,0 +1,18 @@ +/* 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. */ + +#include "paddle/operators/sign_op.h" + +REGISTER_OP_GPU_KERNEL( + sign, paddle::operators::SignKernel); diff --git a/paddle/operators/sign_op.h b/paddle/operators/sign_op.h new file mode 100644 index 00000000000..ab5cd4bac01 --- /dev/null +++ b/paddle/operators/sign_op.h @@ -0,0 +1,38 @@ +/* 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 SignKernel : public framework::OpKernel { + public: + virtual void Compute(const framework::ExecutionContext& context) const { + auto* out = context.Output("Out"); + auto* in = context.Input("X"); + out->mutable_data(in->place()); + + auto eigen_out = framework::EigenVector::Flatten(*out); + auto eigen_in = framework::EigenVector::Flatten(*in); + auto& place = context.GetEigenDevice(); + eigen_out.device(place) = eigen_in.sign(); + } +}; + +} // namespace operators +} // namespace paddle diff --git a/python/paddle/v2/framework/tests/test_sign_op.py b/python/paddle/v2/framework/tests/test_sign_op.py new file mode 100644 index 00000000000..c6b59bcfd8b --- /dev/null +++ b/python/paddle/v2/framework/tests/test_sign_op.py @@ -0,0 +1,22 @@ +import unittest +import numpy as np +from op_test import OpTest + + +class TestSignOp(OpTest): + def setUp(self): + self.op_type = "sign" + self.inputs = { + 'X': np.random.uniform(-10, 10, (10, 10)).astype("float32") + } + self.outputs = {'Out': np.sign(self.inputs['X'])} + + def test_check_output(self): + self.check_output() + + def test_check_grad(self): + self.check_grad(['X'], 'Out') + + +if __name__ == "__main__": + unittest.main() -- GitLab