您好,感谢反馈!您提供的结果表明,在同一输入下显式设置 det=0 时输出字节存在变化,而 det=1 的五次输出一致。核对 cann/ops-math@584b2ea6cbaeba684a51a74296d82d4d50ab3b0f 的约束说明,资料确实写了“aclnnCumsum默认确定性实现”,这处表述与实际配置、执行策略的关系需要进一步核实。
问题分析
当前脚本在每组中都调用了 aclrtCtxSetSysParamOpt(ACL_OPT_DETERMINISTIC, det),因此展示的是显式设置 0 和 1 的对照,尚未展示完全不设置该选项时的行为。判断“默认确定性”是否失效,还需要把未设置开关的情况单独区分出来。公共确定性说明也要求以具体接口文档判断默认策略,并将开启确定性后的保证限定在平台、设备、软件版本及输入等条件相同的范围内。
源码侧,您的 A2、FLOAT、[1024,8]、dim=0 组合不会走要求末轴条件的 CumsumCube,而是进入普通 Cumsum 的 AiCore 路径。第一段选择、后端分派。当前核查尚未确认目标执行路径中造成差异的具体累加或同步步骤;仅凭哈希不同,不能直接断定使用了非确定性原子累加,也不能据此判断数值误差大小。
处理方向
请补充一组完全不调用上述确定性设置函数、其余输入与执行流程保持一致的五次结果,用于区分默认行为与显式 0 配置。若未设置时仍不稳定,就需要沿实际默认执行路径核对确定性保证;若产品实际要求显式开启,则资料应准确说明适用条件,而不能继续给出无条件的默认保证。
固定默认累加策略可能影响性能,修改默认保证也会影响依赖现有说明的调用方,需要结合产品契约评估。您报告的 det=1 结果可作为当前环境下的临时规避依据,其性能影响尚需实际测量;我们会继续确认默认策略及资料的对齐方式。


现象
aclnnCumsum在 fp32[1024,8]、dim=0、默认确定性配置下,同一输入连续 5 次执行得到 5 个不同输出哈希;设置ACL_OPT_DETERMINISTIC=1后,5 次得到同一个哈希。资料要求默认确定性实现。det=0b336efea06128bd3、539fed0d20d4ad1f、e8a3a5340e8d09a8、3ed6d0f33c3ac9d9、7ef8785201337c74det=1375ece58ea1dfdaa×5期望
资料
math/cumsum/docs/aclnnCumsum.md的约束说明原文:「确定性计算:aclnnCumsum默认确定性实现」。因此默认配置下同一输入重复执行应输出逐字节一致;不应出现 5 次 5 种位模式。环境
npu-smi26.1.1cann/ops-math584b2ea6(git fetch后 master)复现步骤
repro.cppbuild.sh并执行bash build.sh./reproCONTROL 对照组 det=0输出 5 个不同哈希、DEFECT 缺陷组 det=1输出 5 个相同哈希复现脚本
// 对照/缺陷两组:默认 vs ACL_OPT_DETERMINISTIC=1,同一输入连续 5 次输出哈希 // g++ -std=c++17 -O2 repro.cpp -o repro -I$ASCEND_HOME_PATH/include -I$ASCEND_HOME_PATH/include/aclnnop -L$ASCEND_HOME_PATH/lib64 -lascendcl -lopapi -lnnopbase #include <acl/acl.h> #include <aclnnop/aclnn_cumsum.h> #include <cstdint> #include <cstdio> #include <cstdlib> #include <vector> #define CK(x) do { if ((int)(x) != 0) { std::printf("ERR %d\n", (int)(x)); std::exit(1); } } while (0) static uint64_t hash_bytes(const void* p, size_t n) { const unsigned char* b = (const unsigned char*)p; uint64_t h = 1469598103934665603ULL; for (size_t i = 0; i < n; ++i) { h ^= b[i]; h *= 1099511628211ULL; } return h; } static void run_group(int det) { aclrtContext ctx; CK(aclrtCreateContext(&ctx, 0)); CK(aclrtSetCurrentContext(ctx)); CK(aclrtCtxSetSysParamOpt(ACL_OPT_DETERMINISTIC, det)); aclrtStream s; CK(aclrtCreateStream(&s)); const int64_t sh[2] = {1024, 8}, st[2] = {8, 1}; const size_t n = 1024 * 8, bytes = n * sizeof(float); std::vector<float> in(n), out(n), zero(n, 0.0f); for (size_t i = 0; i < n; ++i) in[i] = (float)(((int)(i * 37 + 11) % 200) - 100) / 10.0f; void *di = nullptr, *do_ = nullptr; CK(aclrtMalloc(&di, bytes, ACL_MEM_MALLOC_HUGE_FIRST)); CK(aclrtMalloc(&do_, bytes, ACL_MEM_MALLOC_HUGE_FIRST)); CK(aclrtMemcpy(di, bytes, in.data(), bytes, ACL_MEMCPY_HOST_TO_DEVICE)); aclTensor* x = aclCreateTensor(sh, 2, ACL_FLOAT, st, 0, ACL_FORMAT_ND, sh, 2, di); aclTensor* y = aclCreateTensor(sh, 2, ACL_FLOAT, st, 0, ACL_FORMAT_ND, sh, 2, do_); for (int r = 0; r < 5; ++r) { CK(aclrtMemcpy(do_, bytes, zero.data(), bytes, ACL_MEMCPY_HOST_TO_DEVICE)); uint64_t ws = 0; aclOpExecutor* e = nullptr; CK(aclnnCumsumGetWorkspaceSize(x, 0, ACL_FLOAT, y, &ws, &e)); void* w = nullptr; if (ws) CK(aclrtMalloc(&w, ws, ACL_MEM_MALLOC_HUGE_FIRST)); CK(aclnnCumsum(w, ws, e, s)); CK(aclrtSynchronizeStream(s)); CK(aclrtMemcpy(out.data(), bytes, do_, bytes, ACL_MEMCPY_DEVICE_TO_HOST)); std::printf("det=%d run=%d digest=%016llx\n", det, r, (unsigned long long)hash_bytes(out.data(), bytes)); if (w) aclrtFree(w); } aclDestroyTensor(x); aclDestroyTensor(y); aclrtFree(di); aclrtFree(do_); aclrtDestroyStream(s); aclrtDestroyContext(ctx); } int main() { CK(aclInit(nullptr)); CK(aclrtSetDevice(0)); std::printf("CONTROL 对照组 det=0\n"); run_group(0); std::printf("DEFECT 缺陷组 det=1\n"); run_group(1); aclrtResetDevice(0); aclFinalize(); return 0; }实测输出:
影响
默认配置下,依赖 bitwise 复现的训练断点续训、结果对比、缓存复用会拿到不稳定输出;开启
ACL_OPT_DETERMINISTIC=1可规避,但会产生性能代价。建议
在
math/cumsum的默认实现中固定归约/累加顺序并消除非确定性原子累加;或修改资料,把“默认确定性实现”改为“需显式开启ACL_OPT_DETERMINISTIC”。