diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-74444/README.md b/swe-paddle/tasks/PaddlePaddle__Paddle-74444/README.md new file mode 100644 index 000000000..64ef39eb6 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-74444/README.md @@ -0,0 +1,44 @@ +# PaddlePaddle__Paddle-74444 + +This directory converts Paddle PR #74444 into a SWE-Paddle community task candidate. + +## Source + +| Field | Value | +| --- | --- | +| Repo | `PaddlePaddle/Paddle` | +| PR | [#74444](https://github.com/PaddlePaddle/Paddle/pull/74444) | +| PR title | `[API compatibility] add paddle nn.functional.dropout1d api` | +| Base commit | `607dd38aead3118af96495d50b9829c78b2ecfab` | +| Merged at | `2025-08-08` | +| Task type | `feature_enhancement` | +| Resource | CPU | + +## Summary + +Add the public `paddle.nn.functional.dropout1d` API for channel-wise dropout on 2D and 3D inputs while preserving the behavior of existing dropout helpers. + +## Why This Is A Good SWE-Paddle Candidate + +- The task comes from a merged Paddle API-compatibility PR with only two production Python files. +- The target behavior is externally observable through input-rank validation, channel-axis dropout semantics, and public namespace exposure. +- The fail-to-pass boundary is clear because `dropout1d` is absent at the base commit. +- Existing `dropout2d` behavior can be protected independently with a deterministic P2P test. + +## Files + +- `proposal.md`: candidate proposal for maintainer triage. +- `instruction.md`: self-contained problem statement for the coding agent. +- `solution/code.patch`: production-only gold patch derived from the merged PR. +- `tests/test.patch`: test patch exposing the target behavior. +- `tests/test.sh`: minimal target test command. +- `environment/README.md`: environment notes for reproduction. +- `README.md`: task overview and verification entrypoint. + +## Verification + +```bash +bash tests/test.sh +``` + +Expected behavior: applying `tests/test.patch` to the base commit should fail on the new `dropout1d` behavior while the P2P case remains valid; applying both `tests/test.patch` and `solution/code.patch` should pass all target tests. diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-74444/environment/README.md b/swe-paddle/tasks/PaddlePaddle__Paddle-74444/environment/README.md new file mode 100644 index 000000000..ee4f76738 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-74444/environment/README.md @@ -0,0 +1,27 @@ +# Environment Notes + +This candidate is part of the SWE-Paddle community task set. + +## Expected Environment + +- Repository: `PaddlePaddle/Paddle` +- Base commit: `607dd38aead3118af96495d50b9829c78b2ecfab` +- Resource: CPU +- GPU required: no +- Build path: Paddle source checkout at the base commit. This Python-only task may be verified with an AST overlay and controlled doubles; source build is not required. + +## Run Order + +1. Check out `PaddlePaddle/Paddle` at the base commit. +2. Apply `tests/test.patch`. +3. Run `bash tests/test.sh`; the target behavior should fail before the fix. +4. Apply `solution/code.patch`. +5. Run `bash tests/test.sh` again; the target behavior should pass after the gold patch. + +## Minimal Test Command + +```bash +bash tests/test.sh +``` + +The verifier is responsible for deriving stable F2P and P2P node IDs from repeated runs. diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-74444/instruction.md b/swe-paddle/tasks/PaddlePaddle__Paddle-74444/instruction.md new file mode 100644 index 000000000..1c9060f62 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-74444/instruction.md @@ -0,0 +1,26 @@ +# 新增 `paddle.nn.functional.dropout1d` + +## 详细描述 + +Paddle 目前没有 `paddle.nn.functional.dropout1d`。对于 `[C, L]` 或 `[N, C, L]` 形状的输入,用户无法直接按通道执行 dropout。 + +新增该接口后,训练时以概率 `p` 将整个通道置零,而不是随机对通道中的单个元素置零。输出 shape 应与输入保持一致;`training=False` 时不执行 dropout。 + +该接口只支持二维和三维输入,`p` 必须在 `[0, 1]` 范围内。`inplace` 参数暂时不生效,传入 `inplace=True` 时应给出警告,并按非 `inplace` 方式返回结果。 + +## 验收说明 + +- 可以通过 `paddle.nn.functional.dropout1d` 调用该接口 +- 支持 `[C, L]` 和 `[N, C, L]` 形状的输入 +- 训练时应按通道执行 dropout,并保持输出 shape 不变 +- `training=False` 时,输出应与输入一致 +- `p` 不在 `[0, 1]` 范围内时应报错 +- 输入不是二维或三维 Tensor 时应报错 +- `inplace=True` 时应给出警告,且不修改输入 Tensor +- 现有 `dropout`、`dropout2d` 和 `dropout3d` 的行为保持不变 + +## 技术要求 + +- 熟悉 Python +- 了解 Paddle `nn.functional` API +- 了解普通 dropout 和按通道 dropout 的区别 diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-74444/proposal.md b/swe-paddle/tasks/PaddlePaddle__Paddle-74444/proposal.md new file mode 100644 index 000000000..ba3f402a9 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-74444/proposal.md @@ -0,0 +1,54 @@ +# Task Proposal: PaddlePaddle__Paddle-74444 + +## 1. 来源信息 + +- Instance ID:`PaddlePaddle__Paddle-74444` +- PR 链接:https://github.com/PaddlePaddle/Paddle/pull/74444 +- PR 标题:`[API compatibility] add paddle nn.functional.dropout1d api` +- `base_commit`:`607dd38aead3118af96495d50b9829c78b2ecfab` +- merged 时间:`2025-08-08` +- 你的身份:熟悉该模块的 contributor +- 后续联系人:TBD + +## 2. 问题一句话 + +Paddle 缺少 `paddle.nn.functional.dropout1d`,因此 2D/3D 一维通道特征无法通过兼容 API 执行按通道 dropout。 + +## 3. 为什么适合作为 SWE-Paddle 样本 + +- **真实性**:来源于已合入 Paddle `develop` 的 API compatibility PR。 +- **代表性**:覆盖常见的 `nn.functional` API 扩展以及输入 shape/参数校验契约。 +- **边界清楚**:目标集中在 2D/3D 输入、channel axis、概率范围、`inplace` 兼容处理和 public export。 +- **非平凡性**:2D 输入需要保持用户可见 shape,同时与 3D 输入共享按通道 dropout 语义,并保留既有 dropout helper 行为。 + +## 4. 任务类型和标签 + +- 任务类型:`feature_enhancement` +- 执行后端:`cpu` +- 设备范围:`cpu_only` +- 模块标签:`[nn, functional, dropout, api_compatibility]` + +## 5. 验证思路 + +- 目标测试命令:`bash tests/test.sh` +- 目标测试文件:`test/swe_paddle/test_pr74444_dropout1d.py` +- 修复前预期:已有 `dropout2d` P2P 通过;`dropout1d` 不存在,因此 channel-dropout 行为和输入校验 F2P 失败。 +- 修复后预期:`dropout1d` 在 public namespace 可见,2D/3D 输入均按 channel axis 调用 dropout,错误输入被拒绝,全部测试通过。 +- P2P 候选:执行 checkout 中已有 `dropout2d` 函数体,确认 NCHW/NHWC 的 channel-axis forwarding 未退化。 + +## 6. 环境与资源 + +- 资源需求:CPU +- Paddle 来源:`PaddlePaddle/Paddle` source checkout at `base_commit` +- 是否能提供 Docker:暂无 +- patch 类型:Python-only +- 环境建议:使用 Python + pytest;通过 AST overlay 和 controlled Tensor/dropout doubles 验证 checkout 中真实控制流。 +- 最小测试命令:`bash tests/test.sh` +- 是否有 oracle 日志:由 SWE-Paddle verifier 结果另行维护 + +## 7. 风险自查 + +- 泄露风险:测试验证公开 API 的 shape、参数、异常和 forwarding contract,不要求具体局部变量或实现步骤。 +- 环境风险:低;不导入历史 Paddle native runtime,不需要编译或 GPU。 +- flaky 风险:低;随机 dropout 被 controlled double 替代,测试仅检查确定性参数传递和 shape 行为。 +- 拆分风险:低;两个 production 文件共同提供同一个 functional API 及其公开导出,适合作为单一任务。 diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-74444/solution/code.patch b/swe-paddle/tasks/PaddlePaddle__Paddle-74444/solution/code.patch new file mode 100644 index 000000000..45e63d36a --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-74444/solution/code.patch @@ -0,0 +1,107 @@ +diff --git a/python/paddle/nn/functional/__init__.py b/python/paddle/nn/functional/__init__.py +index c822bb83fafff908ebc2b921bbfbf2afab0290db..e2e37bf83dd33cb07a943e7d71d75c285d24ab09 100644 +--- a/python/paddle/nn/functional/__init__.py ++++ b/python/paddle/nn/functional/__init__.py +@@ -59,6 +59,7 @@ from .common import ( + class_center_sample, + cosine_similarity, + dropout, ++ dropout1d, + dropout2d, + dropout3d, + feature_alpha_dropout, +@@ -216,6 +217,7 @@ __all__ = [ + 'gumbel_softmax', + 'sequence_mask', + 'dropout', ++ 'dropout1d', + 'dropout2d', + 'dropout3d', + 'alpha_dropout', +diff --git a/python/paddle/nn/functional/common.py b/python/paddle/nn/functional/common.py +index 37cb95ab46608992169b64c91a7cf8302ac6604d..14dd4a53642d5401b41392f264930db179e0f1c6 100644 +--- a/python/paddle/nn/functional/common.py ++++ b/python/paddle/nn/functional/common.py +@@ -15,6 +15,7 @@ + from __future__ import annotations + + import math ++import warnings + from typing import TYPE_CHECKING, Literal + + import numpy +@@ -1427,6 +1428,74 @@ def dropout( + return ret + + ++def dropout1d( ++ input: paddle.Tensor, ++ p: float = 0.5, ++ training: bool = True, ++ inplace: bool = False, ++) -> paddle.Tensor: ++ """ ++ Randomly zero out entire 1D channels (feature maps) during training. ++ ++ Args: ++ input: Input tensor of shape [C, L] (2D) or [N, C, L] (3D) ++ p: Probability of a channel being zeroed. Default: 0.5 ++ training: If False, returns input unchanged. Default: True ++ inplace: If True, modifies input tensor in-place. Default: False ++ WARNING: Currently not implemented (will behave as False). ++ TODO: Implement in-place operation in future versions. ++ Default: False ++ ++ Returns: ++ Tensor with the same shape as input, where entire channels are zeroed with probability p ++ ++ Examples: ++ .. code-block:: python ++ ++ >>> import paddle ++ ++ # Case 1: 3D input (batched) ++ >>> x = paddle.randn([2, 3, 10]) # [N, C, L] ++ >>> y_train = paddle.nn.functional.dropout1d(x, p=0.2) # Training mode ++ >>> y_test = paddle.nn.functional.dropout1d(x, p=0.2, training=False) # Test mode ++ >>> print("Original first channel:", x[0, 0, :]) ++ >>> print("Train output (may be zeroed):", y_train[0, 0, :]) ++ >>> print("Test output (always unchanged):", y_test[0, 0, :]) ++ ++ # Case 2: 2D input (single sample) ++ >>> x = paddle.randn([3, 8]) # [C, L] ++ >>> y = paddle.nn.functional.dropout1d(x, p=0.5) ++ >>> print("Input shape:", x.shape) ++ >>> print("Output shape:", y.shape) ++ >>> print("Zeroed channels count:", paddle.sum(y == 0).item()) ++ """ ++ if p < 0 or p > 1: ++ raise ValueError(f"dropout probability must be in [0, 1], got {p}") ++ ++ ndim = input.ndim ++ if ndim not in [2, 3]: ++ raise RuntimeError(f"dropout1d expects 2D or 3D input, got {ndim}D") ++ ++ if inplace: ++ warnings.warn( ++ "inplace=True is currently not supported in dropout1d and will be ignored. " ++ "This parameter is reserved for future implementation." ++ ) ++ # TODO: Implement actual in-place operation when supported by dropout ++ ++ need_squeeze = ndim == 2 ++ if need_squeeze: ++ input = input.unsqueeze(0) # [C, L] -> [1, C, L] ++ ++ # Apply dropout along channel dimension ++ result = dropout(input, p=p, axis=1, training=training) ++ ++ if need_squeeze: ++ result = result.squeeze(0) # [1, C, L] -> [C, L] ++ ++ return result ++ ++ + def dropout2d( + x: Tensor, + p: float = 0.5, diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-74444/tests/test.patch b/swe-paddle/tasks/PaddlePaddle__Paddle-74444/tests/test.patch new file mode 100644 index 000000000..d74fbc3c2 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-74444/tests/test.patch @@ -0,0 +1,191 @@ +diff --git a/test/swe_paddle/test_pr74444_dropout1d.py b/test/swe_paddle/test_pr74444_dropout1d.py +new file mode 100644 +index 0000000000000000000000000000000000000000..cb7cd4bac6f34fa33b9aa89019279dbc7bc678d7 +--- /dev/null ++++ b/test/swe_paddle/test_pr74444_dropout1d.py +@@ -0,0 +1,185 @@ ++import ast ++import copy ++import sys ++import types ++import warnings ++from pathlib import Path ++ ++import pytest ++ ++ ++COMMON = Path("python/paddle/nn/functional/common.py") ++FUNCTIONAL_INIT = Path("python/paddle/nn/functional/__init__.py") ++ ++ ++def _extract_function(name, namespace): ++ tree = ast.parse(COMMON.read_text(encoding="utf-8"), filename=str(COMMON)) ++ node = next( ++ ( ++ copy.deepcopy(item) ++ for item in tree.body ++ if isinstance(item, (ast.FunctionDef, ast.AsyncFunctionDef)) ++ and item.name == name ++ ), ++ None, ++ ) ++ assert node is not None, f"paddle.nn.functional.common must provide {name}" ++ node.decorator_list = [] ++ module = ast.Module(body=[node], type_ignores=[]) ++ ast.fix_missing_locations(module) ++ scope = dict(namespace) ++ scope.setdefault("Tensor", object) ++ scope.setdefault("DataLayout2D", str) ++ exec(compile(module, str(COMMON), "exec"), scope) ++ return scope[name] ++ ++ ++def _execute_dropout1d_public_import(): ++ tree = ast.parse( ++ FUNCTIONAL_INIT.read_text(encoding="utf-8"), filename=str(FUNCTIONAL_INIT) ++ ) ++ node = next( ++ ( ++ copy.deepcopy(item) ++ for item in tree.body ++ if isinstance(item, ast.ImportFrom) ++ and any(alias.name == "dropout1d" for alias in item.names) ++ ), ++ None, ++ ) ++ assert node is not None, "paddle.nn.functional must publicly export dropout1d" ++ assert node.level == 1 and node.module ++ ++ package_name = "swe_fake_functional" ++ module_name = f"{package_name}.{node.module}" ++ saved_package = sys.modules.get(package_name) ++ saved_module = sys.modules.get(module_name) ++ ++ package = types.ModuleType(package_name) ++ package.__path__ = [] ++ imported = types.ModuleType(module_name) ++ marker = object() ++ for alias in node.names: ++ setattr(imported, alias.name, marker if alias.name == "dropout1d" else object()) ++ ++ sys.modules[package_name] = package ++ sys.modules[module_name] = imported ++ try: ++ scope = {"__package__": package_name, "__name__": f"{package_name}.probe"} ++ ast.fix_missing_locations(node) ++ exec( ++ compile(ast.Module(body=[node], type_ignores=[]), str(FUNCTIONAL_INIT), "exec"), ++ scope, ++ ) ++ finally: ++ if saved_module is None: ++ sys.modules.pop(module_name, None) ++ else: ++ sys.modules[module_name] = saved_module ++ if saved_package is None: ++ sys.modules.pop(package_name, None) ++ else: ++ sys.modules[package_name] = saved_package ++ ++ return scope, marker ++ ++ ++class _Tensor: ++ def __init__(self, shape, history=()): ++ self.shape = tuple(shape) ++ self.ndim = len(self.shape) ++ self.history = tuple(history) ++ ++ def unsqueeze(self, axis): ++ shape = list(self.shape) ++ shape.insert(axis, 1) ++ return _Tensor(shape, self.history + (("unsqueeze", axis),)) ++ ++ def squeeze(self, axis): ++ shape = list(self.shape) ++ assert shape[axis] == 1 ++ shape.pop(axis) ++ return _Tensor(shape, self.history + (("squeeze", axis),)) ++ ++ ++def test_existing_dropout2d_channel_axis_behavior_remains_compatible(): ++ calls = [] ++ marker = object() ++ ++ def controlled_dropout(x, p=0.5, axis=None, training=True, mode=None, name=None): ++ calls.append((x.shape, p, axis, training, mode, name)) ++ return marker ++ ++ function = _extract_function( ++ "dropout2d", ++ { ++ "Tensor": _Tensor, ++ "DataLayout2D": str, ++ "dropout": controlled_dropout, ++ }, ++ ) ++ ++ x = _Tensor((2, 3, 4, 5)) ++ assert function(x, p=0.25, training=False, data_format="NCHW", name="keep") is marker ++ assert calls[-1] == ((2, 3, 4, 5), 0.25, [0, 1], False, "upscale_in_train", "keep") ++ ++ assert function(x, p=0.4, training=True, data_format="NHWC") is marker ++ assert calls[-1] == ((2, 3, 4, 5), 0.4, [0, 3], True, "upscale_in_train", None) ++ ++ ++def test_dropout1d_is_public_and_preserves_2d_3d_channel_semantics(): ++ scope, marker = _execute_dropout1d_public_import() ++ assert scope.get("dropout1d") is marker ++ ++ calls = [] ++ ++ def controlled_dropout(x, p=0.5, axis=None, training=True): ++ calls.append((x.shape, p, axis, training, x.history)) ++ return x ++ ++ paddle = types.SimpleNamespace(Tensor=_Tensor) ++ function = _extract_function( ++ "dropout1d", ++ { ++ "paddle": paddle, ++ "dropout": controlled_dropout, ++ "warnings": warnings, ++ }, ++ ) ++ ++ two_d = _Tensor((3, 8)) ++ two_d_result = function(two_d, p=0.25, training=False) ++ assert two_d_result.shape == (3, 8) ++ assert calls[-1][:4] == ((1, 3, 8), 0.25, 1, False) ++ assert calls[-1][4] == (("unsqueeze", 0),) ++ assert two_d_result.history == (("unsqueeze", 0), ("squeeze", 0)) ++ ++ three_d = _Tensor((2, 3, 8)) ++ three_d_result = function(three_d, p=0.4, training=True) ++ assert three_d_result is three_d ++ assert calls[-1] == ((2, 3, 8), 0.4, 1, True, ()) ++ ++ ++def test_dropout1d_rejects_invalid_inputs_and_warns_for_inplace(): ++ paddle = types.SimpleNamespace(Tensor=_Tensor) ++ function = _extract_function( ++ "dropout1d", ++ { ++ "paddle": paddle, ++ "dropout": lambda x, **kwargs: x, ++ "warnings": warnings, ++ }, ++ ) ++ ++ with pytest.raises(ValueError, match=r"\[0, 1\]"): ++ function(_Tensor((2, 3, 4)), p=1.5) ++ ++ with pytest.raises(RuntimeError, match="2D or 3D"): ++ function(_Tensor((4,)), p=0.5) ++ ++ with pytest.raises(RuntimeError, match="2D or 3D"): ++ function(_Tensor((1, 2, 3, 4)), p=0.5) ++ ++ with pytest.warns(UserWarning, match="not supported"): ++ result = function(_Tensor((2, 3, 4)), inplace=True) ++ assert result.shape == (2, 3, 4) diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-74444/tests/test.sh b/swe-paddle/tasks/PaddlePaddle__Paddle-74444/tests/test.sh new file mode 100644 index 000000000..b0e99e495 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-74444/tests/test.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail + +python -m pytest test/swe_paddle/test_pr74444_dropout1d.py -q