ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

CANN 多流推理优化 Plan 方案细节规范:流分组、汇合点与 overlap_pct 实测的完整落地指南

CANN 多流推理优化 Plan 方案细节规范:流分组、汇合点与 overlap_pct 实测的完整落地指南 CANN 多流推理优化 Plan 方案细节规范流分组、汇合点与 overlap_pct 实测的完整落地指南【免费下载链接】cann-recipes-infer本项目针对LLM与多模态模型推理业务中的典型模型、加速算法提供基于CANN平台的优化样例项目地址: https://gitcode.com/cann/cann-recipes-infer多流Multi-Stream优化是 CANN 推理侧提升 NPU 资源利用率、压降首 token 时延与 decode 时延的关键手段但在编排 Agent 的工作流中切了几条流只是起点物理上是否真并行才是方案能否成立的裁决依据。本文基于cann-recipes-infer仓库中 model-infer-multi-stream 技能的多流 Plan「方案细节」写作规范系统讲解一个多流 Plan 必须写清的并行对象与流分组、汇合点与同步 API、方案 DAG、实现强度阶梯、GE auto-reorder 风险、overlap_pct 实测、enable 开关与回退路径以及如何把关键结论上浮为编排报告信封的「证据摘要」。读完本文你将掌握一份可被 reviewer 复核、可被 orchestrator 裁决、可被后续 implementer 直接落地执行的标准化多流方案细节的完整写法并能用 profiling 数据亲手判定真并行 / 部分并行 / 假并行。一、方案细节片段在多流编排链路中的定位在仓库的.agents/skills/model-infer-multi-stream技能体系中多流方向的工作产出被明确切分为两类结构由技能定义、编排层orchestrator不解析方向级分析产物整网 module / op DAG 与并行性判断一个模型一份被该方向所有候选 Plan 共享结构见 module-decomposition.md每个 Plan 的方案细节本规范plan-detail-fragment.md定义的自由块只由多流方向的 implementer / reviewer 读写。plan-detail-fragment.md 原文的定位是「用于填写编排报告里某个多流 Plan 的『方案细节』自由块」形成 plan 时给出设计部分review / 落地后回填实测部分。这意味着该片段是一个随方案生命周期持续更新的活文档——设计期回答怎么切、怎么同步、有什么风险落地期追加实测 overlap 是多少、开关怎么关、副作用是什么。依据 SKILL.md 的消费约定被调用方如优化编排流程只消费两类结构本片段即其中每个 Plan 的方案细节而「方向级的 module / op DAG 与并行性分析」明确不写进本片段只在本片段中引用方向级产物即可。二、方案细节的八个组成要素一个完整的多流 Plan 方案细节必须覆盖以下八项内容缺一不可。2.1 并行对象与流分组这一项要回答三个问题并行什么是模块级并行如共享专家与路由专家、算子级并行如 Attention 前处理子链还是跨阶段 overlap各算子 / 模块分到哪条流主流 / 副流 1 / 副流 2 的明确归属tag 粒度同一副流内是串行下发还是拆成多个独立副流。仓库案例给出了三种典型的流分组形态MoE 共享专家双流moe-shared-expert-dual-stream.md主流承载gate / topk / dispatch → router experts → combine副流以npu_stream_switch(enable_multi_streams, 11)承载shared_experts(hidden_states)Indexer Prolog 多流indexer-prolog-multi-stream.mdQ 路径拆到22号流、weights_proj拆到33号流、主流保留wk / k_norm / k_rope属于前处理切流而非完整大模块并行LongCat-Flash 多流 控核longcat-flash-multi-stream-limit-core.md主流跑 dense / attention 主路径副流1提前执行 shortcut MoE 路径。从源码看仓库把切流 API 统一封装在 executor/utils/stream_utils.py 的npu_stream_switch中exe_mode ge_graph时走tng.scope.npu_stream_switch(stream, stream_priority)否则走torch.npu.stream(stream)switch_flag为假时返回FakeContextManager兜底保证关闭多流后代码路径完全无损。方案细节里写流分组时应明确标注该实现走哪条执行路径Ascend IR / GE 图模式 还是 npugraph_ex / aclgraph两条路径的 API 与约束不能混用。2.2 汇合点与同步方式汇合点要写明在哪里汇合、用什么同步且同步原语必须与执行路径匹配执行路径切流 API同步 / 时序 API命名空间Ascend IR / GE 图模式torchair.scope.npu_stream_switch(stream_tag, stream_priority0, enable_inner_parallelTrue)torchair.scope.npu_wait_tensor(self, dependency)已有 tagged event 风格时用torchair.ops.npu_record_tagged_stream/torchair.ops.npu_tagged_event_record/torchair.ops.npu_tagged_event_wait切流与时序在torchair.scoperecord / wait / tagged event 在torchair.ops两个命名空间npugraph_ex / aclgraphtorch.npu.Stream()with torch.npu.stream(stream)torch.npu.Event()Event.record()Event.wait(stream)或 Stream 侧record_event/wait_event/wait_stream显式 stream 对象需要特别注意npugraph_ex 路径下若torch.compile(fullgraphTrue, dynamicTrue)使 dynamo 拦截 Stream / Event 对象缺as_proxy()应改用torch.npu.npugraph_ex.scope.npu_stream_switch(tag)与npu_tagged_event_record/npu_tagged_event_wait这套 string-tag / tagged-event 接口——该路径下切流与 tagged event 都在torch.npu.npugraph_ex.scope命名空间与 GE 路径 tagged event 落在torchair.ops不同。API 选型细节与官方文档入口见 api-routing.md。仓库封装 executor/utils/stream_utils.py 的wait_tensor展示了 GE 图模式下的典型写法switch_flag and exe_mode ge_graph时调用tng.scope.npu_wait_tensor(self, dependency)强制消费者算子等待生产者算子完成保证时序正确。Indexer Prolog 案例中的汇合写法为with npu_stream_switch(enable_multi_streams, 22): if enable_multi_streams: tng.scope.npu_wait_tensor(qr, query_states[0]) q_b self.wq_b(qr, c8_input_dict.get(pertoken_scale, None)) ...2.3 方案 DAG方案细节必须附一张 Mermaid DAG标清主 / 副流归属和 event 边-.-。按 module-decomposition.md 的画法约定统一使用flowchart LR尚未决定流归属时用Main Path / Side Path / Comm Path代码里已明确是Stream0 / Stream1时才用流名做subgraph--表示data或state依赖-.-表示event依赖两个模块共享同一输入如hidden_states同时进入router_path和shared_expert时不在它们之间画依赖边而是补一个共同上游节点。以 MoE 共享专家双流为例moe-shared-expert-dual-stream.mdDAG 的作用是让 reviewer 一眼看清并行窗口在哪、汇合点在哪、有没有未被显式表达的隐式依赖。2.4 实现强度C1 → C2 → C3强度是一个复杂度阶梯不是不同的并行方案。同一个编排可以从低到高逐级加码先用 C1 验证核心编排是否真并行再决定是否上更高强度C1 最小切流仅把并行对象切到副流并补最小同步C2 切流 控核叠加limit_core_num解决流间资源争抢 / 拖尾C3 切流 控核 手动同步点控制进一步显式控制跨流时序与汇合点。关键纪律改变并行对象 / 流分组 / 汇合点属于另一个候选方案不能塞进同一方案的强度递进里每个并行点至少派生 2 种不同编排候选见 module-decomposition.md 的候选编排派生规则。控核 API 同样分路径Ascend IR 用算子级torchair.scope.limit_core_num优先级高于全局config.ge_config.aicore_num ${aicore}|${vector}npugraph_ex 用 Stream 级torch.npu.npugraph_ex.scope.limit_core_num。LongCat-Flash 案例longcat-flash-multi-stream-limit-core.md展示了多流之后还要分核的写法其源码在 models/longcat_flash/models/modeling_longcat_flash.pystream_ctx npu_stream_switch(True, self.npugraph_moe_stream) with stream_ctx: with limit_core_num(True, self.aic_num1, self.aiv_num1): shortcut_mlp_output self.mlp(hidden_states_norm, is_prefill, cur_topk_listcur_topk_list) ... with limit_core_num(not self.enable_afd, self.aic_num2, self.aiv_num2): hidden_states, _, dsq self.mlps02.5 GE auto-reorder 风险Ascend IR 路径设计期必填这是设计期就必须填的字段不是踩坑后补的。依据 ge-reorder-design-check.mdGE 图模式编译期会重排算子最常见的事故是把消费副流输出的轻量 precompute典型为Cast/Reshape/Swish/Sigmoid/Mul例如silu(z) Swish(Cast(z))拉到主流提前下发卡住主流 dominator让切流变成假并行。对每个把 op 切到副流的候选落地前必须逐条回答副流的输出有哪些下游消费者在主流列出tensor 名 → 消费者这些消费者里有没有 cheap precomputeGE 会把这些 precompute 提前下发到哪条流设计期先推断落地后用 profiling 的Stream IDStart Time验证这些 precompute 会不会在主流 FIFO 顺序里排在主流 dominator 之前、形成 barrier应对是否要在副流with npu_stream_switch(...)块内显式预计算这些 op把它们 pin 在副流上而不是依赖 GE 自动放置如果第 2、4 条命中而第 5 条未处理该候选大概率落成假并行——要么把 precompute 钉进副流要么重新设计 op 集合让副流有真正的 dominator 可吃。此清单只适用于 Ascend IR / GE 图模式npugraph_ex / aclgraph 是显式 stream没有 GE 自动重排但仍要关注跨流 tensor 生命周期record_stream()。注意 SKILL.md 强调的npu_stream_switch的 with-block 不是硬边界默认enable_inner_parallelTrue时 GE 仍可在 block 内 / 外做调度源码层级 ≠ 物理层级。2.6 overlap_pct 实测review / 落地后填这是本片段最硬核、也最容易被偷懒的字段。规范明确不允许是 / 否二元结论必须给出三件套副流时间窗[start, end] us、主流 dominator 时间窗[start, end] us、overlap_pct数值及判定真并行 ≥0.5 / 部分 0.05~0.5 / 假并行 ≤0.05。依据 timeline-overlap-check.md按 5 步重建甘特图选窗口副流时间窗 方案切到副流的那段 ops主流 dominator 时间窗 方案假设副流能躲在背后跑的主流 op常见为 conv1d / matmul / FA。取字段只下钻Stream ID/Start Time(us)/Duration(us)几条必要 op不灌整份明细post-mortem 字段集见 kernel-fields-lookup.md。算区间side_window [min(side_op.start), max(side_op.start side_op.duration)] main_window [main_dominator.start, main_dominator.start main_dominator.duration] overlap max(0, min(side_window.end, main_window.end) - max(side_window.start, main_window.start)) side_len side_window.end - side_window.start main_len main_window.end - main_window.start overlap_pct overlap / min(side_len, main_len)判定≥0.5真并行0.05~0.5部分并行op 集合划分要再调≤0.05假并行Stream ID 切对了但物理串行主流大概率被 GE 拉过来的 precompute 卡住。找 barrier op仅假并行时把主流 op 按Start Time(us)排序找主流上第一个输入来自副流的 op X检查它是否排在主流 dominator 之前若是把它显式钉到副流在 with-block 内显式写出f(T)的计算。记录结论只记关键摘要例如side_window [1615.25, 1634.75] us、main_dominator window [1638.00, 1660.75] usin_proj_qkv overlap0us / overlap_pct0%判为假并行barrier ops 55-56 (CastSwish, silu(z))被 GE 拉到主流 下一候选把 silu(z) 显式预计算钉在 with-block 内。两个关键约束Start Time(us)在不同采集之间基准不同、不可比overlap_pct只能在同一次采集内计算判通过和判淘汰之前都必须先算overlap_pct不能把host overhead 吃掉收益当默认解释。2.7 enable 开关与回退路径方案细节必须写明开关名是什么、关掉后走哪条原路径。这是 SKILL.md 的核心原则之一——开关必须可关闭多流路径要保留 enable 开关和原始回退路径方便调试、review 和淘汰时干净隔离。仓库源码中的典型设计self.enable_multi_streams custom_params.get(enable_multi_streams, 0) ... if (self.enable_multi_streams 0) and not is_prefill: return self.multi_stream_forward(...) # 多流分支 # 否则走原单流路径见 models/longcat_flash/models/modeling_longcat_flash.py。同时在 executor/utils/stream_utils.py 中FakeContextManager作为开关关闭时的空上下文兜底保证切流 / 同步代码在单流模式下完全空转、不改变原有行为。review 阶段应验证enable 前后输出一致、开关关闭后原路径正常。2.8 风险与副作用方案细节要主动列出该编排的已知风险仓库规范明确点名了三类TransData/BroadcastTo/MemSet长尾跨流 tensor 维度偏大时搬运算子可能成为新瓶颈按 kernel-fields-lookup.md用aic_mte2_ratio/aiv_mte2_ratio/aiv_mte3_ratio判断搬运占比用aic_mac_ratio/aiv_vec_ratio判断计算占比主副争核用kernel_details.csv的Block Dim/Mix Block Dim加和与设备核数比较不要用算子类型是 MatMul / Vector二元推断MatMul 也可能Block Dim1占很少核shape 劣化切 micro-batch 或跨流后 shape 线性度变差、task 数增加。三、上浮编排报告信封的「证据摘要」方案细节的其余内容都留在本片段内但必须向编排报告信封上浮一段「证据摘要」——这是 orchestrator 裁决要看的核心格式为一句话overlap_pct判定 wall Δ%以性能分析报告为准 关键副作用通过 / 淘汰的状态建议交给 reviewer 和主 agent。例如shared_expert 旁路双流overlap_pct0.62 真并行decode layer wall -18%副作用副流尾部 MemSet 长尾 30us建议通过。证据摘要必须与 timeline-overlap-check.md 的计算口径一致wall Δ% 以性能分析报告同口径指标为准。四、与方向级分析产物的边界哪些内容不允许写进本片段plan-detail-fragment.md 原文特别声明方向级的 module / op DAG 与并行性分析不写在这里——那是被多个 Plan 共享的方向级分析产物按 module-decomposition.md 的结构单独成文本 Plan 引用它即可。方向级产物建议落盘到analysis/multi-stream.md固定骨架为分析范围模型 / 阶段 / 执行模式→ 整网模块清单与依赖清单 → 模块 DAG → 每个候选模块的算子清单与算子 DAG → 候选编排清单每个并行点 ≥2 个候选每个候选给到描述 DAG这一层。更细的流分组、GE auto-reorder 风险、overlap_pct 实测才在对应 Plan 的方案细节里按本规范展开。五、填写纪律判定真假并行的红线综合 SKILL.md 与本文档规范填写方案细节时必须守住以下红线Stream ID 切对 ≠ 物理并行成立任何副流已落到 side stream的结论都不能直接当方案成立必须用Start Time(us)Duration(us)算overlap_pct性能无收益按 3a → 3b → 3c 顺序排查先查副流是否根本没真跑逻辑切流失败再算overlap_pct排除假并行 / GE auto-reorder barrier最后才允许谈资源争抢 / host bound / shape 劣化overlap 不等于收益即使overlap_pct ≥ 0.5真并行出现拖尾、资源争抢、host bound、shape 劣化时 wall 也可能不降要继续评估控核和图模式限制不要混抄案例先确定当前模型走哪条执行模式Ascend IR / GE 图模式 还是 npugraph_ex / aclgraph再选一套主 API 路径不要把 eager 和 graph 风格混着套先证明正确再追性能先验证依赖、功能和精度再看 overlap 和时延收益。选定方案前必须做 Profile 双重验证① 副流算子的stream_id确实落到目标 stream不对就回 3a②overlap_pct时间线验证成立要 ≥0.5③ 控核场景下副流算子Block Dim不超过配置值、主副加和不超过设备核数④ 汇合点后无新的EVENT_WAIT空洞或明显 gap⑤ 跨流 tensor 名称和维度与设计一致。profile 至少跑 5 次丢掉前 2-3 次 cold-start 取中位数。六、仓库配套资源与案例参考技能总纲.agents/skills/model-infer-multi-stream/SKILL.md方向级分析产物结构references/module-decomposition.mdGE auto-reorder 风险清单references/ge-reorder-design-check.mdoverlap 时间线复盘算法references/timeline-overlap-check.mdAPI 路由含官方文档入口references/api-routing.mdkernel_details 字段查法references/kernel-fields-lookup.md案例库与快速选型表examples/README.md其中 MoE 共享专家双流moe-shared-expert-dual-stream.md、Indexer Prolog 多流indexer-prolog-multi-stream.md、多流 控核联动longcat-flash-multi-stream-limit-core.md与本规范逐项对应底层 API 封装executor/utils/stream_utils.pynpu_stream_switch/wait_tensor/record_stream的路径分派与开关兜底代表实现源码models/longcat_flash/models/modeling_longcat_flash.py、models/deepseek_v3_2_exp/models/modeling_deepseek.py、models/glm_5/models/indexer.py。综上一个合格的多流 Plan 方案细节应当是一份设计可预判、实测可复核、裁决可上浮的完整技术档案八个组成要素逐项落地证据摘要一句话定案其余细节留给 implementer 与 reviewer 细读。照此规范填写既能避免Stream ID 切对了就以为并行成立的常见误判也能让多流优化候选在编排链路中被干净地裁决为通过或淘汰。【免费下载链接】cann-recipes-infer本项目针对LLM与多模态模型推理业务中的典型模型、加速算法提供基于CANN平台的优化样例项目地址: https://gitcode.com/cann/cann-recipes-infer创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表