Closed
[Bug-Report|缺陷反馈]: aclnnCumsum 默认路径位模式不确定(5 次 5 种哈希) #3907
liuhanwen8Add on  16 days agoClosed at  1 day ago
liuhanwen8
liuhanwen8
16 days ago Create

现象

aclnnCumsum 在 fp32 [1024,8]、dim=0、默认确定性配置下,同一输入连续 5 次执行得到 5 个不同输出哈希;设置 ACL_OPT_DETERMINISTIC=1 后,5 次得到同一个哈希。资料要求默认确定性实现。

组 两段返回 5 次输出 FNV 哈希 说明
对照组 det=0 0 / 0 b336efea06128bd3、539fed0d20d4ad1f、e8a3a5340e8d09a8、3ed6d0f33c3ac9d9、7ef8785201337c74 5 种位模式
缺陷组 det=1 0 / 0 375ece58ea1dfdaa ×5 1 种位模式

期望

资料 math/cumsum/docs/aclnnCumsum.md 的约束说明原文:「确定性计算:aclnnCumsum默认确定性实现」。因此默认配置下同一输入重复执行应输出逐字节一致;不应出现 5 次 5 种位模式。

环境

  • 硬件:Atlas A2 910B2,8 卡,npu-smi 26.1.1
  • CANN:9.2.0,Linux aarch64,g++ 11.4.0
  • 仓库与提交:cann/ops-math 584b2ea6(git fetch 后 master)
  • 复现日期:2026-10-23

复现步骤

  1. 保存下方脚本为 repro.cpp
  2. 保存编译命令为 build.sh 并执行 bash build.sh
  3. 执行 ./repro
  4. 观察 CONTROL 对照组 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;
}

实测输出:

CONTROL 对照组 det=0
det=0 run=0 digest=b336efea06128bd3
det=0 run=1 digest=539fed0d20d4ad1f
det=0 run=2 digest=e8a3a5340e8d09a8
det=0 run=3 digest=3ed6d0f33c3ac9d9
det=0 run=4 digest=7ef8785201337c74
DEFECT 缺陷组 det=1
det=1 run=0 digest=375ece58ea1dfdaa
det=1 run=1 digest=375ece58ea1dfdaa
det=1 run=2 digest=375ece58ea1dfdaa
det=1 run=3 digest=375ece58ea1dfdaa
det=1 run=4 digest=375ece58ea1dfdaa

影响

默认配置下,依赖 bitwise 复现的训练断点续训、结果对比、缓存复用会拿到不稳定输出;开启 ACL_OPT_DETERMINISTIC=1 可规避,但会产生性能代价。

建议

在 math/cumsum 的默认实现中固定归约/累加顺序并消除非确定性原子累加;或修改资料,把“默认确定性实现”改为“需显式开启 ACL_OPT_DETERMINISTIC”。

likedislike
liuhanwen8liuhanwen8
16 days ago Added label: bug-report
陈思
陈思Collaborators
15 days ago Comments:

您好,感谢反馈!您提供的结果表明,在同一输入下显式设置 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 结果可作为当前环境下的临时规避依据,其性能影响尚需实际测量;我们会继续确认默认策略及资料的对齐方式。

likedislike
陈思陈思Collaborators
15 days ago Assign chen_0715 as responsible person
陈思陈思Collaborators
15 days ago Added label: pending-confirmation
陈思陈思Collaborators
15 days ago Removed label: pending-confirmation
CchenyifengCollaborators
12 days ago Assign sakuraqqz as responsible person
CchenyifengCollaborators
12 days ago Removed responsible person chen_0715
SsakuraqqzCollaborators
6 days ago Associated pull request
CANN-robotCANN-robotCollaborators
1 day ago Close issue
CANN-robotCANN-robotCollaborators
1 day ago changed custom state from 进行中 to 已完成
CANN-robotCANN-robotCollaborators
1 day ago Added label: resolved