未验证 提交 b6ca6a55 编写于 作者: W WeiXin 提交者: GitHub

forward return any type. (#32661)

上级 b7ddd7d7
...@@ -115,12 +115,12 @@ py::object PyLayerApply(const platform::Place& place, const py::object& cls, ...@@ -115,12 +115,12 @@ py::object PyLayerApply(const platform::Place& place, const py::object& cls,
tuple_result[i].cast<std::shared_ptr<imperative::VarBase>>(); tuple_result[i].cast<std::shared_ptr<imperative::VarBase>>();
output_vars.push_back(temp_out); output_vars.push_back(temp_out);
} catch (py::cast_error&) { } catch (py::cast_error&) {
PADDLE_THROW(platform::errors::Unimplemented( // Only collect Tensor type in 'kwargs' and pass them to backward.
"The output of `PyLayer.forward` should be `Tensor`.")); // Ignore other types of input temporarily.
} }
} else { } else {
PADDLE_THROW(platform::errors::Unimplemented( // Only collect Tensor type in 'kwargs' and pass them to backward.
"The output of `PyLayer.forward` can not be `None`.")); // Ignore other types of input temporarily.
} }
} }
} else { } else {
...@@ -130,13 +130,17 @@ py::object PyLayerApply(const platform::Place& place, const py::object& cls, ...@@ -130,13 +130,17 @@ py::object PyLayerApply(const platform::Place& place, const py::object& cls,
result_forward.cast<std::shared_ptr<imperative::VarBase>>(); result_forward.cast<std::shared_ptr<imperative::VarBase>>();
output_vars.push_back(temp_out); output_vars.push_back(temp_out);
} catch (py::cast_error&) { } catch (py::cast_error&) {
PADDLE_THROW(platform::errors::Unimplemented( // Only collect Tensor type in 'kwargs' and pass them to backward.
"The output of `PyLayer.forward` should be `Tensor`.")); // Ignore other types of input temporarily.
} }
} else { } else {
PADDLE_THROW(platform::errors::Unimplemented( // Only collect Tensor type in 'kwargs' and pass them to backward.
"The output of `PyLayer.forward` can not be `None`.")); // Ignore other types of input temporarily.
}
} }
if (output_vars.size() == 0) {
PADDLE_THROW(platform::errors::InvalidArgument(
"At least one output of `PyLayer.forward` is a `Tensor`."));
} }
NameVarBaseMap outs = {{"Out", output_vars}}; NameVarBaseMap outs = {{"Out", output_vars}};
......
...@@ -86,6 +86,12 @@ void RunPyObject(py::object *py_object, ...@@ -86,6 +86,12 @@ void RunPyObject(py::object *py_object,
} }
} }
} else { } else {
if (1 != outs->size()) {
PADDLE_THROW(platform::errors::InvalidArgument(
"The number of outputs of `PyLayer.backward` should be %d, but "
"received 1.",
outs->size()));
}
if ((*outs)[0] != nullptr) { if ((*outs)[0] != nullptr) {
if (Py_None != py_result.ptr()) { if (Py_None != py_result.ptr()) {
try { try {
......
...@@ -30,7 +30,7 @@ class TestPyLayer(unittest.TestCase): ...@@ -30,7 +30,7 @@ class TestPyLayer(unittest.TestCase):
y1 = func1(x1) y1 = func1(x1)
y2 = func1(x2) y2 = func1(x2)
ctx.save_for_backward(y1, y2) ctx.save_for_backward(y1, y2)
return y1, y2 return y1, 1, y2, None
@staticmethod @staticmethod
def backward(ctx, dy1, dy2): def backward(ctx, dy1, dy2):
...@@ -44,7 +44,7 @@ class TestPyLayer(unittest.TestCase): ...@@ -44,7 +44,7 @@ class TestPyLayer(unittest.TestCase):
input1.stop_gradient = False input1.stop_gradient = False
input2.stop_gradient = False input2.stop_gradient = False
z = tanh.apply(input1, input1, paddle.tanh, paddle.square) z = tanh.apply(input1, input1, paddle.tanh, paddle.square)
z = z[0] + z[1] z = z[0] + z[2]
z.mean().backward() z.mean().backward()
z2 = paddle.tanh(input2) + paddle.tanh(input2) z2 = paddle.tanh(input2) + paddle.tanh(input2)
...@@ -61,7 +61,7 @@ class TestPyLayer(unittest.TestCase): ...@@ -61,7 +61,7 @@ class TestPyLayer(unittest.TestCase):
y1 = func1(x1) y1 = func1(x1)
y2 = func1(x2) y2 = func1(x2)
ctx.save_for_backward(y1, y2) ctx.save_for_backward(y1, y2)
return y1, y2 return 1, None, y1, y2, ''
@staticmethod @staticmethod
def backward(ctx, dy1, dy2): def backward(ctx, dy1, dy2):
...@@ -79,7 +79,7 @@ class TestPyLayer(unittest.TestCase): ...@@ -79,7 +79,7 @@ class TestPyLayer(unittest.TestCase):
input3.stop_gradient = True input3.stop_gradient = True
input4.stop_gradient = True input4.stop_gradient = True
z = tanh.apply(input1, input3, paddle.tanh, paddle.square) z = tanh.apply(input1, input3, paddle.tanh, paddle.square)
z = z[0] + z[1] z = z[2] + z[3]
z.mean().backward() z.mean().backward()
z2 = paddle.tanh(input2) + paddle.tanh(input4) z2 = paddle.tanh(input2) + paddle.tanh(input4)
...@@ -115,6 +115,27 @@ class TestPyLayer(unittest.TestCase): ...@@ -115,6 +115,27 @@ class TestPyLayer(unittest.TestCase):
self.assertTrue( self.assertTrue(
np.max(np.abs((input1.grad.numpy() - input2.grad.numpy()))) < 1e-10) np.max(np.abs((input1.grad.numpy() - input2.grad.numpy()))) < 1e-10)
def test_pylayer_num_output_match(self):
class tanh(PyLayer):
@staticmethod
def forward(
ctx,
x1,
x2, ):
return x1 + x2
@staticmethod
def backward(ctx, dy1):
return dy1 + 1
input1 = paddle.randn([2, 3]).astype("float64")
input2 = input1.detach().clone()
input1.stop_gradient = False
input2.stop_gradient = False
z = tanh.apply(input1, input2)
with self.assertRaises(ValueError):
z.mean().backward()
def test_pylayer_dtype(self): def test_pylayer_dtype(self):
class tanh(PyLayer): class tanh(PyLayer):
@staticmethod @staticmethod
...@@ -150,20 +171,20 @@ class TestPyLayer(unittest.TestCase): ...@@ -150,20 +171,20 @@ class TestPyLayer(unittest.TestCase):
return args return args
input1 = paddle.randn([2, 3]).astype("float64") input1 = paddle.randn([2, 3]).astype("float64")
with self.assertRaises(NotImplementedError): with self.assertRaises(ValueError):
z = Layer_None1.apply(input1) z = Layer_None1.apply(input1)
class Layer_None2(PyLayer): class Layer_None2(PyLayer):
@staticmethod @staticmethod
def forward(ctx, *args): def forward(ctx, *args):
return [None, None] return [None, args[0]]
@staticmethod @staticmethod
def backward(ctx, *args): def backward(ctx, *args):
return args return args
input1 = paddle.randn([2, 3]).astype("float64") input1 = paddle.randn([2, 3]).astype("float64")
with self.assertRaises(NotImplementedError): # return None
z = Layer_None2.apply(input1) z = Layer_None2.apply(input1)
class Layer_one1(PyLayer): class Layer_one1(PyLayer):
...@@ -176,20 +197,21 @@ class TestPyLayer(unittest.TestCase): ...@@ -176,20 +197,21 @@ class TestPyLayer(unittest.TestCase):
return args return args
input1 = paddle.randn([2, 3]).astype("float64") input1 = paddle.randn([2, 3]).astype("float64")
with self.assertRaises(NotImplementedError): # At least one output of `PyLayer.backward` is a `Tensor`
with self.assertRaises(ValueError):
z = Layer_one1.apply(input1) z = Layer_one1.apply(input1)
class Layer_one2(PyLayer): class Layer_one2(PyLayer):
@staticmethod @staticmethod
def forward(ctx, *args): def forward(ctx, *args):
return [1, 2] return [1, 2, args[0]]
@staticmethod @staticmethod
def backward(ctx, *args): def backward(ctx, *args):
return args return args
input1 = paddle.randn([2, 3]).astype("float64") input1 = paddle.randn([2, 3]).astype("float64")
with self.assertRaises(NotImplementedError): # return int
z = Layer_one2.apply(input1) z = Layer_one2.apply(input1)
class Layer_no_fw(PyLayer): class Layer_no_fw(PyLayer):
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册