Skip to content
Open
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
51 changes: 51 additions & 0 deletions swe-paddle/tasks/PaddlePaddle__Paddle-73880/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# PaddlePaddle__Paddle-73880

This directory converts Paddle PR #73880 into a SWE-Paddle community task candidate.

## Source

| Field | Value |
| --- | --- |
| Repo | `PaddlePaddle/Paddle` |
| PR | [73880](https://github.com/PaddlePaddle/Paddle/pull/73880) |
| PR title | `[0-size Tensor Job2 No.66] Add 0-size Tensor support for paddle.nn.functional.softmax_with_cross_entropy` |
| Base commit | `e1842d4ce364b6e8334c39a8807b256682185d23` |
| Gold commit | `4b55ef8495c5bdb91e6e96892f31d9cee63ed681` |
| Merged at | `2025-07-16` |
| Task type | `bug_fix` |
| Resource | CPU |
| Scope | C++ operator kernel (CPU/GPU/XPU) |

## Summary

Fix `paddle.nn.functional.softmax_with_cross_entropy` to correctly handle 0-size tensors in CPU/GPU/XPU kernels.

## 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++ kernel level and covers multiple backends (CPU, GPU, XPU).
- The failure is deterministic: the base revision fails when processing 0-size tensors in cross entropy kernels.
- 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) | softmax_with_cross_entropy F2P |
| --- | ---: | ---: |
| Base + `tests/test.patch` | PASS | FAIL |
| Base + `tests/test.patch` + `solution/code.patch` | PASS | PASS |
52 changes: 52 additions & 0 deletions swe-paddle/tasks/PaddlePaddle__Paddle-73880/environment/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Environment Notes

## Expected Environment

- Repository: `PaddlePaddle/Paddle`
- Base commit: `e1842d4ce364b6e8334c39a8807b256682185d23`
- Gold commit: `4b55ef8495c5bdb91e6e96892f31d9cee63ed681`
- Resource: CPU
- GPU required: no
- Patch type: C++ kernel (CPU/GPU/XPU backends)
- Python dependencies: PaddlePaddle (source build), NumPy, pytest

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.

## 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 | softmax_with_cross_entropy F2P |
| --- | ---: | ---: |
| Base + test patch | PASS | FAIL |
| Base + test patch + solution patch | PASS | PASS |

No GPU, distributed runtime, external service, or additional dataset is required.
45 changes: 45 additions & 0 deletions swe-paddle/tasks/PaddlePaddle__Paddle-73880/instruction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# 修复 `paddle.nn.functional.softmax_with_cross_entropy` 对 0-size Tensor 的处理

## 详细描述

当 `paddle.nn.functional.softmax_with_cross_entropy` 的输入 logits 中存在大小为 `0` 的 dimension(即 `softmax->numel() == 0`)时,当前 CPU/GPU/XPU kernel 实现会直接进入后续计算逻辑,导致 kernel 内部对空数据执行计算时出错或产生未定义行为。

典型表现包括:

- kernel 在处理 0-size tensor 时崩溃或报错
- 调用失败并抛出与 shape 或内存访问相关的错误

例如:

```python
import numpy as np
import paddle

paddle.disable_static()
# shape [0, 10], soft_label=False
logits = paddle.to_tensor(np.random.uniform(0.1, 1.0, (0, 10)).astype('float32'))
label = paddle.to_tensor(np.random.randint(0, 10, (0, 1), dtype='int64'))
loss, softmax = paddle.nn.functional.softmax_with_cross_entropy(logits, label, return_softmax=True)
```

上述调用中 `logits` 的 shape 为 `[0, 10]`,不包含任何元素。当 `soft_label` 为 False 时,axis 所在列不能为 0,其他列相同,因此 softmax 和 loss 的 numel 都为 0。按照 API semantics,该调用应正常完成并返回正确 shape 的空 tensor。

需要在 cross entropy kernel 的入口添加 0-size 早期返回处理:
- 当 `softmax->numel() == 0` 时,分配输出内存后直接返回
- 当 `soft_label` 为 True 时,loss 需要填充为 0
- 梯度 kernel 也需要类似处理:当 `logits_grad->numel() == 0` 时分配内存后直接返回

## 验收说明

- 当输入 logits 的 numel 为 0 时,`softmax_with_cross_entropy` 的前向和反向计算应正常完成
- 返回的 softmax 和 loss tensor 应保持正确 shape 和 dtype
- 非 0-size tensor 输入下的 cross entropy 行为不得退化
- CPU、GPU、XPU 后端均应正确处理 0-size 输入

## 技术要求

- 熟悉 C++/CUDA 和 Paddle PHI kernel 开发
- 了解 Tensor shape、0-size Tensor 和 kernel 执行路径
- 了解 cross entropy 算子的前向和反向计算语义
- 了解 Paddle CPU/GPU/XPU kernel 的实现模式
- 需要从源码编译 Paddle 以验证修改
58 changes: 58 additions & 0 deletions swe-paddle/tasks/PaddlePaddle__Paddle-73880/proposal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# SWE-Paddle Task Proposal: PaddlePaddle__Paddle-73880

## 1. 来源信息

- Instance ID: `PaddlePaddle__Paddle-73880`
- PR 链接: https://github.com/PaddlePaddle/Paddle/pull/73880
- PR 标题: `[0-size Tensor Job2 No.66] Add 0-size Tensor support for paddle.nn.functional.softmax_with_cross_entropy`
- Base commit: `e1842d4ce364b6e8334c39a8807b256682185d23`
- Gold commit: `4b55ef8495c5bdb91e6e96892f31d9cee63ed681`
- Merged at: 2025-07-16
- 你的身份: contributor

## 2. 问题一句话

`paddle.nn.functional.softmax_with_cross_entropy` 在输入 logits 为 0-size Tensor 时,CPU/GPU/XPU kernel 未处理 0-size 边界情况导致出错,需要在 kernel 入口添加 0-size 早期返回逻辑。

## 3. 为什么适合作为 SWE-Paddle 样本

- **真实性**: 来自 Paddle「0-size Tensor 机制建设」系列任务,是真实研发需求。
- **代表性**: 覆盖 C++ kernel 层面的 0-size Tensor 边界处理,涉及 CPU、GPU、XPU 三个后端的前向和梯度 kernel。
- **边界清楚**: 目标仅限 `softmax->numel() == 0` 时的 kernel 早期返回;正向非零尺寸输入不应受影响。
- **非平凡性**: 修复需要在 `cross_entropy_kernel.cc`、`cross_entropy_grad_kernel.cc`(CPU)、`cross_entropy_kernel.cu`、`cross_entropy_grad_kernel.cu`(GPU)、`cross_entropy_kernel.cc`、`cross_entropy_grad_kernel.cc`(XPU)中分别添加 `numel() == 0` 的早期返回,涉及对 soft_label 为 True 时 loss 填充 0 的特殊处理。
- **回归护栏明确**: 目标 F2P 可覆盖 0-size Tensor 输入的 `softmax_with_cross_entropy` 算子测试;同文件中已有的 `TestSoftmaxWithCrossEntropyOp` 标准测试用例可作为 P2P 护栏。

## 4. 任务类型和标签

- 任务类型: `bug_fix`
- 执行后端: `cpu`
- 设备范围: `cpu_only`
- 模块标签: `[operator_kernel, cross_entropy, softmax_with_cross_entropy, 0-size_tensor, cpu_kernel, gpu_kernel, xpu_kernel]`

## 5. 验证思路

- 目标测试命令: `bash tests/test.sh`
- 目标测试文件:
- `test/legacy_test/test_softmax_with_cross_entropy_op.py`(`TestSoftmaxWithCrossEntropyOp_ZeroSize`、`TestSoftmaxWithCrossEntropyOp_ZeroSize2`)
- P2P 候选: 同文件中已有的 `TestSoftmaxWithCrossEntropyOp` 标准算子测试用例。
- 修复前预期: `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 端),需要重新编译 Paddle。
- 最小测试命令: `bash tests/test.sh`
- 是否有 oracle 日志: 无

## 7. 风险自查

- 泄露风险: 正式 `instruction.md` 只描述「softmax_with_cross_entropy 对 0-size Tensor 输入的行为异常」,不指出具体 `numel() == 0` 分支逻辑或具体代码位置。
- 环境风险: 中。任务涉及 C++ kernel 修改,需要源码编译 Paddle,编译时间较长。
- flaky 风险: 低。测试使用固定的 0-size Tensor 构造,不依赖随机数差异或多设备同步。
- 拆分风险: 低。该 PR 目标集中在 cross entropy kernel 的 0-size 早期返回,测试明确指向新增的 ZeroSize 测试类,适合作为一个独立样本。
- 其他不确定点: 完整任务包阶段应确认新增 F2P 在 `base_commit` 编译后确实失败。GPU 和 XPU 的修改在 CPU 环境下无法验证,但 CPU kernel 的修改足以让测试通过。
143 changes: 143 additions & 0 deletions swe-paddle/tasks/PaddlePaddle__Paddle-73880/solution/code.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
diff --git a/paddle/phi/kernels/cpu/cross_entropy_grad_kernel.cc b/paddle/phi/kernels/cpu/cross_entropy_grad_kernel.cc
index 7f755227cb7a3..f9b3daee2571a 100644
--- a/paddle/phi/kernels/cpu/cross_entropy_grad_kernel.cc
+++ b/paddle/phi/kernels/cpu/cross_entropy_grad_kernel.cc
@@ -34,6 +34,11 @@ void CrossEntropyWithSoftmaxGradCPUKernel(const CPUContext& dev_ctx,
int ignore_index,
int axis,
DenseTensor* logits_grad) {
+ if (logits_grad->numel() == 0) {
+ dev_ctx.template Alloc<T>(logits_grad);
+ return;
+ }
+
const DenseTensor* out_grad = &loss_grad;
DenseTensor* logit_grad = logits_grad;

diff --git a/paddle/phi/kernels/cpu/cross_entropy_kernel.cc b/paddle/phi/kernels/cpu/cross_entropy_kernel.cc
index fa2728257f883..e170f642f8792 100644
--- a/paddle/phi/kernels/cpu/cross_entropy_kernel.cc
+++ b/paddle/phi/kernels/cpu/cross_entropy_kernel.cc
@@ -17,6 +17,7 @@ limitations under the License. */
#include "paddle/phi/backends/cpu/cpu_context.h"
#include "paddle/phi/core/kernel_registry.h"
#include "paddle/phi/core/tensor_utils.h"
+#include "paddle/phi/kernels/full_kernel.h"
#include "paddle/phi/kernels/funcs/axis_utils.h"
#include "paddle/phi/kernels/funcs/cross_entropy.h"
#include "paddle/phi/kernels/funcs/math_function.h"
@@ -79,6 +80,19 @@ void CrossEntropyWithSoftmaxKernel(const Context& dev_ctx,
int axis,
DenseTensor* softmax,
DenseTensor* loss) {
+ if (softmax->numel() == 0) {
+ // When soft_label is False, the axis column cannot be 0. Other dimensions
+ // are the same, so the numel of softmax and loss are both 0.
+ dev_ctx.template Alloc<T>(softmax);
+ dev_ctx.template Alloc<T>(loss);
+
+ // When soft_label is True, the axis column is 1.
+ if (soft_label) {
+ phi::Full<T, Context>(
+ dev_ctx, phi::IntArray(common::vectorize(loss->dims())), 0, loss);
+ }
+ return;
+ }
// do not with softmax op, and input is softmax
if (!use_softmax) {
CrossEntropy<T>(
diff --git a/paddle/phi/kernels/gpu/cross_entropy_grad_kernel.cu b/paddle/phi/kernels/gpu/cross_entropy_grad_kernel.cu
index ea3be7c95480e..fed6a9778092a 100644
--- a/paddle/phi/kernels/gpu/cross_entropy_grad_kernel.cu
+++ b/paddle/phi/kernels/gpu/cross_entropy_grad_kernel.cu
@@ -241,6 +241,10 @@ void CrossEntropyWithSoftmaxGradKernel(const Context& dev_ctx,
int ignore_index,
int axis,
DenseTensor* logits_grad) {
+ if (logits_grad->numel() == 0) {
+ dev_ctx.template Alloc<T>(logits_grad);
+ return;
+ }
auto dtype = label.dtype();
if (soft_label) {
PADDLE_ENFORCE_EQ(
diff --git a/paddle/phi/kernels/gpu/cross_entropy_kernel.cu b/paddle/phi/kernels/gpu/cross_entropy_kernel.cu
index 790e701b2e57f..7a1be5e4b8d04 100644
--- a/paddle/phi/kernels/gpu/cross_entropy_kernel.cu
+++ b/paddle/phi/kernels/gpu/cross_entropy_kernel.cu
@@ -13,6 +13,7 @@ See the License for the specific language governing permissions and
limitations under the License. */

#include "paddle/phi/kernels/cross_entropy_kernel.h"
+#include "paddle/phi/kernels/full_kernel.h"

#include "glog/logging.h"

@@ -1402,6 +1403,20 @@ void CrossEntropyWithSoftmaxKernel(const Context& dev_ctx,
int axis,
DenseTensor* softmax,
DenseTensor* loss) {
+ if (softmax->numel() == 0) {
+ // When soft_label is False, the axis column cannot be 0. Other dimensions
+ // are the same, so the numel of softmax and loss are both 0.
+ dev_ctx.template Alloc<T>(softmax);
+ dev_ctx.template Alloc<T>(loss);
+
+ // When soft_label is True, the axis column is 1.
+ if (soft_label) {
+ phi::Full<T, Context>(
+ dev_ctx, phi::IntArray(common::vectorize(loss->dims())), 0, loss);
+ }
+ return;
+ }
+
auto dtype = label.dtype();
if (soft_label) {
PADDLE_ENFORCE_EQ(
diff --git a/paddle/phi/kernels/xpu/cross_entropy_grad_kernel.cc b/paddle/phi/kernels/xpu/cross_entropy_grad_kernel.cc
index a4572fea4187c..e660f64b876bc 100644
--- a/paddle/phi/kernels/xpu/cross_entropy_grad_kernel.cc
+++ b/paddle/phi/kernels/xpu/cross_entropy_grad_kernel.cc
@@ -33,6 +33,9 @@ void CrossEntropyWithSoftmaxGradKernel(const Context& dev_ctx,
DenseTensor* logit_grad) {
using XPUType = typename XPUTypeTrait<T>::Type;
dev_ctx.template Alloc<T>(logit_grad);
+ if (logit_grad->numel() == 0) {
+ return;
+ }

const int rank = logit_grad->dims().size();
const int axis = phi::funcs::CanonicalAxis(axis_in, rank);
diff --git a/paddle/phi/kernels/xpu/cross_entropy_kernel.cc b/paddle/phi/kernels/xpu/cross_entropy_kernel.cc
index a574100165aac..a6be20843ed61 100644
--- a/paddle/phi/kernels/xpu/cross_entropy_kernel.cc
+++ b/paddle/phi/kernels/xpu/cross_entropy_kernel.cc
@@ -16,6 +16,7 @@ limitations under the License. */

#include "paddle/phi/backends/xpu/enforce_xpu.h"
#include "paddle/phi/core/kernel_registry.h"
+#include "paddle/phi/kernels/full_kernel.h"
#include "paddle/phi/kernels/funcs/axis_utils.h"

namespace phi {
@@ -31,6 +32,20 @@ void CrossEntropyWithSoftmaxKernel(const Context& dev_ctx,
int axis_in,
DenseTensor* softmax,
DenseTensor* loss) {
+ if (softmax->numel() == 0) {
+ // When soft_label is False, the axis column cannot be 0. Other dimensions
+ // are the same, so the numel of softmax and loss are both 0.
+ dev_ctx.template Alloc<T>(softmax);
+ dev_ctx.template Alloc<T>(loss);
+
+ // When soft_label is True, the axis column is 1.
+ if (soft_label) {
+ phi::Full<T, Context>(
+ dev_ctx, phi::IntArray(common::vectorize(loss->dims())), 0, loss);
+ }
+ return;
+ }
+
using XPUType = typename XPUTypeTrait<T>::Type;
const int rank = logits.dims().size();
const int axis = phi::funcs::CanonicalAxis(axis_in, rank);
Loading