diff --git a/paddle/operators/recurrent_op.cc b/paddle/operators/recurrent_op.cc index ad985839f5908d9235a4dbefc9b841362810114e..494bf2707e402153cde4de67def6000a20f4e254 100644 --- a/paddle/operators/recurrent_op.cc +++ b/paddle/operators/recurrent_op.cc @@ -80,7 +80,6 @@ void RecurrentAlgorithm::CreateScopes(const Scope& scope) const { // Now all variables in scope must be created outside of op. PADDLE_ENFORCE_NOT_NULL(stepnet_); PADDLE_ENFORCE(!(*stepnet_)->Outputs().empty(), "stepnet_ op has no outputs"); - PADDLE_ENFORCE(!(*stepnet_)->Outputs().empty(), "net_op has no outputs"); if (seq_len_ > step_scopes->size()) { for (size_t i = step_scopes->size(); i < seq_len_; ++i) { diff --git a/paddle/pybind/pybind.cc b/paddle/pybind/pybind.cc index c7009a604f60cda11434ad33b6c7d7caee1befdd..7f4bad4df05d4edd72093443bdfb358a1efd9755 100644 --- a/paddle/pybind/pybind.cc +++ b/paddle/pybind/pybind.cc @@ -311,6 +311,15 @@ All parameter, weight, gradient are variables in Paddle. self.set_falsenet(net.Clone()); }); + rnn.def("backward", + [](const operators::RecurrentOp &forwardOp, + const std::unordered_set &no_grad_vars) { + const auto &op = *static_cast(&forwardOp); + return Backward(op, no_grad_vars); + }); + + ExposeOperator(rnn); + m.def("unique_integer", UniqueIntegerGenerator); m.def("is_compile_gpu", IsCompileGPU); diff --git a/python/paddle/v2/framework/tests/test_recurrent_op.py b/python/paddle/v2/framework/tests/test_recurrent_op.py index 79eda70021b76cd06e4c40740b1ca49476f4c503..1842cd74e4aa23c6bd8d25eed0daf28f065cf0b0 100644 --- a/python/paddle/v2/framework/tests/test_recurrent_op.py +++ b/python/paddle/v2/framework/tests/test_recurrent_op.py @@ -3,6 +3,7 @@ import paddle.v2.framework.core as core import unittest import numpy as np from paddle.v2.framework.op import Operator, RecurrentOp +from gradient_checker import GradientChecker def py_sigmoid(x): @@ -68,7 +69,7 @@ def create_tensor(scope, name, shape, np_data): return tensor -class TestRecurrentOp(unittest.TestCase): +class RecurrentOpTest(unittest.TestCase): ''' Test RNNOp @@ -160,5 +161,42 @@ class TestRecurrentOp(unittest.TestCase): self.assertEqual(pd_output.shape, py_output.shape) +class RecurrentGradientOpTest(unittest.TestCase): + def create_forward_op(self): + self.forward_op = RecurrentOp( + # inputs + inlinks=["x"], + boot_memories=["h_boot"], + step_net="stepnet", + # outputs + outlinks=["h"], + step_scopes="step_scopes", + # attributes + inlink_alias=["x@alias"], + outlink_alias=["h@alias"], + pre_memories=["h@pre"], + memories=["h@alias"]) + + # create a stepnet for RNN + stepnet = core.Net.create() + x_fc_op = Operator("mul", X="x@alias", Y="W", Out="Wx") + h_fc_op = Operator("mul", X="h@pre", Y="U", Out="Uh") + sum_op = Operator("add_two", X="Wx", Y="Uh", Out="sum") + sig_op = Operator("sigmoid", X="sum", Y="h@alias") + + for op in [x_fc_op, h_fc_op, sum_op, sig_op]: + stepnet.add_op(op) + stepnet.complete_add_op(True) + self.forward_op.set_stepnet(stepnet) + + def create_gradient_op(self): + a = set() + backward_op = core.RecurrentOp.backward(self.forward_op, a) + + def test_grad(self): + self.create_forward_op() + self.create_gradient_op() + + if __name__ == '__main__': unittest.main()