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.31】 为 Paddle 新增 column_stack / row_stack / dstack / hstack / vstack API #58280

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions python/paddle/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,11 @@
index_add_,
index_put,
index_put_,
column_stack,
row_stack,
dstack,
hstack,
vstack,
unflatten,
as_strided,
view,
Expand Down Expand Up @@ -883,6 +888,11 @@
"index_add_",
"index_put",
"index_put_",
"column_stack",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

没有类成员方式,这里不用导出

"row_stack",
"dstack",
"hstack",
"vstack",
'sgn',
'triu_indices',
'take',
Expand Down
10 changes: 10 additions & 0 deletions python/paddle/tensor/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,11 @@
from .manipulation import index_add_ # noqa: F401
from .manipulation import index_put # noqa: F401
from .manipulation import index_put_ # noqa: F401
from .manipulation import column_stack # noqa: F401
from .manipulation import row_stack # noqa: F401
from .manipulation import dstack # noqa: F401
from .manipulation import hstack # noqa: F401
from .manipulation import vstack # 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 @@ -669,6 +674,11 @@
"index_add_",
'index_put',
'index_put_',
'column_stack',
'row_stack',
'dstack',
'hstack',
'vstack',
'take',
'bucketize',
'sgn',
Expand Down
296 changes: 296 additions & 0 deletions python/paddle/tensor/manipulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -5124,6 +5124,302 @@ def index_put(x, indices, value, accumulate=False, name=None):
return out


def column_stack(x, name=None):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

如果有别名的,直接a=b就可以,复用维护一套代码

column_stack row_stack应该是别名吧

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

底下的row_stack用的是vstack的别名

"""
Stacks 1-D tensors as columns into a 2-D tensor.
First, 1-D arrays are turned into 2-D columns, and then 2-D arrays are stacked as-is, just like with hstack.

Args:
x(tuple[Tensor] or list[Tensor]): A sequence of tensors to concatenate.
name(str, optional): For details, please refer to :ref:`api_guide_Name`. Generally, no setting is required. Default: None.

Returns:
2-D Tensor, formed by stacking the given tensors.

Raises:
TypeError: If `tensors` is not list or tuple.
TypeError: If element in `tensors` is not Tensor.
ValueError: If `tensors` is empty.

Examples:
.. code-block:: python
>>> import paddle
>>> a = paddle.to_tensor([1, 2, 3])
>>> b = paddle.to_tensor([4, 5, 6])
>>> c = paddle.column_stack((a, b))
>>> print(c)
Tensor(shape=[3, 2], dtype=int64, place=Place(cpu), stop_gradient=True,
[[1, 4],
[2, 5],
[3, 6]])
>>> a = paddle.arange(5)
>>> b = paddle.arange(10).reshape([5, 2])
>>> c = paddle.column_stack((a, b, b))
>>> print(c)
Tensor(shape=[5, 5], dtype=int64, place=Place(cpu), stop_gradient=True,
[[0, 0, 1, 0, 1],
[1, 2, 3, 2, 3],
[2, 4, 5, 4, 5],
[3, 6, 7, 6, 7],
[4, 8, 9, 8, 9]])
"""
check_type(x, 'x', (list, tuple), 'column_stack')
if not x:
msg = "For 'column_stack', inputs can not be empty"
raise TypeError(msg)
trans_x = ()

for tensor in x:
check_type(x, 'x', (list, tuple), 'column_stack')
if tensor.ndim < 1:
tensor = paddle.unsqueeze(tensor, 0)
if tensor.ndim == 1:
tensor = paddle.unsqueeze(tensor, 1)
trans_x += (tensor,)
if not trans_x:
raise ValueError(
"For column_stack, the input must have at least 1 tensor, but got 0."
)

return paddle.concat(trans_x, 1)


def dstack(x, name=None):
"""
Stacks tensors along the third axis in sequence depthwise.

First, 1-D tensors should be reshaped to :math:`(1,N,1)`, 2-D tensors should be reshaped to :math:`(M,N,1)`. And then concatenation along the third axis.

Args:
x(tuple[Tensor] or list[Tensor]): A sequence of tensors to concatenate.
name(str, optional): For details, please refer to :ref:`api_guide_Name`. Generally, no setting is required. Default: None.

Returns:
Stacked Tensor, will be at least 3-D.

Raises:
TypeError: If `inputs` is not tuple or list.
ValueError: If `inputs` is empty.

Examples:
.. code-block:: python
>>> import paddle
>>> a = paddle.to_tensor([1, 2, 3])
>>> b = paddle.to_tensor([4, 5, 6])
>>> c = paddle.dstack((a,b))
>>> print(c)
Tensor(shape=[1, 3, 2], dtype=int64, place=Place(cpu), stop_gradient=True,
[[[1, 4],
[2, 5],
[3, 6]]])
>>> a = paddle.to_tensor([[1],[2],[3]])
>>> b = paddle.to_tensor([[4],[5],[6]])
>>> c = paddle.dstack((a,b))
>>> print(c)
Tensor(shape=[3, 1, 2], dtype=int64, place=Place(cpu), stop_gradient=True,
[[[1, 4]],
[[2, 5]],
[[3, 6]]])
"""
check_type(x, 'x', (list, tuple), 'dstack')
if not x:
msg = "For 'dstack', inputs can not be empty"
raise TypeError(msg)
rep = ()
for tensor in x:
check_type(
tensor,
'tensor',
(Variable),
'dstack',
f"For 'dstack', each elements of 'inputs' must be Tensor, but got {type(tensor)}",
)
if tensor.size == 0:
raise TypeError(
"For 'dstack', each elements of 'inputs' can not be empty."
)
ndim = tensor.ndim
# similar to the function of atleast_3d
if ndim == 0:
tensor = paddle.reshape(tensor, (1, 1, 1))
if ndim == 1:
size = tensor.shape[0]
tensor = paddle.reshape(tensor, (1, size, 1))
if ndim == 2:
tensor = paddle.unsqueeze(tensor, axis=-1)
rep += (tensor,)
if not rep:
raise ValueError(
"For 'dstack', at least one tensor is needed to concatenate."
)
return paddle.concat(rep, 2)


def hstack(x, name=None):
"""
Stacks tensors in sequence horizontally(column wise).
For for 1-D tensors,it concatenates along the first axis.The others concatenation along the second axis.

Args:
x(tuple[Tensor] or list[Tensor]): A sequence of tensors to concatenate.
name(str, optional): For details, please refer to :ref:`api_guide_Name`. Generally, no setting is required. Default: None.

Returns:
Stacked Tensor, formed by stacking the given tensors.

Raises:
TypeError: If `tensors` is not list or tuple.
TypeError: If element in `tensors` is not Tensor.
ValueError: If `tensors` is empty.

Examples:
.. code-block:: python
>>> import paddle
>>> a = paddle.to_tensor([1, 2, 3])
>>> b = paddle.to_tensor([4, 5, 6])
>>> c = paddle.hstack((a,b))
>>> print(c)
Tensor(shape=[6], dtype=int64, place=Place(cpu), stop_gradient=True,
[1, 2, 3, 4, 5, 6])
>>> a = paddle.to_tensor([[1],[2],[3]])
>>> b = paddle.to_tensor([[4],[5],[6]])
>>> c = paddle.hstack((a,b))
>>> print(c)
Tensor(shape=[3, 2], dtype=int64, place=Place(cpu), stop_gradient=True,
[[1, 4],
[2, 5],
[3, 6]])
"""
check_type(x, 'x', (list, tuple), 'hstack')
if not x:
msg = "For 'hstack', inputs can not be empty"
raise TypeError(msg)
rep = ()
for tensor in x:
check_type(
tensor,
'tensor',
(Variable),
'hstack',
f"For 'hstack', each element of 'inputs' must be a tensor, but got {type(tensor)}",
)
# similar to the atleast_1d
if tensor.ndim == 0:
tensor = paddle.reshape(tensor, [1])
rep += (tensor,)
if not rep:
raise ValueError(
"For 'hstack', need at least one tensor to concatenate."
)

if rep[0].dim() == 1:
return paddle.concat(rep, 0)

return paddle.concat(rep, 1)


def vstack(x, name=None):
"""
Stacks tensors in sequence vertically(row wise).
First, 1-D arrays of shape (N,) have been reshaped to (1,N).And then oncatenation along the first axis.

Args:
x(tuple[Tensor] or list[Tensor]): A sequence of tensors to concatenate.
name(str, optional): For details, please refer to :ref:`api_guide_Name`. Generally, no setting is required. Default: None.

Returns:
tuple[Tensor] or list[Tensor]: A sequence of tensors to concatenate

Raises:
TypeError: If `inputs` is not list or tuple.
ValueError: If `inputs` is empty.

Examples:
.. code-block:: python
>>> import paddle
>>> a = paddle.to_tensor([1, 2, 3])
>>> b = paddle.to_tensor([4, 5, 6])
>>> c = paddle.vstack((a,b))
>>> print(c)
Tensor(shape=[2, 3], dtype=int64, place=Place(cpu), stop_gradient=True,
[[1, 2, 3],
[4, 5, 6]])
>>> a = paddle.to_tensor([[1],[2],[3]])
>>> b = paddle.to_tensor([[4],[5],[6]])
>>> c = paddle.vstack((a,b))
>>> print(c)
Tensor(shape=[6, 1], dtype=int64, place=Place(cpu), stop_gradient=True,
[[1],
[2],
[3],
[4],
[5],
[6]])
"""
check_type(x, 'x', (list, tuple), 'vstack')
if not x:
msg = "For 'hstack', inputs can not be empty"
raise TypeError(msg)

rep = ()
for tensor in x:
check_type(
tensor,
'tensor',
(Variable),
'hstack',
f"For 'hstack', each element of 'inputs' must be a tensor, but got {type(tensor)}",
)
# similar to the function of atleast_2d
if tensor.ndim == 0:
tensor = paddle.reshape(tensor, [1, 1])
elif tensor.ndim == 1:
tensor = paddle.unsqueeze(tensor, 0)
rep += (tensor,)
if not rep:
raise ValueError(
"For 'hstack', need at least one tensor to concatenate."
)
return paddle.concat(rep, 0)


def row_stack(x, name=None):
"""
Alias for :func:`paddle.vstack`.

Args:
x(tuple[Tensor] or list[Tensor]): A sequence of tensors to concatenate.
name(str, optional): For details, please refer to :ref:`api_guide_Name`. Generally, no setting is required. Default: None.

Returns:
tuple[Tensor] or list[Tensor]: A sequence of tensors to concatenate

Examples:
.. code-block:: python
>>> import paddle
>>> a = paddle.to_tensor([1, 2, 3])
>>> b = paddle.to_tensor([4, 5, 6])
>>> c = paddle.row_stack((a,b))
>>> print(c)
Tensor(shape=[2, 3], dtype=int64, place=Place(cpu), stop_gradient=True,
[[1, 2, 3],
[4, 5, 6]])
>>> a = paddle.to_tensor([[1],[2],[3]])
>>> b = paddle.to_tensor([[4],[5],[6]])
>>> c = paddle.row_stack((a,b))
>>> print(c)
Tensor(shape=[6, 1], dtype=int64, place=Place(cpu), stop_gradient=True,
[[1],
[2],
[3],
[4],
[5],
[6]])
"""
rep = paddle.vstack(x)
return rep


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