已关闭
[RFC]: 支持非饱和模式场景溢出状态设置能力(FORCE_OVERFLOW_CHECK) #4374
wuyouqi1创建于  8月26日关闭于  8月27日
wuyouqi1
wuyouqi1成员
8月26日 创建

状态(Status): Reviewing
作者(Authors): @wuyouqi1
创建日期(Created): 2026-08-26
更新日期(Updated): 2026-08-26
相关 Issue/PR: MR !44962(Ascend/pytorch v2.7.1,分支 v2.7.1-force-overflow-check,单 commit e805760bf);环境变量文档分支 docs/force-overflow-check-master(commit 33fbe097f)

1. 概述

1.1 简介

当前 TorchNPU 仅在饱和模式下支持 stream 级溢出检测开关(aclrtSetStreamOverflowSwitch),非饱和模式(INF_NAN 模式)设备(如 Atlas A2/A3、Ascend 950DT)上的溢出检测只能依赖将梯度同步搬运至 Host 侧做值检测,该过程插入同步点、改变执行时序,导致"时序敏感型"问题无法复现。本提案新增环境变量 FORCE_OVERFLOW_CHECK:在 CANN >= 9.1.0 前提下,放开非饱和模式下溢出检测开关的限制,使溢出状态寄存器(float_status)检测路径在 INF_NAN 模式下同样可用,为大规模训练场景 Inf/NaN 问题的异步、不打断时序定位提供基础能力。

1.2 动机

客户现场 512 卡多模型训练偶现 nan。现有定位手段均破坏执行时序,导致问题无法复现:

  1. dump 定位:插入同步、拖慢执行,时序改变后问题不复现;
  2. 值检测:npu_check_overflow(grad) 在 INF_NAN 模式下需将 grad 求和后 .cpu() 同步判断 inf/nan,同样改变时序;
  3. 客户设备为 A2/A3(默认 INF_NAN 模式),溢出"显形"为 nan 但寄存器路径不可用——饱和模式设备反而具备异步读 float_status 寄存器的能力,能力出现倒挂。

不做此提案的影响:INF_NAN 模式(社区主流设备形态)上始终缺少不影响时序的溢出定位手段,下游精度工具(旁路探测任务异步轮询 float_status)无法落地。

1.3 目标

目标:

  • 新增环境变量 FORCE_OVERFLOW_CHECK,配置为 1 且 CANN >= 9.1.0 时,非饱和模式下 stream 创建时同样开启溢出检测开关;
  • npu_get_float_status / npu_check_overflow / npu_clear_float_status 相关 Python 接口(get_npu_overflow_flag / npu_check_overflow / clear_npu_overflow_flag)在 force 开启时走寄存器异步路径;
  • 新增查询接口 torch_npu.npu.utils.is_force_overflow_check(),供下游精度工具决定探测策略。

非目标(边界):

  • 不改变 IsSupportInfNan() 返回值语义(其同时驱动内核 INF_NAN 编译模式选择,影响面不可控);
  • 不改变浮点计算模式:force 开启后 INF_NAN 模式下溢出结果仍为 Inf/NaN,不会变为饱和值;
  • 不涉及下游异步探测工具本身的实现(本提案只交付"状态设置能力");
  • 不放开 npu_sys_ctrl.cpp 的 OverflowSwitchEnable()(_enable_overflow_npu 已无 Python 调用方);
  • 不修改 GradScaler 的溢出处理路径(_sync_dist_overflow_count 的 INF_NAN 提前 return 行为保持不变)。

2. 用例分析

用例 1:训练过程中 Inf/NaN 异步定位(核心用例)

  • 功能点:训练脚本启动前配置 FORCE_OVERFLOW_CHECK=1;旁路探测任务周期性调用 get_npu_overflow_flag() 读取溢出状态寄存器,定位 nan 产生的时间区间;
  • 关键指标:检测动作不向训练 stream 插入同步点、不改变算子下发时序;
  • 约束:CANN >= 9.1.0(aclrtSetStreamOverflowSwitch 在非饱和模式下生效的版本前提)。

用例 2:溢出检测接口的同步值检测路径替换

  • 功能点:npu_check_overflow(grad) 在 force 开启后不再将 grad 同步搬运至 Host,直接读寄存器并自动清除标志;
  • DFX(可靠性):寄存器检出后自动 clear,避免残留标志导致后续误报。

用例 3:检测能力查询

  • 功能点:精度工具通过 is_force_overflow_check() 区分"寄存器检测可用"与"值检测兜底",选择探测策略;
  • DFX(可维护性):查询语义与 C++ 侧开关判断严格一致,避免工具侧自行重复 env + 版本判断。

使用限制与约束:

  • 仅支持 "0"/"1" 取值,其他取值(如 "2")视为未配置,不报错(与方案 A 的严格 == "1" 判断一致,无 0/1 值域校验);
  • 需在进程启动前配置,运行中修改 os.environ 不会使 C++ 侧开关状态变化(C++ 侧 static 缓存首次建 stream 时的判断结果);
  • 饱和模式设备(Atlas 训练/推理系列)溢出开关默认开启,该环境变量不产生额外影响。

3. 方案设计

3.1 总体方案

采用最小改动方案(方案 A):不修改 IsSupportInfNan() 本身,在两处各内联一份相同的判断逻辑(环境变量 == "1" 且 CANN >= 9.1.0):

                      FORCE_OVERFLOW_CHECK=1 ?
                     /                        \
                   否                           是
                    |                            |
             原有逻辑不变              IsGteCANNVersion("9.1.0")?
              (仅饱和模式                /              \
               开溢出开关)             否                是
                                        |                 |
                              LOGW 一次 + 忽略    非饱和模式也调用
                              (回退原逻辑)        aclrtSetStreamOverflowSwitch(stream, 1)
  • C++ 侧(torch_npu/csrc/core/npu/interface/AclInterface.cpp,AclrtCreateStreamWithConfig):原判断 if (!IsSupportInfNan()) 扩展为 if (!IsSupportInfNan() || forceOverflowCheck);forceOverflowCheck 由 static lambda 一次性求值(进程内仅判断/告警一次),覆盖 torch_npu 创建的所有 stream(默认 stream、secondary stream、stream pool 均经此入口);
  • Python 侧(torch_npu/npu/utils.py):新增 is_force_overflow_check();get_npu_overflow_flag / npu_check_overflow / clear_npu_overflow_flag 三个接口的分支条件由 is_support_inf_nan() 改为 is_support_inf_nan() and not is_force_overflow_check()。

前置条件与约束:CANN >= 9.1.0(依赖 aclrtSetStreamOverflowSwitch 在非饱和模式下使寄存器生效的新能力);用户自定义 stream 若绕过 AclrtCreateStreamWithConfig 创建则开关不生效(现状即如此,非本提案新增问题)。

3.2 技术选型

方案 内容 优点 缺点 结论
A(选定) C++(AclInterface.cpp 内联)与 Python(utils.py 内联)各实现一份 env+版本判断 改动最小(2 文件),无新绑定、不动公共模块 双写需防漂移(两侧语义须严格一致) ✅ 2026-08-20 评审选定
B 抽公共 helper(OptionsManager/NpuVariables)+ Module.cpp 新增绑定集中管理 单点维护 多 3 个文件改动,为低频开关引入跨层接口 放弃
A+ A 基础上另放开 npu_sys_ctrl.cpp OverflowSwitchEnable() 覆盖更多入口 _enable_overflow_npu 已无 Python 调用方,属无效改动 放弃

关键选型说明——为什么新增 is_force_overflow_check() 而不复用(修改)is_support_inf_nan():

  1. 语义正交:is_support_inf_nan() 表达"硬件是否处于 INF_NAN 模式",force 开关不改变硬件模式,只改变检测手段;复用等于谎报硬件模式;
  2. 影响面隔离:is_support_inf_nan() 是公开文档化 API,被 grad_scaler.py 两处及用户代码调用,修改其语义会让调用方在 force 下静默切换行为;
  3. 下游查询需求:精度工具需区分"False 源于饱和模式还是 force 未开启",复用无法区分且迫使工具侧重复判断(双写变三写)。

3.3 功能与性能设计

功能流程:

  1. 进程启动,用户侧已配置 FORCE_OVERFLOW_CHECK=1;
  2. 首个 NPU stream 创建时,C++ static lambda 求值:env == "1" 且 IsGteCANNVersion("9.1.0");版本不满足时 ASCEND_LOGW 告警一次(受 ASCEND_GLOBAL_LOG_LEVEL 门控,默认级别下不打印)并回退原逻辑;
  3. force 开启后所有经 AclrtCreateStreamWithConfig 创建的 stream 均执行 AclrtSetStreamOverflowSwitch(stream, 1),算子执行时溢出写入 float_status 寄存器;
  4. Python 侧三个溢出接口在 force 下走寄存器路径:get_npu_overflow_flag() 读标志;npu_check_overflow(grad) 读标志并自动 clear(不再同步搬运 grad);clear_npu_overflow_flag() 真正执行 clear(原仅告警);
  5. is_support_inf_nan() 返回值不变,内核仍按 INF_NAN 模式编译执行。

数据模型变更: 无。

性能影响: 开启溢出开关后算子执行存在额外开销(写入状态寄存器),为"不影响训练时序"定位能力的必要代价。已提供 --perf 手工对比手段(4096x4096 fp16 mm 迭代耗时,开关开启/关闭各跑一次对比),量化数据待 ≥9.1.0 环境实测补充。注意:性能影响指算子执行开销,不改变算子下发时序(同步点数量不变)。

影响范围: 仅 force 显式开启(env == "1" 且版本满足)时行为变化;默认行为(未配置/版本不满足/非法取值)与修改前完全一致。

3.4 安全隐私与DFX设计

  • 兼容性:默认关闭("0"/未配置),存量用户零感知;新 API is_force_overflow_check() 登记 test/torch_npu_schema.json 受签名兼容性门禁监督;仅导出 npu.utils 命名空间,不做顶级导出(避免额外 schema 登记成本,2026-08-21 评审结论);
  • 可靠性:版本不满足时回退原逻辑并告警一次,不会因环境变量配置错误导致训练失败;非法取值视为未配置;
  • 可测试性:UT 覆盖寄存器级检出、utils 路径、默认行为回归、版本不匹配、非法取值五类场景(见第 4 节);
  • 可维护性:C++/Python 双写判断,语义必须严格一致(均为 env == "1" 且 CANN >= 9.1.0),变更时两处同步修改;
  • 安全隐私:无新增攻击面,仅读取本进程溢出状态寄存器。

3.5 编程与调用设计

3.5.1 编程模型基本设计
  • 开发环境:CANN >= 9.1.0;Atlas A2/A3 训练系列(默认 INF_NAN 模式)或 Ascend 950DT;torch_npu v2.7.1 及以上分支;
  • 开发约束:环境变量须在进程启动前配置;仅 "0"/"1" 有效;CANN 版本不满足时开关静默失效(可设 ASCEND_GLOBAL_LOG_LEVEL=2 观察 WARNING);
  • 可验收设计:验收环境为 CANN >= 9.1.0 的非饱和模式设备;验收标准为 manual_verify_force_overflow.py 全部断言通过(fp16 溢出经寄存器检出、正常运算不误报、npu_check_overflow 检出后自动 clear)+ UT 全绿。
3.5.2 接口定义与设计

变更点 1:新增环境变量 FORCE_OVERFLOW_CHECK

  • 接口描述: 控制非饱和模式(INF_NAN 模式)下是否开启 stream 溢出检测开关。
  • 取值:
取值 含义
0 / 未配置 不开启(默认),非饱和模式行为与现状一致
1 开启溢出检测开关(需 CANN >= 9.1.0,否则忽略并告警一次)
其他 视为未配置
  • 约束说明: 进程启动前配置;饱和模式设备不产生额外影响。
  • 变更说明: 新增,详见 docs/zh/api/environment_variable/op_execution/FORCE_OVERFLOW_CHECK.md(分支 docs/force-overflow-check-master,随资料侧 docs 流程合入)。

变更点 2:新增 Python 查询接口 is_force_overflow_check()

  • 接口描述: 查询 FORCE_OVERFLOW_CHECK 开关是否生效(env == "1" 且 CANN >= 9.1.0)。
  • 接口原型: torch_npu.npu.utils.is_force_overflow_check() -> bool
  • 输入/输出参数: 无
  • 返回参数:
参数名称 类型 描述 取值范围
返回值 bool 开关是否生效 True / False
  • 异常处理: 无(版本查询失败按 False 处理)。
  • 约束说明: 仅 npu.utils 命名空间导出(torch_npu.npu.utils.is_force_overflow_check),不顶级导出。
  • 变更说明: 新增公开 API,已登记 test/torch_npu_schema.json。
  • 调用参考代码:
import torch_npu.npu.utils as utils

if utils.is_force_overflow_check():
    flag = utils.get_npu_overflow_flag()  # 寄存器异步路径

变更点 3:既有接口行为变更(force 开启时)

接口 变更前(INF_NAN 模式) 变更后(force 开启)
get_npu_overflow_flag() raise RuntimeError 读 float_status 寄存器返回溢出标志
npu_check_overflow(grad) grad 求和 .cpu() 同步值检测 读寄存器,检出后自动 clear
clear_npu_overflow_flag() 仅 warning,不执行 实际执行 npu_clear_float_status
  • 变更说明: 分支条件 is_support_inf_nan() → is_support_inf_nan() and not is_force_overflow_check();force 未开启时行为与现状完全一致。

C++ 侧变更(内部接口,不对外暴露): AclrtCreateStreamWithConfig(AclInterface.cpp)内联 forceOverflowCheck 判断,static lambda 单次求值 + 版本不足 LOGW 回退。

3.5.3 编程手册设计

在已有《环境变量参考》中新增 FORCE_OVERFLOW_CHECK 词条(归入"算子执行"分类,紧邻 INF_NAN_MODE_ENABLE / INF_NAN_MODE_FORCE_DISABLE),内容含功能描述(0/1 语义、三接口行为变化、不改变计算模式的说明、NOTICE 性能提示)、配置示例、使用约束(CANN >= 9.1.0、仅 0/1、启动前配置)、支持型号。不新编手册,同步更新 env_variable_list.md 与两级菜单。变更已备于 docs/force-overflow-check-master 分支。

4. 测试设计

单元测试(并入既有 test/npu/test_check_over_flow.py,不新建文件):

用例 场景 断言
test_float_status_detection 模块级 FORCE_OVERFLOW_CHECK=1,非饱和设备 溢出后 float_status 置位;clear 后归零(寄存器级)
test_npu_check_overflow_register_path 同上 npu_check_overflow 检出且自动 clear
test_default_behavior_unchanged 子进程 pop 掉 env is_force_overflow_check() 为 False;get_npu_overflow_flag 仍 raise
test_version_mismatch_warning 子进程 env=1 + ASCEND_GLOBAL_LOG_LEVEL=2 + ASCEND_SLOG_PRINT_TO_STDOUT=1 CANN<9.1.0 时 LOGW 可见;>=9.1.0 时无告警(统一用例,无 skip)
test_invalid_env_value 子进程 FORCE_OVERFLOW_CHECK=2 视为未配置
test_check_over_flow(既有) 模块级 env 下回归 饱和/非饱和设备断言均成立(顺带回归)

设备过滤:NON_SATURATION_DEVICES = [Ascend910B, Ascend910C, Ascend910_93, Ascend950](门禁机器池含 A1 等仅饱和模式设备,避免误导性失败)。

手工验证(e2e):manual_verify_force_overflow.py——环境状态查询 → fp16 溢出(65504+65504)寄存器检出 → npu_check_overflow 路径 + 自动 clear → 正常运算不误报;--perf 提供开关前后 mm 耗时对比。

回归:既有 test_check_over_flow.py、test_inf_nan_mode.py 全量通过;test_compatibility.py 门禁(新 API schema 登记)通过。

限制:寄存器真实检出能力依赖 CANN >= 9.1.0 非饱和设备实测(配套环境满足,无版本 skip),UT 断言已按此设计。

5. 缺点和风险

风险 等级 应对
算子执行性能开销(溢出写寄存器) 中 仅显式开启时生效;文档 NOTICE 提示仅定位场景配置;--perf 实测数据待补
双写漂移(C++/Python 判断不一致) 低 语义严格一致(env=="1" && CANN>=9.1.0);review 时两处对照
C++ static 缓存 vs Python 每次读 env 的不一致 低 实际使用均在进程启动前配置 env;文档已注明约束
无 0/1 值域校验(=2 静默忽略) 低 文档注明;如需校验须两侧同步补(当前评审结论:不补)
GradScaler 混用路径 低 GradScaler 走值检测路径不读寄存器;force 下若用户混用寄存器检测的注意事项写入 release note
LOGW 默认不可见(受 ASCEND_GLOBAL_LOG_LEVEL 门控) 低 文档与 UT 中说明需 level<=2 才可见
API 兼容性 无 新增接口已登记 schema;默认关闭,存量行为不变

实现成本:4 文件 +149/-7(C++ 16 行 / Python 16 行 / UT 121 行 / schema 3 行),维护成本可控。

6. 现有技术

  • PyTorch CUDA 生态:无对应机制——CUDA 上溢出产生 inf/nan 直接可见,且 torch.cuda.amp.GradScaler 检查 inf/nan 依赖 torch.isinf/isnan 值检测(需同步);本提案的寄存器异步检测是 NPU 硬件特性(float_status 寄存器)驱动的差异化能力,借鉴其 GradScaler 溢出检查接口形态(get_npu_overflow_flag 命名与之对齐);
  • 饱和模式既有实现:torch_npu 在饱和模式设备上 aclrtSetStreamOverflowSwitch + npu_get_float_status 的完整链路(FloatStatusKernelNpu.cpp op 实现、OverflowUtils.cpp 调用)即本提案复用的路径,差异仅在于放开 INF_NAN 模式的开关限制(依赖 CANN 9.1.0 新能力)。

7. 未解决问题

  1. 性能量化数据:开关开启前后算子执行开销对比(--perf)待 CANN >= 9.1.0 环境实测后补充归档;
  2. CANN 9.1.0 非饱和模式真实检出能力:手工验证脚本待实测确认(若 CANN 行为与预期不符,UT 断言需相应调整);
  3. 与精度工具的接口对齐:is_force_overflow_check / get_npu_overflow_flag 语义需与下游异步探测工具侧评审确认(探测轮询频率、多 rank 聚合策略不在本提案范围);
  4. 环境变量文档合入节奏:文档分支已备,随资料侧 docs 流程合入 master;
  5. 是否补 0/1 值域校验:当前结论不补(=2 静默忽略),如社区评审认为需要告警,须 C++/Python 两侧同步实现。

附录

  • 参考资料链接
    • 需求分析与实现方案:/home/wyq/q2/Q2/pta_force_overflow_check/需求分析与实现方案.md
    • 实现分支:MR !44962(Ascend/pytorch,v2.7.1-force-overflow-check,commit e805760bf)
    • 文档分支:docs/force-overflow-check-master(commit 33fbe097f)
    • 手工验证脚本:/home/wyq/q2/Q2/pta_force_overflow_check/manual_verify_force_overflow.py
    • 相关环境变量文档:docs/zh/api/environment_variable/op_execution/INF_NAN_MODE_ENABLE.md
  • 术语表
术语 含义
饱和模式 浮点溢出时结果饱和为 ±MAX(不产生 inf/nan),float_status 寄存器可检测溢出
非饱和模式(INF_NAN 模式) 浮点溢出直接产生 inf/nan(IEEE 754),对应 IsSupportInfNan() == true
float_status 硬件溢出状态寄存器,溢出发生时置位,可异步读取
FORCE_OVERFLOW_CHECK 本提案新增环境变量,非饱和模式下开启溢出检测开关
值检测 将 tensor 求和同步搬运至 Host 判断 inf/nan 的兜底路径(影响时序)
  • 文档更新计划
    • 环境变量文档随资料侧 docs 流程合入 master(分支已备);
    • 性能实测数据、CANN 9.1.0 验证结论补入本 RFC 与需求分析文档。

欢迎加入社区,感谢您对社区的贡献 🎉!

likedislike
wuyouqi1wuyouqi1成员
8月26日 添加了label:rfc
wuyouqi1wuyouqi1成员
8月26日 关联了看板:FrameworkPTAdapter 版本issue看板
TorchNPU-BotTorchNPU-Bot成员
8月26日 添加了label:triage-review
TorchNPU-Bot
TorchNPU-Bot成员
8月26日 评论:

issue待分派,添加triage-review标签

likedislike
wuyouqi1wuyouqi1成员
8月26日 修改了issue 的描述
此处折叠了5条事件消息 查看更多
TorchNPU-BotTorchNPU-Bot成员
8月26日 添加了label:bot-triaged;删除了label:triage-review
TorchNPU-Bot
TorchNPU-Bot成员
8月26日 评论:

检测到当前 issue 已关联 PR,自动添加标签:bot-triaged

likedislike
wuyouqi1wuyouqi1成员
8月26日 关联了里程碑:v26.2.0
此处折叠了15条事件消息 查看更多
ascend-robotascend-robot成员
9月14日 关联了pull request:[sync] PR-46197: fix(test): skip float_status UTs on Ascend950