diff --git a/paddle/fluid/operators/reverse_op.cc b/paddle/fluid/operators/reverse_op.cc index 58ca8da7ac0696546929465dd2a703c796db5a88..64c4c37bb06154b2f4ba6b3e5062ad514248ac46 100644 --- a/paddle/fluid/operators/reverse_op.cc +++ b/paddle/fluid/operators/reverse_op.cc @@ -77,23 +77,37 @@ class ReverseOpMaker : public framework::OpProtoAndCheckerMaker { } }; +class ReverseGradMaker : public framework::SingleGradOpDescMaker { + public: + using framework::SingleGradOpDescMaker::SingleGradOpDescMaker; + + std::unique_ptr Apply() const override { + auto* grad_op = new framework::OpDesc(); + grad_op->SetType("reverse"); + grad_op->SetInput("X", OutputGrad("Out")); + grad_op->SetOutput("Out", InputGrad("X")); + grad_op->SetAttr("axis", GetAttr("axis")); + return std::unique_ptr(grad_op); + } +}; + } // namespace operators } // namespace paddle namespace ops = paddle::operators; REGISTER_OPERATOR(reverse, ops::ReverseOp, ops::ReverseOpMaker, - paddle::framework::DefaultGradOpDescMaker); + ops::ReverseGradMaker); REGISTER_OPERATOR(reverse_grad, ops::ReverseOp); REGISTER_OP_CPU_KERNEL( reverse, ops::ReverseKernel, - ops::ReverseKernel, + ops::ReverseKernel, ops::ReverseKernel, ops::ReverseKernel, ops::ReverseKernel, ops::ReverseKernel) REGISTER_OP_CPU_KERNEL( reverse_grad, ops::ReverseKernel, - ops::ReverseKernel, + ops::ReverseKernel, ops::ReverseKernel, ops::ReverseKernel, ops::ReverseKernel, diff --git a/paddle/fluid/operators/reverse_op.cu b/paddle/fluid/operators/reverse_op.cu index 820be6b580803e5a974d68027de0b4072fdfac4b..7a750c75b5be9b0459bbe0ba74893d8524a58501 100644 --- a/paddle/fluid/operators/reverse_op.cu +++ b/paddle/fluid/operators/reverse_op.cu @@ -17,14 +17,14 @@ namespace ops = paddle::operators; REGISTER_OP_CUDA_KERNEL( reverse, ops::ReverseKernel, - ops::ReverseKernel, + ops::ReverseKernel, ops::ReverseKernel, ops::ReverseKernel, ops::ReverseKernel, ops::ReverseKernel) REGISTER_OP_CUDA_KERNEL( reverse_grad, ops::ReverseKernel, - ops::ReverseKernel, + ops::ReverseKernel, ops::ReverseKernel, ops::ReverseKernel, ops::ReverseKernel, diff --git a/python/paddle/fluid/layers/ops.py b/python/paddle/fluid/layers/ops.py index 69cfde852dd087bb9192da1f7582f925582dbce4..749c4d06468ea9af6ecf52dd6028c815321da858 100644 --- a/python/paddle/fluid/layers/ops.py +++ b/python/paddle/fluid/layers/ops.py @@ -60,6 +60,7 @@ __all__ = [ 'elementwise_pow', 'clip', 'clip_by_norm', + 'reverse', 'logical_and', 'logical_or', 'logical_xor', diff --git a/python/paddle/fluid/tests/unittests/test_reverse_op.py b/python/paddle/fluid/tests/unittests/test_reverse_op.py new file mode 100644 index 0000000000000000000000000000000000000000..f845575a02869f08299d76b5600074598ca27f6c --- /dev/null +++ b/python/paddle/fluid/tests/unittests/test_reverse_op.py @@ -0,0 +1,67 @@ +# Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved. +# +# 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. + +import unittest +import numpy as np +from op_test import OpTest + + +class TestReverseOp(OpTest): + def initTestCase(self): + self.x = np.random.random((3, 4)).astype('float32') + self.axis = [0] + + def setUp(self): + self.initTestCase() + self.op_type = "reverse" + self.inputs = {"X": self.x} + self.attrs = {'axis': self.axis} + out = self.x + for a in self.axis: + out = np.flip(out, axis=a) + self.outputs = {'Out': out} + + def test_check_output(self): + self.check_output() + + def test_check_grad(self): + self.check_grad(['X'], 'Out') + + +class TestCase0(TestReverseOp): + def initTestCase(self): + self.x = np.random.random((3, 4)).astype('float32') + self.axis = [1] + + +class TestCase1(TestReverseOp): + def initTestCase(self): + self.x = np.random.random((3, 4)).astype('float32') + self.axis = [0, 1] + + +class TestCase2(TestReverseOp): + def initTestCase(self): + self.x = np.random.random((3, 4, 5)).astype('float32') + self.axis = [0, 2] + + +class TestCase3(TestReverseOp): + def initTestCase(self): + self.x = np.random.random((3, 4, 5)).astype('float32') + self.axis = [1, 2] + + +if __name__ == '__main__': + unittest.main()