From 09c0c82ec9e5c2bff8da4a8598e80ea962fce390 Mon Sep 17 00:00:00 2001 From: Abhinav Arora Date: Thu, 19 Oct 2017 22:51:13 -0700 Subject: [PATCH] Adding increment op (#4940) * Adding incremnt op * Fixing comment about step attribute --- paddle/operators/increment_op.cc | 75 +++++++++++++++++++ paddle/operators/increment_op.cu | 19 +++++ paddle/operators/increment_op.h | 40 ++++++++++ .../v2/framework/tests/test_increment_op.py | 41 ++++++++++ 4 files changed, 175 insertions(+) create mode 100644 paddle/operators/increment_op.cc create mode 100644 paddle/operators/increment_op.cu create mode 100644 paddle/operators/increment_op.h create mode 100644 python/paddle/v2/framework/tests/test_increment_op.py diff --git a/paddle/operators/increment_op.cc b/paddle/operators/increment_op.cc new file mode 100644 index 0000000000..139392c691 --- /dev/null +++ b/paddle/operators/increment_op.cc @@ -0,0 +1,75 @@ +/* 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/increment_op.h" + +namespace paddle { +namespace operators { + +class IncrementOp : public framework::OperatorWithKernel { + public: + using framework::OperatorWithKernel::OperatorWithKernel; + + void InferShape(framework::InferShapeContext *ctx) const override { + PADDLE_ENFORCE(ctx->HasInput("X"), + "Input(X) of IncrementOp should not be null."); + PADDLE_ENFORCE(ctx->HasOutput("Out"), + "Output(Out) of IncrementOp should not be null."); + ctx->SetOutputDim("Out", ctx->GetInputDim("X")); + ctx->ShareLoD("X", /*->*/ "Out"); + } +}; + +template +class IncrementOpMaker : public framework::OpProtoAndCheckerMaker { + public: + IncrementOpMaker(framework::OpProto *proto, + framework::OpAttrChecker *op_checker) + : OpProtoAndCheckerMaker(proto, op_checker) { + AddInput("X", "(Tensor) The input tensor of increment operator"); + AddOutput("Out", "(Tensor) The output tensor of increment operator."); + AddComment(R"DOC(Increment operator + +The equation is: Out = X + step +)DOC"); + AddAttr("step", + "The step size by which the " + "input tensor will be incremented.") + .SetDefault(1.0); + } +}; + +class IncrementGradOpMaker : 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", 1.0f); + return std::unique_ptr(grad_op); + } +}; + +} // namespace operators +} // namespace paddle + +namespace ops = paddle::operators; + +REGISTER_OPERATOR(increment, ops::IncrementOp, ops::IncrementOpMaker, + ops::IncrementGradOpMaker); +REGISTER_OP_CPU_KERNEL(increment, + ops::IncrementKernel); diff --git a/paddle/operators/increment_op.cu b/paddle/operators/increment_op.cu new file mode 100644 index 0000000000..659c380d14 --- /dev/null +++ b/paddle/operators/increment_op.cu @@ -0,0 +1,19 @@ +/* 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/increment_op.h" + +REGISTER_OP_GPU_KERNEL( + increment, + paddle::operators::IncrementKernel); diff --git a/paddle/operators/increment_op.h b/paddle/operators/increment_op.h new file mode 100644 index 0000000000..342e254fc4 --- /dev/null +++ b/paddle/operators/increment_op.h @@ -0,0 +1,40 @@ +/* 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 IncrementKernel : public framework::OpKernel { + public: + virtual void Compute(const framework::ExecutionContext& context) const { + auto* tensor = context.Output("Out"); + auto* in = context.Input("X"); + tensor->mutable_data(in->place()); + + auto step = static_cast(context.Attr("step")); + + auto eigen_out = framework::EigenVector::Flatten(*tensor); + auto eigen_in = framework::EigenVector::Flatten(*in); + auto& place = context.GetEigenDevice(); + eigen_out.device(place) = eigen_in + step; + } +}; + +} // namespace operators +} // namespace paddle diff --git a/python/paddle/v2/framework/tests/test_increment_op.py b/python/paddle/v2/framework/tests/test_increment_op.py new file mode 100644 index 0000000000..e174272b05 --- /dev/null +++ b/python/paddle/v2/framework/tests/test_increment_op.py @@ -0,0 +1,41 @@ +import unittest +import numpy as np +from op_test import OpTest + + +class TestIncrementOpPositiveStep(OpTest): + """Test increment op with positive step + """ + + def setUp(self): + self.op_type = "increment" + self.inputs = {'X': np.random.random((10, 10)).astype("float32")} + self.attrs = {'step': 14.8} + self.outputs = {'Out': self.inputs['X'] + self.attrs['step']} + + def test_check_output(self): + self.check_output() + + def test_check_grad(self): + self.check_grad(['X'], 'Out') + + +class TestIncrementOpNegativeStep(OpTest): + """Test increment op with negative step + """ + + def setUp(self): + self.op_type = "increment" + self.inputs = {'X': np.random.random((10, 10)).astype("float32")} + self.attrs = {'step': -3.8} + self.outputs = {'Out': self.inputs['X'] + self.attrs['step']} + + def test_check_output(self): + self.check_output() + + def test_check_grad(self): + self.check_grad(['X'], 'Out') + + +if __name__ == "__main__": + unittest.main() -- GitLab