From 8af250efc9ed6af24467905d4ebadb47a781fe42 Mon Sep 17 00:00:00 2001 From: co63oc <4617245+co63oc@users.noreply.github.com> Date: Wed, 29 Jul 2026 11:12:02 +0800 Subject: [PATCH 1/3] [SWE-Paddle] Add task PaddlePaddle__Paddle-74305 --- .../PaddlePaddle__Paddle-74305/README.md | 52 +++++++++++++++++++ .../environment/README.md | 37 +++++++++++++ .../PaddlePaddle__Paddle-74305/instruction.md | 39 ++++++++++++++ .../PaddlePaddle__Paddle-74305/proposal.md | 21 ++++---- .../solution/code.patch | 27 ++++++++++ .../tests/test.patch | 20 +++++++ .../PaddlePaddle__Paddle-74305/tests/test.sh | 4 ++ 7 files changed, 189 insertions(+), 11 deletions(-) create mode 100644 swe-paddle/tasks/PaddlePaddle__Paddle-74305/README.md create mode 100644 swe-paddle/tasks/PaddlePaddle__Paddle-74305/environment/README.md create mode 100644 swe-paddle/tasks/PaddlePaddle__Paddle-74305/instruction.md create mode 100644 swe-paddle/tasks/PaddlePaddle__Paddle-74305/solution/code.patch create mode 100644 swe-paddle/tasks/PaddlePaddle__Paddle-74305/tests/test.patch create mode 100644 swe-paddle/tasks/PaddlePaddle__Paddle-74305/tests/test.sh diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-74305/README.md b/swe-paddle/tasks/PaddlePaddle__Paddle-74305/README.md new file mode 100644 index 000000000..fad1d6204 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-74305/README.md @@ -0,0 +1,52 @@ +# PaddlePaddle__Paddle-74305 + +This directory converts Paddle PR #74305 into a SWE-Paddle community task candidate. + +## Source + +| Field | Value | +| --- | --- | +| Repo | `PaddlePaddle/Paddle` | +| PR | [74305](https://github.com/PaddlePaddle/Paddle/pull/74305) | +| PR title | `[0-size Tensor No.354、355] Add 0-size Tensor support for unique` | +| Base commit | `2e4a7184e806f1780f7695be46952d651993ed4e` | +| Gold commit | `28db7b832e42f69f48c3f95d651ae57e961aa433` | +| Merged at | `2025-07-31` | +| Task type | `bug_fix` | +| Resource | CPU | +| Scope | Python Tensor API | + +## Summary + +Fix `paddle.unique` to correctly handle 0-size tensors in dynamic mode. + +## Why This Is A Good SWE-Paddle Candidate + +- It is derived from a merged Paddle bug-fix PR rather than a synthetic issue. +- The target behavior is isolated to the Python Tensor API and does not require rebuilding C++ kernels. +- The failure is deterministic: the base revision fails when processing 0-size tensors in dynamic mode. +- The task has clear regression coverage for existing non-zero-size behavior. +- The task runs on CPU and does not require distributed execution, external services, or additional datasets. + +## Files + +- `proposal.md`: candidate proposal for maintainer triage. +- `instruction.md`: self-contained problem statement for the coding agent. +- `solution/code.patch`: gold implementation patch. +- `tests/test.patch`: tests exposing the target behavior. +- `tests/test.sh`: minimal target test command. +- `environment/README.md`: environment and reproduction notes. + +## Verification + +```bash +bash tests/test.sh +``` + +Expected behavior: + +| Revision state | Existing behavior (P2P) | unique F2P | +| --- | ---: | ---: | +| Base + `tests/test.patch` | PASS | FAIL | +| Base + `tests/test.patch` + `solution/code.patch` | PASS | PASS | +PASS | PASS | diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-74305/environment/README.md b/swe-paddle/tasks/PaddlePaddle__Paddle-74305/environment/README.md new file mode 100644 index 000000000..521dec5aa --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-74305/environment/README.md @@ -0,0 +1,37 @@ +# Environment Notes + +## Expected Environment + +- Repository: `PaddlePaddle/Paddle` +- Base commit: `2e4a7184e806f1780f7695be46952d651993ed4e` +- Gold commit: `28db7b832e42f69f48c3f95d651ae57e961aa433` +- Resource: CPU +- GPU required: no +- Patch type: Python-only +- Python dependencies: PaddlePaddle, NumPy, pytest + +The verifier should execute against the Paddle source revision represented by the selected patch state. A source build is not required when an equivalent Python overlay is available and the underlying runtime remains API-compatible. + +## Run Order + +1. Check out `PaddlePaddle/Paddle` at the base commit. +2. Apply `tests/test.patch`. +3. Run the P2P tests; existing non-zero-size behavior should pass. +4. Run the 0-size tensor tests; the target case should fail before the fix. +5. Apply `solution/code.patch`. +6. Run `bash tests/test.sh`; all target tests should pass. + +## Minimal Test Command + +```bash +bash tests/test.sh +``` + +## Expected Matrix + +| Revision state | P2P | unique F2P | +| --- | ---: | ---: | +| Base + test patch | PASS | FAIL | +| Base + test patch + solution patch | PASS | PASS | + +No GPU, distributed runtime, external service, or additional dataset is required. diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-74305/instruction.md b/swe-paddle/tasks/PaddlePaddle__Paddle-74305/instruction.md new file mode 100644 index 000000000..13c55f06b --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-74305/instruction.md @@ -0,0 +1,39 @@ +# 修复 `paddle.unique` 对 0-size Tensor 的处理 + +## 详细描述 + +当 `paddle.unique(x)` 的输入 `x` 中存在大小为 `0` 的 dimension,即 `x.numel() == 0` 时,当前实现在动态图模式下会直接进入底层算子,导致报错。 + +典型表现包括: + +- 底层算子在处理 0-size tensor 时 shape 推断异常 +- 调用失败并抛出与 shape 相关的错误 + +例如: + +```python +import numpy as np +import paddle + +paddle.disable_static() +x = paddle.to_tensor(np.random.randint(0, 10, (0, 2))) +out = paddle.unique(x) +``` + +上述调用中 `x` 的 shape 为 `[0, 2]`,不包含任何元素。按照 API semantics,当输入 tensor 的 numel 为 0 时,不存在需要去重的元素,因此该调用应正常完成并返回空 tensor。 + +当前 Python 层在进入底层 unique kernel 之前,没有对 0-size tensor 输入进行显式的早期返回处理。当输入 tensor 的任意维度为 0 时,应直接构造并返回正确 shape 的空 tensor,同时正确处理 `return_inverse`、`return_counts`、`return_index` 等可选返回值。 + +## 验收说明 + +- 当输入 tensor 的 numel 为 0 时,`paddle.unique` 应正常完成,返回正确 shape 的空 tensor +- 返回的 out tensor 应保持与输入相同的 dtype +- 当启用 `return_inverse`、`return_counts` 或 `return_index` 时,对应的辅助输出也应为空 tensor,dtype 为 int32 或 int64(根据 dtype 参数决定) +- 非 0-size tensor 输入下的去重行为不得退化 + +## 技术要求 + +- 熟悉 Python 和 Paddle Tensor API +- 了解 Tensor shape、0-size Tensor 和动态图执行路径 +- 了解 unique 算子的多返回值语义 +- 了解 Paddle 动态图和静态图执行路径的区别 diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-74305/proposal.md b/swe-paddle/tasks/PaddlePaddle__Paddle-74305/proposal.md index 9c622db8a..d88a99f7b 100644 --- a/swe-paddle/tasks/PaddlePaddle__Paddle-74305/proposal.md +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-74305/proposal.md @@ -11,31 +11,30 @@ ## 2. 问题一句话 -`paddle.unique` 和 `paddle.unique_consecutive` 在动态图模式下对 0-size tensor(任意维度含有 0)的输入缺少显式处理,导致进入底层算子时出错,需要补齐 0-size tensor 支持。 +`paddle.unique` 在动态图模式下对 0-size tensor(任意维度含有 0)的输入缺少显式处理,导致进入底层算子时出错,需要补齐 0-size tensor 支持。 ## 3. 为什么适合作为 SWE-Paddle 样本 -- **真实性**:该问题来自 Paddle 的「0-size Tensor 机制建设」系列任务,是真实研发需求,目标是为 `unique` 和 `unique_consecutive` 算子补齐 0-size tensor 支持。 +- **真实性**:该问题来自 Paddle 的「0-size Tensor 机制建设」系列任务,是真实研发需求,目标是为 `unique` 算子补齐 0-size tensor 支持。 - **代表性**:覆盖 Python API 层面的算子边界处理,涉及 dynamic mode 下的 tensor 维度判断和多返回值语义(inverse、counts、index),是 Paddle API 算子机制增强的典型样本。 - **边界清楚**:目标仅限 0-size tensor 输入的动态图早期返回逻辑,返回值为空 tensor 且保持 dtype 一致;正向非零尺寸输入不应受影响。 -- **非平凡性**:修复需要在 `manipulation.py` 中同时为两个 API 分别添加 `math.prod(x.shape) == 0` 的早期返回分支,涉及 axis 为 `[]` 的展平情况、返回 dtype(int32/int64)判断、以及多返回值解包,不是简单机械修改。 -- **回归护栏明确**:目标 F2P 可覆盖 0-size tensor 输入的 `unique` 和 `unique_consecutive` 动态图调用;同文件已有的标准唯一化算子测试用例可作为 P2P 护栏。 +- **非平凡性**:修复需要在 `manipulation.py` 中为 `unique` API 添加 `math.prod(x.shape) == 0` 的早期返回分支,涉及返回 dtype(int32/int64)判断、以及多返回值解包,不是简单机械修改。 +- **回归护栏明确**:目标 F2P 可覆盖 0-size tensor 输入的 `unique` 动态图调用;同文件已有的标准唯一化算子测试用例可作为 P2P 护栏。 ## 4. 任务类型和标签 - 任务类型:`bug_fix` - 执行后端:`cpu` - 设备范围:`cpu_only` -- 模块标签:`[python_api, manipulation, 0-size_tensor, unique, unique_consecutive, dynamic_mode]` +- 模块标签:`[python_api, manipulation, 0-size_tensor, unique, dynamic_mode]` ## 5. 验证思路 - 目标测试命令:`bash tests/test.sh` - 目标测试文件: - `test/legacy_test/test_unique.py`(`TestUniqueAPI_ZeroSize`) - - `test/legacy_test/test_unique_consecutive_op.py`(`TestUniqueConsecutive_ZeroSize`) -- P2P 候选:同文件中已有的 `TestUniqueAPI`、`TestUniqueConsecutive` 等标准唯一化算子测试用例。 -- 修复前预期:`base_commit` + `tests/test.patch` 后,0-size tensor 输入在 `paddle.unique` / `paddle.unique_consecutive` 的动态图调用中失败(进入底层算子时 shape 推断异常)。 +- P2P 候选:同文件中已有的 `TestUniqueAPI` 等标准唯一化算子测试用例。 +- 修复前预期:`base_commit` + `tests/test.patch` 后,0-size tensor 输入在 `paddle.unique` 的动态图调用中失败(进入底层算子时 shape 推断异常)。 - 修复后预期:继续应用 `solution/code.patch` 后,0-size tensor 输入返回正确的空 tensor(shape 与预期一致),同时支持 `return_inverse`、`return_counts`、`return_index` 等可选输出,P2P 存量测试仍然通过。 ## 6. 环境与资源 @@ -52,8 +51,8 @@ ## 7. 风险自查 -- 泄露风险:正式 `instruction.md` 只描述「动态图下 unique / unique_consecutive 对 0-size tensor 输入的行为异常」,不指出具体 `math.prod(x.shape) == 0` 分支逻辑或具体代码位置。 +- 泄露风险:正式 `instruction.md` 只描述「动态图下 unique 对 0-size tensor 输入的行为异常」,不指出具体 `math.prod(x.shape) == 0` 分支逻辑或具体代码位置。 - 环境风险:低。任务为 Python-only,无需特殊镜像、外部服务或不可固定下载。 - flaky 风险:低。测试使用固定的 0-size tensor 构造,不依赖随机数差异或多设备同步。 -- 拆分风险:低。该 PR 目标集中在 `manipulation.py` 中两个 API 的 0-size 早期返回,测试也明确指向 unique 和 unique_consecutive 的零尺寸分支,适合作为一个独立样本。 -- 其他不确定点:完整任务包阶段应确认新增 F2P(`TestUniqueAPI_ZeroSize`、`TestUniqueConsecutive_ZeroSize`)在 `base_commit` 上确实失败,并选择同文件中已有的 `TestUniqueAPI`、`TestUniqueConsecutive` 等标准测试用例作为在 base 与修复后都稳定通过的 P2P nodeid。 +- 拆分风险:低。该 PR 目标集中在 `manipulation.py` 中 `unique` API 的 0-size 早期返回,测试也明确指向 unique 的零尺寸分支,适合作为一个独立样本。 +- 其他不确定点:完整任务包阶段应确认新增 F2P(`TestUniqueAPI_ZeroSize`)在 `base_commit` 上确实失败,并选择同文件中已有的 `TestUniqueAPI` 等标准测试用例作为在 base 与修复后都稳定通过的 P2P nodeid。 diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-74305/solution/code.patch b/swe-paddle/tasks/PaddlePaddle__Paddle-74305/solution/code.patch new file mode 100644 index 000000000..0a415d323 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-74305/solution/code.patch @@ -0,0 +1,27 @@ +diff --git a/python/paddle/tensor/manipulation.py b/python/paddle/tensor/manipulation.py +index 6048900844ce0..7341ed30d0cbe 100644 +--- a/python/paddle/tensor/manipulation.py ++++ b/python/paddle/tensor/manipulation.py +@@ -3738,6 +3756,22 @@ def unique( + axis = [axis] + attr_dtype = convert_np_dtype_to_dtype_(dtype) + if in_dynamic_mode(): ++ if math.prod(x.shape) == 0: ++ outs = [x.clone()] ++ if dtype == 'int32' or dtype == paddle.int32: ++ return_dtype = paddle.int32 ++ else: ++ return_dtype = paddle.int64 ++ if return_index: ++ outs.append(paddle.to_tensor([], dtype=return_dtype)) ++ if return_inverse: ++ outs.append(paddle.to_tensor([], dtype=return_dtype)) ++ if return_counts: ++ outs.append(paddle.to_tensor([], dtype=return_dtype)) ++ if len(outs) == 1: ++ return outs[0] ++ return tuple(outs) ++ + out, indices, inverse, counts = _C_ops.unique( + x, return_index, return_inverse, return_counts, axis, attr_dtype + ) diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-74305/tests/test.patch b/swe-paddle/tasks/PaddlePaddle__Paddle-74305/tests/test.patch new file mode 100644 index 000000000..bc38b2323 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-74305/tests/test.patch @@ -0,0 +1,20 @@ +diff --git a/test/legacy_test/test_unique.py b/test/legacy_test/test_unique.py +index 1ea524169f378..cb2efccb122f6 100644 +--- a/test/legacy_test/test_unique.py ++++ b/test/legacy_test/test_unique.py +@@ -482,5 +482,15 @@ def test_dtype(): + self.assertRaises(TypeError, test_axis) + + ++class TestUniqueAPI_ZeroSize(unittest.TestCase): ++ def test_dygraph_api_out(self): ++ paddle.disable_static() ++ x_data = np.random.randint(0, 10, (0, 2)) ++ x = paddle.to_tensor(x_data) ++ out = paddle.unique(x) ++ expected_out = np.random.random([0, 2]) ++ np.testing.assert_allclose(out.numpy(), expected_out) ++ ++ + if __name__ == "__main__": + unittest.main() diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-74305/tests/test.sh b/swe-paddle/tasks/PaddlePaddle__Paddle-74305/tests/test.sh new file mode 100644 index 000000000..aae0584e4 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-74305/tests/test.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail + +python -m pytest test/legacy_test/test_unique.py::TestUniqueAPI_ZeroSize -q From 2d79698c8fd5b5f9ba62b82d3e4b6cfd65e0aa6c Mon Sep 17 00:00:00 2001 From: co63oc <4617245+co63oc@users.noreply.github.com> Date: Wed, 29 Jul 2026 11:42:25 +0800 Subject: [PATCH 2/3] update --- swe-paddle/tasks/PaddlePaddle__Paddle-74305/proposal.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-74305/proposal.md b/swe-paddle/tasks/PaddlePaddle__Paddle-74305/proposal.md index d88a99f7b..3722c2443 100644 --- a/swe-paddle/tasks/PaddlePaddle__Paddle-74305/proposal.md +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-74305/proposal.md @@ -18,7 +18,7 @@ - **真实性**:该问题来自 Paddle 的「0-size Tensor 机制建设」系列任务,是真实研发需求,目标是为 `unique` 算子补齐 0-size tensor 支持。 - **代表性**:覆盖 Python API 层面的算子边界处理,涉及 dynamic mode 下的 tensor 维度判断和多返回值语义(inverse、counts、index),是 Paddle API 算子机制增强的典型样本。 - **边界清楚**:目标仅限 0-size tensor 输入的动态图早期返回逻辑,返回值为空 tensor 且保持 dtype 一致;正向非零尺寸输入不应受影响。 -- **非平凡性**:修复需要在 `manipulation.py` 中为 `unique` API 添加 `math.prod(x.shape) == 0` 的早期返回分支,涉及返回 dtype(int32/int64)判断、以及多返回值解包,不是简单机械修改。 +- **非平凡性**:修复需要在 `manipulation.py` 中为 `unique` API 添加 `math.prod(x.shape) == 0` 的早期返回分支,涉及 axis 为 `[]` 的展平情况、返回 dtype(int32/int64)判断、以及多返回值解包,不是简单机械修改。 - **回归护栏明确**:目标 F2P 可覆盖 0-size tensor 输入的 `unique` 动态图调用;同文件已有的标准唯一化算子测试用例可作为 P2P 护栏。 ## 4. 任务类型和标签 From 8f2604f27f7c82210347067d149eaea7e49fa13c Mon Sep 17 00:00:00 2001 From: co63oc <4617245+co63oc@users.noreply.github.com> Date: Wed, 29 Jul 2026 17:39:10 +0800 Subject: [PATCH 3/3] Add P2P tests for TestUniqueOp --- swe-paddle/tasks/PaddlePaddle__Paddle-74305/tests/test.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-74305/tests/test.sh b/swe-paddle/tasks/PaddlePaddle__Paddle-74305/tests/test.sh index aae0584e4..61cc45a26 100644 --- a/swe-paddle/tasks/PaddlePaddle__Paddle-74305/tests/test.sh +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-74305/tests/test.sh @@ -1,4 +1,8 @@ #!/usr/bin/env bash set -euo pipefail +# P2P tests (pass-to-pass) +python -m pytest test/legacy_test/test_unique.py::TestUniqueOp -q + +# F2P tests (fail-to-pass) python -m pytest test/legacy_test/test_unique.py::TestUniqueAPI_ZeroSize -q