您好,感谢反馈!
问题分析
核对 cann/ops-math 固定版本 8c1f633e3679,接口资料没有对 unbiased=true 增加归约元素数必须大于 1 的限制。这里需要按归约轴的元素数 N 判断,self=[1,3]、dim=[0] 同样属于 N=1,不能仅检查输入总元素数。
aclnn_var.cpp 中,aclnnVar 在空张量和参数处理后,没有对 unbiased=true、N=1 提前构建 NaN 输出;910B 所在的非 RegBase 分支仍进入均值、广播及 ReduceStdV2Update 组合链。您提供的日志显示,目标环境的 tiling 按 correction=1 处理无偏估计并拒绝 N=1;对应的 L0 包装在任务构造失败后返回空结果,上层将其映射为 ACLNN_ERR_INNER_NULLPTR(561103),因此失败可以出现在第一段接口,而非数值比对阶段。
同文件的 aclnnVarCorrection 已有 shapeProd==1 && shapeProd<=correction 时填充 NaN 的分支,可在 correction=1 时绕过上述组合计算。这说明两接口对等价边界的处理存在缺口;该对照并不代表底层 kernel 原生支持这一边界。当前确认的是固定版本源码差异,报告中 910B3、CANN 26.1.1 的设备结果尚未由我们独立复测;RegBase 的 ReduceVar 路径也需分别看待。
处理方向
一个可行的方案是在 aclnnVar 完成参数检查、空张量处理及归约轴解析后,为非 RegBase 路径的 unbiased=true、N=1 补充 NaN 输出处理,参考已有 VarCorrection 的填充方式,同时保留填充返回状态、实际 workspace 和 executor 的正常交付。
这一分支需按归约轴乘积覆盖标量、全归约及局部归约,并兼容 keepdim、输出类型和非连续输出;unbiased=false、N=1 的零方差以及现有空张量处理需保持原有语义。我们会继续跟踪这一退化边界的处理差异。


一、问题描述
aclnnVar对资料允许的合法输入(self任意合法 shape、dim任意合法取值、unbiased无附加限制)在unbiased=true且归约轴元素数恰为 1 时,第一段aclnnVarGetWorkspaceSize直接返回 561103(
ACLNN_ERR_INNER,内部错误),而不是按方差语义返回nan。关键对照:同一份代码里的兄弟接口
aclnnVarCorrection在完全等价的输入(
correction=1、归约轴元素数 1)下正常返回 0 且输出 nan —— 因为它在aclnn_var.cpp:301-318有一段
shapeProd <= correction → 填 NAN / INFINITY的早退分支,而aclnnVar没有。plog 原文(CANN 自身打印,非推测):
即
aclnnVar(unbiased=true)把unbiased直接当correction=1传给ReduceStdV2Update(
aclnn_var.cpp:224),而该内核的 tiling 明确拒绝input_shape <= correction;由于aclnnVar没有像
aclnnVarCorrection那样提前拦下这个退化情形,tiling 失败被 l0op 冒泡成 561103。影响面(同一轮 1000 条用例实测,非抽样猜测):
unbiased=true且归约轴元素数 = 1判据是集合完全等价:ERROR 集合与
{unbiased=true ∧ N_red=1}逐条相等(无多、无少)。归约轴元素数=1 在真实模型里很常见(batch=1、seq=1、单通道、归一化维=1),一旦命中即整网报错。
二、环境信息
/usr/local/Ascend/ascend-toolkit)master,math/reduce_var(ref_commit72d787648)math/reduce_var/docs/aclnnVar.md(389 行,sha256960025a5…)三、重现步骤
var_n1.cpp(A子例=被测点,D子例=aclnnVarCorrection对照);g++ -std=c++17 var_n1.cpp -o var_n1 -I$ASCEND_HOME_PATH/include -L$ASCEND_HOME_PATH/lib64 -lascendcl -lnnopbase -lopapi;./var_n1 A(被测)与./var_n1 D(对照),同一份输入self=[1]、dim=nullptr、keepdim=true。#include <cstdio> #include <vector> #include "acl/acl.h" #include "aclnnop/aclnn_var.h" static aclTensor* Mk(float v, void** addr) { std::vector<int64_t> sh{1}, st{1}; aclrtMalloc(addr, 4, ACL_MEM_MALLOC_HUGE_FIRST); aclrtMemcpy(*addr, 4, &v, 4, ACL_MEMCPY_HOST_TO_DEVICE); return aclCreateTensor(sh.data(), 1, ACL_FLOAT, st.data(), 0, ACL_FORMAT_ND, sh.data(), 1, *addr); } int main(int argc, char** argv) { bool corr = (argc > 1 && argv[1][0] == 'D'); // D = VarCorrection 对照 aclInit(nullptr); aclrtSetDevice(0); aclrtStream s = nullptr; aclrtCreateStream(&s); void *sa = nullptr, *oa = nullptr; float v = 7.0f, o = -12345.0f; aclTensor* self = Mk(v, &sa); // self = [1] aclTensor* out = Mk(o, &oa); // out = [1](keepdim=true) uint64_t ws = 0; aclOpExecutor* e = nullptr; aclnnStatus r1 = corr ? aclnnVarCorrectionGetWorkspaceSize(self, nullptr, 1, true, out, &ws, &e) : aclnnVarGetWorkspaceSize(self, nullptr, /*unbiased=*/true, true, out, &ws, &e); printf("ret1=%d\n", (int)r1); if (r1 == 0) { void* wsp = nullptr; if (ws > 0) aclrtMalloc(&wsp, ws, ACL_MEM_MALLOC_HUGE_FIRST); aclnnStatus r2 = corr ? aclnnVarCorrection(wsp, ws, e, s) : aclnnVar(wsp, ws, e, s); aclrtSynchronizeStream(s); aclrtMemcpy(&o, 4, oa, 4, ACL_MEMCPY_DEVICE_TO_HOST); printf("ret2=%d\nout=%f\n", (int)r2, o); } return 0; }实测输出(910B3,CANN 26.1.1):
控制变量矩阵(每行只改一个变量,其余同
A):B/C 通过说明探针构造与绑定无误;D 通过说明不是内核不支持,而是
aclnnVar少了一段退化分支。四、预期结果
aclnnVar(self=[1], dim=nullptr, unbiased=true, keepdim=true)应返回 0,out = nan(与
torch.var(x, dim=None, correction=1)的语义一致;torch.var在该输入下返回nan,aclnnVarCorrection已按此实现);unbiased=true附加任何 shape 限制,因此当前行为属于「合法输入被拒 + 错误码为内部错误」双重不符。修复方向(与同文件既有写法对齐,
aclnn_var.cpp:301-310可直接复用):// aclnnVarGetWorkspaceSize 中,dimArray 解析完成之后、Contiguous/Cast 之前 int64_t shapeProd = CalcShapeProd(self, dimArray); // 该函数本文件已有(:129-138) if (shapeProd <= (unbiased ? 1 : 0)) { // 即 N - correction <= 0 ret = CheckFillScalarShapeStdAndVar(out, NAN, uniqueExecutor.get()); *workspaceSize = uniqueExecutor->GetWorkspaceSize(); uniqueExecutor.ReleaseTo(executor); return ret; }备注
aclnnVar/方差/ReduceStdV2Update/561103在 cann/ops-math 全量翻页检索(≥3000 条),未发现同现象单据。#2565(closed)处理的是「空 tensor / corner case 路径
workspaceSize被误写为 0」,最终结果是 workspace 不足,不是本单的「缺退化分支 → tiling 报错」;#4172 是
aclnnVarMean的 bf16 问题,接口与现象都不同。#3987 是 aclnnVar 文档链接错误。self=bf16[1]|dim=null|unbiased=true,该基线自身返回 561103,导致该线 6 条「与资料一致」的判据一并降级为
MATCH_UNVERIFIED——这是同一缺陷的第二个受害面(它把别的判据的基线也污染了)。