Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
47 changes: 47 additions & 0 deletions swe-paddle/tasks/PaddlePaddle__Paddle-78138/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# PaddlePaddle__Paddle-78138

This directory converts Paddle PR #78138 into a focused SWE-Paddle community task.

## Source

| Field | Value |
| --- | --- |
| Repository | `PaddlePaddle/Paddle` |
| PR | [#78138](https://github.com/PaddlePaddle/Paddle/pull/78138) |
| PR title | `[API Compatibility] cpp sink paddle.nn.functional.pixel_shuffle -part` |
| Base commit | `555b4a95615a35b301f348e081e56435a6d75da6` |
| Squash commit | `01b7cdd95813a88bca9569f55328c4f6f0e675cb` |
| Merged at | `2026-03-11T02:13:30Z` |
| Task type | `feature_enhancement` |
| Resource | CPU with a mandatory source rebuild |

## Behavioral Summary

The task moves `paddle.nn.functional.pixel_shuffle` to the generated C++-sink API path while preserving its public behavior. Calls using a positional input Tensor or the existing `x=` keyword remain valid, and the PyTorch-compatible `input=` alias is added. Positional, `x=`, and `input=` forms must produce identical results in dynamic and static graph modes.

Existing pixel-shuffle behavior remains unchanged, including output values and shape, `NCHW`/`NHWC` layouts, supported dtypes, gradients, and argument validation.

The squash commit also reorganized `paddle.unique` documentation and tests. Those independent changes are intentionally excluded from this focused task.

## Artifacts

- `proposal.md`: approved task proposal and scope.
- `instruction.md`: self-contained observable requirements for the solver.
- `solution/code.patch`: exact base-to-gold changes for the five task-relevant production files.
- `tests/test.patch`: focused compatibility import and `TestPixelShuffleAPI_Compatibility` class only.
- `tests/test.sh`: strict F2P compatibility test followed by the complete P2P pixel-shuffle operator module.
- `environment/README.md`: base revision, build requirements, patch order, commands, and risks.

## Verification Overview

Package validation is performed from a clean snapshot at the exact base commit. It checks artifact presence, shell syntax, patch whitespace and application order, byte equality of all five production results against the squash commit, focused test equality against gold, exclusion of the unrelated `unique` changes, and Python syntax.

Runtime verification requires a Paddle package built from the patched source tree after code generation. A prebuilt wheel or a build from another revision is not sufficient for the generated binding changes.

Local package-level validation passed. Runtime target tests were not run because the available Paddle installation reports commit `d9242d558766b5d24fa3231a798864c37cdd5cda`, not an exact build of this task's patched base; source-build execution therefore remains unverified locally.

From the root of a rebuilt Paddle checkout with both patches applied:

```bash
bash tests/test.sh
```
64 changes: 64 additions & 0 deletions swe-paddle/tasks/PaddlePaddle__Paddle-78138/environment/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Environment Notes

## Expected Environment

- Repository: `PaddlePaddle/Paddle`
- Base commit: `555b4a95615a35b301f348e081e56435a6d75da6`
- Gold commit: `01b7cdd95813a88bca9569f55328c4f6f0e675cb`
- Resource: CPU
- GPU required: no
- Suggested platform: Linux x86_64 with a Python version, CMake, C++ compiler, NumPy, and pytest supported by the base revision.
- Container or pinned external wheel: none provided.

## Mandatory Build Requirement

A source rebuild is required. The solution changes pybind C++ code and Python API YAML consumed by Paddle's code-generation and compilation pipeline. Apply the patches in the source checkout, rerun the normal code-generation/build process, and ensure the tested Python interpreter imports the resulting package.

A Python source overlay, an arbitrary installed wheel, or a stale build directory cannot verify this task. A locally built wheel is acceptable only when it was produced from the exact patched base revision.

## Patch And Test Order

Run from the root of a clean Paddle checkout at the exact base commit:

1. Apply `tests/test.patch`.
2. Build the base-with-tests state if checking F2P behavior.
3. Run the compatibility class. Positional and `x=` calls should remain valid, while `input=` should fail in both dynamic and static graph paths before the solution.
4. Apply `solution/code.patch`.
5. Regenerate and rebuild Paddle from source.
6. Run `bash tests/test.sh`. Both the F2P compatibility class and the complete P2P operator module should pass.

Example patch commands when the task package is available at `$TASK_DIR`:

```bash
git apply "$TASK_DIR/tests/test.patch"
git apply "$TASK_DIR/solution/code.patch"
```

## Target Commands

```bash
python -m pytest \
test/legacy_test/test_api_compatibility.py::TestPixelShuffleAPI_Compatibility \
-q

python -m pytest test/legacy_test/test_pixel_shuffle_op.py -q
```

The equivalent strict wrapper is:

```bash
bash tests/test.sh
```

## Verification Scope

- F2P: `TestPixelShuffleAPI_Compatibility`, covering positional, `x=`, and `input=` calls in dynamic and static graph modes.
- P2P: the complete `test/legacy_test/test_pixel_shuffle_op.py` module, covering numerical output, shape/layout, dtypes, gradients, and validation semantics.

## Known Risks

- Generated bindings can remain stale if code generation or compilation is skipped.
- Importing an unrelated installed Paddle wheel can produce misleading results; confirm `paddle.__file__` points to the intended build.
- Patch context and generated API metadata are tied to the exact base commit.
- CPU execution is sufficient, but Paddle's full source build still requires the normal native build toolchain.
- The upstream squash commit contains unrelated `paddle.unique` cleanup. It is deliberately absent from both task patches.
19 changes: 19 additions & 0 deletions swe-paddle/tasks/PaddlePaddle__Paddle-78138/instruction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# 完善 pixel_shuffle 的 API 兼容性

`paddle.nn.functional.pixel_shuffle` 需要在保持现有算子语义的同时,支持与 PyTorch 一致的输入参数别名。

## 行为要求

- 继续支持将输入 Tensor 作为第一个位置参数传入。
- 继续支持通过关键字参数 `x` 传入输入 Tensor。
- 新增关键字参数别名 `input`;它与 `x` 表示同一个输入参数。
- `upscale_factor` 继续支持现有的位置参数和关键字参数调用形式。
- 位置参数、`x=` 和 `input=` 三种输入形式在动态图和静态图中均可用,并产生完全相同的结果。
- 保持 `data_format` 和 `name` 的现有接口行为。
- `data_format` 只接受 `NCHW` 或 `NHWC`;非法值应继续抛出参数错误。
- 保持 pixel shuffle 的原有数值、输出形状、布局、数据类型、梯度和输入校验语义,不引入算子行为变化。
- 为公开 API 提供与上述签名和行为一致的英文文档。

## 验收标准

在 CPU 环境中,兼容性测试应覆盖动态图和静态图下的位置参数、`x=` 与 `input=` 调用并比较输出。现有完整 pixel-shuffle 算子测试也必须继续通过,以验证数值结果、形状和布局、数据类型、梯度以及错误检查没有回归。
181 changes: 181 additions & 0 deletions swe-paddle/tasks/PaddlePaddle__Paddle-78138/solution/code.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
diff --git a/paddle/fluid/pybind/arg_pre_process.cc b/paddle/fluid/pybind/arg_pre_process.cc
index 003223e871..5cdee6bf04 100644
--- a/paddle/fluid/pybind/arg_pre_process.cc
+++ b/paddle/fluid/pybind/arg_pre_process.cc
@@ -554,6 +554,15 @@ void BaddbmmPreProcess(pir::Value* input, pir::Value* x, pir::Value* y) {
}
}

+void PixelShufflePreProcess(std::string* data_format) {
+ if (*data_format != "NCHW" && *data_format != "NHWC") {
+ PADDLE_THROW(common::errors::InvalidArgument(
+ "Attr(data_format) should be 'NCHW' or 'NHWC'."
+ "But receive Attr(data_format): %s",
+ *data_format));
+ }
+}
+
// Renorm preprocessing: handle negative axis
void NegativeAxisPreProcess(Tensor* x, int* axis) {
int rank = x->dims().size();
diff --git a/paddle/fluid/pybind/arg_pre_process.h b/paddle/fluid/pybind/arg_pre_process.h
index 9df7054188..9e2d0d0e35 100644
--- a/paddle/fluid/pybind/arg_pre_process.h
+++ b/paddle/fluid/pybind/arg_pre_process.h
@@ -80,6 +80,8 @@ void BaddbmmPreProcess(pir::Value* input, pir::Value* x, pir::Value* y);
void NegativeAxisPreProcess(Tensor* x, int* axis);
void NegativeAxisPreProcess(Value* x, int* axis);

+void PixelShufflePreProcess(std::string* data_format);
+
// Inplace API broadcast validation for dygraph
void InplaceShapePreProcess(Tensor* x, Tensor* y);

diff --git a/paddle/phi/ops/yaml/python_api_info.yaml b/paddle/phi/ops/yaml/python_api_info.yaml
index c6619d0fb9..4349c0fdeb 100644
--- a/paddle/phi/ops/yaml/python_api_info.yaml
+++ b/paddle/phi/ops/yaml/python_api_info.yaml
@@ -467,6 +467,13 @@
args_alias :
use_default_mapping : True

+- op : pixel_shuffle
+ name : [paddle.nn.functional.pixel_shuffle]
+ args_alias :
+ use_default_mapping : True
+ pre_process :
+ func : PixelShufflePreProcess(data_format)
+
- op : reciprocal
name : [paddle.reciprocal, paddle.Tensor.reciprocal]
args_alias :
diff --git a/python/paddle/_paddle_docs.py b/python/paddle/_paddle_docs.py
index e38e435ffa..1d20d47735 100644
--- a/python/paddle/_paddle_docs.py
+++ b/python/paddle/_paddle_docs.py
@@ -2247,6 +2247,43 @@ def grid_sample(
""",
)

+add_doc_and_signature(
+ "pixel_shuffle",
+ r"""
+ This API implements pixel shuffle operation.
+ See more details in :ref:`PixelShuffle <api_paddle_nn_PixelShuffle>` .
+
+ Parameters:
+ x (Tensor): 4-D tensor, the data type should be float32 or float64.
+ alias: ``input``.
+ upscale_factor (int): factor to increase spatial resolution.
+ data_format (str, optional): The data format of the input and output data. An optional string from: ``"NCHW"``, ``"NHWC"``. When it is ``"NCHW"``, the data is stored in the order of: [batch_size, input_channels, input_height, input_width]. Default: ``"NCHW"``.
+ name (str|None, optional): Name for the operation (optional, default is None). For more information, please refer to :ref:`api_guide_Name`.
+
+ Returns:
+ Out (Tensor): Reshaped tensor according to the new dimension.
+
+ Examples:
+ .. code-block:: pycon
+
+ >>> import paddle
+ >>> import paddle.nn.functional as F
+
+ >>> x = paddle.randn(shape=[2, 9, 4, 4])
+ >>> out_var = F.pixel_shuffle(x, 3)
+ >>> print(out_var.shape)
+ paddle.Size([2, 1, 12, 12])
+""",
+ """
+def pixel_shuffle(
+ x: Tensor,
+ upscale_factor: int,
+ data_format: DataLayout2D = 'NCHW',
+ name: str | None = None,
+) -> Tensor
+""",
+)
+
add_doc_and_signature(
"gelu",
r"""
diff --git a/python/paddle/nn/functional/vision.py b/python/paddle/nn/functional/vision.py
index 884d6baa2e..01046271ca 100644
--- a/python/paddle/nn/functional/vision.py
+++ b/python/paddle/nn/functional/vision.py
@@ -18,7 +18,10 @@ from typing import TYPE_CHECKING

import paddle
from paddle import _C_ops, in_dynamic_mode
-from paddle._C_ops import grid_sample # noqa: F401
+from paddle._C_ops import (
+ grid_sample, # noqa: F401
+ pixel_shuffle, # noqa: F401
+)
from paddle.base.framework import (
in_dynamic_or_pir_mode,
in_pir_mode,
@@ -153,65 +156,6 @@ def affine_grid(
return out


-def pixel_shuffle(
- x: Tensor,
- upscale_factor: int,
- data_format: DataLayout2D = 'NCHW',
- name: str | None = None,
-) -> Tensor:
- """
- This API implements pixel shuffle operation.
- See more details in :ref:`PixelShuffle <api_paddle_nn_PixelShuffle>` .
-
-
- Parameters:
- x(Tensor): 4-D tensor, the data type should be float32 or float64.
- upscale_factor(int): factor to increase spatial resolution.
- data_format (str, optional): The data format of the input and output data. An optional string from: ``"NCHW"``, ``"NHWC"``. When it is ``"NCHW"``, the data is stored in the order of: [batch_size, input_channels, input_height, input_width]. Default: ``"NCHW"``.
- name (str|None, optional): Name for the operation (optional, default is None). For more information, please refer to :ref:`api_guide_Name`.
-
- Returns:
- Out(tensor): Reshaped tensor according to the new dimension.
-
- Examples:
- .. code-block:: pycon
-
- >>> import paddle
- >>> import paddle.nn.functional as F
-
- >>> x = paddle.randn(shape=[2, 9, 4, 4])
- >>> out_var = F.pixel_shuffle(x, 3)
- >>> print(out_var.shape)
- paddle.Size([2, 1, 12, 12])
- """
- if not isinstance(upscale_factor, int):
- raise TypeError("upscale factor must be int type")
-
- if data_format not in ["NCHW", "NHWC"]:
- raise ValueError(
- "Attr(data_format) should be 'NCHW' or 'NHWC'."
- f"But receive Attr(data_format): {data_format} "
- )
- if in_dynamic_or_pir_mode():
- return _C_ops.pixel_shuffle(x, upscale_factor, data_format)
- else:
- helper = LayerHelper("pixel_shuffle", **locals())
- check_variable_and_dtype(
- x, 'x', ['float16', 'float32', 'float64'], 'pixel_shuffle'
- )
- out = helper.create_variable_for_type_inference(dtype=x.dtype)
- helper.append_op(
- type="pixel_shuffle",
- inputs={"X": x},
- outputs={"Out": out},
- attrs={
- "upscale_factor": upscale_factor,
- "data_format": data_format,
- },
- )
- return out
-
-
@param_one_alias(["x", "input"])
def pixel_unshuffle(
x: Tensor,
82 changes: 82 additions & 0 deletions swe-paddle/tasks/PaddlePaddle__Paddle-78138/tests/test.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
diff --git a/test/legacy_test/test_api_compatibility.py b/test/legacy_test/test_api_compatibility.py
index d47bdb886b..92985565a2 100644
--- a/test/legacy_test/test_api_compatibility.py
+++ b/test/legacy_test/test_api_compatibility.py
@@ -17,6 +17,7 @@ import unittest
import numpy as np

import paddle
+import paddle.nn.functional as F


# Edit By AI Agent
@@ -2466,6 +2467,69 @@ class TestTensorHypotInplace(unittest.TestCase):
paddle.enable_static()


+# Test pixel_shuffle compatibility
+class TestPixelShuffleAPI_Compatibility(unittest.TestCase):
+ def setUp(self):
+ np.random.seed(123)
+ paddle.enable_static()
+ self.shape = [2, 9, 4, 4]
+ self.dtype = 'float32'
+ self.init_data()
+
+ def init_data(self):
+ self.np_input = np.random.randn(*self.shape).astype(self.dtype)
+
+ def test_dygraph_Compatibility(self):
+ paddle.disable_static()
+ x = paddle.to_tensor(self.np_input)
+ paddle_dygraph_out = []
+
+ # Position args
+ out1 = F.pixel_shuffle(x, 3)
+ paddle_dygraph_out.append(out1)
+
+ # Paddle keyword args
+ out2 = F.pixel_shuffle(x=x, upscale_factor=3)
+ paddle_dygraph_out.append(out2)
+
+ # Torch keyword args (input alias)
+ out3 = F.pixel_shuffle(input=x, upscale_factor=3)
+ paddle_dygraph_out.append(out3)
+
+ # Mixed args
+ out4 = F.pixel_shuffle(x, upscale_factor=3)
+ paddle_dygraph_out.append(out4)
+
+ # Verify all outputs match
+ for out in paddle_dygraph_out:
+ np.testing.assert_array_equal(out1.numpy(), out.numpy())
+
+ paddle.enable_static()
+
+ def test_static_Compatibility(self):
+ paddle.enable_static()
+ main = paddle.static.Program()
+ startup = paddle.static.Program()
+ with paddle.base.program_guard(main, startup):
+ x = paddle.static.data(name="x", shape=self.shape, dtype=self.dtype)
+
+ # Position args
+ out1 = F.pixel_shuffle(x, 3)
+ # Paddle keyword args
+ out2 = F.pixel_shuffle(x=x, upscale_factor=3)
+ # Torch keyword args (input alias)
+ out3 = F.pixel_shuffle(input=x, upscale_factor=3)
+
+ exe = paddle.base.Executor(paddle.CPUPlace())
+ fetches = exe.run(
+ main,
+ feed={"x": self.np_input},
+ fetch_list=[out1, out2, out3],
+ )
+ for out in fetches[1:]:
+ np.testing.assert_array_equal(fetches[0], out)
+
+
# Test index_fill compatibility
class TestIndexFillAPI(unittest.TestCase):
def setUp(self):
Loading