楼主: 龙猫NO
125 0

【昇腾NPU】【精度】【数据踩踏】Linspace算子数值计算不等价踩踏问题 [推广有奖]

  • 0关注
  • 0粉丝

等待验证会员

学前班

40%

还不是VIP/贵宾

-

威望
0
论坛币
0 个
通用积分
0
学术水平
0 点
热心指数
0 点
信用等级
0 点
经验
20 点
帖子
1
精华
0
在线时间
0 小时
注册时间
2018-7-28
最后登录
2018-7-28

楼主
龙猫NO 发表于 2025-12-9 15:21:09 |AI写论文

+2 论坛币
k人 参与回答

经管之家送您一份

应届毕业生专属福利!

求职就业群
赵安豆老师微信:zhaoandou666

经管之家联合CDA

送您一个全额奖学金名额~ !

感谢您参与论坛问题回答

经管之家送您两个论坛币!

+2 论坛币

1. 精度异常现象

在调用 linspace 算子时,当参数 dim 设置为 69 时,出现精度异常情况。尽管差异极小,但多次输入相同参数后,部分输出位置的数值存在微小波动。

torch.linspace(-dim, dim, steps=dim, device="npu")

这些偏差虽不显著,但在推理任务中可能对最终结果产生潜在影响。具体错误出现在索引位置 61 和 62。

3.8147e-06

2. 假设、实验与观察

2.1 多次运行偶现不一致

在重复执行过程中,该异常并非每次都会触发,但一旦发生,出错位置固定,初步判断可能是内存访问越界或数据覆盖所致。更值得注意的是,浮点值差异非常细微,容易误判为硬件层面(如芯片)问题。然而,在多台设备上复现该现象后,确认问题根源在于算子实现本身,属于软件层 bug。

2.2 出错索引特征分析

linspace 算子用于一维插值,生成指定数量 steps 的等差序列。测试发现,当 steps 取值为 8、16、24、32、40 等时无异常;但取 41、69、70 时则出现精度偏差,且错误均集中在输出数组末尾区域。

dim

代码审查发现,为满足硬件 32 字节对齐要求,系统对最后一个计算核(尾核)采用反向地址回退策略:从数据末端逆序计算偏移并完成加载、运算与存储操作。此机制可能导致倒数第二个核与尾核在数据处理范围上重叠,造成部分元素被重复计算。

3. 根源分析:精度误差来源

以 FP32 数据类型为例,每个元素占 4 字节,32 字节对齐需连续 8 个元素。当 dim = 69 时,总索引范围为 0 到 68。按照对齐规则,尾核起始位置设为 64,需处理 64 至 71 的数据段,但实际最大索引仅为 68,无法满足对齐长度。

为解决该问题,系统采取“地址回退”策略:从索引 68 开始向前回退 8 个元素,即处理区间 61–68。虽然技术上可行,但导致索引 61–63 区域被尾核和倒数第二个核共同计算,形成重复写入。

倒数第二个核的计算逻辑如下:

尾核的计算流程如下:

尽管两段逻辑在数学上等价——例如索引 61 处分别由以下两种方式计算:

stop-5*s-2*s

stop-7*s

但由于浮点数在芯片中的表示和运算存在舍入误差,不同核心的执行结果可能略有差异。此外,因核间并行执行,结果写回顺序不确定,导致索引 61 的最终值可能来自任一核,从而引发多次运行结果不一致。

base0 = stop - 5*s

4. 解决方案

为避免区域重叠带来的重复计算问题,可在倒数第二个核的数据搬运阶段使用非对齐搬运 API:

DataCopyPad

通过设置

DataCopyExtParams

参数,仅搬运索引 56–60 的数据,将 61–68 的完整处理交由尾核统一完成。如此可彻底消除计算交集,确保每次运行输出一致。

优化后的结果表现为确定性输出:

if (blockIdx == m_tilingData.realCoreNum - 2) {
        int64_t alignNum =
            outLen - (this->CeilDiv(m_tilingData.tailNum, elementPerBlock) * elementPerBlock - m_tilingData.tailNum);
        LocalTensor<T> outLocal = outQueue.DeQue<T>();
        DataCopyExtParams copyParams{1, static_cast<uint32_t>(alignNum * sizeof(T)), 0, 0, 0};
        DataCopyPad(outputGm[gmOutOffset], outLocal, copyParams);
        outQueue.FreeTensor(outLocal);
    } else {
        LocalTensor<T> outLocal = outQueue.DeQue<T>();
        DataCopy(outputGm[gmOutOffset], outLocal, outLen);
        outQueue.FreeTensor(outLocal);
    }

5. 经验总结

在算子开发过程中,开发者常出于性能优化或实现便捷性考虑,采用数学等价变换(如对齐优化、分段计算)。然而,此类变换可能引入不可忽视的精度波动。尤其当多次运行结果不一致时,应视为严重缺陷。

本案例表明,即便理论计算等价,硬件执行层面的浮点误差与并行调度不确定性仍可能导致输出波动。此类行为在推理场景下不可接受,必须作为 bug 进行修复。

二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

关键词:Space SPAC 数值计算 SPA Lin

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
扫码
拉您进交流群
GMT+8, 2026-1-17 04:10