Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【Hackathon 5th No.33】 为 Paddle 新增 atleast_1d / atleast_2d / atleast_3d API #57940

Closed
wants to merge 12 commits into from
6 changes: 6 additions & 0 deletions python/paddle/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,9 @@
index_add_,
index_put,
index_put_,
atleast_1d,
atleast_2d,
atleast_3d,
unflatten,
as_strided,
view,
Expand Down Expand Up @@ -876,6 +879,9 @@
"index_add_",
"index_put",
"index_put_",
"atleast_1d",
"atleast_2d",
"atleast_3d",
'sgn',
'triu_indices',
'take',
Expand Down
6 changes: 6 additions & 0 deletions python/paddle/tensor/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,9 @@
from .manipulation import index_add_ # noqa: F401
from .manipulation import index_put # noqa: F401
from .manipulation import index_put_ # noqa: F401
from .manipulation import atleast_1d # noqa: F401
from .manipulation import atleast_2d # noqa: F401
from .manipulation import atleast_3d # noqa: F401
from .manipulation import unflatten # noqa: F401
from .manipulation import as_strided # noqa: F401
from .manipulation import view # noqa: F401
Expand Down Expand Up @@ -665,6 +668,9 @@
"index_add_",
'index_put',
'index_put_',
'atleast_1d',
'atleast_2d',
'atleast_3d',
'take',
'bucketize',
'sgn',
Expand Down
213 changes: 213 additions & 0 deletions python/paddle/tensor/manipulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -4946,6 +4946,219 @@ def index_put(x, indices, value, accumulate=False, name=None):
return out


def atleast_1d(x, name=None):
r"""
Returns a 1-dimensional view of each input tensor with zero dimensions. Input tensors with one or more dimensions are returned as-is.

Args:
x (Tensor or list of Tensors): a tensor or a list of tensors to operate
name(str, optional): For details, please refer to :ref:`api_guide_Name`. Generally, no setting is required. Default: None.

Returns:
output (Tensor or tuple of Tensors)

Raises:
TypeError: If the `input` is not a tensor or a list of tensors.

Examples:
.. code-block:: python
>>> import paddle
>>> x = paddle.to_tensor(2)
>>> print(x)
Tensor(shape=[], dtype=int64, place=Place(cpu), stop_gradient=True,
2)
>>> x = paddle.atleast_1d(x)
>>> print(x)
Tensor(shape=[1], dtype=int64, place=Place(cpu), stop_gradient=True,
[2])
>>> x = paddle.arange(2)
>>> print(x)
Tensor(shape=[2], dtype=int64, place=Place(cpu), stop_gradient=True,
[0, 1])
>>> x = paddle.atleast_1d(x)
>>> print(x)
Tensor(shape=[2], dtype=int64, place=Place(cpu), stop_gradient=True,
[0, 1])
>>> x = paddle.to_tensor(0.5)
>>> y = paddle.to_tensor(1.)
>>> x_y = paddle.atleast_1d((x, y))
>>> print(x_y)
(Tensor(shape=[1], dtype=float32, place=Place(cpu), stop_gradient=True,
[0.50000000]), Tensor(shape=[1], dtype=float32, place=Place(cpu), stop_gradient=True,
[1.]))
"""

def _expend1(tensor):
if tensor.ndim == 0:
return paddle.reshape(tensor, [1])
else:
return tensor

check_type(x, 'x', (Variable, list, tuple), 'atleast_1d')
if isinstance(x, Variable):
return _expend1(x)
for tensor in x:
check_type(
tensor,
'tensor',
(Variable),
'atleast_1d',
f"For 'atleast_1d', each element of 'inputs' must be a tensor, but got {type(tensor)}",
)

return tuple([_expend1(tensor) for tensor in x])


def atleast_2d(x, name=None):
r"""
Returns a 2-dimensional view of each input tensor with zero dimensions. Input tensors with two or more dimensions are returned as-is.

Args:
x (Tensor or list of Tensors): a tensor or a list of tensors to operate
name(str, optional): For details, please refer to :ref:`api_guide_Name`. Generally, no setting is required. Default: None.

Returns:
output (Tensor or tuple of Tensors)

Raises:
TypeError: If the `input` is not a tensor or a list of tensors.

Examples:
.. code-block:: python
>>> import paddle
>>> x = paddle.to_tensor(1.)
>>> print(x)
Tensor(shape=[], dtype=float32, place=Place(cpu), stop_gradient=True,
1.)
>>> x = paddle.atleast_2d(x)
>>> print(x)
Tensor(shape=[1, 1], dtype=float32, place=Place(cpu), stop_gradient=True,
[[1.]])
>>> x = paddle.arange(4).reshape([2, 2])
>>> print(x)
Tensor(shape=[2, 2], dtype=int64, place=Place(cpu), stop_gradient=True,
[[0, 1],
[2, 3]])
>>> x = paddle.atleast_2d(x)
>>> print(x)
Tensor(shape=[2, 2], dtype=int64, place=Place(cpu), stop_gradient=True,
[[0, 1],
[2, 3]])
>>> x = paddle.to_tensor(0.5)
>>> y = paddle.to_tensor(1.)
>>> x_y = paddle.atleast_2d((x, y))
>>> print(x_y)
(Tensor(shape=[1, 1], dtype=float32, place=Place(cpu), stop_gradient=True,
[[0.50000000]]), Tensor(shape=[1, 1], dtype=float32, place=Place(cpu), stop_gradient=True,
[[1.]]))

"""

def _expand2(x):
if x.ndim == 0:
return paddle.reshape(x, [1, 1])
elif x.ndim == 1:
return paddle.unsqueeze(x, 0)
else:
return x

check_type(x, 'x', (Variable, list, tuple), 'atleast_2d')
if isinstance(x, Variable):
return _expand2(x)
for tensor in x:
check_type(
tensor,
'tensor',
(Variable),
'atleast_2d',
"expect Tensor or list of tensors, but got " + f"{type(tensor)}",
)

return tuple([_expand2(tensor) for tensor in x])


def atleast_3d(x, name=None):
r"""
Returns a 3-dimensional view of each input tensor with zero dimensions. Input tensors with three or more dimensions are returned as-is.

Args:
x (Tensor or list of Tensors): a tensor or a list of tensors to operate
name(str, optional): For details, please refer to :ref:`api_guide_Name`. Generally, no setting is required. Default: None.

Returns:
output (Tensor or tuple of Tensors)

Raises:
TypeError: If the `input` is not a tensor or a list of tensors.

Examples:
.. code-block:: python
>>> import paddle
>>> x = paddle.to_tensor(0.5)
>>> print(x)
Tensor(shape=[], dtype=float32, place=Place(cpu), stop_gradient=True,
0.50000000)
>>> x = paddle.atleast_3d(x)
>>> print(x)
Tensor(shape=[1, 1, 1], dtype=float32, place=Place(cpu), stop_gradient=True,
[[[0.50000000]]])
>>> x = paddle.arange(4).reshape([2, 2])
>>> print(x)
Tensor(shape=[2, 2], dtype=int64, place=Place(cpu), stop_gradient=True,
[[0, 1],
[2, 3]])
>>> x = paddle.atleast_3d(x)
>>> print(x)
Tensor(shape=[2, 2, 1], dtype=int64, place=Place(cpu), stop_gradient=True,
[[[0],
[1]],
[[2],
[3]]])
>>> x = paddle.to_tensor(1).reshape([1, 1, 1])
>>> print(x)
Tensor(shape=[1, 1, 1], dtype=int64, place=Place(cpu), stop_gradient=True,
[[[1]]])
>>> x = paddle.atleast_3d(x)
>>> print(x)
Tensor(shape=[1, 1, 1], dtype=int64, place=Place(cpu), stop_gradient=True,
[[[1]]])
>>> x = paddle.to_tensor(0.5)
>>> y = paddle.to_tensor(1.)
>>> x_y = paddle.atleast_3d((x, y))
>>> print(x_y)
(Tensor(shape=[1, 1, 1], dtype=float32, place=Place(cpu), stop_gradient=True,
[[[0.50000000]]]), Tensor(shape=[1, 1, 1], dtype=float32, place=Place(cpu), stop_gradient=True,
[[[1.]]]))

"""

def _expand3(arr):
ndim = arr.ndim
if ndim == 0:
return paddle.reshape(arr, (1, 1, 1))
if ndim == 1:
size = arr.shape[0]
return paddle.reshape(arr, (1, size, 1))
if ndim == 2:
arr = paddle.unsqueeze(arr, axis=-1)

return arr

check_type(x, 'x', (Variable, list, tuple), 'atleast_3d')
if isinstance(x, Variable):
return _expand3(x)
for tensor in x:
check_type(
tensor,
'tensor',
(Variable),
'atleast_3d',
f"For 'atleast_3d', each element of 'x' must be a tensor, but got {type(tensor)}",
)

return tuple([_expand3(arr) for arr in x])


def unflatten(x, axis, shape, name=None):
"""
Expand a certain dimension of the input x Tensor into a desired shape.
Expand Down
Loading