已关闭
[Documentation|文档反馈]: aclnnAminmaxAll 资料未声明出参形状约束,161002 错误码表缺「出参元素数不一致」子项 #4287
liuhanwen8创建于  5 天前关闭于  2 天前
liuhanwen8
liuhanwen8
5 天前 创建

环境

  • 资料:math/reduce_min/docs/aclnnAminmaxAll.md(cann/ops-math master 1d0e7bab)
  • 头文件:aclnnop/aclnn_aminmax_all.h(CANN 9.2.0 随包)
  • 硬件/软件:Atlas A3 训练系列(Ascend 910_93)/ CANN 9.2.0 / Linux aarch64

现象

两处「用户按资料写代码必踩、但资料没说」的缺口,都在出参形状上:

  1. minOut / maxOut 的形状约束没写。参数表两行的「维度(shape)」列都是 -,
    而实现要求出参元素数必须是 1(CheckShapeAndScalarSame:与归约结果同形,或元素数为 1)。
    示例 L293 用 outShape = {1},仓库 ut 却用 0 维 TensorDesc({}, ...) —— 两种都合法,但资料正文没写。
  2. 错误码表 161002 只有 3 个子项(rowspan="3":dtype 不在支持范围 / minOut/maxOut 与 self
    dtype 不一致 / shape 超过 8 维),没有「出参元素数与归约结果不一致」这一条。
    而这恰好是最容易踩的:把出参建成输入的形状(self=[2,3,2] 就配 minOut=[2,3,2])会直接 161002。

实测(A3 单卡,CANN 9.2.0)

self minOut / maxOut 第一段返回 第二段
fp32[2,3,2] fp32[2,3](6 元素) 161002 未执行
fp32[2,3,2] fp32[2](2 元素) 161002 未执行
fp32[2,3,2] fp32[1] 0 0,min=-12.25 / max=9
fp32[2,3,2] fp32[](0 维) 0 0,min=-12.25 / max=9
fp32[2,3,2] fp32[1,1] 0 0,min=-12.25 / max=9

即:1 元素的任意形状都放行,元素数 ≠1 一律 161002(与 0 维出参同形也放行)。

期望

  1. 错误码表 161002 补第 4 子项,例如:「minOut 或 maxOut 的元素数与归约结果不一致时。」
  2. 参数表 minOut / maxOut 的「维度(shape)」列补一句硬约束:
    「与归约结果同形(0 维)或元素数为 1;否则返回 161002」。

影响

按资料写代码的调用方无法判断该给 [] 还是 [1],也不知道把出参建成输入形状会被拒;
反过来,维护者排查「为什么 161002」时,错误码表给不出对应子项。

复现

自包含探针(只依赖 CANN 9.2.0 + 一张 NPU;出参预填哨兵,顺带能看到出参是否被写):

// g++ -std=c++17 -O2 repro.cpp -o repro -I$ASCEND_HOME_PATH/include \
//     -L$ASCEND_HOME_PATH/lib64 -lascendcl -lnnopbase -lopapi
#include <cstdio>
#include <vector>
#include "acl/acl.h"
#include "aclnnop/aclnn_aminmax_all.h"

static aclTensor* Make(const std::vector<int64_t>& sh, aclDataType dt, void* addr) {
  std::vector<int64_t> st(sh.size(), 1);
  for (int64_t i = (int64_t)sh.size() - 2; i >= 0; i--) st[i] = sh[i + 1] * st[i + 1];
  return aclCreateTensor(sh.data(), sh.size(), dt, st.data(), 0, ACL_FORMAT_ND,
                         sh.data(), sh.size(), addr);
}

static void Run(const char* tag, aclrtStream s, const std::vector<int64_t>& osh) {
  std::vector<int64_t> ssh = {2, 3, 2};
  float data[12] = {3, -1, 7.5f, 0, -12.25f, 5, 9, 2, -3, 8, 1, 4};
  int64_t on = 1;
  for (auto v : osh) on *= v;
  void *sa = nullptr, *ma = nullptr, *xa = nullptr;
  aclrtMalloc(&sa, sizeof(data), ACL_MEM_MALLOC_HUGE_FIRST);
  aclrtMemcpy(sa, sizeof(data), data, sizeof(data), ACL_MEMCPY_HOST_TO_DEVICE);
  aclrtMalloc(&ma, on * 4, ACL_MEM_MALLOC_HUGE_FIRST);
  aclrtMalloc(&xa, on * 4, ACL_MEM_MALLOC_HUGE_FIRST);
  aclTensor* self = Make(ssh, ACL_FLOAT, sa);
  aclTensor* mn = Make(osh, ACL_FLOAT, ma);
  aclTensor* mx = Make(osh, ACL_FLOAT, xa);
  uint64_t ws = 0; aclOpExecutor* ex = nullptr;
  auto rc1 = aclnnAminmaxAllGetWorkspaceSize(self, mn, mx, &ws, &ex);
  int rc2 = -1;
  if (rc1 == 0) {
    void* wa = nullptr;
    if (ws > 0) aclrtMalloc(&wa, ws, ACL_MEM_MALLOC_HUGE_FIRST);
    rc2 = aclnnAminmaxAll(wa, ws, ex, s);
    aclrtSynchronizeStream(s);
    if (wa) aclrtFree(wa);
  }
  float vmin = 0, vmax = 0;
  if (rc1 == 0) {
    aclrtMemcpy(&vmin, 4, ma, 4, ACL_MEMCPY_DEVICE_TO_HOST);
    aclrtMemcpy(&vmax, 4, xa, 4, ACL_MEMCPY_DEVICE_TO_HOST);
  }
  printf("%-22s out=[%s] rc1=%d rc2=%d min=%g max=%g\n", tag,
         osh.empty() ? "0d" : "n", rc1, rc2, vmin, vmax);
  aclDestroyTensor(self); aclDestroyTensor(mn); aclDestroyTensor(mx);
  aclrtFree(sa); aclrtFree(ma); aclrtFree(xa);
}

int main() {
  aclInit(nullptr); aclrtSetDevice(0);
  aclrtStream s = nullptr; aclrtCreateStream(&s);
  Run("out=[2,3]", s, {2, 3});
  Run("out=[2]", s, {2});
  Run("out=[1]", s, {1});
  Run("out=[] 0-dim", s, {});
  Run("out=[1,1]", s, {1, 1});
  aclrtDestroyStream(s); aclrtResetDevice(0); aclFinalize();
  return 0;
}

本机输出:

out=[2,3]              out=[n] rc1=161002 rc2=-1 min=0 max=0
out=[2]                out=[n] rc1=161002 rc2=-1 min=0 max=0
out=[1]                out=[n] rc1=0      rc2=0  min=-12.25 max=9
out=[] 0-dim           out=[0d] rc1=0     rc2=0  min=-12.25 max=9
out=[1,1]              out=[n] rc1=0      rc2=0  min=-12.25 max=9

补充(同一接口,另一条已在 issue 中跟踪,不在此重复)

空 tensor(self=[0,4] 等)两段返回 0 但两个出参都不写入,信息与本条无关,
已在 #3838 中跟踪,此处仅说明本条不涉及其行为。

likedislike
liuhanwen8liuhanwen8
5 天前 添加了label:documentation
陈思
陈思成员
5 天前 评论:

您好,感谢反馈!

问题分析

对于您给出的非空、非零维输入,接口在完成全轴 ReduceMin/ReduceMax 后,分别调用 CheckShapeAndScalarSame 检查两个出参,不满足时返回 ACLNN_ERR_PARAM_INVALID。资料的输出 shape 列目前没有约束描述,161002 表也仅列 dtype 和最大维度三项,确实没有交代这一归约结果与出参的形状关系。您报告的 []、[1]、[1,1] 放行和多元素出参被拒,与这一调用位置吻合。

核查源码与资料为 cann/ops-math@8c1f633e3679f83b55a237c552f842cdcf80462f:math/reduce_min/op_api/aclnn_aminmax_all.cpp、math/reduce_min/docs/aclnnAminmaxAll.md。

处理方向

可在 minOut/maxOut 参数说明中写清标量归约结果及单元素输出的兼容关系,并在 161002 下补充形状不匹配说明,注明出参仍需满足最大 8 维等已有约束。零维 self 走直接 ViewCopy 分支,空输入也有提前返回,因此文档措辞需要区分这些路径,避免把非空、非零维输入的验证结论扩大到所有输入;您另行跟踪的空 tensor 写回行为可继续留在 #3838。

likedislike
陈思陈思成员
5 天前 将 chen_0715 设为负责人
陈思陈思成员
5 天前 添加了label:pending-confirmation
Cchenyifeng成员
5 天前 将 m0_55003149 设为负责人
Cchenyifeng成员
5 天前 移除了负责人 chen_0715
weikeweike成员
4 天前 关联了pull request:docs(reduce): 澄清 MeanV2/MaxV2/AminmaxAll 接口约束
CANN-robotCANN-robot成员
2 天前 关闭了 issue
CANN-robotCANN-robot成员
2 天前 添加了label:resolved