Closed
[Bug-Report|缺陷反馈]: aclnnMultinomial / aclnnMultinomialTensor 空 self 早退不填非空输出(返回 SUCCESS 但 out 保持未初始化,脏数据流出) #3560
liuhanwen8Add on  26 days agoClosed at  24 days ago
liuhanwen8
liuhanwen8
26 days ago Create

现象

aclnnMultinomialGetWorkspaceSize / aclnnMultinomialTensorGetWorkspaceSize 在 self 为空张量时裸早退:置 workspaceSize=0 直接返回 ACLNN_SUCCESS,不进入计算、也不对输出 out 做任何写入。当 out 为非空张量时(shape 不小于 self 的对应维度),调用方拿到的是未初始化内存(脏数据/随机值),且接口无任何报错。

代码位置

random/stateless_sample_multinomial/op_api/aclnn_multinomial.cpp

// :463-467  aclnnMultinomialGetWorkspaceSize
if (self->IsEmpty()) {
    *workspaceSize = 0;
    uniqueExecutor.ReleaseTo(executor);
    return ACLNN_SUCCESS;          // <- out 完全未被写入
}

// :569-573  aclnnMultinomialTensorGetWorkspaceSize(同型)
if (self->IsEmpty()) {
    *workspaceSize = 0;
    uniqueExecutor.ReleaseTo(executor);
    return ACLNN_SUCCESS;
}

相关校验:

  • CheckShape(:153-182):仅约束 self 维度数 ∈ {1,2}、out 维度数 == self 维度数、out 末维 == numsamples、2 维时 out 首维 == self 首维;未约束 out 空性随 self 联动。
  • CheckValueRange(:184-203):numsamples > 0 恒强制;!replacement && numsamples > C 报错;C ≤ 2^24。
    ⇒ C=0(self 末维为 0)时,仅 replacement=true 可通过校验并抵达早退(replacement=false 会因 numsamples > C=0 被拒)。

影响

取 self 末维 C=0、replacement=true、numsamples ≥ 1:

  • CheckShape 放行:1 维 self=[0] → out=[numsamples];2 维 self=[N,0] → out=[N, numsamples],均为非空张量;
  • CheckValueRange 放行(numsamples>0;replacement=true 跳过 numsamples ≤ C;C=0 ≤ 2^24);
  • 命中 :463 早退,返回 ACLNN_SUCCESS,out 保持分配时的未初始化显存 → 调用方读到脏数据。

正确语义:C=0 表示无类别可采样,应报错拒绝(PyTorch 对空输入 multinomial 抛错),或按 out shape 填默认值;当前「成功却不写输出」属静默脏数据。

复现(NPU 实测)

环境:CANN 9.2.0-beta.2,Ascend 910B2,device 2。以 ctypes 直调 libopapi_math.so;self 用 FP32 全 0.25,out 为 INT64 并预填哨兵 999999,seed=1, offset=0:

用例 self out numsamples replacement 结果
实验1 [0](C=0,空) [2](非空) 2 true ret=0 ACLNN_SUCCESS, workspaceSize=0,out 全 999999(未写)
实验2 [3,0](C=0,空) [3,2](非空) 2 true ret=0 ACLNN_SUCCESS, workspaceSize=0,out 全 999999(未写)

即接口返回成功,但非空 out 完全未被写入(应为报错或全 0)。

期望行为

C == 0 时:① 返回 ACLNN_ERR_PARAM_INVALID(161002)拒绝,或 ② 对 out 填默认值后再返回成功。二者取其一,保持「成功 ⇒ 输出有定义」。

修复建议

任选其一:

  1. 收窄早退条件为「self 空且 out 空」;
  2. 推荐:在 CheckParams/CheckParamsTensor 增加 C > 0 约束,C == 0 时返回 ACLNN_ERR_PARAM_INVALID;
  3. 保留宽容语义时,在早退前对 out 做 Fill 0 + ViewCopy 回填(参考 ops-cv aclnn_roi_align.cpp:189-197 空张量填 0 范式)。

aclnnMultinomial 与 aclnnMultinomialTensor 两处早退需一并处理。

环境

  • CANN 9.2.0-beta.2
  • 仓库:cann/ops-math(当前 master 仍存在)
  • 平台:Ascend 910B2

关联(同机理、不同算子,非重复)

  • #3360(aclnnCdistBackward 空输入 × 非空 out 早退不填输出)
  • #3553(pad 系反向与 UnfoldGrad 空输入 × 非空出参早退不填输出)
likedislike
liuhanwen8liuhanwen8
26 days ago Added label: bug-report
陈思
陈思Collaborators
25 days ago Comments:

您好,感谢反馈!

问题分析

核查 cann/ops-math master 8f1aae7e1927 的 Multinomial 实现,两个第一段入口共用 CheckShape/CheckValueRange:当前限制 numsamples 为正、无放回时不超过类别数,但没有排除类别维 C=0。因此在 replacement=true 时,self=[0] → out=[2] 或 self=[3,0] → out=[3,2] 可通过检查,再从 self->IsEmpty() 分支直接成功返回,未构造采样或写回节点。这与您提供的 out 哨兵值不变现象一致。

处理方向

一个更符合采样含义的方向是在共用校验中拒绝 C=0,使标量 seed/offset 和 Tensor seed/offset 两个入口保持一致。类别集合为空时,填索引 0 也不能代表一个有效采样结果,因此不宜仅通过回填 0 让接口返回成功。

还需要区分“零类别”与“零批次”:[0,C] 且 C>0 的结果 [0,numsamples] 本身为空,不能因为 self->IsEmpty() 就与 [N,0] 一并拒绝。可分别覆盖这两类形状以及 replacement 的两个取值,确认错误码和合法空输出路径。我们会持续跟踪这一参数校验问题。

likedislike
yue-maCollaborators
25 days ago Comments:

assign @ji-songyuan

likedislike
ZzhuzemaoCollaborators
25 days ago Assign zhuzemao as responsible person
ZzhuzemaoCollaborators
25 days ago Associated pull request
CANN-robotCANN-robotCollaborators
24 days ago Close issue
CANN-robotCANN-robotCollaborators
24 days ago Added label: resolved