Open
[确定性][一致性] sparse_lightning_indexer_kl_loss_grad:det 用例 deterministic_check Fail 复现与代码分析 #588
Alice_zhouAdd on  1 day ago
Alice_zhouCollaborators
1 day ago Create

背景

  • 目标算子:sparse_lightning_indexer_kl_loss_grad。
  • 触发用例:sparse_lightning_indexer_kl_loss_grad_flash_dsv4_test_01_det、..._test_05_det(is_deterministic=True)。
  • 判定逻辑:libs/comparator.py:636-647 tensor_deterministic_check 使用 torch.eq 逐位比较输出。
  • 复现环境:
    • 155:100.105.89.155,Ascend950DT_9582,CANN 9.3.0(ascend-toolkit/latest → cann-9.3.0);
    • 195:100.102.205.195,Ascend950PR_9589,CANN 9.3.0。

问题现象与复现结果

1) deterministic_check 结果(两台环境一致)

用例 155 195 run_status
test_01_det Fail Fail Success
test_02_det Pass Pass Success
test_03_det Pass Pass Success
test_04_det Pass Pass Success
test_05_det Fail Fail Success
  • 失败集合在 155/195 完全相同,可稳定复现,不是偶发。

2) 逐元素差异定位

固定输入连续调用算子 10 次,与首轮结果逐位对比:

用例 输出 差异元素数 占比 最大绝对误差
test_01_det dq 9,683 / 33,554,432 0.029% 0.03125
test_01_det dk 0 0% 0
test_01_det dw 0 0% 0
test_01_det softmax_out 0 0% 0
test_05_det dq 9,362 / 33,554,432 0.028% 0.03125
test_05_det dk 0 0% 0
test_05_det dw 0 0% 0
test_05_det softmax_out 0 0% 0
  • 只有 dq 不稳定;dk/dw/softmax_out 全部逐位一致。
  • 10 次调用差异位置、数值完全一致(同一批元素反复出现),差异为 bf16 的若干 ULP。
  • 进一步探测:dq 在两种稳定状态 A/B 间切换(A:sum=-1892.79248;B:sum=-1892.36475);执行 torch.npu.empty_cache() 或改变显存分配历史后,结果在 A/B 间翻转,同一状态下连续调用逐位一致。
  • NaN / 0x1234 哨兵预填充同尺寸 bf16 显存后再调用:dq 中 NaN 数 = 0、哨兵数 = 0,排除“输出未初始化”,说明是算子内部 dq 归约对调度/内存状态敏感。

现场/代码分析(含 tiling 侧确定性参数确认)

0) 补充确认(2026-11-14):tiling 侧确实获取了确定性参数

  • 代码位置:
    • op_host/arch35/sparse_lightning_indexer_kl_loss_grad_tiling_general_regbase.cpp:270
    • op_host/sparse_lightning_indexer_kl_loss_grad_tiling_general.cpp:177
    • op_host/arch92/sparse_lightning_indexer_kl_loss_grad_tiling_general_regbase_arch92.cpp:270
    deterministic = (context_->GetDeterministic() == 1);
    
  • context_->GetDeterministic() 定义在 include/exe_graph/runtime/tiling_context.h:464,读取框架下发的“确定性计算等级”(隐藏 tiling 上下文输入),不是算子 attr;等级 1 表示开启确定性计算配置(include/base/context_builder/op_tiling_context_builder.h:60)。
  • 现场实测(195,同一 test_01 shape,det vs nondet):
    • det:workspace size:[43120640], multicoreTotalsize:[26343424]
    • nondet:workspace size:[25820160], multicoreTotalsize:[9042944]
    • 日志:..._tiling_general_regbase.cpp:1151 [GetWorkspaceSize]
    • 与 GetWorkspaceSize() 中 if (deterministic) 分支一致(deterministic 会额外分配 bmm3Size*coreNum + scatterAddOutSize*2),说明 det 用例在 tiling 侧拿到的就是 deterministic=1;harness 同时打印了 set torch.use_deterministic_algorithms True。
  • 因此前版结论“torch 确定性开关没有下发到算子/tiling”不成立,现予更正。

1) 确定性标志进入 tiling key,并选择 kernel 的确定性模板

  • GetTilingKey 直接包含 deterministic(..._tiling_general_regbase.cpp:1118;tiling_general.cpp:610 还包含 privateScatter)。
  • kernel 侧存在大量 if constexpr (Deterministic) 分支(如 op_kernel/.../..._kernel_base.h:440/588/625/638/644/660/666/683/707/781、..._vector_block.h:241/251/256/263/269),且有确定性 scatter/rendezvous 实现。
  • 结论:确定性 tiling/kernel 路径存在且已选中。

2) 仍成立的事实:schema / C++ 封装没有显式 deterministic 入参

  • cann_ops_transformer/ops/attention/sparse_lightning_indexer_kl_loss_grad/sparse_lightning_indexer_kl_loss_grad.py:31-46:metadata 与主算子均无 deterministic 入参。
  • csrc/attention/sparse_lightning_indexer_kl_loss_grad.cpp:57-77:调用 aclnnSparseLightningIndexerKLLossGrad 时未传 deterministic;脚本里的 deterministic=is_deterministic 只传给了 CPU 参考实现(harness 第 505 行)。
  • 但确定性并非只能靠 aclnn 入参下发:tiling 通过 context_->GetDeterministic() 从框架获取,实测有效(见第 0 节)。

3) 判定标准是逐位相等

  • libs/comparator.py:636-647:torch.eq(golden_flat, real_flat),任何 ULP 差异即 Fail。

4) 新结论

  • 确定性开关有效、确定性 tiling/kernel 分支已实际选中,但 dq 仍不可逐位复现。
  • 问题应定位到 deterministic 路径下 dq 的 scatter/归约实现本身(privateScatter 判定、SLI_DETER_SCATTER_BANK_NUM 分 bank 归约、CrossCoreSetFlag/CrossCoreWaitFlag 跨核 rendezvous、固定 reduce 顺序),而不是“开关未下发”。

结论与建议

  1. test_01_det、test_05_det 在 155/195 均稳定 deterministic_check=Fail,可判定为算子确定性问题。
  2. 已确认 tiling 侧获取 deterministic(GetDeterministic()==1),det 用例实际走确定性分支;建议算子 owner 聚焦 deterministic 路径下 dq 的归约实现:
    • 检查 privateScatter 判定与 SLI_DETER_SCATTER_BANK_NUM 分 bank 归约是否真正固定顺序;
    • 检查 CrossCoreSetFlag/CrossCoreWaitFlag 的 set/wait 配对与跨核 rendezvous 是否完整;
    • 确保 dq 在 deterministic 模式下不使用依赖调度顺序的 atomic/分块累加。
  3. 在算子修复前,sparse_lightning_indexer_kl_loss_grad 的“确定性性能”数据需注明 det 侧不保证逐位一致。

执行步骤

cd <WORKDIR>/TuringBigKernel/FusionOp_Test
export PATH=<CONDA_BIN>:$PATH
source activate <CONDA_ENV>
source <CANN_TOOLKIT>/set_env.sh
# 过滤后的 5 条 det 用例(test_01~05_det)
python3 dailyauto_fusion_david_fast.py \
  --timeout=1200 \
  --casefile=<CASE_DIR>/sligklg_det_only.xlsx \
  --runtype=2 --deviceid=<DEVICE_ID> --need_lock_freq=False \
  --sheetname=Sheet1 --ti=0-5

如需观察 tiling 是否拿到确定性参数:设置 ASCEND_SLOG_PRINT_TO_STDOUT=1、ASCEND_GLOBAL_LOG_LEVEL=2,对比 det/nondet 的 workspace size: 日志(deterministic 分支 workspace 明显更大)。

附件

备注/限制

  • dq 差异统计来自固定输入直接调用算子 10 次(torch.eq 逐位比较),未经过 profiler。
  • A/B 状态切换通过 torch.npu.empty_cache() 复现,说明结果依赖调度/显存分配状态。
  • det/nondet workspace 对比来自 195 上单 case 复跑(test_01_det vs test_01_nondet),仅用于确认 GetDeterministic() 取值。
  • 关联性能汇总 issue:见 sparse_lightning_indexer_kl_loss_grad 网络用例确定性/非确定性性能对比 issue。
likedislike
AAlice_zhouCollaborators
11 hours ago Modify description of issue
Alice_zhouCollaborators
7 hours ago Comments:

已提单:DTS2026111406621

likedislike