已合并
【PR】: fix reduce layer norm #1891
czways创建于 8月31日
【PR】: fix reduce layer norm #1891
已合并
Pull Request已成功合入, 合并人@CANN-robot
(感谢 czways 的贡献)8月31日 添加了label:enhancement
atomgit-bot
8月31日 评论:
8月31日 评论:
变更摘要
本 PR 旨在修复 reduce 算子调度用例生成中的切分逻辑(标题 fix reduce layer norm),主要重构了 ReducePartitionCaseGenerator::ReducePartitionMultipleCitations:不再简单收集多输出节点后逐个切分,而是按"引用组"(source/citation/reduce 三元组)组织多输出节点,仅沿数据边查找 reduce,并借助并查集合并共享 reduce 的组、以组内 reduce id 最小的锚点为基准去重切分,避免重复切分与潜在依赖环;同时为 PartitionByNode 增加边替换跟踪日志,并新增对应单元测试。
主要改动
- 重构多引用切分逻辑:
ReducePartitionMultipleCitations由收集multi_output_nodes改为构造Citation结构(source/citation/reduce)组成的citation_groups,按 reduce id、citation id 排序后分组,并只统计GetOutDataNodes().size() > 1且非 Load/Store/Workspace 的节点。 - 并查集合并与锚点去重:引入
parent/find_root并查集,合并共享同一 reduce 的引用组,每组以 reduce id 最小的节点作为group_anchors锚点,仅对非锚点且未被partitioned_edges记录过的边调用PartitionByNode,防止重复切分。 - 改为仅沿数据边查找 reduce:
FindOutputReduce及遍历逻辑由GetOutNodes()改为GetOutDataNodes(),reduce 查找与引用方向均只沿数据边(data edges)进行。 - 切边替换跟踪与日志:
PartitionByNode中新增replaced_edge标记,实际移除 src->dst 边时置位并打印[TEMP_REDUCE]日志,若未找到直接边替换则输出告警日志GELOGW。 - 新增单元测试:
test_reduce_schedule_case_generator.cpp增加TestReduce_Multi_Cita_Multi_Out_NoDependencyCycle,使用AscGraphBuilder构造Sum被Abs/Tanh/Add/Relu多引用的图,验证GeneratorTask返回成功且任务列表非空。


不准确?
atomgit-bot
8月31日 评论:
8月31日 评论:
代码审查
审查结论
变更文件审查确认
- autofuse/optimize/task_generator/reduce_schedule_case_generator.cpp — 已审查。核心变更:重写
ReducePartitionMultipleCitations(citation 收集 + union-find 分组 + anchor 选取 + 切分去重)、FindOutputReduce改为仅沿数据边递归、PartitionByNode增加replaced_edge跟踪与日志。发现 2 个问题(见下)。 - autofuse/tests/ut/optimize/task_generator/test_reduce_schedule_case_generator.cpp — 已审查。新增
TestReduce_Multi_Cita_Multi_Out_NoDependencyCycle,其构建图仅含一个 reduce,ReducePartitionMultipleCitations在入口处即提前返回,新增测试未执行任何被重写的逻辑。发现 1 个问题(见下)。
Findings 统计
| 优先级 | 数量 | 摘要 |
|---|---|---|
| P2 | 1 | 新增测试未覆盖重写后的切分逻辑(测试图仅 1 个 reduce,函数在 IsOnlyHasOneOrLessReduce 处提前返回,407-500 行新代码一行未执行) |
| P3 | 1 | 生产 pass 中遗留约 10 处 [TEMP_REDUCE] 临时 GELOGI/GELOGW 调试日志,线上 INFO/WARN 刷屏 |
| P3 | 1 | 新 anchor 分组语义与旧实现不一致(多源共享 reduce 时切分边集合改变、单引用源节点可能被切、重复调用 PartitionByNode 会向已改写锚点重复附加 store/workspace/load 链),且无测试兜底(低置信度) |
总体风险评估
本 PR 对 ReducePartitionMultipleCitations 的切分算法进行了完整重写,算法内部(union-find 合并、anchor 选取、去重)逻辑自洽,未发现必然崩溃或数据损坏类缺陷;但存在两方面风险:其一,唯一新增测试因图结构只有一个 reduce 而完全未触达新逻辑,重写的复杂分支逻辑处于零回归保护状态;其二,新旧实现切分边集合在跨源共享 reduce 场景下明显不同,属行为变更,在缺少测试与明确语义说明的情况下存在功能回归隐患。此外遗留的临时调试日志应在合并前清理。整体风险中等,建议补齐能真正执行新逻辑的测试用例后再合入。
| 类型 | 数量 |
|---|---|
| 🔴 阻塞 | 0 |
| 🟡 建议 | 1 |
💬 仅评论


不准确?
8月31日 添加了label:stat/needs-squash
此处折叠了54条消息 查看更多
yangyongqiang
9月2日 评论:
9月2日 评论:
/approve


9月2日 添加了label:approved
CANN-robot
9月2日 评论:
9月2日 评论:
The MR can not be merged, because of CodeReview discussion not resolved
If you want to solve this problem, you can click here to do it in the FAQs.


9月2日 解决了最后一个问题
9月2日 合入了pull request
Pull Request
Inductor LayerNorm 双链多引用断图方向不一致导致 SortSubGraphsByDependency 依赖环编译失败
描述
请清晰准确地描述本次 Pull Request 的意图和变更内容。
变更类型
请选择本次引入的变更类型:
关联的Issue
Closes #293
如何测试
描述测试此变更的步骤和前提条件:
1.
2.
核对清单
其他信息
在此添加任何其他关于本次 PR 的说明。
PR #1891 修改说明:fix reduce layer norm
1. 问题现象
Inductor 场景执行 LayerNorm 融合用例
tc_af_inductor_layernorm_backend_0193(输入 shape=(128,6,23),模型为两条 LayerNorm 路径 + 三路输出:sum(layernorm(x.transpose(0,1)))、mean(layernorm(x))、abs(layernorm(x)))时,Autofuse Optimize 阶段在SortSubGraphsByDependency报sorted[4] != total[7],拓扑排序卡死,整体编译以Optimize fail ret 1343225857中断。7 个子图中只排出 4 个,子图 1 与子图 3 互相等待——本 PR 修复该依赖环的根因。
2. 根因分析
2.1 图结构前提
Inductor 将整个模型融合为单张 HintGraph,含两条几乎镜像的 LayerNorm 计算链(A 链 = transpose 后 LN,B 链 = 原始输入 LN),两链之间无直接数据边,但共享同一批输入节点:
broadcast2(÷23 常量)、broadcast8(beta 权重)、broadcast9(gamma 权重)、scalar1(eps)。2.2 断图机制
GenerateGeneralCase依次执行三个断图 pass(ReducePartitionPostFusion → PartitionNorm → ReducePartitionMultipleCitations)。断开一条边的标准产物是 4 个新节点:写侧句柄与读侧句柄是两个不同节点、同一个名字,运行时靠同名配对传递内存。剪哪条边就是在决定"谁供谁"——pre 落在生产侧子图,post 落在消费侧子图,形成一条"生产方必须先执行"的跨子图依赖。
2.3 故障机制:断图方向不一致制造真实依赖环
ReducePartitionMultipleCitations(修复前)对每个多输出共享节点独立决策:"保留第一个遍历到的 consumer 方向,断开其余"。由于各节点 consumer 遍历顺序不同,方向互相矛盾:broadcast2(÷23)broadcast8(beta)broadcast9(gamma)子图依赖图:
原图是无环 DAG;环完全由断图方向不一致制造,且每条依赖边都对应真实 workspace 数据流(非名称匹配假依赖),无法在排序层补救。
2.4 已证伪的备选方案(避免重走弯路)
GetOutNodes()换成GetOutDataNodes()mean_Load)确实拥有多个数据输出,API 切换挡不住,必须按节点类型过滤3. 修复思路与实现
3.1 共享引用链统一 anchor(断图方向全局裁决)
ReducePartitionMultipleCitations(reduce_schedule_case_generator.cpp/.h)重写为两阶段,并拆分为三个职责单一的函数:阶段一:收集 citation(先于任何本 pass 内的断边,避免被自己改写过的图污染)
!IsLoad && !IsStore && !IsOps<Workspace> && GetOutDataNodes().size() > 1——显式排除 synthetic 节点(断图产物 Store/Load/Ws 虽确实有多个数据输出,但不是用户图的真实共享节点);FindOutputReduce仅沿数据边(GetOutNodes()→GetOutDataNodes())递归探测每个输出最终流到的 Reduce,形成 citation 三元组(source, citation, reduce);不处理控制边是正确选择——下游依赖矩阵(HasDataDependency)本身只按数据边推导,方向决策必须与被保护的约束同构;阶段二 a:共享链合并与 anchor 选取
阶段二 b:统一方向断图
citation.reduce == anchor的路径保留原始数据边;其余路径统一调用PartitionByNode断开。所有断边方向一致把非 anchor 侧(sum3 侧)隔离为纯消费侧,依赖图在构造上不可能成环;PartitionByNode(src, dst)只剪断 src→dst 单边(实现含peer == dst_node守卫,不改道 src 其余出边)。修复前的旧实现通过reduce_nodes集合隐式按 (source, reduce) 去重——首个 Reduce 方向保留直连,每个新出现的 Reduce 只切一次;按 (source, citation) 边去重会切掉同一 source 流向同一非 anchor Reduce 的全部 citation 边,切分边集合较旧实现扩大、属行为变更,故对齐旧语义(每个非 anchor Reduce 只切一条 citation 边,其余保持直连,行为保守且不引入额外跨分量依赖)。3.2 与旧实现的行为对比
GetOutNodes().size() > 1(含控制边、含 synthetic 节点)3.3 真实图验证(2026-08-31 bugshot 回归)
修复后
[TEMP_REDUCE]插桩日志(验证时临时添加,PR 已清理)逐条确认:b2→truediv、b9→add3、b8→mul5、rsqrt→broadcast11、add3→sum3、scalar1→add)方向一致断向 sum3 侧——对照修复前b2→truediv1断向 sum2 侧的方向反转,反向依赖对消除;1 ⇄ 3环消失,SortSubGraphsByDependency通过。4. 变更文件清单
autofuse/optimize/task_generator/reduce_schedule_case_generator.cppReducePartitionMultipleCitations重写(拆分三函数);FindOutputReduce数据边化;新增<map>/<numeric>/<set>头autofuse/optimize/task_generator/reduce_schedule_case_generator.hCitation/CitationGroups类型与三个函数声明(均在private:段,无 ABI 影响)autofuse/tests/ut/optimize/task_generator/test_reduce_schedule_case_generator.cpp5. 测试设计
TestReduce_Multi_Cita_Multi_Out_NoDependencyCycleIsOnlyHasOneOrLessReduce早退);断言调度成功 +kCommon模板 + 两组 workspace 断点对恰各一对TestReduce_Multi_Cita_SameReduce_NoDuplicatePartition已执行的验证:
asc_tiling.py)6. 性能影响
FindOutputReduce无 memo,重汇聚宽图存在重复子遍历(可观测但非运行时问题)7. 遗留与后续
GetCacheReuseInfo修复由他人交付后,在真实 bugshot 环境联合重跑:确认asc_tiling.pyhost C++ 编译通过 → 设备端三路输出精度校验通过(E2E 闭环);FindOutputReduce增加节点级 memo(node → 首个可达 reduce)与 visited 保护:重汇聚图上避免重复子遍历,总复杂度降为 O(V+E),同时消除理论上的递归栈溢出风险(阶段一无图改写,memo 安全);PartitionByNode对多输出口 source 会为每个 out_anchor 建 Store/Ws 写链——dst 未连接的端口产生无读者的悬空写链;本 PR 场景 source 均单口未触发。