CANN/ge 图拆分模块约束文档
图拆分模块约束文档
【免费下载链接】geGE(Graph Engine)是面向昇腾的图编译器和执行器,提供了计算图优化、多流并行、内存复用和模型下沉等技术手段,加速模型执行效率,减少模型内存占用。 GE 提供对 PyTorch、TensorFlow 前端的友好接入能力,并同时支持 onnx、pb 等主流模型格式的解析与编译。项目地址: https://gitcode.com/cann/ge
图执行模块应该尽量避免动态申请内存(可能会导致随机性能劣化)。 图编译模块内存复用处理阶段禁止改图(多种复用算法会多线程并发处理,会导致异常)。
1. 模块定位与边界
图拆分模块的职责是对计算图进行执行语义上的模型切分,明确哪些节点或子图进入动态图执行器,哪些节点或子图进入静态图执行器,核心边界是“动态图执行器 / 静态图执行器”的模型边界。
图拆分模块只负责切图本身,不负责拆分后子图内部的算子执行器选择、kernel选择、流分配、内存分配、GenTask以及运行时调度策略,不应感知其他组件的内部实现细节,也不应通过跨组件写属性的方式耦合其他模块逻辑。
设计上应将“切图决策”和“执行实现”严格分离:
- 图拆分模块负责节点归属、路径闭包、cluster合并和子图构建;
- 引擎选择、流分配、内存复用、任务下发等模块分别对拆分结果负责;
- 若拆分前后都需要使用某些属性或扩展信息,必须明确定义继承和传递规则,避免边界模糊和职责泄漏。
2. 核心设计原则
单一职责原则图拆分模块只回答“节点/路径/cluster应进入哪个执行器”的问题,不承担执行器内部调度和资源管理职责。
规则显式化原则所有动态图拆分依据必须是显式、可解释、可维测的规则,禁止引入无法从代码和日志中直接解释的隐式判定。
拓扑与语义闭包原则切分结果必须保持拓扑依赖和执行语义正确性。对动态路径上的静态节点,若其形状、tiling或运行时依赖无法在静态侧独立成立,则必须并入动态图执行器,保证语义闭包。
最小侵入原则能通过cluster内部状态表达的,不额外写入Node/OpDesc属性;必须写属性时,只允许写入执行边界判定所必需的稳定属性,且写入点必须集中、可追踪、可验证。
稳定性优先原则图拆分是流分配、内存复用、GenTask等后续流程的前置阶段,任何设计修改都应优先保证图结构稳定、切分结果稳定和下游模块行为稳定。
可演化原则规则扩展应优先采用新增独立规则、独立开关、独立属性的方式,避免直接修改已有默认语义,降低对老图、老配置和历史维测方法的冲击。
3. 动态图拆分依据
当前动态图拆分规则如下:
- 算子为动态Shape算子(Shape中维度存在 -1 或 -2),走动态图执行器,影响整图是否走动态图拆分流程;
- 算子被标记为
force_unknown,走动态图执行器,影响整图是否走动态图拆分流程; - 算子存在Tiling依赖但不支持Tiling下沉,走动态图执行器,影响整图是否走动态图拆分流程;
- 算子被设置了
_is_support_addr_refresh=false,走动态图执行器,影响整图是否走动态图拆分流程; - 算子位于两个已标记为动态图执行器算子的路径上,需要切到动态图执行器,不影响整图是否走动态图拆分流程;
- 算子属于HostCpu引擎,需要切到动态图执行器,不影响整图是否走动态图拆分流程;
- 拆分出的静态图子图算子数量小于阈值(阈值可通过
ge.exec.static_model_ops_lower_limit配置),需要切到动态图执行器,不影响整图是否走动态图拆分流程。
在上述规则基础上,还应遵循以下约束:
- 动态路径吸附、小cluster降级、no-tiling退化等行为,本质上属于执行语义正确性和整体性能平衡的联合规则,不允许只从局部节点属性出发做孤立判断;
- 不允许为了保留局部静态子图而破坏动态链路连续性;
- 不允许为了减少切图数量而错误扩大动态图执行器范围,导致不必要的静态能力退化。
4. 多线程并发场景原则
图对象并发模型明确原则图基础结构默认不支持并发修改,并发安全由业务层保证。图拆分流程不应假设
ComputeGraph、Node、OpDesc等对象具备并发写能力。并发阶段禁止改图原则图编译模块在内存复用等多线程并发阶段禁止改图,因此图拆分相关的图结构修改、属性写入和子图构建必须在后续并发阶段之前完成,不允许在内存复用等阶段回写图结构。
共享资源保护原则若新增全局缓存、规则表、统计信息、注册表等共享资源,必须显式说明线程安全模型,做好共享资源保护。读多写少场景优先采用初始化期构建、运行期只读的方式,避免在图拆分热路径上引入锁竞争和状态漂移。
少写属性原则在多线程语义场景中,尽量不写入属性,尤其是OpDesc属性。由于属性属于跨组件可见状态,禁止在无明确边界约束的情况下扩散属性写入。
结果确定性原则图拆分结果应尽量基于拓扑序、cluster id、显式排序等稳定顺序生成,避免依赖非确定性容器遍历顺序,保证同一张图在相同输入条件下切分结果一致。
5. 维测与日志原则
边界变化必有关键日志节点发生属性变化、执行器归属变化、整图拆分决策变化、cluster类型变化等边界行为,必须有统一且稳定的关键日志。
关键字稳定原则节点发生属性变化的地方使用关键字
Mark node,保证历史脚本、维测方法和问题定位经验的一致性。已有关键日志口径应保持稳定,禁止随意更改关键字和语义。日志少而准原则日志应避免高频打印,优先落在状态切换点、规则命中点、降级点和异常边界点,内容应包含节点名、节点类型、触发原因、关键属性和前后状态,便于快速定界。
决策链可追踪原则维测不仅要能看到“节点变成动态图/静态图”,还应能定位具体触发原因,例如动态shape、force_unknown、tiling依赖不支持下沉、地址刷新不支持、小cluster降级、路径吸附等。
新增规则同步补齐可观测性新增切分规则、cluster类型、属性字段时,必须同步补充日志、调试输出、序列化或其他维测手段,避免出现功能已生效但无法定位的问题。
6. 兼容性修改原则
对外变更必须评审原则涉及对外option、环境变量、接口、数据结构、日志口径的变更,均可能影响兼容性,需要经过评审并形成通过结论后方可实施。
优先新增原则接口和规则演化优先采用新增接口、新增属性、新增开关的方式,避免直接修改现有接口默认参数、已有规则语义和历史行为。
边界稳定原则图拆分边界一旦变化,会联动影响引擎切分、流分配、内存复用、GenTask、dump/prof、RT2动态流程等多个模块,因此兼容性分析必须覆盖整条链路,而非只分析图拆分模块本身。
属性继承完整性原则若新增ExtAttr或其他拆分前后均需使用的属性,必须保证子图构建、子图合并、整图恢复等流程中的属性继承完整,避免出现图拆分后属性丢失、语义不一致的问题。
历史行为保持原则对已有图模型、已有配置和现网维测方法,默认应保持原行为不变;若必须调整,应提供明确开关、迁移方案和验证结论。
7. 性能原则
尽量等价修改原则图拆分相关需求和缺陷修复应优先采用等价修改,保证原有执行语义、kernel执行路径和整体性能特征不发生非必要变化。
不引入kernel性能劣化原则若修改不涉及kernel本身,则不应通过切分边界变化将原有静态执行路径无故降级到动态执行路径,导致kernel侧额外调度、同步或数据搬运开销。
避免执行期动态申请内存原则图执行模块应尽量避免动态申请内存;图拆分设计应优先在编译期完成决策,不得通过新增运行时动态资源申请引入随机性能劣化。
减少碎片子图原则应避免产生大量过小的静态子图或动态图子图。小cluster降级、路径吸附等机制本质上是为了降低子图碎片度、减少执行器切换、减少Host/Device往返和同步开销。
热路径轻量化原则图拆分相关热路径禁止增加非必要日志、时间戳获取、重复计算和临时对象开销;性能评估应覆盖切图耗时、子图数量、跨子图边界数量以及后续执行链路开销。
8. 典型约束与实施要求
- 图拆分设计和实现应优先遵守模块边界,不得扩展为“顺带完成引擎选择/流分配/资源调度”的混合模块。
- 新增规则必须满足“规则可解释、日志可观测、行为可验证、结果可复现”。
- 任何涉及属性写入的修改,都应通过UT/ST验证写入范围、写入时机和前后状态,必要时增加图拆分前后属性一致性校验。
- 任何涉及边界变化的修改,都应补充整图场景、混合图场景、小cluster场景、HostCpu场景、动态路径吸附场景和兼容场景验证。
- 若修改会影响后续小引擎切分、流分配、内存复用、RT2动态流程、dump/prof等模块,必须进行交叉分析和联动验证,避免局部正确、全链路异常。
9. 图拆分模块设计评审检查清单
一、模块边界
- 是否明确本次修改只作用于“图拆分”边界,不扩散到执行器选择、流分配、内存分配、GenTask、运行时调度。
- 是否明确新增逻辑属于“切图决策”而不是“执行实现”。
- 是否识别并说明会受影响的相邻模块:小引擎切分、流分配、内存复用、RT2、dump/prof。
- 是否定义了新增属性或状态在拆分前后、子图构建前后的归属和继承规则。
二、规则正确性
- 新规则是否显式、可解释、可维测,避免隐式判定。
- 是否说明规则命中的输入条件、边界条件、排斥条件。
- 是否说明该规则是否影响“整图是否进入动态图拆分流程”。
- 是否说明该规则是“节点级转动态”还是“路径/cluster级转动态”。
- 是否验证不会破坏动态链路连续性。
- 是否验证不会错误扩大动态图执行器范围。
- 是否验证不会错误保留本应进入动态图执行器的静态节点。
三、拓扑与图结构稳定性
- 是否保证切分前后拓扑依赖语义不变。
- 是否保证cluster合并、降级、吸附后不会引入环。
- 是否保证图拆分期间图结构修改时机受控。
- 是否保证后续内存复用、多线程阶段之前完成所有必要改图。
- 是否评估对topo排序、topo id、cluster排序稳定性的影响。
- 是否避免依赖不稳定容器遍历顺序导致结果漂移。
四、并发与线程安全
- 是否明确本次修改涉及的数据结构是否会被多线程访问。
- 是否避免在多线程语义场景下无约束写OpDesc/Node属性。
- 若引入全局缓存、表、注册信息,是否说明线程安全模型。
- 若有共享资源,是否有锁、只读初始化或生命周期保护设计。
- 是否验证同一张图在相同输入下多次切分结果一致。
五、维测与日志
- 是否在边界变化点提供关键日志。
- 是否保持
Mark node等已有关键字稳定。 - 是否能通过日志区分具体触发原因:
- dynamic shape
- force_unknown
- tiling depend不支持下沉
_is_support_addr_refresh=false- 路径吸附
- 小cluster降级
- HostCpu引擎
- 日志是否避免高频打印。
- 日志内容是否包含节点名、类型、原因、关键属性、前后状态。
- 新增规则或属性是否同步补齐调试输出或其他可观测性手段。
六、兼容性
- 是否涉及对外option、环境变量、接口、数据结构、日志口径变更。
- 若涉及,是否已完成评审并有明确结论。
- 是否优先采用“新增规则/新增开关/新增属性”而非修改旧语义。
- 是否评估老图、老配置、历史场景的兼容性。
- 是否定义了新增属性在子图构建、子图合并、整图恢复中的继承规则。
- 是否评估对脚本、维测、现网排障方法的兼容性。
七、性能
- 是否遵循“尽量等价修改”。
- 是否确认不会无故将原静态路径降级为动态路径。
- 是否确认不会引入kernel性能劣化。
- 是否避免新增执行期动态内存申请。
- 是否评估对子图数量、跨子图边界数量、同步/搬运次数的影响。
- 是否评估对Host/Device往返、调度开销、执行器切换的影响。
- 热路径是否避免新增非必要日志、时间戳、重复计算、临时对象。
八、测试覆盖
- 是否有UT覆盖新增规则命中场景。
- 是否有UT覆盖规则未命中场景。
- 是否有UT覆盖边界场景:混合图、路径吸附、小cluster、HostCpu、force_unknown、tiling depend、addr refresh。
- 是否有ST覆盖与小引擎切分、流分配、内存复用、RT2、dump/prof的联动场景。
- 是否有前后属性一致性校验。
- 是否有日志关键字和维测口径校验。
- 是否验证同图重复执行结果稳定。
九、结论项
- 规则正确。
- 边界清晰。
- 并发安全。
- 维测可用。
- 兼容性可接受。
- 性能无劣化。
- 测试充分。
- 可进入开发/可合入。
【免费下载链接】geGE(Graph Engine)是面向昇腾的图编译器和执行器,提供了计算图优化、多流并行、内存复用和模型下沉等技术手段,加速模型执行效率,减少模型内存占用。 GE 提供对 PyTorch、TensorFlow 前端的友好接入能力,并同时支持 onnx、pb 等主流模型格式的解析与编译。项目地址: https://gitcode.com/cann/ge
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
