{
"cells": [
{
"cell_type": "markdown",
"id": "b68347cc",
"metadata": {},
"source": [
"# AscendIR — 用户构图的基础概念\n",
"\n",
"本节开始深入学习 GE 编译流程使用的核心 IR —— AscendIR,掌握构图的基础概念。这些知识将为你后续使用 ATC 编译模型或通过 GeSession 在线构图奠定基础。\n",
"\n",
"本节学习大纲如下:\n",
"\n",
"- AscendIR 概述\n",
"- 图的对象模型:ComputeGraph → Node → OpDesc → GeTensorDesc(含属性表)\n",
"- Tensor 描述:shape、dtype、format\n",
"- 数据边与控制边、Anchor\n",
"- 静态 Shape 与动态 Shape\n",
"- 算子生态\n",
"- 构图方式预览"
]
},
{
"cell_type": "markdown",
"id": "e07130b2",
"metadata": {},
"source": [
"## 1. AscendIR 概述\n",
"\n",
"AscendIR 是 AI 处理器专用的抽象数据结构,用于表达计算流程。PyTorch、TensorFlow、MindSpore、PaddlePaddle 等主流框架的模型可统一转换为 AscendIR 表示的计算图,用户也可以通过 GE 接口直接构图。后续的编译、优化和执行调度都围绕该计算图展开。\n",
"\n",
"AscendIR(Ascend Intermediate Representation,昇腾中间表示)是 GE 编译流程使用的核心 IR,用图结构表达模型的计算逻辑与数据依赖关系。AscendIR 也被简称为 \"AIR\",TorchAir 中的 \"Air\" 取自于此。\n",
"\n",
"在抽象层级上,AscendIR 与 ONNX、AtenIR、StableHLO 等同属高层图表示(HLO 级别),以算子和张量为基本构成单元,用于描述模型的运算语义与图结构。\n",
"\n",
"下图是一个使用 AscendIR 表示的计算图示例:两个 `Data` 输入经 `Matmul` 做矩阵乘,再经 `ReLU` 激活,最终由 `NetOutput` 节点汇总输出。\n",
"\n",
"<p align=\"left\"><img src=\"./images/ascendir_graph.svg\" alt=\"使用 AscendIR 表示的计算图\" width=\"75%\"></p>\n",
"\n",
"图中的 `Graph`、`Node`、Tensor 数据边和输出节点之间的对应关系可用下面的结构图进一步核对。它把一张图拆解为可用于构图和编译的基本元素:\n",
"\n",
"<p align=\"left\"><img src=\"./images/ascendir_elements.svg\" alt=\"AscendIR 图的组成要素\" width=\"85%\"></p>\n",
"\n",
"### AscendIR 的定位\n",
"\n",
"- **统一编译入口**:无论来自前端框架(通过 Adapter),还是来自模型文件(通过 ATC / Parser),所有输入都会先转换为 AscendIR,再进入 GE Compiler。\n",
"- **统一优化底座**:转换为 AscendIR 后,GE 能以整图视角进行常量折叠、算子融合、内存复用等优化。\n",
"\n",
"<div align=\"left\">\n",
"<blockquote style=\"margin-left: 0; margin-right: auto;\">\n",
"<p><strong>AscendIR 既能表达静态 Shape 图,也能表达动态 Shape 图,GE 均支持二者的编译与执行:</strong></p>\n",
"<ul><li><strong>静态 Shape 图</strong>:多次执行中所有 Tensor 的 shape 均固定。</li><li><strong>动态 Shape 图</strong>:不同执行中,部分 Tensor 的 shape 可能随实际输入变化。</li></ul>\n",
"</blockquote>\n",
"</div>"
]
},
{
"cell_type": "markdown",
"id": "83ecdfcf",
"metadata": {},
"source": [
"## 2. 图的对象模型\n",
"\n",
"AscendIR 图是一张有向无环图(DAG)。它的核心对象模型由四个层次**层层持有**构成:\n",
"\n",
"- **ComputeGraph(图)**:图的容器,管理节点集合、图的输入/输出、子图等。\n",
"- **Node(节点 / 算子)**:图中的算子节点,持有一个 **OpDesc** 和一组 **Anchor(锚点)**。\n",
"- **OpDesc(算子描述符)**:定义算子的名称(name)、类型(type)、属性、推导函数,以及**输入/输出 Tensor 描述**。\n",
"- **GeTensorDesc(张量描述)**:描述一个张量的 shape、dtype、format 等信息,作为节点的 input_desc / output_desc 由 OpDesc 持有。\n",
"\n",
"一个关键设计特征是:**图中不存在独立的 Edge(边)对象**,节点之间的连边由成对的 **Anchor** 维护(详见第 4 节)。因此 Tensor 描述并不漂浮在数据边上,而是分别存放在生产者节点的 output_desc 与消费者节点的 input_desc 中。\n",
"\n",
"下面分别展开用户构图时最常接触的 Tensor、Node、Graph 的属性(OpDesc 作为 Node 内部的算子描述符,其字段在 Node 一节一并说明)。"
]
},
{
"cell_type": "markdown",
"id": "e9a4e8de",
"metadata": {},
"source": [
"### 2.1 Tensor\n",
"\n",
"Tensor 是算子的输入输出数据实体,**包括 Tensor 描述与数据两部分**。Tensor 描述包含该 Tensor 的 name、shape、dtype、format 信息。\n",
"\n",
"<div align=\"left\">\n",
"<table style=\"margin-left: 0; margin-right: auto;\">\n",
"<thead>\n",
"<tr><th>属性</th><th>定义</th></tr>\n",
"</thead>\n",
"<tbody>\n",
"<tr><td>名称(name)</td><td>用于对 Tensor 进行索引,不同 Tensor 的 name 需要保持唯一。</td></tr>\n",
"<tr><td>形状(shape)</td><td>Tensor 的形状,例如 <code>(10,)</code>、<code>(1024, 1024)</code> 或 <code>(2, 3, 4)</code> 等。如形状 <code>(3, 4)</code> 表示第一维有 3 个元素、第二维有 4 个元素,即一个 3 行 4 列的矩阵数组。形式为 <code>(i1, i2, …, in)</code>,静态 shape 下 i1 到 in 均为正整数;动态 shape 下还可取 <code>-1</code> / <code>-2</code> 作为占位(见下方说明)。</td></tr>\n",
"<tr><td>数据类型(dtype)</td><td>Tensor 对象中每个元素的数据类型。取值范围:float16, float32, int8, int16, int32, uint8, uint16, bfloat16, bool 等。</td></tr>\n",
"<tr><td>数据排布格式(format)</td><td>数据的物理排布格式,如 ND / NCHW / NHWC / NC1HWC0 等。</td></tr>\n",
"</tbody>\n",
"</table>\n",
"</div>\n",
"\n",
"<div align=\"left\">\n",
"<blockquote style=\"margin-left: 0; margin-right: auto;\">\n",
"<p>说明:在 GE 编译期,Tensor 描述(name/shape/dtype/format)用于推导与优化;真实数据通常在执行期才填入,构图阶段一般只描述元信息。</p>\n",
"<p><strong>动态 shape 的特殊取值</strong>:当某些维度在编译期无法确定时,shape 用负数占位:</p>\n",
"<ul><li><strong><code>-1</code>(UNKNOWN_DIM,未知维度)</strong>:表示<strong>某一维</strong>的大小编译期未知、运行时才确定,但维度个数(rank)已知。例如 <code>(-1, 3, 224, 224)</code> 表示 batch 维动态、其余维固定。</li><li><strong><code>-2</code>(UNKNOWN_RANK,未知秩)</strong>:作为<strong>整个 shape</strong>(即 <code>[-2]</code>)时,表示 shape 完全未知——连维度个数(rank)都不确定,是动态程度最高的情形。</li></ul>\n",
"<p>这两种取值的具体编译与执行处理,会在后续「静态 Shape 与动态 Shape」一节及进阶章节展开。</p>\n",
"</blockquote>\n",
"</div>"
]
},
{
"cell_type": "markdown",
"id": "210d9604",
"metadata": {},
"source": [
"### 2.2 Node\n",
"\n",
"Node 表示算子级计算单元,是图中执行计算的基本实体。它持有一个 **OpDesc(算子描述符)**,下表中算子的 name、type、输入、输出、属性等信息都记录在该 OpDesc 中。\n",
"\n",
"<div align=\"left\">\n",
"<table style=\"margin-left: 0; margin-right: auto;\">\n",
"<thead>\n",
"<tr><th>属性</th><th>定义</th></tr>\n",
"</thead>\n",
"<tbody>\n",
"<tr><td>名称(name)</td><td>算子的名称,用于标识图中的某个算子,<strong>同一图中算子的名称需保持唯一</strong>。如下图中的 Conv1、Pool1、Conv2 都是算子名称。</td></tr>\n",
"<tr><td>类型(type)</td><td>算子根据 type 进行实现匹配,<strong>相同 type 的算子实现逻辑相同</strong>。同一图中同 type 算子可能有多个,例如下图中 Conv1 与 Conv2 的 type 都是 <code>Convolution</code>,表示各做一次卷积。</td></tr>\n",
"<tr><td>输入(input)</td><td>算子的输入 Tensor 数据。</td></tr>\n",
"<tr><td>输出(output)</td><td>算子的输出 Tensor 数据。</td></tr>\n",
"<tr><td>属性(Attributes)</td><td>定义算子的行为和功能,常见属性如轴(Axis)、权重(Weight)、偏差(Bias)。属性在构图时确定。</td></tr>\n",
"</tbody>\n",
"</table>\n",
"</div>\n",
"\n",
"<p align=\"left\"><img src=\"./images/node_example.svg\" alt=\"算子命名示例:Conv1、Pool1、Conv2\" width=\"78%\"></p>\n",
"\n",
"<div align=\"left\">\n",
"<blockquote style=\"margin-left: 0; margin-right: auto;\">\n",
"<p>注意区分 <strong>name</strong> 与 <strong>type</strong>:name 是图中唯一的\"身份标识\",type 是决定计算逻辑的\"算子种类\"。上图中 Conv1 与 Conv2 是两个不同的 name,但共享同一个 type <code>Convolution</code>。</p>\n",
"</blockquote>\n",
"</div>"
]
},
{
"cell_type": "markdown",
"id": "87ff499a",
"metadata": {},
"source": [
"### 2.3 Graph\n",
"\n",
"Graph 是图的容器,承载节点、连边、输入输出描述等,是 GE 编译的基本处理单元。\n",
"\n",
"<div align=\"left\">\n",
"<table style=\"margin-left: 0; margin-right: auto;\">\n",
"<thead>\n",
"<tr><th>属性</th><th>定义</th></tr>\n",
"</thead>\n",
"<tbody>\n",
"<tr><td>名称(name)</td><td>图的名称,用于标识网络中的某个 Graph,同一网络中 Graph 的名称需保持唯一。</td></tr>\n",
"<tr><td>算子列表</td><td>图中所有节点(Node)的列表。</td></tr>\n",
"<tr><td>输入算子(input)</td><td>图的输入算子(通常是 Data / 输入占位节点)。</td></tr>\n",
"<tr><td>输出算子(output)</td><td>图的输出算子。</td></tr>\n",
"</tbody>\n",
"</table>\n",
"</div>\n",
"\n",
"- 一个 Graph 包含若干 Node 以及它们之间的连接关系。\n",
"- ComputeGraph 可包含子图(如 If / While 等控制流算子产生的子图)。"
]
},
{
"cell_type": "markdown",
"id": "66816244",
"metadata": {},
"source": [
"## 3. Tensor 描述\n",
"\n",
"承接上一节的 Tensor 属性表,这里把构图时最常关注的 shape、dtype、format 三项展开说明。\n",
"\n",
"### 3.1 Shape\n",
"\n",
"描述 Tensor 各维度的大小,例如:\n",
"\n",
"- 一张 224×224 的 RGB 图片(NCHW):`[1, 3, 224, 224]`\n",
"- 一个 batch size 为 32 的向量序列:`[32, 128, 768]`\n",
"- 一个 3 行 4 列的矩阵:`(3, 4)`\n",
"\n",
"### 3.2 DataType\n",
"\n",
"描述 Tensor 中每个元素的数据类型,GE 中常见取值如下:\n",
"\n",
"<div align=\"left\">\n",
"<table style=\"margin-left: 0; margin-right: auto;\">\n",
"<thead>\n",
"<tr><th>数据类型(dtype)</th><th>说明</th></tr>\n",
"</thead>\n",
"<tbody>\n",
"<tr><td>float32</td><td>32 位浮点数</td></tr>\n",
"<tr><td>float16</td><td>16 位浮点数</td></tr>\n",
"<tr><td>bfloat16</td><td>16 位脑浮点数(指数位更宽,常用于训练/混精)</td></tr>\n",
"<tr><td>int8 / int16 / int32</td><td>有符号整数</td></tr>\n",
"<tr><td>uint8 / uint16</td><td>无符号整数</td></tr>\n",
"<tr><td>bool</td><td>布尔值</td></tr>\n",
"</tbody>\n",
"</table>\n",
"</div>\n",
"\n",
"<div align=\"left\">\n",
"<blockquote style=\"margin-left: 0; margin-right: auto;\">\n",
"<p>完整取值范围:float16, float32, int8, int16, int32, uint8, uint16, bfloat16, bool 等。</p>\n",
"</blockquote>\n",
"</div>\n",
"\n",
"### 3.3 Format\n",
"\n",
"描述 Tensor 在内存中的物理排列方式,常见的有:\n",
"\n",
"<div align=\"left\">\n",
"<table style=\"margin-left: 0; margin-right: auto;\">\n",
"<thead>\n",
"<tr><th>格式</th><th>说明</th></tr>\n",
"</thead>\n",
"<tbody>\n",
"<tr><td>ND</td><td>通用多维数组格式(N-Dimension),不绑定语义维度</td></tr>\n",
"<tr><td>NCHW</td><td>按 Batch-Channel-Height-Width 排列</td></tr>\n",
"<tr><td>NHWC</td><td>按 Batch-Height-Width-Channel 排列</td></tr>\n",
"<tr><td>NC1HWC0</td><td>昇腾特有的 5HD 格式,适配 AI Core 计算单元</td></tr>\n",
"</tbody>\n",
"</table>\n",
"</div>\n",
"\n",
"<div align=\"left\">\n",
"<blockquote style=\"margin-left: 0; margin-right: auto;\">\n",
"<p>GE 编译过程中会根据算子要求和硬件特性自动进行 format 推导与转换(<strong>InferFormat</strong>),用户构图时通常只需关注 ND 等通用格式,无需手工指定昇腾私有格式。</p>\n",
"</blockquote>\n",
"</div>"
]
},
{
"cell_type": "markdown",
"id": "86021c4e",
"metadata": {},
"source": [
"## 4. 数据边、控制边与 Anchor\n",
"\n",
"AscendIR 图中的节点通过两种“边”连接:数据边与控制边。\n",
"\n",
"<p align=\"left\"><img src=\"./images/data_control_edge.svg\" alt=\"数据边与控制边示意\" width=\"72%\"></p>\n",
"\n",
"### 4.1 数据边\n",
"\n",
"数据边表示 Tensor 的生产者与消费者关系,方向由源节点(src)指向目标节点(dst)。Node A 的输出 Tensor 作为 Node B 的输入 Tensor,承载实际的数据依赖关系。\n",
"\n",
"### 4.2 控制边\n",
"控制边表示纯依赖关系,无数据传递;用于显式约束执行顺序,保证 src 节点先于 dst 节点执行,常用于变量更新、资源管理等场景。\n",
"\n",
"### 4.3 Anchor\n",
"\n",
"在 GE 的实际实现中,**图里并不存在独立的 Edge 对象**,而是通过\"锚点(Anchor)\"来表达节点间的连边关系:\n",
"\n",
"- **DataAnchor**:表示数据边(数据流向)。一个节点的每个输入 / 输出端口对应一个 DataAnchor。\n",
"- **CtrlAnchor**:表示控制边(仅约束执行顺序)。\n",
"\n",
"每个锚点维护其对端锚点(peer anchor),通过 src 锚点与 dst 锚点的配对来描述一条连边。换言之,GE 用\"成对的 Anchor\"代替了独立的\"Edge\"对象。"
]
},
{
"cell_type": "markdown",
"id": "dfe9a21d",
"metadata": {},
"source": [
"## 5. 静态 Shape 与动态 Shape\n",
"\n",
"根据 Tensor shape 在编译期是否完全确定,以及执行时是否可能随输入变化,常见场景可以分为静态 Shape、动态分档和纯动态 Shape。\n",
"\n",
"### 5.1 静态 Shape 图\n",
"\n",
"- 所有 Tensor 的 shape 在编译期完全确定。\n",
"- 编译产物可直接下沉执行,运行时开销最低。\n",
"- 适合输入规格固定的推理场景(如固定分辨率的图片分类)。\n",
"\n",
"### 5.2 动态分档与纯动态 Shape\n",
"\n",
"动态 Shape 图中需要区分两类处理方式:\n",
"\n",
"- **动态分档**:提前设置多个 shape 档位,例如 `[1, 128]`、`[1, 256]`、`[1, 512]`。每个档位内的 shape 相对确定,编译和执行方式更接近静态 Shape;运行时根据实际输入选择匹配的档位。\n",
"- **纯动态 Shape**:不依赖预设档位覆盖所有输入规格,执行时根据实际输入计算 shape、tiling 和资源使用。它更灵活,但通常需要更多运行时推导与调度开销。\n",
"\n",
"<div align=\"left\">\n",
"<table style=\"margin-left: 0; margin-right: auto;\">\n",
"<thead>\n",
"<tr><th>维度</th><th>静态 Shape 图</th><th>动态分档</th><th>纯动态 Shape 图</th></tr>\n",
"</thead>\n",
"<tbody>\n",
"<tr><td>Shape 确定性</td><td>编译期完全确定</td><td>运行时从预设档位中选择,档位内相对确定</td><td>执行时根据实际输入确定</td></tr>\n",
"<tr><td>编译方式</td><td>一次编译固定规格</td><td>为多个档位分别生成或选择相对确定的编译产物</td><td>编译产物保留动态维度,运行时计算 shape / tiling / 资源</td></tr>\n",
"<tr><td>运行时开销</td><td>低</td><td>中等,主要来自档位匹配和必要的地址刷新</td><td>较高,主要来自运行时 shape 推导、tiling 和资源决策</td></tr>\n",
"<tr><td>典型场景</td><td>固定输入推理</td><td>常见变长序列、有限分辨率集合</td><td>输入规格变化范围大或无法提前枚举档位的场景</td></tr>\n",
"</tbody>\n",
"</table>\n",
"</div>\n",
"\n",
"<div align=\"left\">\n",
"<blockquote style=\"margin-left: 0; margin-right: auto;\">\n",
"<p>后续章节讲解动态 Shape 编译与执行时,需要先确认讨论的是动态分档还是纯动态 Shape,避免把二者混为一种机制。</p>\n",
"</blockquote>\n",
"</div>"
]
},
{
"cell_type": "markdown",
"id": "a1564cc8",
"metadata": {},
"source": [
"## 6. 算子生态\n",
"\n",
"在 GE 的整体架构中,AscendIR 的基础结构(包括 Graph、Node、Tensor、Attribute 等)由 GE 仓维护;然而,**具体的算子定义并不位于 GE 仓,而由独立的算子仓进行维护**。\n",
"\n",
"这种设计的原因是:\n",
"\n",
"- 算子实现需要在\"入图(Graph)\"和\"aclnn(原生 API 调用)\"两类场景中保持统一。\n",
"- 算子仓独立维护,使算子实现不受 GE 编译流程的约束。\n",
"- GE 通过算子注册机制识别和调用算子。\n",
"\n",
"### 自定义算子\n",
"\n",
"当业务特有算子不在 GE 内置算子库中时,用户可以通过 AscendC 开发自定义算子并注册入 GE 图编译流程:\n",
"\n",
"<p align=\"left\"><img src=\"./images/custom_op_flow.svg\" alt=\"自定义算子注册入图流程\" width=\"78%\"></p>\n",
"\n",
"<div align=\"left\">\n",
"<blockquote style=\"margin-left: 0; margin-right: auto;\">\n",
"<p>自定义算子入图的详细开发流程将在第三章\"图编译\"中深入讲解。</p>\n",
"</blockquote>\n",
"</div>"
]
},
{
"cell_type": "markdown",
"id": "3dd9c094",
"metadata": {},
"source": [
"## 7. 构图方式预览\n",
"\n",
"了解了 AscendIR 的元素与连边后,自然的问题是:**用户如何构建一张 AscendIR 图?** GE 提供了三种主流方式,本节先做概览,后续章节再深入。\n",
"\n",
"### 7.1 GE 图引擎 C++ 接口(全新构建)\n",
"\n",
"用算子原型(`op::` 风格)逐个实例化算子、连接输入输出,从零构建一张 Graph。代码直观、控制力最强:\n",
"\n",
"```cpp\n",
"auto data0 = op::Data(\"data0\");\n",
"auto data1 = op::Data(\"data1\");\n",
"auto add = op::Add(\"add\").set_input_x1(data0).set_input_x2(data1);\n",
"\n",
"Graph graph(\"demo_graph\");\n",
"graph.SetInputs({data0, data1}).SetOutputs({add});\n",
"```\n",
"\n",
"<div align=\"left\">\n",
"<blockquote style=\"margin-left: 0; margin-right: auto;\">\n",
"<p>上述为示意写法,旨在说明\"算子原型 + set_input + 组图\"的范式,实际接口名以版本文档为准。</p>\n",
"</blockquote>\n",
"</div>\n",
"\n",
"### 7.2 Parser 接口(从已有模型解析)\n",
"\n",
"将已有的 onnx / pb 等模型文件解析为 AscendIR Graph,无需手工逐算子搭建。典型接口如 `aclgrphParseONNX`(解析 ONNX)、`aclgrphParseTensorFlow`(解析 TF pb)等:\n",
"\n",
"```\n",
"model.onnx ──▶ aclgrphParseONNX ──▶ AscendIR Graph\n",
"```\n",
"\n",
"### 7.3 ES 极简构图(函数风格)\n",
"\n",
"采用函数风格的极简接口构图,相比 C++ 原型风格代码量更少,适合快速搭建与实验。GE 仓提供了可执行的 ES examples,例如 [examples/es/normal_input](https://gitcode.com/cann/ge/tree/master/examples/es/normal_input) 中的 C++ 示例会构建 `input -> Relu -> Relu -> Add -> output` 图并支持 dump / run。\n",
"\n",
"下面的代码片段摘取并简化自该示例,保留 ES 构图的核心步骤:创建 `EsGraphBuilder`、创建输入、用函数式 API 连接算子、设置输出并构建 Graph。\n",
"\n",
"```cpp\n",
"#include \"es_Add.h\"\n",
"#include \"es_Relu.h\"\n",
"#include \"ge/ge_api.h\"\n",
"\n",
"using namespace ge;\n",
"using namespace ge::es;\n",
"\n",
"std::unique_ptr<ge::Graph> MakeReluAddGraphByEs() {\n",
" auto graph_builder = std::make_unique<EsGraphBuilder>(\"MakeReluAddGraph\");\n",
" auto input = graph_builder->CreateInput(0, \"input\", ge::DT_FLOAT, ge::FORMAT_ND, {2, 3});\n",
"\n",
" auto relu1 = Relu(input);\n",
" auto relu2 = Relu(relu1);\n",
" auto result = Add(input, relu2);\n",
"\n",
" (void)graph_builder->SetOutput(result, 0);\n",
" return graph_builder->BuildAndReset();\n",
"}\n",
"```\n",
"\n",
"完整工程的构建脚本、运行方式,维测说明可参考 GE 仓 examples 目录:\n",
"\n",
"- [examples/es](https://gitcode.com/cann/ge/tree/master/examples/es)\n",
"\n",
"\n",
"### 三种方式与后续章节的关系\n",
"\n",
"<div align=\"left\">\n",
"<table style=\"margin-left: 0; margin-right: auto;\">\n",
"<thead>\n",
"<tr><th>构图方式</th><th>风格</th><th>适用场景</th></tr>\n",
"</thead>\n",
"<tbody>\n",
"<tr><td>GE C++ 接口(op:: 原型)</td><td>显式、可控</td><td>全新构图、精细控制</td></tr>\n",
"<tr><td>Parser 接口</td><td>复用已有模型</td><td>已有 onnx / pb 模型迁移</td></tr>\n",
"<tr><td>ES 极简构图</td><td>函数式、简洁</td><td>快速实验、代码量敏感</td></tr>\n",
"</tbody>\n",
"</table>\n",
"</div>\n",
"\n",
"<div align=\"left\">\n",
"<blockquote style=\"margin-left: 0; margin-right: auto;\">\n",
"<p><strong>三种方式产出的都是同一种 AscendIR 图</strong>,差别只在\"怎么写\"。无论哪种方式构图,后续都会进入统一的 GE 编译与执行流程:</p>\n",
"<ul><li><strong><a href=\"../02_inference_workflow/02.02_offline_inference.ipynb\">2.2 离线推理流程:ATC 编译与 ACL 推理</a></strong>:走<strong>离线</strong>路径(ATC 编译为 OM + ACL 加载执行)。</li><li><strong><a href=\"../02_inference_workflow/02.03_online_execution.ipynb\">2.3 在线执行流程:GeSession 构图与执行</a></strong>:走<strong>在线</strong>路径(GeSession 在线构图、编译并执行)。</li></ul>\n",
"</blockquote>\n",
"</div>"
]
},
{
"cell_type": "markdown",
"id": "b1d841a7",
"metadata": {},
"source": [
"## 课后练习\n",
"\n",
"本节介绍了 AscendIR 的核心概念和构图基础,请根据学习内容完成以下题目进行自测。\n",
"\n",
"1. (判断题)AscendIR 是 GE 编译流程使用的核心 IR,用图结构表达模型的计算逻辑与数据依赖关系。\n",
"\n",
"2. (判断题)在 GE 的实际实现中,图中存在独立的 Edge 对象来描述节点间的连接关系。\n",
"\n",
"3. (单选题)AscendIR 的核心对象模型是一条自顶向下、层层持有的链路,下列哪一项正确?\n",
" A. ComputeGraph → Node → Edge → Tensor\n",
" B. ComputeGraph → Node → OpDesc → GeTensorDesc\n",
" C. ComputeGraph → OpDesc → Node → Anchor\n",
" D. Graph → Tensor → Node → OpDesc\n",
"\n",
"4. (单选题)关于 AscendIR 中 Tensor 描述的存放位置,下列说法正确的是?\n",
" A. Tensor 是独立漂浮在数据边上的对象,不被任何节点持有\n",
" B. 每个 Node 持有一个算子描述符 OpDesc,算子的输入/输出 Tensor 描述就保存在 OpDesc 中(input_desc / output_desc),即 Tensor 描述由节点持有\n",
" C. Graph 直接持有所有 Tensor,Node 只负责把它们连接起来\n",
" D. Tensor 描述独立于 Node,单独存放在图的全局张量表中\n",
"\n",
"5. (单选题)以下关于控制边的描述,哪个是正确的?\n",
" A. 控制边用于传递 Tensor 数据\n",
" B. 控制边表示纯依赖关系,无数据传递,仅约束执行顺序\n",
" C. 控制边和数据边的功能完全相同\n",
" D. 控制边只能用于输入节点和输出节点之间\n",
"\n",
"6. (多选题)以下关于静态 Shape、动态分档和纯动态 Shape 的描述,哪些是正确的?\n",
" A. 静态 Shape 图的所有 Tensor shape 在编译期完全确定\n",
" B. 动态分档会设置多个 shape 档位,每个档位按相对确定的静态 shape 方式编译 / 执行\n",
" C. 静态 Shape 图的运行时开销通常低于动态 Shape 图\n",
" D. GE 不支持动态 Shape 图的编译和执行\n",
"\n",
"7. (单选题)某图中有两个算子 Conv1 和 Conv2,它们的 type 都是 Convolution。以下说法正确的是?\n",
" A. name 相同、type 不同\n",
" B. name 不同、type 相同,二者实现逻辑相同\n",
" C. 这是非法的,同一图中不允许出现两个卷积算子\n",
" D. 二者的 name 必须相同才能共享 type\n",
"\n",
"8. (多选题)以下关于 Anchor 与构图方式的描述,哪些是正确的?\n",
" A. GE 实现中没有独立的 Edge 对象,用 DataAnchor 表数据边、CtrlAnchor 表控制边\n",
" B. Parser 接口(如 aclgrphParseONNX)可将已有 onnx 模型解析为 AscendIR Graph\n",
" C. GE C++ 接口、Parser、ES 极简构图三种方式产出的都是同一种 AscendIR 图\n",
" D. CtrlAnchor 用于传递 Tensor 数据\n",
"\n",
"**执行以下代码获取答案。**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"!cat answer/01.03_answer.txt"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"name": "python",
"version": "3.8.0"
}
},
"nbformat": 4,
"nbformat_minor": 5
}