Closed
[Bug-Report|缺陷反馈]: aclnnCdistBackward 空输入 × 非空 out 早退不填输出,返回成功但 out 为未初始化内存 #3360
liuhanwen8Add on  Sep 29Closed at  28 days ago
liuhanwen8
liuhanwen8
Sep 29 Create

Describe the current behavior / 问题描述 (Mandatory / 必填)

math/cdist_grad/op_api/aclnn_cdist_backward.cpp:当 grad/x1/x2/cdist 任一为空张量时,:172-176 直接早退返回 ACLNN_SUCCESS,无任何 Fill/ViewCopy,out 不被触碰:

172:    if (grad->IsEmpty() || x1->IsEmpty() || x2->IsEmpty() || cdist->IsEmpty()) {
173:        *workspaceSize = 0;
174:        uniqueExecutor.ReleaseTo(executor);
175:        return ACLNN_SUCCESS;
176:    }

契约 shape:grad/cdist=[B,P,Q]、x1/out=[B,P,M]、x2=[B,Q,M](:130-131 强校验 cdist==grad、out==x1)。当 x2 的 Q=0 时 x2=[B,0,M] 为空、grad/cdist=[B,P,0] 为空,而 out=[B,P,M] 非空 → 命中该早退分支,workspaceSize=0(图里没有算子)。

数学上 Q=0 时 x1 的梯度 = 对空 j 集求和 = 0(PyTorch cdist 反传同样返回全零),正确行为应把非空 out 填 0;实际却是返回成功、out 保持调用方 GM 残留值(未初始化内存/历史数据),属静默错误。

对照同仓族正确样板:ops-cv objdetect/roi_align/op_api/aclnn_roi_align.cpp:189-199(空张量早退时 GetOutTensorWithValueZero + ViewCopy 填 0,workspaceSize 非 0)。

Environment Information / 环境信息 (Mandatory / 必填)

  • 昇腾硬件型号:Ascend910_93
  • CANN 版本:9.2.0
  • 代码基线:ops-math master(2026-09-28,6e9ed32)
  • 调用方式:C 直调 aclnn 两段式接口

Steps to reproduce the issue / 重现步骤 (Mandatory / 必填)

dtype=float32、p=2.0、x1=[2,3,4]、x2=[2,0,4]、grad=[2,3,0]、cdist=[2,3,0]、out=[2,3,4](先用可识别值预置 out 的 GM),调用 aclnnCdistBackwardGetWorkspaceSize + 第二段。910_93 实测(读回值):

用例 输入 GetWorkspaceSize workspaceSize out 读回
A 空输入 × 非空 out x2 [2,0,4] ret=0 0 预置 NaN → 24/24 仍为 NaN
C 空输入 × 非空 out x2 [2,0,4] ret=0 0 预置 12345.0 → 24/24 仍为 12345.0
B 对照 x2 [2,5,4] ret=0 16779776 正常写入,NaN 0/24

C 用例为决定性证据:调用方预置值原样返回,表明输出内存完全未被算子触碰;B 用例证明同一 harness 下算子可正常写入、workspaceSize 非 0。

Describe the expected behavior / 预期结果 (Mandatory / 必填)

早退分支对非空 out 执行填 0(仿 roi_align 样板 GetOutTensorWithValueZero + l0op::ViewCopy,保留 ReleaseTo),或显式返回 ACLNN_ERR_PARAM_INVALID 拒绝该组合;不应返回成功却把未初始化内存当结果交给调用方。

CASE=A_nan    x2Qempty=1 ret=0 ws=0        | out 读回 NaN=24/24
CASE=C_sent   x2Qempty=1 ret=0 ws=0        | out 读回 12345.0=24/24
CASE=B_ok     x2Qempty=0 ret=0 ws=16779776 | out 读回 NaN=0/24(正常写入)

命中行:op_api/aclnn_cdist_backward.cpp:172-176(早退不填输出);契约校验 :130-131。

Special notes for this issue/备注 (Optional / 选填)

  • 触发条件收敛:只有 x2 的 Q=0(B,P,M>0)会让 out 非空而输入为空;其余 B=0/P=0/M=0 时 out 也为空,早退属无害 no-op。
  • 影响场景:点云/度量学习类(Chamfer、triplet/对比学习、距离矩阵)中某样本点集为空、x2 = feats[mask] 过滤后数量为 0、变长/动态 shape 致某维退化为 0;配合框架用 empty 分配梯度缓冲(未清零)时会踩中,表现为梯度为 NaN/脏值且无任何报错。
  • 同族第 4 例(GridSampler2DBackward / GridSampler3DBackward / ops-cv#1124 UpsampleBilinear2dAABackward),建议 op_api 空张量早退统一按 roi_align 样板批量修复。
likedislike
liuhanwen8liuhanwen8
Sep 29 Added label: bug-report
陈思
陈思Collaborators
Sep 30 Comments:

您好,感谢反馈!

问题分析

已核对您给出的 ops-math 基线 6e9ed32722ac18519e48602394a1e30d88a51e19。aclnnCdistBackwardGetWorkspaceSize 在参数校验之后,只要任一输入 Tensor 为空就直接设置 workspaceSize=0 并返回成功;此时尚未构建 CdistGrad 或输出 ViewCopy 任务,也没有补零操作。相关实现

在您提供的 x1/out=[2,3,4]、x2=[2,0,4]、grad/cdist=[2,3,0] 用例中,Q=0 使输入为空,但输出仍有 24 个元素。反向结果是对第二个点集的贡献求和,空集合对应全零梯度,不能按“输出也为空”处理。现有早退没有任何写输出任务,与您报告的 NaN 和 12345.0 预置值原样保留相符;这是空输入分支遗漏输出初始化的问题。

处理方向

可行的修正是在公共 API 的空输入分支中区分输出是否为空:输出为空时保留无计算早退;输出非空时,按 out 的逻辑形状和数据类型生成零值 Tensor,再通过 ViewCopy 写回调用方输出,使非连续输出也遵循正常的视图写回语义。补零和写回任务需要加入同一个 executor,并从 executor 获取实际 workspace 大小后再移交,不能在添加任务后仍固定填写零。

现有接口允许这组形状,按空集合求和语义补零可以保留该用法;直接改为参数错误则会改变其接受范围。验证重点是您提供的两种预置值能否全部被零覆盖,同时确认空输出仍可直接返回,以及非空输入和非连续输出的行为。您已提供足够的最小用例和读回结果,我们会继续跟踪该空输入分支的处理。

likedislike
陈思陈思Collaborators
Sep 30 Assign sakuraqqz as responsible person
fitZepHYrfitZepHYrCollaborators
Oct 8 Associated pull request
CANN-robotCANN-robotCollaborators
28 days ago Close issue
fitZepHYrfitZepHYrCollaborators
28 days ago Associated pull request
CANN-robotCANN-robotCollaborators
28 days ago Added label: resolved