自动融合精度测试报告
【免费下载链接】graph-autofusionGraph-autofusion 是一个面向昇腾(Ascend)芯片的轻量级、解耦式组件集合,旨在通过自动融合技术加速模型执行。 目前已开源 SuperKernel 组件,未来将持续开放更多自动融合相关模块。项目地址: https://gitcode.com/cann/graph-autofusion
关联文档:自动融合精度一致性说明
本报告为主文档四项核心论点提供实测数据支撑。测试结果回流主文档 §三与 §6.1。
一、概述
本报告拆分为 8 个独立任务(含一项共享基础设施),便于并行推进。每个任务自包含目的、配置、步骤、预期结果与产出物,可独立分配给不同负责人。
二、任务分工表
| 编号 | 测试名称 | 对应论点 | 负责人 | 工作量 | 优先级 | 前置依赖 | 状态 |
|---|---|---|---|---|---|---|---|
| S | 精度测试工具包(bit-diff / ULP / fp64 reference) | 共享基础设施 | TODO | 1d | P0(阻塞项) | 无 | 待开始 |
| A | 自动融合自身的二进制确定性 | 主文档 §3.3 | TODO | 0.5d | P0 | 无 | 待开始 |
| C1 | Tensor × Scalar 指令选择差异 | 主文档 §1.2 (2) | TODO | 0.5d | P0 | 无 | 待开始 |
| C2 | Reduction 累加顺序差异 | 主文档 §1.2 (3) | TODO | 0.5d | P0 | 切块控制接口 | 待开始 |
| C3 | rsqrt 算法迭代差异 | 主文档 §1.2 (4) | TODO | 0.5d | P0 | 迭代次数控制接口 | 待开始 |
| D | 纯搬运类算子一致性 | 主文档 §二 | TODO | 0.5d | P1 | S 完成 | 待开始 |
| B | Eager vs AutoFuse 累积误差 | 主文档 §3.2 | TODO | 2–3d | P1 | S 完成 | 待开始 |
| E | 端到端训练指标对齐 | 主文档 §3.2 现实投射 | TODO | 5–7d | P2 | S 完成、NPU 资源 | 待开始 |
三、并行推进建议
- Day 0 单独启动:S(基础设施,1 天,阻塞其他依赖它的任务)。
- Day 0 起并行启动:A、C1、C2、C3 均不依赖 S,可与 S 同步开始。
- Day 1 起并行启动:B、D、E 在 S 完成后切入。
- 最小人力配置:2 人 ≈ 1 周;建议 4–5 人 ≈ 3–4 天。
- 最短路径:P0 全部完成后,主文档已可补充关键数据。P1/P2 结果用于强化 §6.1 与端到端说服力。
四、任务 S — 精度测试工具包
目的
为 A/B/D/E 提供共享的数值比较工具,避免重复造轮子。工具包本身不产出论据,但是其它任务的前置依赖。
交付清单
bit_equal(a, b) -> bool:逐元素 bit-wise 比较,返回是否完全一致。ulp_diff(a, b) -> ndarray:逐元素 ULP 差。error_stats(a, ref) -> dict:统计 max / mean / P50 / P99 的绝对误差、相对误差、ULP 误差。fp64_reference(graph, inputs) -> tensor:把子图用 numpy / torch CPU fp64 重算,作为真值基准。- 打包形式:内部 pip 包 + pytest fixture 入口。
步骤
- 拉群对齐工具包接口与仓库位置。
- 先出
bit_equal与ulp_diff,满足 A/D 立即可用;其他功能两天内补齐。 - 单测覆盖:fp16 / bf16 / fp32 三档;正常值、非规范数、inf / nan 全覆盖。
- 发布到内部 pypi 或以源码形式集成。
产出物
工具包仓库链接、接口文档、单测报告。
五、任务 A — 自动融合自身的二进制确定性
目的
验证主文档 §3.3:编译期输入与运行期输入不变时,多次运行输出二进制一致,且编译产物本身 hash 稳定。
测试配置
- 子图:
matmul → add → layernorm → gelu(Transformer FFN 前半段)。 - 输入 shape:
[8, 2048, 4096](fp16)。 - 硬件:单卡,固定型号。
步骤
- 构建子图,开启自动融合,采集融合 kernel 的二进制 hash(记为
H_k0)。 - 用固定种子生成一组输入 tensor,保存到磁盘。
- 同一进程内连续执行 1000 次,保存每次输出的 MD5。
- 清空 JIT 缓存,冷启动新进程,重新编译,再执行 1000 次。
- 汇总:
- 第一轮 1000 次输出 MD5 集合大小应为 1。
- 第二轮 kernel hash 应等于
H_k0,输出 MD5 应与第一轮相等。
预期结果
- 运行输出 hash:全部一致。
- 编译产物 hash:冷启动后不变。
- 若出现不一致:定位来源(随机 dropout、非确定性 reduce、NUMA 飘移等),记录并反馈框架团队。
产出物
表格:运行次数 / 唯一 hash 数 / 最大 ULP 差,期望1000 / 1 / 0。
六、任务 C1 — Tensor × Scalar 指令选择差异
目的
验证主文档 §1.2 (2):同一数学语义走不同硬件指令,会产生末位差异。
测试配置
- 输入 A:fp16 tensor shape
[1024, 1024],固定种子生成U(-1, 1)。 - 标量:
0.7。 - 路径 A:走标量乘指令(
muls或等效 Python 写法x * 0.7,让框架自动降为 muls)。 - 路径 B:先将标量 broadcast 为
[1024, 1024]的 tensor,再走向量乘指令(x * scalar_tensor.expand_as(x))。
步骤
- 编写两个最小复现脚本。
- 用 profiler / op trace 验证两条路径实际生成的指令不同。
- 两条路径同一输入各执行 1 次,保存输出。
- 用工具 S 统计两者 ULP 差分布。
- 汇报:ULP = 0 / ULP = 1 / ULP ≥ 2 各占比。
预期结果
两条路径输出不完全一致,大多数元素 ULP ≤ 1,极少量更高。数据本身就是"指令选择引入末位差异"的证据。
可行性风险
框架可能自动选择指令,需要 profiler 确认两条路径实际生成了不同指令;否则测试意义丧失。若无法控制,改为"观察一条路径的指令变化"并如实披露。
产出物
脚本 + profiler 截图 + ULP 差直方图。
七、任务 C2 — Reduction 累加顺序差异
目的
验证主文档 §1.2 (3):浮点加法不满足结合律,切块大小不同会引入末位差异。
测试配置
- 输入:fp16 tensor shape
[1, 16384],固定种子。 - 操作:
sum(dim=-1)。 - 路径 A:切块 512。
- 路径 B:切块 1024。
- 路径 C:切块 2048。
- 参考:fp64 CPU 精算。
步骤
- 通过框架的切块配置(编译 flag 或 kernel 级 hint)生成三个切块版本。
- 每个版本用同一输入跑 1000 次,校验自身确定性(工具 S 的
bit_equal)。 - 三版本之间两两比较 ULP 差。
- 每个版本与 fp64 参考比较,看哪个更接近。
预期结果
- 每个版本自身 1000 次完全一致(自身确定性)。
- 不同切块版本之间存在 ULP ≥ 1 的差。
- 三者都落在 fp64 基准的随机误差范围内。
可行性风险
框架不对外暴露切块控制时,需要框架团队配合出一个调试 flag。无此接口时该测试需搁置,或改为"观测不同 shape 下框架自选切块策略与输出的关系"。
产出物
三版输出的 ULP 差矩阵、与 fp64 的对比表。
八、任务 C3 — rsqrt 算法迭代差异
目的
验证主文档 §1.2 (4):迭代逼近类算子的实现差异直接反映为末位精度差。
测试配置
- 输入:fp16 tensor shape
[1024, 1024],值域U(0.01, 100),固定种子。 - 操作:
rsqrt。 - 路径 A:框架默认实现。
- 路径 B:同一框架下调整迭代次数(例如 2 轮 vs 3 轮牛顿迭代)。
- 参考:fp64 精算。
步骤
- 联系框架团队获取迭代次数配置接口(环境变量或编译开关)。
- 两路径同输入各跑 1 次,保存输出。
- 用工具 S 统计 A / B 两者与 fp64 参考的 ULP 差分布。
- 若顺畅,可再补一个例子:
div(x, y),机理相同。
预期结果
- A 与 B 输出不完全一致。
- 迭代次数更多的路径 ULP 差更小。
可行性风险
与 C2 相同:若无法控制迭代次数,改为"框架实现 A vs 同语义的 numpy fp32 实现"对比,说服力略降但仍能展示算法层差异。
产出物
两路径 ULP 差直方图 + 迭代次数与末位差的关系表。
九、任务 D — 纯搬运类算子一致性
目的
验证主文档 §二:不做数学运算的搬运类算子,自动融合与 Eager 可以二进制一致。
测试配置
- 算子清单:
transpose/reshape/slice/concat/split/broadcast。 - 组合子图(需要触发融合):
transpose → concatslice → broadcast → concatsplit → transpose → concat
- 输入:fp16 / bf16 / fp32 各一套,shape 覆盖典型业务值。
步骤
- 对每个子图分别跑 Eager 与 AutoFuse。
- 用工具 S 的
bit_equal校验。 - 枚举 dtype × shape 组合,填充勾选表。
- 出现反例时(例如 broadcast 伴随隐式类型提升),记录并说明原因。
预期结果
所有纯搬运子图 bit-wise 一致;带隐式计算的 broadcast 可能有差异,单独标注。
产出物
勾选表 + 反例清单。
十、任务 B — Eager vs AutoFuse 累积误差对比
目的
支撑主文档 §3.2 最核心的定量结论:自动融合累积误差 ≤ Eager 模式。
测试配置
- 算子链(覆盖不同计算模式):
- 纯 elementwise:
mul → add → gelu → mul - 含 reduction:
layernorm、softmax - 含 matmul:
matmul → add → layernorm(FFN 前半段) - 可选:
attention的qk → softmax → pv片段
- 纯 elementwise:
- 输入:每条链 1000 组随机输入,固定种子池。
- 三路执行:
- fp64 CPU 参考(真值)
- fp16 Eager(逐算子执行,边界落盘)
- fp16 AutoFuse
步骤
- 用工具 S 的
fp64_reference生成真值。 - 分别跑 Eager 与 AutoFuse,收集输出。
- 对两路径各计算最大绝对误差、相对误差、ULP 误差的 P50 / P99 / Max。
- 画 1000 组误差的直方图与 CDF。
- 逐算子链对比:AutoFuse 的 P99 / Max 是否 ≤ Eager 的 P99 / Max。
- 出现反例时:
- 定位具体算子与输入分布。
- 结果回流主文档 §6.1,作为"需要按算子类型关闭融合"的实证依据。
预期结果
- 绝大多数算子链 AutoFuse 的 P99 / Max 误差 ≤ Eager。
- 个别反例需单独落到主文档 §6.1。
产出物
- 每条算子链一张误差分布对比图 + 一行汇总表。
- 反例清单(直接交给 §6.1 作者)。
十一、任务 E — 端到端训练指标对齐
目的
支撑主文档 §六开头"关注数值正确性可直接启用"的建议,用下游模型实验回应训练稳定性担忧。
测试配置
模型候选(按成本升序):
- GPT-2 small(124M)—— 最小成本,1k step 约数小时。
- LLaMA-7B 的 LoRA 微调 —— 中等成本。
- 小规模 pretrain(如 300M 模型 5k step)—— 最有说服力但最贵。
起步建议:先跑候选 1,结论明确可跳过后续。每个模型固定:种子、数据集、batch、lr schedule、optimizer。
步骤
- 搭建可复现训练脚本(Eager 与 AutoFuse 两个开关)。
- 同一脚本两套开关各跑一次,采样间隔 50 step。
- 对比指标:
- loss 曲线(train / eval)。
- grad norm。
- 若为 LM:PPL。
- 两条曲线应在正常随机波动内重合。如显著偏离:
- 记录偏离点、偏离量。
- 回流主文档 §6.1。
预期结果
候选 1 跑完即能得到初步结论。两条曲线应基本重合。
可行性风险
需要 NPU / GPU 资源和数据集配合。若资源紧张,至少先做候选 1。
产出物
loss / eval 指标对比曲线图 + 最终指标差异表。
十二、完成后的回流动作
测试执行完成后:
- 将 A / B 两张关键结论表以链接形式反向嵌入主文档 §三。
- 若 B / E 出现反例,驱动主文档 §6.1(@wangxiaotian)落地具体开关列表。
- 工具 S 作为后续精度回归基准设施长期保留。
【免费下载链接】graph-autofusionGraph-autofusion 是一个面向昇腾(Ascend)芯片的轻量级、解耦式组件集合,旨在通过自动融合技术加速模型执行。 目前已开源 SuperKernel 组件,未来将持续开放更多自动融合相关模块。项目地址: https://gitcode.com/cann/graph-autofusion
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考