diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-73691/README.md b/swe-paddle/tasks/PaddlePaddle__Paddle-73691/README.md new file mode 100644 index 000000000..0cd526f69 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-73691/README.md @@ -0,0 +1,51 @@ +# PaddlePaddle__Paddle-73691 + +This directory converts Paddle PR #73691 into a SWE-Paddle community task candidate. + +## Source + +| Field | Value | +| --- | --- | +| Repo | `PaddlePaddle/Paddle` | +| PR | [73691](https://github.com/PaddlePaddle/Paddle/pull/73691) | +| PR title | `[0-size Tensor No.159、161、163] Add 0-size Tensor support for conv1d` | +| Base commit | `3efb8dbb51547f0235a402135c54ed83c2f12d61` | +| Gold commit | `8fb677bc3c9678fb9ef31044f9ba624616a3ee06` | +| Merged at | `2025-07-01` | +| Task type | `bug_fix` | +| Resource | CPU | +| Scope | C++ Operator Kernel | + +## Summary + +Fix `paddle.nn.functional.conv1d`, `conv2d`, `conv3d` to correctly handle 0-size tensors in CPU/GPU/XPU kernels by adding early-return logic when input has 0 elements, and fixing InferMeta to correctly compute output shapes for 0-size inputs. + +## 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 C++ operator kernel level and requires rebuilding Paddle from source. +- The failure is deterministic: the base revision fails when processing 0-size tensors due to missing early-return logic in conv kernels and incorrect InferMeta shape computation. +- 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 (C++ kernel changes). +- `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) | conv F2P | +| --- | ---: | ---: | +| Base + `tests/test.patch` | PASS | FAIL | +| Base + `tests/test.patch` + `solution/code.patch` | PASS | PASS | diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-73691/environment/README.md b/swe-paddle/tasks/PaddlePaddle__Paddle-73691/environment/README.md new file mode 100644 index 000000000..68ea7e33f --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-73691/environment/README.md @@ -0,0 +1,52 @@ +# Environment Notes + +## Expected Environment + +- Repository: `PaddlePaddle/Paddle` +- Base commit: `3efb8dbb51547f0235a402135c54ed83c2f12d61` +- Gold commit: `8fb677bc3c9678fb9ef31044f9ba624616a3ee06` +- Resource: CPU +- GPU required: no +- Patch type: C++ kernel (CPU/GPU/XPU backends) + InferMeta + Symbolic Shape +- Python dependencies: PaddlePaddle (source build), NumPy + +The verifier should execute against the Paddle source revision represented by the selected patch state. A source build is required since the patch modifies C++ kernel code, InferMeta, and symbolic shape inference. + +## Build Instructions + +1. Check out `PaddlePaddle/Paddle` at the base commit. +2. Apply `tests/test.patch`. +3. Build Paddle from source (CPU-only build is sufficient): + ```bash + mkdir build && cd build + cmake .. -DWITH_GPU=OFF -DWITH_TESTING=ON -DCMAKE_BUILD_TYPE=Release + make -j$(nproc) + ``` +4. Install the built Paddle package. + +## Run Order + +1. Check out `PaddlePaddle/Paddle` at the base commit. +2. Build and install Paddle from source. +3. Apply `tests/test.patch`. +4. Run the P2P tests; existing non-zero-size behavior should pass. +5. Run the 0-size tensor tests; the target case should fail before the fix. +6. Apply `solution/code.patch`. +7. Rebuild Paddle from source. +8. Reinstall Paddle package. +9. Run `bash tests/test.sh`; all target tests should pass. + +## Minimal Test Command + +```bash +bash tests/test.sh +``` + +## Expected Matrix + +| Revision state | P2P | conv 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-73691/instruction.md b/swe-paddle/tasks/PaddlePaddle__Paddle-73691/instruction.md new file mode 100644 index 000000000..7d9cab9fc --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-73691/instruction.md @@ -0,0 +1,61 @@ +# 修复 `paddle.nn.functional.conv1d/conv2d/conv3d` 对 0-size Tensor 的处理 + +## 详细描述 + +当 `paddle.nn.functional.conv1d/conv2d/conv3d` 的输入为 0-size Tensor 时,当前 CPU/GPU/XPU kernel 实现会直接进入后续计算逻辑,导致 kernel 内部对空数据执行计算或产生其他错误。同时,InferMeta 对 0-size 输入的输出形状计算也不正确。 + +典型表现包括: + +- kernel 在执行卷积计算时崩溃或报错 +- 0-size Tensor 输入无法通过 `conv1d/conv2d/conv3d` 算子 +- InferMeta 计算出的输出形状不正确 + +例如: + +```python +import numpy as np +import paddle + +paddle.disable_static() + +# conv1d 0-size tensor 输入 +x = paddle.to_tensor(np.random.randn(0, 1, 2).astype('float32')) +filter = paddle.to_tensor(np.random.randn(1, 1, 2).astype('float32')) +out = paddle.nn.functional.conv1d(x, filter) +# 期望返回 shape 为 (0, 1, 1) 的全零 Tensor + +# conv2d 0-size tensor 输入 +x = paddle.to_tensor(np.random.random([0, 3, 4, 4]).astype('float32')) +filter = paddle.to_tensor(np.random.random([2, 3, 3, 3]).astype('float32')) +out = paddle.nn.functional.conv2d(x, filter) +# 期望返回 shape 为 (0, 2, 2, 2) 的全零 Tensor + +# conv3d 0-size tensor 输入 +x = paddle.to_tensor(np.random.random([4, 3, 0, 8, 8]).astype('float32')) +filter = paddle.to_tensor(np.random.random([5, 3, 3, 3, 3]).astype('float32')) +out = paddle.nn.functional.conv3d(x, filter, padding=1) +# 期望返回 shape 为 (4, 5, 0, 8, 8) 的全零 Tensor +``` + +上述调用中输入包含 0-size 维度。按照 API 语义,0-size Tensor 的卷积操作应正常返回正确 shape 的全零 Tensor。 + +需要在 CPU/GPU/XPU kernel 层添加 0-size 早期返回处理,并修复 InferMeta 的形状计算逻辑: +- 在卷积前向 kernel 中,检查输入 `input.numel() == 0` 并使用 `phi::Full` 填充全零后直接返回 +- 在卷积反向 kernel 中,检查输入 `input.numel() == 0` 并分配内存后直接返回 +- 在 InferMeta 中,修复对 0-size 输入的输出形状计算 + +## 验收说明 + +- 当输入为 0-size Tensor 时,`paddle.nn.functional.conv1d/conv2d/conv3d` 应正常完成,返回正确 shape 的全零 Tensor +- 输出的 shape 应与输入一致 +- 非 0-size Tensor 输入下的 conv1d/conv2d/conv3d 行为不得退化 +- 梯度计算也应正常工作(0-size Tensor 的梯度也为全零 Tensor) + +## 技术要求 + +- 熟悉 C++ 和 Paddle PHI kernel 开发 +- 了解 Tensor shape、0-size Tensor 和 kernel 执行路径 +- 了解 conv1d/conv2d/conv3d 算子的输入输出语义 +- 了解 Paddle CPU/GPU/XPU kernel 的实现模式 +- 了解 InferMeta 的形状推导机制 +- 需要从源码编译 Paddle 以验证修改 diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-73691/proposal.md b/swe-paddle/tasks/PaddlePaddle__Paddle-73691/proposal.md new file mode 100644 index 000000000..25622b78e --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-73691/proposal.md @@ -0,0 +1,60 @@ +# SWE-Paddle Task Proposal: PaddlePaddle__Paddle-73691 + +## 1. 来源信息 + +- Instance ID: `PaddlePaddle__Paddle-73691` +- PR 链接: https://github.com/PaddlePaddle/Paddle/pull/73691 +- PR 标题: `[0-size Tensor No.159、161、163] Add 0-size Tensor support for conv1d` +- Base commit: `3efb8dbb51547f0235a402135c54ed83c2f12d61` +- Gold commit: `8fb677bc3c9678fb9ef31044f9ba624616a3ee06` +- Merged at: 2025-07-01 +- 你的身份: contributor + +## 2. 问题一句话 + +`paddle.nn.functional.conv1d/conv2d/conv3d` 在输入为 0-size Tensor 时,CPU/GPU/XPU kernel 未处理 0-size 边界情况导致崩溃或报错,需要在 kernel 入口添加 0-size 早期返回逻辑,并修复 InferMeta 的形状计算。 + +## 3. 为什么适合作为 SWE-Paddle 样本 + +- **真实性**: 来自 Paddle「0-size Tensor 机制建设」系列任务,是真实研发需求。 +- **代表性**: 覆盖 C++ kernel 层面的 0-size Tensor 边界处理,涉及 CPU/GPU/XPU 三端 kernel、梯度 kernel 和 InferMeta。 +- **边界清楚**: 目标仅限输入为 0-size 时的 kernel 早期返回和形状计算;正向非零尺寸输入不应受影响。 +- **非平凡性**: 修复需要在多个 kernel 中添加 `input.numel() == 0` 的早期返回,并使用 `phi::Full` 填充全零,同时修复 InferMeta 对 0-size 输入的形状推导,涉及对 kernel 执行流程和形状推导机制的理解。 +- **回归护栏明确**: 目标 F2P 可覆盖 0-size Tensor 输入的 `conv1d/conv2d/conv3d` 算子测试;同文件中已有的标准测试用例可作为 P2P 护栏。 + +## 4. 任务类型和标签 + +- 任务类型: `bug_fix` +- 执行后端: `cpu` +- 设备范围: `cpu_only` +- 模块标签: `[operator_kernel, conv1d, conv2d, conv3d, 0-size_tensor, cpu_kernel, gpu_kernel, xpu_kernel]` + +## 5. 验证思路 + +- 目标测试命令: `bash tests/test.sh` +- 目标测试文件: + - `test/legacy_test/test_functional_conv1d.py`(`TestFunctionalConv1D_ZeroSize`) + - `test/legacy_test/test_functional_conv2d.py`(`TestFunctionalConv2D_ZeroSize`) + - `test/legacy_test/test_functional_conv3d.py`(`TestFunctionalConv3D_ZeroSize2`) +- P2P 候选: 同文件中已有的 `TestFunctionalConv1DError`、`TestFunctionalConv2DError`、`TestFunctionalConv3DError` 等标准算子测试用例。 +- 修复前预期: `base_commit` + `tests/test.patch` 后,0-size Tensor 输入的算子测试失败(kernel 崩溃或报错)。 +- 修复后预期: 继续应用 `solution/code.patch` 并重新编译后,0-size Tensor 输入正常返回全零 Tensor,P2P 存量测试仍然通过。 + +## 6. 环境与资源 + +- 是否能提供 Docker: 无 +- Dockerfile 或镜像地址: 暂无 +- Paddle 来源: `PaddlePaddle/Paddle` source checkout at `base_commit`,需要源码编译。 +- OS / Python / CUDA / cuDNN / 其他关键依赖: Linux CPU + Python + numpy;编译需要 CMake、GCC;不要求 CUDA/cuDNN(CPU 编译即可验证)。 +- 硬件: CPU 即可(编译和测试均不需要 GPU)。 +- patch 类型: 含 C++ kernel 修改(CPU/GPU/XPU 三端)+ InferMeta + 符号推导,需要重新编译 Paddle。 +- 最小测试命令: `bash tests/test.sh` +- 是否有 oracle 日志: 无 + +## 7. 风险自查 + +- 泄露风险: 正式 `instruction.md` 只描述「conv1d/conv2d/conv3d 对 0-size Tensor 输入的行为异常」,不指出具体 `input.numel() == 0` 分支逻辑或具体代码位置。 +- 环境风险: 中。任务涉及 C++ kernel 修改,需要源码编译 Paddle,编译时间较长。 +- flaky 风险: 低。测试使用固定的 0-size Tensor 构造,不依赖随机数差异或多设备同步。 +- 拆分风险: 低。该 PR 目标集中在 `conv1d/conv2d/conv3d` 的 CPU/GPU/XPU kernel 0-size 早期返回和 InferMeta 形状修复,测试明确指向新增的 ZeroSize 测试类,适合作为一个独立样本。 +- 其他不确定点: 完整任务包阶段应确认新增 F2P 在 `base_commit` 编译后确实失败。注意该 PR 同时修改了前向和反向 kernel,以及 InferMeta 和符号推导。 diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-73691/solution/code.patch b/swe-paddle/tasks/PaddlePaddle__Paddle-73691/solution/code.patch new file mode 100644 index 000000000..8c45508b9 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-73691/solution/code.patch @@ -0,0 +1,274 @@ +diff --git a/paddle/fluid/pir/dialect/operator/interface/infer_symbolic_shape/binary_infer_sym.cc b/paddle/fluid/pir/dialect/operator/interface/infer_symbolic_shape/binary_infer_sym.cc +index 2bb9befe1ce2c6..0491ffb30e52cf 100644 +--- a/paddle/fluid/pir/dialect/operator/interface/infer_symbolic_shape/binary_infer_sym.cc ++++ b/paddle/fluid/pir/dialect/operator/interface/infer_symbolic_shape/binary_infer_sym.cc +@@ -414,7 +414,11 @@ bool Conv2dOpInferSymbolicShape(pir::Operation *op, + const symbol::ShapeOrDataDimExprs &shape_data = [&] { + std::vector out_s_or_d({in_s_or_d.shape()[0]}); + if (!channel_last) { +- out_s_or_d.push_back(filter_s_or_d.shape()[0]); ++ if (filter_s_or_d.shape()[1] == 0) { ++ out_s_or_d.push_back(symbol::DimExpr{0}); ++ } else { ++ out_s_or_d.push_back(filter_s_or_d.shape()[0]); ++ } + } + + for (size_t i = 0; i < in_data_dims.size(); ++i) { +@@ -427,7 +431,11 @@ bool Conv2dOpInferSymbolicShape(pir::Operation *op, + out_s_or_d.push_back(output_size); + } + if (channel_last) { +- out_s_or_d.push_back(filter_s_or_d.shape()[0]); ++ if (filter_s_or_d.shape()[1] == 0) { ++ out_s_or_d.push_back(symbol::DimExpr{0}); ++ } else { ++ out_s_or_d.push_back(filter_s_or_d.shape()[0]); ++ } + } + + return symbol::ShapeOrDataDimExprs{ +diff --git a/paddle/phi/infermeta/binary.cc b/paddle/phi/infermeta/binary.cc +index f3392caa15595f..766528e00b1771 100644 +--- a/paddle/phi/infermeta/binary.cc ++++ b/paddle/phi/infermeta/binary.cc +@@ -588,13 +588,6 @@ void ConvInferMeta(const MetaTensor& input, + const bool channel_last = (config.is_run_mkldnn_kernel == false) && + (data_format == "NHWC" || data_format == "NDHWC"); + +- for (int i = 0; i < 2; ++i) { +- PADDLE_ENFORCE_NE(in_dims[i], +- 0, +- common::errors::InvalidArgument( +- "The size of Op(Conv) inputs should not be 0.")); +- } +- + PADDLE_ENFORCE_EQ( + in_dims.size() == 4 || in_dims.size() == 5, + true, +@@ -706,11 +699,15 @@ void ConvInferMeta(const MetaTensor& input, + + std::vector output_shape({in_dims[0]}); + if (!channel_last) { +- output_shape.push_back(filter_dims[0]); ++ if (filter_dims[1] == 0) { ++ output_shape.push_back(0); ++ } else { ++ output_shape.push_back(filter_dims[0]); ++ } + } + for (int i = 0; i < in_data_dims.size(); ++i) { + if ((!config.is_runtime) && +- (in_data_dims[i] <= 0 || filter_dims[i + 2] <= 0)) { ++ (in_data_dims[i] < 0 || filter_dims[i + 2] < 0)) { + output_shape.push_back(-1); + } else { + const int dkernel = +@@ -723,7 +720,11 @@ void ConvInferMeta(const MetaTensor& input, + } + } + if (channel_last) { +- output_shape.push_back(filter_dims[0]); ++ if (filter_dims[1] == 0) { ++ output_shape.push_back(0); ++ } else { ++ output_shape.push_back(filter_dims[0]); ++ } + } + + out->set_dims(common::make_ddim(output_shape)); +diff --git a/paddle/phi/kernels/gpu/depthwise_conv_grad_kernel.cu b/paddle/phi/kernels/gpu/depthwise_conv_grad_kernel.cu +index 2c3baea01c1620..02c8625ab8966c 100644 +--- a/paddle/phi/kernels/gpu/depthwise_conv_grad_kernel.cu ++++ b/paddle/phi/kernels/gpu/depthwise_conv_grad_kernel.cu +@@ -18,6 +18,7 @@ + #include "paddle/phi/common/float16.h" + #include "paddle/phi/core/kernel_registry.h" + #include "paddle/phi/kernels/cpu/conv_util.h" ++#include "paddle/phi/kernels/full_kernel.h" + #include "paddle/phi/kernels/funcs/batch_norm_utils.h" + #include "paddle/phi/kernels/funcs/math_function.h" + #include "paddle/phi/kernels/gpu/depthwise_conv.h" +@@ -40,6 +41,18 @@ void DepthwiseConvGradKernel(const Context& dev_ctx, + const DenseTensor* output_grad = &out_grad; + + if (!input_grad && !filter_grad) return; ++ // 0-size ++ if (input.numel() == 0) { ++ if (input_grad) dev_ctx.template Alloc(input_grad); ++ if (filter_grad) { ++ phi::Full( ++ dev_ctx, ++ phi::IntArray(common::vectorize(filter_grad->dims())), ++ 0, ++ filter_grad); ++ } ++ return; ++ } + + bool has_fuse_relu = dev_ctx.HasDnnAttr("fuse_relu_before_depthwise_conv"); + bool fuse_relu = +diff --git a/paddle/phi/kernels/gpu/depthwise_conv_kernel.cu b/paddle/phi/kernels/gpu/depthwise_conv_kernel.cu +index deabeca8361178..7c86b6ac596a63 100644 +--- a/paddle/phi/kernels/gpu/depthwise_conv_kernel.cu ++++ b/paddle/phi/kernels/gpu/depthwise_conv_kernel.cu +@@ -33,6 +33,10 @@ void DepthwiseConvKernel(const Context& dev_ctx, + const std::vector& dilations_t, + const std::string& data_format, + DenseTensor* out) { ++ if (input.numel() == 0) { ++ dev_ctx.template Alloc(out); ++ return; ++ } + DenseTensor* output = out; + dev_ctx.template Alloc(output); + +diff --git a/paddle/phi/kernels/gpudnn/conv_grad_kernel.cu b/paddle/phi/kernels/gpudnn/conv_grad_kernel.cu +index f6a43f198d5fd6..1cb7c205844da6 100644 +--- a/paddle/phi/kernels/gpudnn/conv_grad_kernel.cu ++++ b/paddle/phi/kernels/gpudnn/conv_grad_kernel.cu +@@ -31,10 +31,10 @@ + #include "paddle/phi/common/bfloat16.h" + #include "paddle/phi/common/float16.h" + #include "paddle/phi/kernels/cpu/conv_util.h" ++#include "paddle/phi/kernels/full_kernel.h" + #include "paddle/phi/kernels/funcs/batch_norm_utils.h" + #include "paddle/phi/kernels/funcs/padding.h" + #include "paddle/phi/kernels/impl/conv_cudnn_impl.h" +- + #ifdef PADDLE_WITH_CUDNN_FRONTEND + // clang-format off + #include "paddle/phi/backends/dynload/cudnn_frontend.h" +@@ -416,6 +416,18 @@ void ConvCudnnGradKernel(const Context& dev_ctx, + const std::string& data_format, + DenseTensor* input_grad, + DenseTensor* filter_grad) { ++ // 0-size ++ if (input.numel() == 0) { ++ if (input_grad) dev_ctx.template Alloc(input_grad); ++ if (filter_grad) { ++ phi::Full( ++ dev_ctx, ++ phi::IntArray(common::vectorize(filter_grad->dims())), ++ 0, ++ filter_grad); ++ } ++ return; ++ } + if (input_grad) { + dev_ctx.template Alloc(input_grad); + } +diff --git a/paddle/phi/kernels/gpudnn/conv_kernel.cu b/paddle/phi/kernels/gpudnn/conv_kernel.cu +index 96bc014662c55d..998360dcb8aba9 100644 +--- a/paddle/phi/kernels/gpudnn/conv_kernel.cu ++++ b/paddle/phi/kernels/gpudnn/conv_kernel.cu +@@ -313,6 +313,10 @@ void ConvCudnnKernel(const Context& dev_ctx, + int groups, + const std::string& data_format, + DenseTensor* output) { ++ if (input.numel() == 0) { ++ dev_ctx.template Alloc(output); ++ return; ++ } + dev_ctx.template Alloc(output); + std::vector paddings = paddings_t; + std::vector dilations = dilations_t; +diff --git a/paddle/phi/kernels/impl/conv_grad_kernel_impl.h b/paddle/phi/kernels/impl/conv_grad_kernel_impl.h +index 3baf3fd84b0c49..6066720ab07934 100644 +--- a/paddle/phi/kernels/impl/conv_grad_kernel_impl.h ++++ b/paddle/phi/kernels/impl/conv_grad_kernel_impl.h +@@ -15,12 +15,12 @@ + #pragma once + + #include "paddle/phi/kernels/cpu/conv_util.h" ++#include "paddle/phi/kernels/full_kernel.h" + #include "paddle/phi/kernels/funcs/batch_norm_utils.h" + #include "paddle/phi/kernels/funcs/blas/blas.h" + #include "paddle/phi/kernels/funcs/im2col.h" + #include "paddle/phi/kernels/funcs/math_function.h" + #include "paddle/phi/kernels/funcs/vol2col.h" +- + namespace phi { + + template +@@ -45,6 +45,19 @@ void ConvGradKernel(const Context& dev_ctx, + std::vector dilations = dilations_t; + + DenseTensor filter = filter_t; ++ // 0-size ++ if (input.numel() == 0) { ++ if (input_grad) dev_ctx.template Alloc(input_grad); ++ if (filter_grad) { ++ phi::Full( ++ dev_ctx, ++ phi::IntArray(common::vectorize(filter_grad->dims())), ++ 0, ++ filter_grad); ++ } ++ return; ++ } ++ + const bool channel_last = (data_format == "NHWC" || data_format == "NDHWC"); + + DenseTensor transformed_input(input.type()); +diff --git a/paddle/phi/kernels/impl/conv_kernel_impl.h b/paddle/phi/kernels/impl/conv_kernel_impl.h +index e40ba59a2d3a11..1427a3f6cad0a8 100644 +--- a/paddle/phi/kernels/impl/conv_kernel_impl.h ++++ b/paddle/phi/kernels/impl/conv_kernel_impl.h +@@ -38,6 +38,10 @@ void ConvKernelImpl(const Context& dev_ctx, + std::vector paddings = paddings_t; + std::vector dilations = dilations_t; + DenseTensor filter = filter_t; ++ if (input.numel() == 0) { ++ dev_ctx.template Alloc(output); ++ return; ++ } + // The filter will be reshaped in the calculations, + // so here use an assignment operation, + // that avoids modifying the variable in the Scope. +diff --git a/paddle/phi/kernels/xpu/conv_grad_kernel.cc b/paddle/phi/kernels/xpu/conv_grad_kernel.cc +index ff5a327ff3fe9b..e54f22a28dce72 100644 +--- a/paddle/phi/kernels/xpu/conv_grad_kernel.cc ++++ b/paddle/phi/kernels/xpu/conv_grad_kernel.cc +@@ -17,6 +17,7 @@ + #include "paddle/phi/backends/xpu/enforce_xpu.h" + #include "paddle/phi/core/kernel_registry.h" + #include "paddle/phi/kernels/cpu/conv_util.h" ++#include "paddle/phi/kernels/full_kernel.h" + #include "paddle/phi/kernels/xpu/conv_utils_xpu.h" + #include "paddle/phi/kernels/xpu/xpu_api_wrapper.h" + #ifdef PADDLE_WITH_XPU_XRE5 +@@ -47,6 +48,18 @@ void ConvGradKernel(const Context& dev_ctx, + // so here use an assignment operation, + // that avoids modifying the variable in the Scope. + if (!input_grad && !filter_grad) return; ++ // 0-size ++ if (input.numel() == 0) { ++ if (input_grad) dev_ctx.template Alloc(input_grad); ++ if (filter_grad) { ++ phi::Full( ++ dev_ctx, ++ phi::IntArray(common::vectorize(filter_grad->dims())), ++ 0, ++ filter_grad); ++ } ++ return; ++ } + PADDLE_ENFORCE_EQ( + data_format == "NDHWC", + false, +diff --git a/paddle/phi/kernels/xpu/conv_kernel.cc b/paddle/phi/kernels/xpu/conv_kernel.cc +index c51dd9b2eeba97..5b70b105dd3c55 100644 +--- a/paddle/phi/kernels/xpu/conv_kernel.cc ++++ b/paddle/phi/kernels/xpu/conv_kernel.cc +@@ -37,6 +37,10 @@ void ConvKernel(const Context& dev_ctx, + int groups, + const std::string& data_format, + DenseTensor* out) { ++ if (input.numel() == 0) { ++ dev_ctx.template Alloc(out); ++ return; ++ } + using XPUType = typename XPUTypeTrait::Type; + std::vector paddings(paddings_t.begin(), paddings_t.end()); + std::vector dilations(dilations_t.begin(), dilations_t.end()); \ No newline at end of file diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-73691/tests/test.patch b/swe-paddle/tasks/PaddlePaddle__Paddle-73691/tests/test.patch new file mode 100644 index 000000000..b9f5fd9f6 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-73691/tests/test.patch @@ -0,0 +1,260 @@ +diff --git a/test/legacy_test/test_functional_conv1d.py b/test/legacy_test/test_functional_conv1d.py +index 760e1a2f2b..645c24017a 100644 +--- a/test/legacy_test/test_functional_conv1d.py ++++ b/test/legacy_test/test_functional_conv1d.py +@@ -12,6 +12,7 @@ + # See the License for the specific language governing permissions and + # limitations under the License. + ++import os + import unittest + from unittest import TestCase + +@@ -20,6 +21,7 @@ import numpy as np + import paddle + import paddle.base.dygraph as dg + import paddle.nn.functional as F ++from paddle import base + + + class TestFunctionalConv1DError(TestCase): +@@ -70,18 +72,6 @@ class TestFunctionalConv1DErrorCase1(TestFunctionalConv1DError): + self.data_format = "NCL" + + +-class TestFunctionalConv1DErrorCase2(TestFunctionalConv1DError): +- def setUp(self): +- self.input = np.random.randn(0, 0, 0) +- self.filter = np.random.randn(1, 0, 0) +- self.bias = None +- self.padding = 0 +- self.stride = 1 +- self.dilation = 1 +- self.groups = 1 +- self.data_format = "NCL" +- +- + class TestFunctionalConv1D_CPU_FP16(TestCase): + def setUp(self): + self.padding = 0 +@@ -108,5 +98,60 @@ class TestFunctionalConv1D_CPU_FP16(TestCase): + np.testing.assert_allclose(y.numpy(), [[[2]]]) + + ++class TestFunctionalConv1D_ZeroSize(TestCase): ++ def init_data(self): ++ self.input = np.random.randn(0, 1, 2) ++ self.filter = np.random.randn(1, 1, 2) ++ self.np_out = np.random.random([0, 1, 1]) ++ ++ def setUp(self): ++ self.init_data() ++ self.bias = None ++ self.padding = 0 ++ self.stride = 1 ++ self.dilation = 1 ++ self.groups = 1 ++ self.data_format = "NCL" ++ self.places = [] ++ if ( ++ os.environ.get('FLAGS_CI_both_cpu_and_gpu', 'False').lower() ++ in ['1', 'true', 'on'] ++ or not base.core.is_compiled_with_cuda() ++ ): ++ self.places.append(base.CPUPlace()) ++ if base.core.is_compiled_with_cuda(): ++ self.places.append(base.CUDAPlace(0)) ++ ++ def test_dygraph(self): ++ for place in self.places: ++ with dg.guard(place): ++ input = paddle.to_tensor(self.input) ++ input.stop_gradient = False ++ filter = paddle.to_tensor(self.filter) ++ filter.stop_gradient = False ++ y = F.conv1d( ++ input, ++ filter, ++ self.bias, ++ padding=self.padding, ++ stride=self.stride, ++ dilation=self.dilation, ++ groups=self.groups, ++ data_format=self.data_format, ++ ) ++ np.testing.assert_allclose(y.numpy(), self.np_out) ++ loss = y.sum() ++ loss.backward() ++ np.testing.assert_allclose(input.grad.shape, input.shape) ++ np.testing.assert_allclose(filter.grad, np.zeros(filter.shape)) ++ ++ ++class TestFunctionalConv1D_ZeroSize2(TestFunctionalConv1D_ZeroSize): ++ def init_data(self): ++ self.input = np.random.randn(0, 0, 2) ++ self.filter = np.random.randn(1, 0, 2) ++ self.np_out = np.random.random([0, 0, 1]) ++ ++ + if __name__ == "__main__": + unittest.main() +diff --git a/test/legacy_test/test_functional_conv2d.py b/test/legacy_test/test_functional_conv2d.py +index 1b69e2cc15..74cd777bae 100644 +--- a/test/legacy_test/test_functional_conv2d.py ++++ b/test/legacy_test/test_functional_conv2d.py +@@ -12,6 +12,7 @@ + # See the License for the specific language governing permissions and + # limitations under the License. + ++import os + import unittest + from unittest import TestCase + +@@ -41,6 +42,7 @@ class TestFunctionalConv2DError(TestCase): + self.data_format = "NHWC" + + def test_exception(self): ++ paddle.enable_static() + self.prepare() + with self.assertRaises(ValueError): + self.static_graph_case() +@@ -282,6 +284,59 @@ class TestFunctionalConv2DErrorCase14(TestFunctionalConv2DErrorCase12): + self.data_format = "NCHW" + + ++class TestFunctionalConv2D_ZeroSize(TestCase): ++ def init_data(self): ++ self.input = np.random.random([0, 3, 4, 4]) ++ self.filter = np.random.random([2, 3, 3, 3]) ++ self.np_out = np.random.random([0, 2, 2, 2]) ++ ++ def setUp(self): ++ self.init_data() ++ self.bias = None ++ self.padding = 0 ++ self.stride = 1 ++ self.dilation = 1 ++ self.groups = 1 ++ self.data_format = "NCHW" ++ self.places = [] ++ if ( ++ os.environ.get('FLAGS_CI_both_cpu_and_gpu', 'False').lower() ++ in ['1', 'true', 'on'] ++ or not base.core.is_compiled_with_cuda() ++ ): ++ self.places.append(base.CPUPlace()) ++ if base.core.is_compiled_with_cuda(): ++ self.places.append(base.CUDAPlace(0)) ++ ++ def test_dygraph(self): ++ for place in self.places: ++ with dg.guard(place): ++ input = paddle.to_tensor(self.input) ++ input.stop_gradient = False ++ filter = paddle.to_tensor(self.filter) ++ y = F.conv2d( ++ input, ++ filter, ++ self.bias, ++ padding=self.padding, ++ stride=self.stride, ++ dilation=self.dilation, ++ groups=self.groups, ++ data_format=self.data_format, ++ ) ++ np.testing.assert_allclose(y.numpy(), self.np_out) ++ loss = y.sum() ++ loss.backward() ++ np.testing.assert_allclose(input.grad.shape, input.shape) ++ ++ ++class TestFunctionalConv2D_ZeroSize2(TestFunctionalConv2D_ZeroSize): ++ def init_data(self): ++ self.input = np.random.random([0, 0, 4, 4]) ++ self.filter = np.random.random([2, 0, 3, 3]) ++ self.np_out = np.random.random([0, 0, 2, 2]) ++ ++ + if __name__ == "__main__": + paddle.enable_static() + unittest.main() +diff --git a/test/legacy_test/test_functional_conv3d.py b/test/legacy_test/test_functional_conv3d.py +index 2b61cf8570..72c5779cda 100644 +--- a/test/legacy_test/test_functional_conv3d.py ++++ b/test/legacy_test/test_functional_conv3d.py +@@ -12,6 +12,7 @@ + # See the License for the specific language governing permissions and + # limitations under the License. + ++import os + import unittest + from unittest import TestCase + +@@ -41,6 +42,7 @@ class TestFunctionalConv3DError(TestCase): + self.data_format = "NDHWC" + + def test_exception(self): ++ paddle.enable_static() + self.prepare() + with self.assertRaises(ValueError): + self.static_graph_case() +@@ -263,6 +265,59 @@ class TestFunctionalConv3DErrorCase13(TestFunctionalConv3DErrorCase11): + self.data_format = "NCDHW" + + ++class TestFunctionalConv3D_ZeroSize(TestCase): ++ def init_data(self): ++ self.input = np.random.random([4, 3, 0, 8, 8]) ++ self.filter = np.random.random([5, 3, 3, 3, 3]) ++ self.np_out = np.random.random([4, 5, 0, 8, 8]) ++ ++ def setUp(self): ++ self.init_data() ++ self.bias = None ++ self.padding = 1 ++ self.stride = 1 ++ self.dilation = 1 ++ self.groups = 1 ++ self.data_format = "NCDHW" ++ self.places = [] ++ if ( ++ os.environ.get('FLAGS_CI_both_cpu_and_gpu', 'False').lower() ++ in ['1', 'true', 'on'] ++ or not base.core.is_compiled_with_cuda() ++ ): ++ self.places.append(base.CPUPlace()) ++ if base.core.is_compiled_with_cuda(): ++ self.places.append(base.CUDAPlace(0)) ++ ++ def test_dygraph(self): ++ for place in self.places: ++ with dg.guard(place): ++ input = paddle.to_tensor(self.input) ++ input.stop_gradient = False ++ filter = paddle.to_tensor(self.filter) ++ y = F.conv3d( ++ input, ++ filter, ++ self.bias, ++ padding=self.padding, ++ stride=self.stride, ++ dilation=self.dilation, ++ groups=self.groups, ++ data_format=self.data_format, ++ ) ++ np.testing.assert_allclose(y.numpy(), self.np_out) ++ loss = y.sum() ++ loss.backward() ++ np.testing.assert_allclose(input.grad.shape, input.shape) ++ ++ ++class TestFunctionalConv3D_ZeroSize2(TestFunctionalConv3D_ZeroSize): ++ def init_data(self): ++ self.input = np.random.random([4, 0, 0, 8, 8]) ++ self.filter = np.random.random([5, 0, 3, 3, 3]) ++ self.np_out = np.random.random([4, 0, 0, 8, 8]) ++ ++ + if __name__ == "__main__": + paddle.enable_static() + unittest.main() diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-73691/tests/test.sh b/swe-paddle/tasks/PaddlePaddle__Paddle-73691/tests/test.sh new file mode 100755 index 000000000..fce9cd900 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-73691/tests/test.sh @@ -0,0 +1,12 @@ +#!/bin/bash +set -e + +# P2P tests (pass-to-pass) +python -m pytest test/legacy_test/test_functional_conv1d.py::TestFunctionalConv1DError -q +python -m pytest test/legacy_test/test_functional_conv2d.py::TestFunctionalConv2DError -q +python -m pytest test/legacy_test/test_functional_conv3d.py::TestFunctionalConv3DError -q + +# F2P tests (fail-to-pass) +python -m pytest test/legacy_test/test_functional_conv1d.py::TestFunctionalConv1D_ZeroSize -q +python -m pytest test/legacy_test/test_functional_conv2d.py::TestFunctionalConv2D_ZeroSize -q +python -m pytest test/legacy_test/test_functional_conv3d.py::TestFunctionalConv3D_ZeroSize2 -q