当前位置: 首页 > news >正文

GE 自定义算子架构设计

GE 自定义算子架构设计

【免费下载链接】geGE(Graph Engine)是面向昇腾的图编译器和执行器,提供了计算图优化、多流并行、内存复用和模型下沉等技术手段,加速模型执行效率,减少模型内存占用。 GE 提供对 PyTorch、TensorFlow 前端的友好接入能力,并同时支持 onnx、pb 等主流模型格式的解析与编译。项目地址: https://gitcode.com/cann/ge

1. 简介

1.1 目的

本文档描述 GE 自定义算子接入机制的架构设计,面向 GE 内部开发者和架构师。文档覆盖自定义算子的接口体系、注册与加载机制、编译期和运行期的内部流程,以及与 GE 各子系统的交互方式。

面向外部算子开发者的使用指南参见custom_op_development_guide.md

1.2 范围

本文档覆盖:

  • 自定义算子的接口设计与注册机制
  • SO 交付件加载与生命周期管理
  • 自定义算子在 GE 编译器和执行器中的调度路径
  • 前端(PyTorch / TensorFlow / ONNX)接入架构
  • 设计约束与特性交叉分析

不覆盖:

  • 具体算子的 kernel 实现(Ascend C / Triton 等)
  • GE 内置算子的引擎调度细节

2. 总体概述

2.1 设计动机

GE 对自定义算子接入有两个核心诉求:

  1. 语言无关:算子开发不拘泥于特定编程语言(Ascend C、Triton、PPTO 等),通过统一的接入接口将算子集成过程与具体编成语言解耦。
  2. 渐进式开发体验:开发者可按需逐步补充能力(执行 → 下沉 → 编译优化 → 离线 OM),每完成一个阶段即可获得对应的性能收益,而非一次性完成全部接入工作。

2.2 设计目标

目标说明
语言无关接口层不假设 kernel 的实现语言,只关心 kernel binary 的加载和 launch
渐进式能力按需组合能力接口,从最小可运行到全量下沉逐步演进
交付件类组织一个 .so 包含一个或多个算子的全部接入逻辑,便于分发和维护
与内置算子共存自定义算子与内置算子在同一张图中混合执行,共享流分配和内存规划
基础设施定位接口层作为基础设施,各编成语言可构建公共层进一步降低开发难度

2.3 三阶段演进路线

阶段核心能力新增交付件性能收益状态
阶段 1Execute(host 调度 kernel)1 个 .so可运行,有 host 调度开销已完成
阶段 2.1Execute(下沉调度)无新增静态 shape 下消除 host 调度开销已完成
阶段 2.2+ InferShape + Compile无新增shape 推导、内存复用、算子在线编译已完成
阶段 3+ Serialize / Deserialize无新增离线 OM 部署已完成

2.4 基础设施定位与语言公共层

当前的接口体系(BaseCustomOp+ 5 个能力接口)定位为基础设施层,而非面向终端算子开发者的最终 API。各算子编成语言(Ascend C、Triton、PPTO 等)可在此基础设施之上构建语言公共层,封装重复的 boilerplate 逻辑,使单个算子的入图开发量降至最低。

分层职责:

层次职责维护方
GE 基础设施层提供统一的算子接入接口、注册机制、编译/执行回调、序列化协议GE 团队
语言公共层封装特定编成语言的重复逻辑(binary 加载、args 构造、kernel launch 等),提供简化的注册宏或 API各语言 SDK 团队
算子开发者只需实现 kernel 逻辑 + 少量声明(输入输出规格、tiling 参数等)算子开发者

语言公共层可封装的典型 boilerplate:

重复逻辑当前(基础设施层)封装后(语言公共层)
kernel binary 加载开发者手动调用aclrtBinaryLoadFromData+aclrtBinaryGetFunction公共层自动加载,开发者只需声明 kernel 名称
args 构造开发者手动拼装 packed struct,处理对齐和指针公共层根据 kernel 签名自动生成 args
block_num 计算开发者手动根据 shape 和 BLOCK_SIZE 计算 grid公共层提供 tiling 辅助函数或自动计算
REG_OP + REG_AUTO_MAPPING_OP开发者手动编写 proto 定义和注册宏公共层提供声明式 API,自动生成 proto 和注册代码
ShapeInferOp 实现开发者手动实现 InferShape / InferDataType公共层提供常见推导模式(same-as-input、broadcast 等)的模板

设计意义:通过将基础设施层与语言公共层分离,GE 保持了接口稳定性和语言无关性,同时各语言 SDK 可以独立演进、竞争优化,最终让算子开发者只需关注 kernel 本身。

2.5 与老版本自定义算子机制的对比

在新版本BaseCustomOp机制之前,GE 通过IMPL_OP宏 +OpImplRegisterV2链式注册来接入自定义算子。理解两者的差异有助于把握新版本的设计意图。

老版本机制概述

老版本采用无状态函数指针组合模式,算子开发者注册一组函数指针,框架全权调度:

// 老版本注册方式 IMPL_OP(MyOp) .InferShape(my_infer_shape_func) // shape 推导函数指针 .InferShapeRange(my_shape_range_func) // 动态 shape 范围推导 .InferDataType(my_infer_datatype_func) // dtype 推导函数指针 .InferFormat(my_infer_format_func) // 格式推导函数指针 .Tiling(my_tiling_func) // AICore tiling 函数 .TilingParse<MyCompileInfo>(my_parse_func) // tiling 解析函数 .InputsDataDependency({0}) // 声明哪些输入需要数据 .PrivateAttr("attr_name", int64_t(42)); // 私有属性

老版本面向AICore 标准引擎流水线设计:算子提供 tiling 函数和 shape 推导函数,框架的 FE 引擎和 DavinciModel 代劳编译、序列化、调度和地址刷新。

核心差异:"谁控制"

新老版本的关键差异不是"有没有"某项能力,而是谁控制这项能力:

能力老版本(IMPL_OP)新版本(BaseCustomOp)
执行框架内嵌(引擎调度 tiling + kernel launch)用户自定义(EagerExecuteOp::Execute()
在线编译框架内嵌(FE 引擎调度 TBE/AscendC 编译器)用户自定义(CompilableOp::Compile()
序列化框架内嵌(FE 引擎自动序列化 tiling data / compile info)用户自定义(PortableOp::Serialize/Deserialize
地址刷新框架内嵌(DavinciModel SinkTask 自动处理)用户自定义(ArgsUpdater::UpdateHostArgs()

其他接口层面的差异:

维度老版本(IMPL_OP)新版本(BaseCustomOp)
注册风格链式函数指针虚函数继承 + 工厂注册
状态管理无状态函数指针有状态对象(成员变量)
Shape 推导InferShapeKernelFunc函数指针ShapeInferOp::InferShape()虚方法
Shape 范围推导InferShapeRangeKernelFunc独立注册复用InferShape(-1 表示 unknown 维)
DataType 推导InferDataTypeKernelFunc函数指针ShapeInferOp::InferDataType()虚方法
格式推导InferFormatKernelFunc独立注册暂时不支持,设计中
数据依赖声明显式.InputsDataDependency({indices})隐式(通过 context 访问)
私有属性.PrivateAttr(name, value)不支持
Tiling专用.Tiling()/.TilingParse<>()接口弱化tiling的概念,由子类自主处理
设计面向AICore 内置算子(标准引擎流水线)外部自定义算子(任意 kernel binary)
kernel 语言Ascend C / TBE(框架编译)任意(用户自行编译或 RTC)
设计演进动机

  1. 老版本面向标准引擎流水线设计:算子必须走 TBE/AscendC → tiling → kernel launch 的标准路径,框架全权代劳编译、序列化和调度。这对内置算子很高效,但无法接纳非标准 kernel(如 Triton npubin、第三方预编译 binary)。

  2. 新版本将控制权交给算子开发者:通过虚函数接口暴露执行、编译、序列化和地址刷新的控制权,使任意 kernel binary 都能接入 GE。代价是开发者需要自行实现这些环节(但可通过语言公共层封装)。

  3. 两者互补而非替代:老版本适合标准 AICore 算子(框架全托管,开发量小),新版本适合非标准 kernel(用户全控制,灵活性高)。两套机制在 GE 中共存,各自服务于不同的算子接入场景。


3. 系统架构

3.1 架构视图

3.2 与内置算子的关系

自定义算子通过独立的自定义引擎DNN_VM_CUSTOM与内置算子区分:

维度内置算子自定义算子
引擎DNNEngine(AiCore / VectorCore / AICPU)DNN_VM_CUSTOM
算子注册算子仓 REG_OP + 引擎 OpsKernelInfoStoreREG_OP + REG_AUTO_MAPPING_OP + CustomOpsKernelInfoStore
Kernel 构建TBE / AICPU KernelBuilderCustomOpsKernelBuilder(生成 MODEL_TASK_CUSTOM_KERNEL)
编译优化GE 图优化 pass + 引擎内部优化CustomGraphOptimizer(回调 Compile)
执行调度引擎 TaskInfo(TBE / AICPU)CustomTaskInfo(回调 Execute)
流分配独立引擎流与 AiCore 合并分配流

关键设计决策:自定义算子在流分配阶段与 AiCore 引擎节点合并处理(engine_partitioner.cc),确保自定义算子能正确参与多流并行调度,而不是被隔离到独立流上。


4. 核心组件设计

4.1 接口体系

设计原则:

  • 能力组合:开发者按需继承,不强制实现所有接口。GE 通过dynamic_cast在运行时检测算子具备哪些能力。
  • 正交设计:每个接口对应独立的回调时机,接口之间无耦合。
  • Context 隔离:每个回调接收专用的 Context 对象,只暴露算子需要的信息。

能力检测机制:

auto *base = CustomOpFactory::CreateOrGetCustomOp(op_type); auto *compilable = dynamic_cast<CompilableOp*>(base); if (compilable != nullptr) { compilable->Compile(ctx); }

4.2 注册与工厂机制

实例化策略CustomOpFactoryImpl对每个 op type 采用懒加载单例模式。同一 op type 的所有图节点共享同一个BaseCustomOp实例。

设计约束

  • 实现类的成员变量是跨节点共享的(如device_elves_map)
  • Compile回调可能被并行调用(CustomGraphOptimizer使用线程池),实现需保证线程安全
  • 注册是一次性的,重复注册同一 op type 会返回GRAPH_FAILED

4.3 SO 加载机制

加载限制(PluginManager 强制):

限制项上限
.so 文件数量64 个
单个 .so 大小800 MB
总加载大小1000 MB

4.4 自定义引擎(DNN_VM_CUSTOM)

自定义算子通过独立的引擎组件接入 GE 编译流程:

组件职责关键文件
CustomOpsKernelInfoStore初始化时查询已注册 op type,生成 OpInfocompiler/engines/custom_engine/custom_ops_kernel_info_store.cc
CustomGraphOptimizer并行遍历自定义算子节点,回调 Compilecompiler/engines/custom_engine/custom_graph_optimizer.cc
CustomOpsKernelBuilder生成 MODEL_TASK_CUSTOM_KERNEL TaskDefcompiler/engines/custom_engine/custom_ops_kernel_builder.cc

5. 关键流程

5.1 SO 加载与注册流程

5.2 编译期流程

5.3 执行期流程

V1 静态执行器(Known Shape):

V2 动态执行器(Unknown Shape / RT2.0):

5.4 序列化/反序列化流程

序列化互斥约束:一张图中不能同时包含实现了PortableOp和未实现PortableOp的自定义算子。


6. 前端接入架构

6.1 GE 原生构图

最简单的路径。构图侧直接引用 REG_OP proto 头文件,通过OperatorFactory::CreateOperator创建节点。

6.2 PyTorch + TorchAir

6.3 TensorFlow

与 GE 原生构图不同,TensorFlow 场景下REG_AUTO_MAPPING_OP可从 TF 算子原型自动生成 GE 算子原型,开发者无需额外编写REG_OP

6.4 ONNX

ONNX 解析插件通过REGISTER_CUSTOM_OP注册,dlopen 时自动收集到OpRegistry。插件需实现ParseParamsFn,将 ONNXNodeProto的属性映射为 GEOperator的属性。


7. 设计约束与不变量

约束说明影响
单例实例 per op typeCreateOrGetCustomOp为每个 op type 创建唯一实例成员变量跨节点共享;Compile并行调用需线程安全
dynamic_cast 能力检测GE 通过dynamic_cast判断算子支持哪些接口未实现的接口自动跳过,不影响其他流程
注册一次性RegisterCustomOpCreator拒绝重复注册同一进程中不可注册同名 op type
序列化互斥图中不可混合可序列化和不可序列化的自定义算子OM 下沉场景所有自定义算子必须实现PortableOp
SO 加载限制最多 64 个 .so,单个 ≤ 800MB,总计 ≤ 1000MB大量自定义算子需合并到少量 .so 中
共享 AiCore 流自定义算子在流分配时与 AiCore 合并自定义算子可参与 AiCore 的多流并行
地址刷新实现ArgsUpdater的算子走预留内存分配路径零拷贝场景需实现ArgsUpdater

8. 特性交叉分析

场景适用性分析说明
静态 Shape适用阶段 2.1 下沉调度消除 host 开销。CustomTaskInfo::Distribute()在 DavinciModel SinkTask 流程中调用 Execute。输出 tensor size 参与逻辑内存复用。
动态 Shape适用阶段 1 核心场景。V2 执行器通过LoweringCustomNode生成FindCustomOp+ExecuteCustomOpkernel,运行时 host 调度执行。
动态 Shape 静态子图适用静态子图走 V1DavinciModelKernel路径,自定义算子通过CustomTaskInfo::Distribute()执行,与纯静态 shape 场景一致。
离线场景(atc 编译)适用阶段 3 覆盖。ATC 编译时回调 Compile + Serialize,OM 加载时回调 Deserialize + Execute。
在线场景(框架适配)适用PyTorch/TorchAir 和 TensorFlow 通过各自 Adapter 映射为 GE 自定义算子节点,走统一编译执行流程。

9. 非功能需求

9.1 性能

阶段编译期影响执行期影响
阶段 1(host 调度)CustomOpsKernelInfoStore::Initialize遍历已注册 op type,O(n)每个自定义算子节点有 host 侧 Execute 调用开销
阶段 2.1(下沉)无额外编译开销消除 host 调度开销,kernel 直接在下沉流中执行
阶段 2.2(全量)CustomGraphOptimizer并行回调 Compile,增加编译时间shape 推导和内存复用带来执行期收益
阶段 3(离线 OM)Serialize 增加 OM 保存时间Deserialize 增加 OM 加载时间,执行期无额外开销

9.2 兼容性

  • OM 前向兼容:新版本 GE 可加载旧版本 OM 中的自定义算子序列化数据
  • 接口兼容BaseCustomOp及其子接口均为纯虚函数,新增接口不影响已有实现

9.3 可维护性

  • 自定义算子代码完全在 GE 仓外维护,通过 .so 动态加载
  • 接口变更需同步更新custom_op.h头文件,属于 GE 公共 API
  • Context 类的扩展需保持 POD 布局兼容

【免费下载链接】geGE(Graph Engine)是面向昇腾的图编译器和执行器,提供了计算图优化、多流并行、内存复用和模型下沉等技术手段,加速模型执行效率,减少模型内存占用。 GE 提供对 PyTorch、TensorFlow 前端的友好接入能力,并同时支持 onnx、pb 等主流模型格式的解析与编译。项目地址: https://gitcode.com/cann/ge

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

http://www.jsqmd.com/news/1046642/

相关文章:

  • gh_mirrors/conf1/conf用户案例:打造高效Focused工作环境
  • 终极Raylib跨平台游戏开发指南:从零到专业级游戏引擎
  • CANN/GE获取Graph输出属性API
  • CANN/ops-math取余算子标量接口
  • IEC 60730标准下的MCU功能安全测试:从Class B到Class C的工程实践
  • CANN/ge图引擎字符串属性设置API
  • 深入解析MCF5282/MCF5216微控制器:架构、外设与低功耗设计实战
  • 告别抢票焦虑:大麦网自动化工具终极指南
  • (2026新)石家庄正规防水补漏公司口碑榜TOP5权威推荐!卫生间/厨房/阳台/屋顶/天花板/地下室渗漏水检测维修攻略-靠谱漏水检测维修师傅推荐 - 安佳防水
  • (2026新)福州正规防水补漏公司口碑榜TOP5权威推荐!卫生间/厨房/阳台/屋顶/天花板/地下室渗漏水检测维修攻略-靠谱漏水检测维修师傅推荐 - 安佳防水
  • 深度解析Maya权重平滑:如何用brSmoothWeights解决角色动画的5大技术难题
  • 如何5分钟快速上手GuoFeng3:古风AI绘画的终极完整指南
  • mal_unpack高级参数完全指南:/shellc、/hooks、/trigger等选项实战应用 [特殊字符]
  • 无线计算技术AirCPU框架:原理、优势与应用
  • Hermes Agent实战手册:轻量级AI智能体本地部署与调试指南
  • 2026赣州漏水检测维修精选优质服务商TOP5推荐!卫生间漏水/厨房漏水/屋顶天花板漏水/阳台漏水/地下室漏水防水补漏检测维修-正规防水补漏公司优选口碑榜测评推荐 - 即刻修防水
  • MC68HC(7)08KH12:经典USB HUB微控制器架构与嵌入式开发实战
  • Awesome-AI 开源仓库架构设计与技术学习路线工程化沉淀方案
  • Cursor AI版本管理完整指南:专业下载链接验证与安全降级策略
  • 2026赣州本地人必选防水补漏检测维修公司靠谱服务商TOP5推荐:房屋渗漏水检测维修/卫生间/厨房/天花板/阳台/外墙渗漏水检测补漏维修-暗管漏水检测专业仪器精准定位漏水点 - 即刻修防水
  • (2026新)珠海正规防水补漏公司口碑榜TOP5权威推荐!卫生间/厨房/阳台/屋顶/天花板/地下室渗漏水检测维修攻略-靠谱漏水检测维修师傅推荐 - 安佳防水
  • 深入解析CAN总线标识符过滤:原理、配置与MSCAN实战指南
  • 终极指南:跨平台获取macOS系统镜像的完整解决方案
  • 深入解析MC68HC908AS32A SPI模块:从寄存器配置到中断与错误处理实战
  • 2026贵阳漏水检测维修精选优质服务商TOP5推荐!卫生间漏水/厨房漏水/屋顶天花板漏水/阳台漏水/地下室漏水防水补漏检测维修-正规防水补漏公司优选口碑榜测评推荐 - 即刻修防水
  • TheRouter实战指南:从基础配置到高级功能解析
  • Dify本地部署构建AI Agent可信评测沙盒实战指南
  • xtb:当传统量子化学计算让你束手无策时,这个半经验扩展紧束缚程序包如何成为你的科研加速器?
  • CANN/ops-math Mod取模算子
  • GPT-SoVITS v4深度解析:三阶段架构如何实现少样本语音合成的革命性突破