在昇腾 CANN 里,有一个仓库叫 ge,全称 Graph Executor,翻译过来就是图执行引擎

这个名字听起来很底层,很多人不知道它是干什么的。但如果你在昇腾 NPU 上跑过模型,不管是训练还是推理,你的模型都要经过 ge 的处理——它是昇腾 CANN 里负责图编译、图优化、图执行的核心组件。

今天把 ge 说清楚。


ge 到底是什么

ge 是昇腾 CANN 开源社区里的一个核心仓库,定位是图执行引擎。它负责把上层框架(PyTorch、TensorFlow、MindSpore 等)传下来的计算图,编译成昇腾 NPU 能高效执行的格式。

这里有个关键概念要讲清楚:计算图

你写的 PyTorch 模型,本质上是一个计算图——每一层是一个节点,层之间的数据流是边。PyTorch 默认是 eager 模式(动态图),每执行一行代码就马上算;但要想在 NPU 上跑得快,必须把整个计算图 capture 下来,做全局优化,再编译成 NPU 的机器码。

ge 就是做这件事的:捕获计算图 → 图优化 → 编译成 NPU 可执行格式

昇腾异构计算架构里,ge 的位置在这里:

框架层(PyTorch / TensorFlow / MindSpore / ...)
  └─ 框架适配器(Framework Adaptor,CANN 第2层)
      └─ ge(图执行引擎,编译 + 执行)
          └─ BiSheng / ATC 编译器(CANN 第3层,生成 NPU 机器码)
              └─ 昇腾 NPU 硬件

ge 的核心工作流程

ge 的工作可以分成三个阶段:图准备、图编译、图执行

第一阶段:图准备。 ge 从框架适配器拿到计算图(可能是 ONNX 格式,也可能是框架自己的图格式),然后做初步的图解析——把图里的算子节点和边整理成 ge 自己的图表示(叫 GE Graph)。

这个阶段还会做算子合法性检查——看看图里有没有 ge 不支持的算子,如果有,提前报错,避免编译到一半失败。

第二阶段:图编译。 这是 ge 最核心的阶段,做了大量优化:

GE Graph
  ├─ 算子融合(Operator Fusion):把相邻的小算子合并成大算子
  ├─ 内存优化(Memory Optimization):复用显存,减少显存峰值占用
  ├─ 数据流转优化(Data Flow Optimization):减少 DDR 和 SRAM 之间的数据搬运
  └─ 生成编译中间表示(IR)→ 交给 BiSheng / ATC 编译器 → NPU 机器码

第三阶段:图执行。 编译完成后,ge 把 NPU 机器码加载到 NPU 上执行。这个阶段 ge 还负责运行时管理——显存分配、算子执行顺序调度、异常处理等。

# ge 的工作对大多数开发者是透明的
# 你只需要正常写 PyTorch 代码,ge 会在底层自动处理

import torch
import torch_npu

# 把模型转成 NPU 可调用的格式(底层调用 ge)
model = YourModel().npu()

# 推理模式,ge 会捕获计算图并编译
with torch.no_grad():
    output = model(input_npu)   # 第一次跑:ge 捕获图 → 编译 → 执行
                                # 后续跑:直接执行编译好的图,很快

ge 和图自动融合(graph-autofusion)的关系

又是一个容易混淆的点。ge 里也做算子融合,graph-autofusion 仓库也做算子融合,它们有什么区别?

简单说:ge 做的是离线融合(编译期),graph-autofusion 做的是在线融合(运行期)

维度 ge(图执行引擎) graph-autofusion
融合时机 编译期(离线) 运行期(在线)
融合策略 基于静态图结构,全局优化 基于实际运行时数据 shape,动态决策
适用场景 固定 shape 的推理(部署场景) 变长序列推理(LLM 场景)
性能稳定性 高(编译期已定) 中(运行时决策,偶尔选错)

如果你在做什么推理部署,模型 shape 是固定的,ge 的离线融合效果更稳定,性能也更好。

如果你在做什么大模型推理,输入序列长度是变的(512、1024、2048 都可能出现),graph-autofusion 的在线融合更灵活,能根据实际 shape 选择最优融合策略。


ge 和 TorchAir 的关系

TorchAir 是昇腾提供的一个工具,专门用来把 PyTorch 的动态图转换成 GE 的静态图

PyTorch 默认是动态图(eager mode),每执行一行代码就马上算;但 ge 需要静态图(整个计算图都确定了才能编译优化)。这两个之间的矛盾,TorchAir 来解决。

工作流程:

PyTorch 动态图
  └─ TorchAir(捕获动态图,转换成静态图表示)
      └─ ge(编译静态图,生成 NPU 可执行格式)
          └─ 执行

如果你在用 PyTorch 做昇腾 NPU 的推理部署,大概率会和 TorchAir 打交道。训练场景一般用动态图(eager mode)就行,不需要 TorchAir;但推理部署场景,用 TorchAir + ge 的静态图编译,性能会好很多。


ge 的几个关键概念

理解 ge,需要理解几个它里面的核心概念:

GE Graph:ge 内部的计算图表示。所有的图优化、图编译,都是基于 GE Graph 做的。

GE Operator:GE Graph 里的节点,对应一个算子(比如 MatMul、ReLU 等)。每个 GE Operator 有自己的输入输出描述、属性配置等。

GE Session:ge 的执行会话。一个 GE Session 管理一个计算图的完整生命周期——编译、执行、销毁。

GE Graph 优化 pass:ge 内置了很多图优化 pass(类似编译器里的优化 pass),比如:

  • 算子融合 pass:合并相邻算子
  • 内存复用 pass:让不同算子复用同一块显存
  • 死代码消除 pass:删掉计算图里没有用到的节点

这些 pass 在图编译阶段自动执行,不需要开发者手动配置。


几个踩坑经验

坑一:第一次跑模型会很慢。 ge 的图编译是需要时间的,特别是大模型,第一次跑的时候要等它编译完。编译完成后,后续的推理会很快(因为直接用编译好的图)。如果你在做什么在线服务,建议先做预热(warm-up)——用几个 dummy 输入跑一遍模型,触发 ge 的图编译,避免第一个真实请求卡很久。

坑二:动态 shape 场景要小心。 ge 擅长静态 shape(编译期 shape 就确定了),如果你在做什么输入 shape 会变的应用(比如 LLM 推理),ge 可能每次都要重新编译图,性能很差。这种场景建议用 graph-autofusion 的在线融合,或者给 ge 配置 shape 范围(告诉 ge 可能的 shape 范围,让它提前编译多个版本的图)。

坑三:ge 的报错信息不太友好。 如果图编译失败,ge 报的错误有时候比较底层,不好定位问题。建议先在自己的开发机上用 CPU 模式把模型调通,再拿到 NPU 上跑——这样至少能排除模型代码本身的 bug,确定是 ge 编译的问题。


结尾

ge 是昇腾 CANN 生态里最底层的图执行引擎,它不性感,但每个跑在昇腾 NPU 上的模型都要经过它。

理解 ge 的价值不在于"怎么直接用它"(大多数时候框架适配器帮你调了),而在于理解你的模型在 NPU 上是怎么被编译、怎么被优化的、什么场景 ge 效果好、什么场景要用别的方案

和 graph-autofusion(在线融合)、TorchAir(PyTorch 图转换)一起,构成了昇腾 NPU 完整的图编译和执行体系。

源码在 https://atomgit.com/cann/ge

Logo

鲲鹏昇腾开发者社区是面向全社会开放的“联接全球计算开发者,聚合华为+生态”的社区,内容涵盖鲲鹏、昇腾资源,帮助开发者快速获取所需的知识、经验、软件、工具、算力,支撑开发者易学、好用、成功,成为核心开发者。

更多推荐