未验证 提交 347d2123 编写于 作者: Z zhaoyingli 提交者: GitHub

[Zero-Dim] reshape/reshape_/reverse 0D support (#49357)

* [Zero-Dim] reshape/reshape_/reverse 0D support

* rm comment

* change paddle.to_tensor to paddle.full

* fix docs

* update paddle.full
上级 021085e3
...@@ -114,11 +114,6 @@ class ReshapeOp : public framework::OperatorWithKernel { ...@@ -114,11 +114,6 @@ class ReshapeOp : public framework::OperatorWithKernel {
return; return;
} }
PADDLE_ENFORCE_EQ(!shape.empty(),
true,
platform::errors::InvalidArgument(
"The parameter 'shape' in ReshapeOp must be set. "
"But received 'shape' is empty."));
auto x_dims = ctx->GetInputDim("X"); auto x_dims = ctx->GetInputDim("X");
auto out_dims = ValidateShape(shape, x_dims); auto out_dims = ValidateShape(shape, x_dims);
ctx->SetOutputDim("Out", out_dims); ctx->SetOutputDim("Out", out_dims);
......
...@@ -49,20 +49,20 @@ class TestReshapeOp(OpTest): ...@@ -49,20 +49,20 @@ class TestReshapeOp(OpTest):
class TestReshapeOp_ZeroDim1(OpTest): class TestReshapeOp_ZeroDim1(OpTest):
def init_data(self): def init_data(self):
self.ori_shape = () self.ori_shape = ()
self.new_shape = 1 self.new_shape = (1,)
self.infered_shape = 1 self.infered_shape = (1,)
class TestReshapeOp_ZeroDim2(OpTest): class TestReshapeOp_ZeroDim2(OpTest):
def init_data(self): def init_data(self):
self.ori_shape = () self.ori_shape = ()
self.new_shape = -1 self.new_shape = (-1,)
self.infered_shape = 1 self.infered_shape = (1,)
class TestReshapeOp_ZeroDim3(OpTest): class TestReshapeOp_ZeroDim3(OpTest):
def init_data(self): def init_data(self):
self.ori_shape = 1 self.ori_shape = (1,)
self.new_shape = () self.new_shape = ()
self.infered_shape = () self.infered_shape = ()
......
...@@ -756,6 +756,105 @@ class TestSundryAPI(unittest.TestCase): ...@@ -756,6 +756,105 @@ class TestSundryAPI(unittest.TestCase):
np.testing.assert_array_equal(out3_1.numpy(), out3_2.numpy()) np.testing.assert_array_equal(out3_1.numpy(), out3_2.numpy())
np.testing.assert_array_equal(out3_2.numpy(), np.asarray(1)) np.testing.assert_array_equal(out3_2.numpy(), np.asarray(1))
def test_reshape_list(self):
x = paddle.rand([])
x.stop_gradient = False
out = paddle.reshape(x, [])
out.backward()
self.assertEqual(x.grad.shape, [])
self.assertEqual(out.shape, [])
self.assertEqual(out.grad.shape, [])
out = paddle.reshape(x, [1])
out.backward()
self.assertEqual(x.grad.shape, [])
self.assertEqual(out.shape, [1])
self.assertEqual(out.grad.shape, [1])
out = paddle.reshape(x, [-1])
out.backward()
self.assertEqual(x.grad.shape, [])
self.assertEqual(out.shape, [1])
self.assertEqual(out.grad.shape, [1])
out = paddle.reshape(x, [-1, 1])
out.backward()
self.assertEqual(x.grad.shape, [])
self.assertEqual(out.shape, [1, 1])
self.assertEqual(out.grad.shape, [1, 1])
def test_reshape_tensor(self):
x = paddle.rand([1, 1])
x.stop_gradient = False
out = paddle.reshape(x, [])
out.backward()
self.assertEqual(x.grad.shape, [1, 1])
self.assertEqual(out.shape, [])
self.assertEqual(out.grad.shape, [])
new_shape = paddle.full([1], 1, "int32")
out = paddle.reshape(x, new_shape)
out.backward()
self.assertEqual(x.grad.shape, [1, 1])
self.assertEqual(out.shape, [1])
self.assertEqual(out.grad.shape, [1])
new_shape = paddle.full([1], -1, "int32")
out = paddle.reshape(x, new_shape)
out.backward()
self.assertEqual(x.grad.shape, [1, 1])
self.assertEqual(out.shape, [1])
self.assertEqual(out.grad.shape, [1])
new_shape = [paddle.full([], -1, "int32"), paddle.full([], 1, "int32")]
out = paddle.reshape(x, new_shape)
out.backward()
self.assertEqual(x.grad.shape, [1, 1])
self.assertEqual(out.shape, [1, 1])
self.assertEqual(out.grad.shape, [1, 1])
def test_reshape__list(self):
x = paddle.rand([])
out = paddle.reshape_(x, [])
self.assertEqual(out.shape, [])
out = paddle.reshape_(x, [1])
self.assertEqual(out.shape, [1])
out = paddle.reshape_(x, [-1])
self.assertEqual(out.shape, [1])
out = paddle.reshape_(x, [-1, 1])
self.assertEqual(out.shape, [1, 1])
def test_reshape__tensor(self):
x = paddle.rand([1, 1])
out = paddle.reshape_(x, [])
self.assertEqual(out.shape, [])
new_shape = paddle.full([1], 1, "int32")
out = paddle.reshape_(x, new_shape)
self.assertEqual(out.shape, [1])
new_shape = paddle.full([1], -1, "int32")
out = paddle.reshape_(x, new_shape)
self.assertEqual(out.shape, [1])
new_shape = [paddle.full([], -1, "int32"), paddle.full([], 1, "int32")]
out = paddle.reshape_(x, new_shape)
self.assertEqual(out.shape, [1, 1])
def test_reverse(self):
x = paddle.rand([])
x.stop_gradient = False
out = paddle.reverse(x, axis=[])
out.backward()
self.assertEqual(x.shape, [])
self.assertEqual(out.shape, [])
self.assertEqual(out.grad.shape, [])
class TestSundryAPIStatic(unittest.TestCase): class TestSundryAPIStatic(unittest.TestCase):
def setUp(self): def setUp(self):
...@@ -1011,6 +1110,78 @@ class TestSundryAPIStatic(unittest.TestCase): ...@@ -1011,6 +1110,78 @@ class TestSundryAPIStatic(unittest.TestCase):
np.testing.assert_array_equal(out3_1, out3_2) np.testing.assert_array_equal(out3_1, out3_2)
np.testing.assert_array_equal(out3_2, np.asarray(1)) np.testing.assert_array_equal(out3_2, np.asarray(1))
@prog_scope()
def test_reshape_list(self):
x1 = paddle.rand([])
x2 = paddle.rand([])
x3 = paddle.rand([])
x4 = paddle.rand([])
x1.stop_gradient = False
x2.stop_gradient = False
x3.stop_gradient = False
x4.stop_gradient = False
out1 = paddle.reshape(x1, [])
paddle.static.append_backward(out1)
out2 = paddle.reshape(x2, [1])
paddle.static.append_backward(out2)
out3 = paddle.reshape(x3, [-1])
paddle.static.append_backward(out3)
out4 = paddle.reshape(x4, [-1, 1])
paddle.static.append_backward(out4)
program = paddle.static.default_main_program()
res1, res2, res3, res4 = self.exe.run(
program, fetch_list=[out1, out2, out3, out4]
)
self.assertEqual(res1.shape, ())
self.assertEqual(res2.shape, (1,))
self.assertEqual(res3.shape, (1,))
self.assertEqual(res4.shape, (1, 1))
@prog_scope()
def test_reshape_tensor(self):
x1 = paddle.rand([])
x2 = paddle.rand([])
x3 = paddle.rand([])
x1.stop_gradient = False
x2.stop_gradient = False
x3.stop_gradient = False
new_shape = paddle.full([1], 1, "int32")
out1 = paddle.reshape(x1, new_shape)
paddle.static.append_backward(out1)
new_shape = paddle.full([1], -1, "int32")
out2 = paddle.reshape(x2, new_shape)
paddle.static.append_backward(out2)
new_shape = [paddle.full([], -1, "int32"), paddle.full([], 1, "int32")]
out3 = paddle.reshape(x3, new_shape)
paddle.static.append_backward(out3)
program = paddle.static.default_main_program()
res1, res2, res3 = self.exe.run(program, fetch_list=[out1, out2, out3])
self.assertEqual(res1.shape, (1,))
self.assertEqual(res2.shape, (1,))
self.assertEqual(res3.shape, (1, 1))
@prog_scope()
def test_reverse(self):
x = paddle.rand([])
x.stop_gradient = False
out = paddle.reverse(x, axis=[])
paddle.static.append_backward(out)
program = paddle.static.default_main_program()
res1, res2 = self.exe.run(program, fetch_list=[x, out])
self.assertEqual(res1.shape, ())
self.assertEqual(res2.shape, ())
# Use to test API whose zero-dim input tensors don't have grad and not need to test backward in OpTest. # Use to test API whose zero-dim input tensors don't have grad and not need to test backward in OpTest.
class TestNoBackwardAPI(unittest.TestCase): class TestNoBackwardAPI(unittest.TestCase):
......
...@@ -556,6 +556,96 @@ class TestSundryAPI(unittest.TestCase): ...@@ -556,6 +556,96 @@ class TestSundryAPI(unittest.TestCase):
np.testing.assert_array_equal(out3_1.numpy(), out3_2.numpy()) np.testing.assert_array_equal(out3_1.numpy(), out3_2.numpy())
np.testing.assert_array_equal(out3_2.numpy(), np.asarray(1)) np.testing.assert_array_equal(out3_2.numpy(), np.asarray(1))
def test_reshape_list(self):
x = paddle.rand([])
x.stop_gradient = False
out = paddle.reshape(x, [])
out.backward()
self.assertEqual(x.grad.shape, [])
self.assertEqual(out.shape, [])
self.assertEqual(out.grad.shape, [])
out = paddle.reshape(x, [1])
out.backward()
self.assertEqual(x.grad.shape, [])
self.assertEqual(out.shape, [1])
self.assertEqual(out.grad.shape, [1])
out = paddle.reshape(x, [-1])
out.backward()
self.assertEqual(x.grad.shape, [])
self.assertEqual(out.shape, [1])
self.assertEqual(out.grad.shape, [1])
out = paddle.reshape(x, [-1, 1])
out.backward()
self.assertEqual(x.grad.shape, [])
self.assertEqual(out.shape, [1, 1])
self.assertEqual(out.grad.shape, [1, 1])
def test_reshape_tensor(self):
x = paddle.rand([1, 1])
x.stop_gradient = False
out = paddle.reshape(x, [])
out.backward()
self.assertEqual(x.grad.shape, [1, 1])
self.assertEqual(out.shape, [])
self.assertEqual(out.grad.shape, [])
new_shape = paddle.full([], 1, "int32")
out = paddle.reshape(x, new_shape)
out.backward()
self.assertEqual(x.grad.shape, [1, 1])
self.assertEqual(out.shape, [1])
self.assertEqual(out.grad.shape, [1])
new_shape = paddle.full([], -1, "int32")
out = paddle.reshape(x, new_shape)
out.backward()
self.assertEqual(x.grad.shape, [1, 1])
self.assertEqual(out.shape, [1])
self.assertEqual(out.grad.shape, [1])
new_shape = [paddle.full([], -1, "int32"), paddle.full([], 1, "int32")]
out = paddle.reshape(x, new_shape)
out.backward()
self.assertEqual(x.grad.shape, [1, 1])
self.assertEqual(out.shape, [1, 1])
self.assertEqual(out.grad.shape, [1, 1])
def test_reshape__list(self):
x = paddle.rand([])
out = paddle.reshape_(x, [])
self.assertEqual(out.shape, [])
out = paddle.reshape_(x, [1])
self.assertEqual(out.shape, [1])
out = paddle.reshape_(x, [-1])
self.assertEqual(out.shape, [1])
out = paddle.reshape_(x, [-1, 1])
self.assertEqual(out.shape, [1, 1])
def test_reshape__tensor(self):
x = paddle.rand([1, 1])
out = paddle.reshape_(x, [])
self.assertEqual(out.shape, [])
new_shape = paddle.full([1], 1, "int32")
out = paddle.reshape_(x, new_shape)
self.assertEqual(out.shape, [1])
new_shape = paddle.full([1], -1, "int32")
out = paddle.reshape_(x, new_shape)
self.assertEqual(out.shape, [1])
new_shape = [paddle.full([], -1, "int32"), paddle.full([], 1, "int32")]
out = paddle.reshape_(x, new_shape)
self.assertEqual(out.shape, [1, 1])
# Use to test API whose zero-dim input tensors don't have grad and not need to test backward in OpTest. # Use to test API whose zero-dim input tensors don't have grad and not need to test backward in OpTest.
class TestNoBackwardAPI(unittest.TestCase): class TestNoBackwardAPI(unittest.TestCase):
......
...@@ -3450,7 +3450,7 @@ def reshape(x, shape, name=None): ...@@ -3450,7 +3450,7 @@ def reshape(x, shape, name=None):
Args: Args:
x (Tensor): An N-D Tensor. The data type is ``float32``, ``float64``, ``int32``, ``int64`` or ``bool`` x (Tensor): An N-D Tensor. The data type is ``float32``, ``float64``, ``int32``, ``int64`` or ``bool``
shape (list|tuple|Tensor): Define the target shape. At most one dimension of the target shape can be -1. shape (list|tuple|Tensor): Define the target shape. At most one dimension of the target shape can be -1.
The data type is ``int32`` . If ``shape`` is a list or tuple, the elements of it should be integers or Tensors with shape [1]. The data type is ``int32`` . If ``shape`` is a list or tuple, the elements of it should be integers or Tensors with shape [].
If ``shape`` is an Tensor, it should be an 1-D Tensor . If ``shape`` is an Tensor, it should be an 1-D Tensor .
name (str, optional): Name for the operation (optional, default is None). For more information, please refer to :ref:`api_guide_Name`. name (str, optional): Name for the operation (optional, default is None). For more information, please refer to :ref:`api_guide_Name`.
...@@ -3574,10 +3574,6 @@ def reshape(x, shape, name=None): ...@@ -3574,10 +3574,6 @@ def reshape(x, shape, name=None):
shape.stop_gradient = True shape.stop_gradient = True
inputs["Shape"] = shape inputs["Shape"] = shape
elif isinstance(shape, (list, tuple)): elif isinstance(shape, (list, tuple)):
assert len(shape) > 0, (
"The size of 'shape' in reshape can't be zero, "
"but received %s." % len(shape)
)
attrs["shape"] = get_attr_shape(shape) attrs["shape"] = get_attr_shape(shape)
if utils._contain_var(shape): if utils._contain_var(shape):
inputs['ShapeTensor'] = utils._convert_to_tensor_list(shape) inputs['ShapeTensor'] = utils._convert_to_tensor_list(shape)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册