-
Notifications
You must be signed in to change notification settings - Fork 5.9k
【Hackathon 9th Sprint No.1】add api compatibility for paddle.unique - part #76387
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
Changes from 15 commits
ac045fd
8e5e6ac
80764fd
7a1d555
fb311dd
8b6e2d7
46814a0
68fca13
379a6ea
d8cc756
8be342b
c9b57aa
f5c9c30
659bfee
f845a1f
76f6321
dd247c8
ea1c1f1
71af57d
6d41363
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -47,6 +47,7 @@ | |
| 'split', | ||
| 'min', | ||
| 'max', | ||
| 'unique', | ||
| 'median', | ||
| 'nanmedian', | ||
| 'seed', | ||
|
|
@@ -795,6 +796,75 @@ def sort( | |
| return SortRetType(values=outputs, indices=indices) | ||
|
|
||
|
|
||
| @ForbidKeywordsDecorator( | ||
| illegal_keys={"x", "axis"}, | ||
| func_name="paddle.compat.unique", | ||
| correct_name="paddle.unique", | ||
| ) | ||
| def unique( | ||
| input: Tensor, | ||
| sorted: bool = True, | ||
| return_inverse: bool = False, | ||
| return_counts: bool = False, | ||
| dim=None, | ||
| ) -> Tensor | tuple[Tensor, ...]: | ||
|
||
| r""" | ||
| Returns the unique elements of `input` in ascending order. | ||
|
|
||
| Args: | ||
| input(Tensor): The input tensor, it's data type should be float32, float64, int32, int64. | ||
| sorted(bool, optional): Does not affect the return result, same as PyTorch. | ||
| return_inverse(bool, optional): If True, also return the indices for where elements in | ||
| the original input ended up in the returned unique tensor. | ||
| return_counts(bool, optional): If True, also return the counts for each unique element. | ||
| dim(int, optional): The axis to apply unique. If None, the input will be flattened. | ||
| Default: None. | ||
|
|
||
| Returns: | ||
| tuple (output, inverse_indices, counts). `output` is the unique tensor for `input`. \ | ||
| `inverse_indices` is provided only if `return_inverse` \ | ||
| is True. `counts` is provided only if `return_counts` is True. | ||
|
|
||
| Examples: | ||
| .. code-block:: python | ||
|
|
||
| >>> import paddle | ||
|
|
||
| >>> x = paddle.to_tensor([2, 3, 3, 1, 5, 3]) | ||
| >>> unique = paddle.compat.unique(x) | ||
| >>> print(unique) | ||
| Tensor(shape=[4], dtype=int64, place=Place(cpu), stop_gradient=True, | ||
| [1, 2, 3, 5]) | ||
|
|
||
| >>> _, inverse_indices, counts = paddle.compat.unique(x, return_inverse=True, return_counts=True) | ||
| >>> print(inverse_indices) | ||
| Tensor(shape=[6], dtype=int64, place=Place(cpu), stop_gradient=True, | ||
| [1, 2, 2, 0, 3, 2]) | ||
| >>> print(counts) | ||
| Tensor(shape=[4], dtype=int64, place=Place(cpu), stop_gradient=True, | ||
| [1, 1, 3, 1]) | ||
|
|
||
| >>> x = paddle.to_tensor([[2, 1, 3], [3, 0, 1], [2, 1, 3]]) | ||
| >>> unique = paddle.compat.unique(x) | ||
| >>> print(unique) | ||
| Tensor(shape=[4], dtype=int64, place=Place(cpu), stop_gradient=True, | ||
| [0, 1, 2, 3]) | ||
|
|
||
| >>> unique = paddle.compat.unique(x, dim=0) | ||
| >>> print(unique) | ||
| Tensor(shape=[2, 3], dtype=int64, place=Place(cpu), stop_gradient=True, | ||
| [[2, 1, 3], | ||
| [3, 0, 1]]) | ||
| """ | ||
| return paddle.unique( | ||
| input, | ||
| return_inverse=return_inverse, | ||
| return_counts=return_counts, | ||
| axis=dim, | ||
| sorted=sorted, | ||
| ) | ||
|
|
||
|
|
||
| @ForbidKeywordsDecorator( | ||
| illegal_keys={"x", "num_or_sections", "axis", "name"}, | ||
| func_name="paddle.compat.split", | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3672,6 +3672,7 @@ def unique( | |
| return_counts: Literal[True] = ..., | ||
| axis: int | None = ..., | ||
| dtype: DTypeLike = ..., | ||
| sorted: bool = ..., | ||
| name: str | None = ..., | ||
| ) -> tuple[Tensor, Tensor, Tensor, Tensor]: ... | ||
|
|
||
|
|
@@ -3684,6 +3685,7 @@ def unique( | |
| return_counts: Literal[True] = ..., | ||
| axis: int | None = ..., | ||
| dtype: DTypeLike = ..., | ||
| sorted: bool = ..., | ||
| name: str | None = ..., | ||
| ) -> tuple[Tensor, Tensor, Tensor]: ... | ||
|
|
||
|
|
@@ -3696,6 +3698,7 @@ def unique( | |
| return_counts: Literal[True] = ..., | ||
| axis: int | None = ..., | ||
| dtype: DTypeLike = ..., | ||
| sorted: bool = ..., | ||
| name: str | None = ..., | ||
| ) -> tuple[Tensor, Tensor, Tensor]: ... | ||
|
|
||
|
|
@@ -3708,6 +3711,7 @@ def unique( | |
| return_counts: Literal[False] = ..., | ||
| axis: int | None = ..., | ||
| dtype: DTypeLike = ..., | ||
| sorted: bool = ..., | ||
| name: str | None = ..., | ||
| ) -> tuple[Tensor, Tensor, Tensor]: ... | ||
|
|
||
|
|
@@ -3720,6 +3724,7 @@ def unique( | |
| return_counts: Literal[True] = ..., | ||
| axis: int | None = ..., | ||
| dtype: DTypeLike = ..., | ||
| sorted: bool = ..., | ||
| name: str | None = ..., | ||
| ) -> tuple[Tensor, Tensor]: ... | ||
|
|
||
|
|
@@ -3732,6 +3737,7 @@ def unique( | |
| return_counts: Literal[False] = ..., | ||
| axis: int | None = ..., | ||
| dtype: DTypeLike = ..., | ||
| sorted: bool = ..., | ||
| name: str | None = ..., | ||
| ) -> tuple[Tensor, Tensor]: ... | ||
|
|
||
|
|
@@ -3744,6 +3750,7 @@ def unique( | |
| return_counts: Literal[False] = ..., | ||
| axis: int | None = ..., | ||
| dtype: DTypeLike = ..., | ||
| sorted: bool = ..., | ||
| name: str | None = ..., | ||
| ) -> tuple[Tensor, Tensor]: ... | ||
|
|
||
|
|
@@ -3756,6 +3763,7 @@ def unique( | |
| return_counts: Literal[False] = ..., | ||
| axis: int | None = ..., | ||
| dtype: DTypeLike = ..., | ||
| sorted: bool = ..., | ||
| name: str | None = ..., | ||
| ) -> Tensor: ... | ||
|
|
||
|
|
@@ -3768,6 +3776,7 @@ def unique( | |
| return_counts: bool = False, | ||
| axis: int | None = ..., | ||
| dtype: DTypeLike = ..., | ||
| sorted: bool = ..., | ||
| name: str | None = ..., | ||
| ) -> Tensor | tuple[Tensor, ...]: ... | ||
|
|
||
|
|
@@ -3779,6 +3788,7 @@ def unique( | |
| return_counts=False, | ||
| axis=None, | ||
| dtype="int64", | ||
| sorted=True, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 这个目前应该无法实现 API完全一致吧,参数顺序不同。 group_norm也有这个问题。不过这个没法判断数据类型了,只能新增加一个paddle.compat.unique了?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 好的那增加paddle.compat.unique
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @zhwesky2010 已增加paddle.compat.unique CI完成,PaConvert PaddlePaddle/PaConvert#758 修改测试通过
co63oc marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| name=None, | ||
| ): | ||
| r""" | ||
|
|
@@ -3795,6 +3805,7 @@ def unique( | |
| Default: None. | ||
| dtype(str|paddle.dtype|np.dtype, optional): The date type of `indices` or `inverse` tensor: int32 or int64. | ||
| Default: int64. | ||
| sorted(bool, optional): Does not affect the return result, same as PyTorch. | ||
| name(str|None, optional): Name for the operation. For more information, please refer to | ||
| :ref:`api_guide_Name`. Default: None. | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| # Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved. | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
|
|
||
| import unittest | ||
|
|
||
| import numpy as np | ||
|
|
||
| import paddle | ||
| from paddle import base | ||
|
|
||
|
|
||
| class TestCompatUniqueAPI(unittest.TestCase): | ||
| def test_basic(self): | ||
| paddle.disable_static() | ||
| x = paddle.to_tensor([2, 3, 3, 1, 5, 3]) | ||
| result = paddle.compat.unique(x) | ||
| expected = paddle.to_tensor([1, 2, 3, 5], dtype='int64') | ||
| np.testing.assert_allclose(result.numpy(), expected.numpy()) | ||
|
|
||
| _, inverse_indices, counts = paddle.compat.unique( | ||
| x, return_inverse=True, return_counts=True | ||
| ) | ||
| expected_indices = paddle.to_tensor([1, 2, 2, 0, 3, 2], dtype='int64') | ||
| expected_counts = paddle.to_tensor([1, 1, 3, 1], dtype='int64') | ||
| np.testing.assert_allclose( | ||
| inverse_indices.numpy(), expected_indices.numpy() | ||
| ) | ||
| np.testing.assert_allclose(counts.numpy(), expected_counts.numpy()) | ||
|
|
||
| x = paddle.to_tensor([[2, 1, 3], [3, 0, 1], [2, 1, 3]]) | ||
| result = paddle.compat.unique(x) | ||
| expected = paddle.to_tensor([0, 1, 2, 3], dtype='int64') | ||
| np.testing.assert_allclose(result.numpy(), expected.numpy()) | ||
| paddle.enable_static() | ||
|
|
||
| def test_static(self): | ||
| paddle.enable_static() | ||
|
|
||
| with paddle.static.program_guard( | ||
| paddle.static.Program(), paddle.static.Program() | ||
| ): | ||
| x = paddle.static.data(name='input', shape=[6], dtype='int64') | ||
| out, inverse_indices, counts = paddle.compat.unique( | ||
| x, return_inverse=True, return_counts=True | ||
| ) | ||
|
|
||
| exe = base.Executor(base.CPUPlace()) | ||
| x_data = np.array([2, 3, 3, 1, 5, 3], dtype='int64') | ||
| result = exe.run( | ||
| feed={'input': x_data}, | ||
| fetch_list=[out, inverse_indices, counts], | ||
| ) | ||
|
|
||
| np.testing.assert_allclose(result[1], [1, 2, 2, 0, 3, 2]) | ||
| np.testing.assert_allclose(result[2], [1, 1, 3, 1]) | ||
|
|
||
| with paddle.static.program_guard( | ||
| paddle.static.Program(), paddle.static.Program() | ||
| ): | ||
| x = paddle.static.data(name='input', shape=[3, 3], dtype='int64') | ||
| out = paddle.compat.unique(x) | ||
|
|
||
| exe = base.Executor(base.CPUPlace()) | ||
| x_data = np.array([[2, 1, 3], [3, 0, 1], [2, 1, 3]], dtype='int64') | ||
| result = exe.run(feed={'input': x_data}, fetch_list=[out]) | ||
|
|
||
| expected = np.array([0, 1, 2, 3], dtype='int64') | ||
| np.testing.assert_allclose(result[0], expected) | ||
|
|
||
| paddle.disable_static() | ||
|
|
||
|
|
||
| if __name__ == '__main__': | ||
| unittest.main() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
需要添加类型提示
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
再提交PR加上
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个急么?为啥要等下个 PR?赶发版还是啥?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
如果修改较多,CI不容易成功,所以拆为多个PR修改
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
啊?这个 PR 涉及 API 变动,什么时候这个也要拆了?有这时间 CI 都过完了
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
已修改