Thanks for sending an issue! Please fill in the following template to help quickly solve your problem.
nc100:strided_slice:f4:combo:1
(64, 1021)
(((64,4084),(64,1021)), …)
(((4084,4),(1021,1)), …)
nc100:expand_bcast:f2:combo:11
(8, 64, 127)
两例共同特征(失败面精确画像):int32 张量 × int64 全值域标量。清洁轮 26 个 int32 用例中,仅这 2 例标量为全值域随机——其余 24 例标量范围 0/1/16/1000 等(fp32 可精确表示)全部 PASS,即失败与 NC 布局无关、只与标量是否超出 fp32 精确表示域有关。
int32 张量 × int64 全值域标量
x(int32) 正确 wrap(x×1605116159) 缺陷 wrap(x×1605116160) torch CPU/NPU 基准 -1273774738 -281055086 -1554829824 -281055086 ✓ -2147483648 -2147483648 0 -2147483648 ✓ 2147483647 542367489 -1605116160 542367489 ✓ 1 1605116159 1605116160 1605116159 ✓
NPU 输出与 wrap(x × 1605116160) 逐位一致、与正确结果 wrap(x × 1605116159) 全失配 → 缺陷语义 = y = wrap(x × int32_sat(fp32(s))):乘法本身精确(int32 wrap 整乘),精度损失仅发生在标量的 fp32 舍入一处。
wrap(x × 1605116160)
wrap(x × 1605116159)
y = wrap(x × int32_sat(fp32(s)))
_foreach_mul([x],[s])
x*s
x*int64_0dim
aclnnForeachMulScalarList
_foreach_mul
缺陷位置:ops/ops-nn/foreach/foreach_mul_scalar_list/op_kernel/arch35/foreach_mul_scalar_list_regbase.h:49(修复前)
ops/ops-nn/foreach/foreach_mul_scalar_list/op_kernel/arch35/foreach_mul_scalar_list_regbase.h:49
// 实例化(arch35/foreach_mul_scalar_list.cpp:41):int 路径为 // ForeachMulScalarListImpl<int32_t, int64_t>(...) → T=int32_t, ScalarT=int64_t using scalarCalcType = typename Conditional< AscendC::IsSameType<ScalarT, int32_t>::value, // ← BUG:判据用【标量 dtype】 int32_t, // ScalarT=int64_t(op def 契约)→ 恒为 false float>::type; // ← 恒落入 float scalarCalcType scaleVal = scalarCalcType(inScalarGM_.GetValue(tensorIndex)); // ↑ int64 标量 → float 转换点:1605116159 → 1605116160(fp32 舍入)
根因链:
scalars
x(DT_INT32) × scalars(DT_INT64)
y_i = x_i * scalars_i
Conditional
foreach_one_scalar_list_binary.h
T(GetValue)
foreach_add_scalar_list_regbase.h:49
Adds
历史注记:20260825 验证报告曾把同类现象判为纯 golden bug(golden 用 float64 计算 >2⁵³ 丢精度——确为真 bug 已修)并回滚了当时的 kernel 修改;本轮受控实验将两者分离实锤:golden float64 是一回事,kernel 标量 fp32 舍入是另一回事,均真实存在。
torch_npu op-plugin(ForeachMulKernelNpuOpApi.cpp)对 _foreach_mul(TensorList, ScalarList) 的分流:
ForeachMulKernelNpuOpApi.cpp
_foreach_mul(TensorList, ScalarList)
if (!at::native::can_use_fast_route(tensors, scalars, /*does_op_promote_integer_inputs_to_float=*/true)) { return at::native::foreach_tensor_mul_scalarlist_kernel_slow(tensors, scalars); // ← int32×int 走这里 } EXEC_NPU_CMD(aclnnForeachMulScalarList, ...) // fast path
ATen 规则:整型张量 + 整型标量(promote=true)→ fast path 被禁 → slow path 逐张量 at::mul(int32, int64_scalar)(整型精确)。真机行为矩阵全部吻合:int32×INT→slow 精确;int32×FLOAT→先 torch promote 输出 fp32;fp32×INT→fast path 尝试被 op def 矩阵拒(161002,反向证明 INT 标量对浮点张量确实进 fast path)。
at::mul(int32, int64_scalar)
结论:torch_npu 的"正确"来自 op-plugin fallback 的巧合性屏蔽,非算子无缺陷。影响面 = 直调 aclnnForeachMulScalarList 且标量为 INT64 的调用方(TTK、自研引擎);PTA 生产栈不受影响。
// 修复后(mul + add 两文件同款):判据改为【张量 dtype T】 using scalarCalcType = typename Conditional< AscendC::IsSameType<T, int32_t>::value, // int 路径 T=int32_t → true int32_t, // int64→int32 直接截断 float>::type;
正确性:int32 wrap 乘法结果只依赖标量 mod 2³²,int64→int32 截断保持低 32 位不变 → 与 int64 精确乘再 wrap 逐位等价(torch 基准验证)。编译先例:foreach_addc_list_regbase.h ComputeIntPath 已用 int32_t 标量调 Muls(RegTensor<int32_t>,…,int32_t,maskReg)。附:div_scalar_list 无此问题(其 def 契约 x/scalars 全浮点,float 承载即语义本身)。
foreach_addc_list_regbase.h
Muls(RegTensor<int32_t>,…,int32_t,maskReg)
修复文件:
ops/ops-nn/foreach/foreach_add_scalar_list/op_kernel/arch35/foreach_add_scalar_list_regbase.h:49
待算子重建后复跑 python3 rerun_nc100_failed_cann92.py ForeachMulScalarList(RERUN_CANN=完整 9.2.0 包)验证。
python3 rerun_nc100_failed_cann92.py ForeachMulScalarList
quality-report/nc_et_v6/ForeachMulScalarList/ForeachMulScalarList_nc100{,_result}.csv
/tmp/opencode/mulsll_probe*
/tmp/opencode/mulsll_sem*
/tmp/opencode/nc_test/test_foreach_mulsll_direct.cpp
quality-report/NC100_ACLNN_VALIDATION_FINAL_20260901.md
DEFECT_FIX_REPORT_NC100_20260831.md
CANN 9.2.0,Ascend950PR
构造int64 scalar输入用例,值固定为1605116159: case_id source_case_id testcase_name network_name api_name tensor_view_shapes tensor_dtypes tensor_formats tensor_storage_shapes tensor_view_offsets tensor_view_strides output_tensor_indexes output_inplace_indexes attributes scalar_dtypes scalar_data_ranges input_data_ranges precision_tolerances absolute_precision is_enabled remark soc_series priority dump_file_prefix manual_tensor_binaries manual_golden_binaries coverage_tags ForeachMulScalarList_NCG_0006 ForeachMulScalarList_CASE126 ForeachMulScalarList_NCG_0006 op_quality_review aclnnForeachMulScalarList (((64, 1021), (64, 1021)), ((64, 1021), (64, 1021))) (('int32', 'int32'), ('int32', 'int32')) (('ND', 'ND'), ('ND', 'ND')) (((64, 4084), (64, 1021)), ((64, 1021), (64, 1021))) ((0, 0), (0, 0)) (((4084, 4), (1021, 1)), ((1021, 1), (1021, 1))) (1,) () {} (('int64', 'int64'),) (((1605116159, 1605116159), (1605116159, 1605116159)),) (((-2147483648, 2147483647), (-2147483648, 2147483647)), ((None, None), (None, None))) 0 TRUE nc100:strided_slice:f4:combo:1 0 () () prototype;prototype_dtype_format_attr;dtype;format;shape;optional_input;optional_input:NOT_APPLICABLE;dynamic_shape;shape_bucket:medium;value_profile:mixed_magnitude;value_profile;shape_structure;thin_dimension;pta_aclnn;geir;dtype_relation:impl_inferred;attr:NOT_APPLICABLE;attr_boundary:NOT_APPLICABLE;attr_pairwise_combo:NOT_APPLICABLE;input_correlation;empty_tensor:NOT_APPLICABLE;format_variant:NOT_APPLICABLE;magnitude_profile:mixed_magnitude;magnitude_profile;alignment;broadcast;core_count;host_tiling;kernel_branch;kernel_entry;tail;tilingKey;tiling_data;workspace;non_contiguous:strided_slice:f4:1 ForeachMulScalarList_NCG_0035 ForeachMulScalarList_CASE726 ForeachMulScalarList_NCG_0035 op_quality_review aclnnForeachMulScalarList (((8, 64, 127), (8, 64, 127)), ((8, 64, 127), (8, 64, 127))) (('int32', 'int32'), ('int32', 'int32')) (('ND', 'ND'), ('ND', 'ND')) (((1, 64, 127), (1, 64, 127)), ((8, 64, 127), (8, 64, 127))) ((0, 0), (0, 0)) (((0, 127, 1), (0, 127, 1)), ((8128, 127, 1), (8128, 127, 1))) (1,) () {} (('int64', 'int64'),) (((1605116159, 1605116159), (1605116159, 1605116159)),) (((-2147483648, 2147483647), (-2147483648, 2147483647)), ((None, None), (None, None))) 0 TRUE nc100:expand_bcast:f2:combo:11 0 () () prototype;prototype_dtype_format_attr;dtype;format;shape;optional_input;optional_input:NOT_APPLICABLE;dynamic_shape;shape_bucket:medium;value_profile:mixed_magnitude;value_profile;shape_structure;thin_dimension;pta_aclnn;geir;dtype_relation:impl_inferred;attr:NOT_APPLICABLE;attr_boundary:NOT_APPLICABLE;attr_pairwise_combo:NOT_APPLICABLE;input_correlation;empty_tensor:NOT_APPLICABLE;format_variant:NOT_APPLICABLE;magnitude_profile:mixed_magnitude;magnitude_profile;alignment;broadcast;core_count;host_tiling;kernel_branch;kernel_entry;tail;tilingKey;tiling_data;workspace;non_contiguous:expand_bcast:f2:11
预期精度通过
精度失败
Thanks for sending an issue! Please fill in the following template to help quickly solve your problem.
Describe the current behavior / 问题描述 (Mandatory / 必填)
ForeachMulScalarList 失败用例与根因分析
一、失败用例
用例 1:ForeachMulScalarList_NCG_0006
nc100:strided_slice:f4:combo:1(注入性 strided 视图:x[0] 末维 stride×4,外层 stride 同步 storage 加宽 4084=1021×4,无重叠 ✓)(64, 1021),dtype int32,全值域随机(((64,4084),(64,1021)), …)/(((4084,4),(1021,1)), …)用例 2:ForeachMulScalarList_NCG_0035
nc100:expand_bcast:f2:combo:11(x[0] stride-0 广播视图,仅输入;输出连续)(8, 64, 127),dtype int32,全值域随机两例共同特征(失败面精确画像):
int32 张量 × int64 全值域标量。清洁轮 26 个 int32 用例中,仅这 2 例标量为全值域随机——其余 24 例标量范围 0/1/16/1000 等(fp32 可精确表示)全部 PASS,即失败与 NC 布局无关、只与标量是否超出 fp32 精确表示域有关。二、受控实验证据(jp CANN 9.2.0,Ascend950PR device 4)
实验 1:固定标量分离变量(同用例 NCG_0035/0006)
实验 2:数值取证(dump 反解,65344/65344 元素逐位)
NPU 输出与
wrap(x × 1605116160)逐位一致、与正确结果wrap(x × 1605116159)全失配 →缺陷语义 =
y = wrap(x × int32_sat(fp32(s))):乘法本身精确(int32 wrap 整乘),精度损失仅发生在标量的 fp32 舍入一处。实验 3:归因排除链
_foreach_mul([x],[s])/x*s/x*int64_0dim(三形式)aclnnForeachMulScalarList(aclScalarList=ACL_INT64,脱离 TTK/golden)_foreach_mul三、根因(源码级)
缺陷位置:
ops/ops-nn/foreach/foreach_mul_scalar_list/op_kernel/arch35/foreach_mul_scalar_list_regbase.h:49(修复前)// 实例化(arch35/foreach_mul_scalar_list.cpp:41):int 路径为 // ForeachMulScalarListImpl<int32_t, int64_t>(...) → T=int32_t, ScalarT=int64_t using scalarCalcType = typename Conditional< AscendC::IsSameType<ScalarT, int32_t>::value, // ← BUG:判据用【标量 dtype】 int32_t, // ScalarT=int64_t(op def 契约)→ 恒为 false float>::type; // ← 恒落入 float scalarCalcType scaleVal = scalarCalcType(inScalarGM_.GetValue(tensorIndex)); // ↑ int64 标量 → float 转换点:1605116159 → 1605116160(fp32 舍入)根因链:
scalars支持 INT64(aclnnForeachMulScalarList.md),int32 x 的合法组合为x(DT_INT32) × scalars(DT_INT64);公式y_i = x_i * scalars_i为整数乘法。Conditional按标量 dtype(ScalarT)选型——但整型数据路径的标量按契约必为 int64_t,条件恒 false,标量恒以 float 承载。foreach_one_scalar_list_binary.h用T(GetValue)按张量 dtype 直接整型截断,精确——缺陷仅在 arch35 regbase(Ascend950 实际执行路径)。foreach_add_scalar_list_regbase.h:49同一行写法(int32×INT64 组合Adds路径),清洁轮 26 个 int32 用例标量恰在 fp32 精确域未触发——已一并修复。历史注记:20260825 验证报告曾把同类现象判为纯 golden bug(golden 用 float64 计算 >2⁵³ 丢精度——确为真 bug 已修)并回滚了当时的 kernel 修改;本轮受控实验将两者分离实锤:golden float64 是一回事,kernel 标量 fp32 舍入是另一回事,均真实存在。
四、为什么 torch_npu 真机没问题(影响面界定)
torch_npu op-plugin(
ForeachMulKernelNpuOpApi.cpp)对_foreach_mul(TensorList, ScalarList)的分流:if (!at::native::can_use_fast_route(tensors, scalars, /*does_op_promote_integer_inputs_to_float=*/true)) { return at::native::foreach_tensor_mul_scalarlist_kernel_slow(tensors, scalars); // ← int32×int 走这里 } EXEC_NPU_CMD(aclnnForeachMulScalarList, ...) // fast pathATen 规则:整型张量 + 整型标量(promote=true)→ fast path 被禁 → slow path 逐张量
at::mul(int32, int64_scalar)(整型精确)。真机行为矩阵全部吻合:int32×INT→slow 精确;int32×FLOAT→先 torch promote 输出 fp32;fp32×INT→fast path 尝试被 op def 矩阵拒(161002,反向证明 INT 标量对浮点张量确实进 fast path)。结论:torch_npu 的"正确"来自 op-plugin fallback 的巧合性屏蔽,非算子无缺陷。影响面 = 直调
aclnnForeachMulScalarList且标量为 INT64 的调用方(TTK、自研引擎);PTA 生产栈不受影响。五、修复
// 修复后(mul + add 两文件同款):判据改为【张量 dtype T】 using scalarCalcType = typename Conditional< AscendC::IsSameType<T, int32_t>::value, // int 路径 T=int32_t → true int32_t, // int64→int32 直接截断 float>::type;正确性:int32 wrap 乘法结果只依赖标量 mod 2³²,int64→int32 截断保持低 32 位不变 → 与 int64 精确乘再 wrap 逐位等价(torch 基准验证)。编译先例:
foreach_addc_list_regbase.hComputeIntPath 已用 int32_t 标量调Muls(RegTensor<int32_t>,…,int32_t,maskReg)。附:div_scalar_list 无此问题(其 def 契约 x/scalars 全浮点,float 承载即语义本身)。修复文件:
ops/ops-nn/foreach/foreach_mul_scalar_list/op_kernel/arch35/foreach_mul_scalar_list_regbase.h:49ops/ops-nn/foreach/foreach_add_scalar_list/op_kernel/arch35/foreach_add_scalar_list_regbase.h:49(潜伏同步修)待算子重建后复跑
python3 rerun_nc100_failed_cann92.py ForeachMulScalarList(RERUN_CANN=完整 9.2.0 包)验证。附:取证数据索引
quality-report/nc_et_v6/ForeachMulScalarList/ForeachMulScalarList_nc100{,_result}.csv/tmp/opencode/mulsll_probe*、/tmp/opencode/mulsll_sem*/tmp/opencode/nc_test/test_foreach_mulsll_direct.cppForeachMulKernelNpuOpApi.cpp(gitee 镜像)+ 真机行为矩阵quality-report/NC100_ACLNN_VALIDATION_FINAL_20260901.md、DEFECT_FIX_REPORT_NC100_20260831.mdEnvironment / 环境信息 (Mandatory / 必填)
CANN 9.2.0,Ascend950PR
Steps to reproduce the issue / 重现步骤 (Mandatory / 必填)
构造int64 scalar输入用例,值固定为1605116159:
case_id source_case_id testcase_name network_name api_name tensor_view_shapes tensor_dtypes tensor_formats tensor_storage_shapes tensor_view_offsets tensor_view_strides output_tensor_indexes output_inplace_indexes attributes scalar_dtypes scalar_data_ranges input_data_ranges precision_tolerances absolute_precision is_enabled remark soc_series priority dump_file_prefix manual_tensor_binaries manual_golden_binaries coverage_tags
ForeachMulScalarList_NCG_0006 ForeachMulScalarList_CASE126 ForeachMulScalarList_NCG_0006 op_quality_review aclnnForeachMulScalarList (((64, 1021), (64, 1021)), ((64, 1021), (64, 1021))) (('int32', 'int32'), ('int32', 'int32')) (('ND', 'ND'), ('ND', 'ND')) (((64, 4084), (64, 1021)), ((64, 1021), (64, 1021))) ((0, 0), (0, 0)) (((4084, 4), (1021, 1)), ((1021, 1), (1021, 1))) (1,) () {} (('int64', 'int64'),) (((1605116159, 1605116159), (1605116159, 1605116159)),) (((-2147483648, 2147483647), (-2147483648, 2147483647)), ((None, None), (None, None))) 0 TRUE nc100:strided_slice:f4:combo:1 0 () () prototype;prototype_dtype_format_attr;dtype;format;shape;optional_input;optional_input:NOT_APPLICABLE;dynamic_shape;shape_bucket:medium;value_profile:mixed_magnitude;value_profile;shape_structure;thin_dimension;pta_aclnn;geir;dtype_relation:impl_inferred;attr:NOT_APPLICABLE;attr_boundary:NOT_APPLICABLE;attr_pairwise_combo:NOT_APPLICABLE;input_correlation;empty_tensor:NOT_APPLICABLE;format_variant:NOT_APPLICABLE;magnitude_profile:mixed_magnitude;magnitude_profile;alignment;broadcast;core_count;host_tiling;kernel_branch;kernel_entry;tail;tilingKey;tiling_data;workspace;non_contiguous:strided_slice:f4:1
ForeachMulScalarList_NCG_0035 ForeachMulScalarList_CASE726 ForeachMulScalarList_NCG_0035 op_quality_review aclnnForeachMulScalarList (((8, 64, 127), (8, 64, 127)), ((8, 64, 127), (8, 64, 127))) (('int32', 'int32'), ('int32', 'int32')) (('ND', 'ND'), ('ND', 'ND')) (((1, 64, 127), (1, 64, 127)), ((8, 64, 127), (8, 64, 127))) ((0, 0), (0, 0)) (((0, 127, 1), (0, 127, 1)), ((8128, 127, 1), (8128, 127, 1))) (1,) () {} (('int64', 'int64'),) (((1605116159, 1605116159), (1605116159, 1605116159)),) (((-2147483648, 2147483647), (-2147483648, 2147483647)), ((None, None), (None, None))) 0 TRUE nc100:expand_bcast:f2:combo:11 0 () () prototype;prototype_dtype_format_attr;dtype;format;shape;optional_input;optional_input:NOT_APPLICABLE;dynamic_shape;shape_bucket:medium;value_profile:mixed_magnitude;value_profile;shape_structure;thin_dimension;pta_aclnn;geir;dtype_relation:impl_inferred;attr:NOT_APPLICABLE;attr_boundary:NOT_APPLICABLE;attr_pairwise_combo:NOT_APPLICABLE;input_correlation;empty_tensor:NOT_APPLICABLE;format_variant:NOT_APPLICABLE;magnitude_profile:mixed_magnitude;magnitude_profile;alignment;broadcast;core_count;host_tiling;kernel_branch;kernel_entry;tail;tilingKey;tiling_data;workspace;non_contiguous:expand_bcast:f2:11
Describe the expected behavior / 预期结果 (Mandatory / 必填)
预期精度通过
Related log / screenshot / 日志 / 截图 (Mandatory / 必填)
精度失败
Special notes for this issue/备注 (Optional / 选填)