在 CANN 的五层架构里GE 处在 AscendCL 和 Runtime 之间的枢纽位置。它不直接参与算子计算不管理 NPU 资源但它决定了这张计算图怎么跑——算子的执行顺序、哪些可以并发的、哪些可以融合的、中间 Tensor 放哪。GEGraph Engine是整个推理链路中最容易被忽视但影响最大的组件。没有 GE 的图优化Runtime 拿到的就是一张原始的 ONNX 算子列表——每个算子独立调度、独立分配内存、独立搬运数据。有了 GE 的优化同一张图的推理延迟可以快 2-3 倍。GE 为什么存在AI 推理跟普通程序执行最大的区别是计算图是已知的。普通程序有分支和循环编译器无法预知执行路径——变量 x 的值取决于用户的输入。AI 模型的计算图是固定的——模型训练结束后网络结构就锁死了每条数据进来走的计算路径完全一样。固定图这个特性给了 GE 巨大的优化空间。它可以在模型加载阶段花几十毫秒做全局分析——扫描整张图、找融合机会、做内存预分配——这些优化只需要做一次后续每次推理都能受益。图执行的全链路GE 的工作从 AscendCL 调用aclmdlLoadFromFile加载 OM 模型开始阶段 1图解析。GE 读取 OM 中的序列化计算图重建算子节点和数据边。每个算子节点记录了类型、输入输出 Tensor 的形状和数据类型、属性参数。阶段 2图编译。GE 内部有一个轻量级 Graph Compiler它把原始的计算图改造成更适合在昇腾上执行的形态。Graph Compiler 的优化不会一直触发。如果 GE 发现模型加载时 OM 中已经包含了优化后的执行计划即 ATC 编译时已经做过了完整优化就直接跳到阶段 4。如果 OM 中没有比如手动构建的计算图Graph Compiler 会执行完整的编译流程。Graph Compiler 的核心 Pass算子融合把多个连续算子合并成一个 Fusion 算子内存复用分析分析每个 Tensor 的生命周期让不同 Tensor 复用同一块显存Layout 优化为关键算子插入 ND↔NZ 转换常量折叠在编译期算出常量算子的结果阶段 3内存分配。基于 Tensor 生命周期分析为每个 Tensor 分配物理显存地址。// GE 的内存分配策略简化for(autotensor:graph.tensors){if(tensor.lifetime_overlaps_with(existing)){tensor.addrallocate_new();// 生命周期不重叠的 Tensor 复用地址}else{tensor.addrfind_reusable_addr(tensor.lifetime,tensor.size);}}阶段 4Task 生成。把优化后的图拆解成 Runtime 可执行的 Task 列表。阶段 5Task 下发。把 Task 提交到 Runtime 的 Stream 队列。GE 在这一步可以控制哪些 Task 走同一个 Stream、哪些走不同 Stream。Graph Compiler 如何优化图以 GE 对 Attention 子图的编译优化为例。GE 收到 GEMM → BiasAdd → Softmax → GEMM 这个子图后模式匹配。扫描到连续 4 个节点构成 Attention 的标准模式融合评估。检查 L1 容量——Softmax 的中间 Tensor 大小不超过 L1可以融合替换。把 4 个算子替换成一个 FlashAttention 融合算子内存分析。FlashAttention 内部的中间 TensorS_ij 分块在 L1 上流转不需要 DDR 分配编译后的执行图从 4 个算子变成 1 个融合算子。融合算子内部的循环和分块逻辑在 Kernel 编译期已经展开运行时不产生额外调度开销。GE 如何连接 RuntimeGraph Compiler 产出的 Task 列表需要通过 Runtime 才能真正执行。GE 和 Runtime 的接口很简单——GE 把 Task 推送到 Runtime 的 Stream 里。一个 Task 包含Kernel 句柄指向编译好的算子二进制输入 Tensor 的显存地址列表输出 Tensor 的显存地址列表Stream ID任务应该提交到哪个 StreamGE 把这些 Task 按依赖关系排序后逐个调用aclrtLaunchTask提交到 Runtime// GE 把 Task 提交到 Runtimefor(autotask:optimized_task_list){aclrtLaunchTask(task.kernel,task.input_addrs,task.output_addrs,task.stream_id);}Runtime 拿到 Task 后把 Task 推送到对应 Stream 的硬件队列。Stream 调度器根据 Task 的 Event 依赖关系决定执行顺序。Transformer 推理中的 GELLaMA-7B 加载时的 GE 优化统计优化项原始图GE 优化后减少算子节点数1,24728677%中间 Tensor 数89217480%显存分配大小3.8GB1.2GB68%Task 数1,24728677%77% 的算子被融合或消除。80% 的中间 Tensor 不需要显存分配在片上 L1 流转或复用已有显存。模型从 3.8GB 降到 1.2GB 的显存占用。GE 的优化收益在 Transformer 这类规整结构的模型上最明显——重复的 Decoder Block、固定的 Attention 模式、确定的 FFN 结构Graph Compiler 的模式匹配引擎对这类图的识别率很高。继续学习GE 做完图优化后输出的优化执行计划交给 Runtime 执行。理解了 GE 的图编译和优化机制就理解了模型从 ONNX 到真正在 NPU 上执行中间经过了哪些步骤。GE 图执行引擎graph-autofusion 自动融合框架GE 的轻量级 vs 全量编译GE 的 Graph Compiler 有两种工作模式。全量编译在 ATC 模型转换时触发——完整跑一遍所有优化 Pass产出最终的执行计划。轻量级编译在 OM 模型加载时触发——如果 OM 中已经包含 ATC 编好的执行计划GE 只做必要的最小量优化如动态 Shape 的内存重分配。轻量级编译的典型场景模型已在 ATC 阶段优化过加载 OM 时 GE 不需要重新做算子融合和内存分析。加载时间从几秒降到几十毫秒。GE 在多模型场景中的角色同时部署多个模型时GE 为每个模型维护独立的图执行环境。模型 A 的优化决策不影响模型 B。但 GE 可以在 Runtime 层共享公共资源——比如算子 Kernel 的二进制缓存。模型 A 和模型 B 共用相同形状的 GEMM 时Runtim 不会重复编译 Kernel。多模型场景下 GE 的监控接口输出每个模型的图优化统计——融合率、内存复用率、Task 数量。这些指标可以帮助判断某个模型的部署配置是否需要调整。GE 在图编译阶段的调试方法GE 的 Graph Compiler 支持导出中间图用于调试# 导出 GE 优化后的计算图exportDUMP_GE_GRAPH2# 图以 pbtxt 格式输出到 /tmp/ge_graph/导出的文件可以用 Netron 或脚本可视化。对比融合前后的图结构检查哪些算子被 GE 融合了、哪些没被融合。如果发现预期应该融合的算子没有被融合检查该模式是否在 GE 的融合规则表中——或者检查中间 Tensor 的 L1 容量是否足够。常用检查点融合前的图有多少节点融合后的图有多少节点没有被融合的算子链中哪些因为 L1 限制、哪些因为执行单元冲突总结GE 是 CANN 推理链路中最容易被低估的组件。它不直接产出性能数字但没有 GE 的图编译和优化Runtime 拿到的就是一张原始的 ONNX 算子列表——每个算子独立调度、独立分配内存。GE 的图优化做得好不好直接决定了模型推理性能的上限。理解 GE 的图编译和优化机制是深入 CANN 推理性能优化的必经之路。从 Graph Compiler 的融合 Pass到内存分析的复用策略再到 Task 生成和下发——每一步都决定了计算图最终在 NPU 上的执行效率。GE 在大型模型上的表现在 LLaMA-70B 的张量并行场景中GE 需要同时管理多张卡的图执行计划。每张卡的 GE 实例独立执行——卡 0 的 GE 优化 Block 1-20 的计算图卡 1 的 GE 优化 Block 21-40——不跨卡同步。跨卡的图优化由训练框架DeepSpeed、Megatron-LM在模型切分阶段完成GE 只负责单卡部分的图执行优化。这种分工让 GE 在大模型场景中保持了图编译的独立性——每张卡的算子融合和内存分配不需要知道其他卡的图结构。GE 的优化复杂度不随卡数增加而增长。参考仓库GE 图执行引擎graph-autofusion 自动融合框架