news 2026/6/10 10:26:51

CANN/GE语言无关自定义算子接入

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CANN/GE语言无关自定义算子接入

[RFC] 语言无关自定义算子接入 GE

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

Summary(摘要)

本文提出一种语言无关的自定义算子接入 GE 的机制。通过定义统一的算子接入接口,将自定义算子的集成过程与具体的算子编成语言(Ascend C、Triton、PPTO 等)解耦,并提供渐进式的开发体验——从只支持运行时执行,到参与编译时优化,逐步获得更高的性能收益。

Motivation(动机)

当前 GE 对自定义算子接入的支持有 2 个关键痛点:

  1. 只支持 Ascend C 语言开发的自定义算子接入。随着算子多样化编成语言的发展(如 Triton 在易用性上有较高吸引力),用户希望其他语言开发的算子也能接入 GE。
  2. 入图交付件多且零散,易用性有待提升。开发者需要同时维护 proto 定义、执行逻辑、编译逻辑等多个文件,缺乏统一的交付件组织方式。

Proposed Design(设计方案)

架构视图

通过统一的开发界面,对接不同的编成语言。自定义算子以.so交付件形式加载到 GE,参与图编译和执行的全流程。

渐进式能力模型

自定义算子入图分为 3 个阶段,开发工作量与性能收益逐步递增:

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

伪代码开发示例

以下以 Add 算子为例,展示各阶段的开发者体验。

阶段 1:动态 shape host 调度

只需实现Execute,完成 kernel 的加载和 launch:

class AddCustom : public EagerExecuteOp { public: graphStatus Execute(gert::EagerOpExecutionContext *ctx) override { // 1. 获取输入 auto *x = ctx->GetInputTensor(0); auto *y = ctx->GetInputTensor(1); // 2. 分配输出 auto *z = ctx->MallocOutputTensor(0, x->GetShape(), x->GetFormat(), x->GetDataType()); // 3. 加载 kernel binary(预编译的 npubin / Ascend C binary) auto bin_data = LoadBinary("add_kernel.npubin"); auto func_handle = GetKernelFunction(bin_data, "add_kernel"); // 4. 构造 args 并 launch int64_t n = x->GetShapeSize(); int32_t block_num = CeilDiv(n, BLOCK_SIZE); struct Args { const void *in0, *in1; void *out; int32_t n, gx, gy, gz; } args = {x->GetAddr(), y->GetAddr(), z->GetAddr(), (int32_t)n, block_num, 1, 1}; aclrtLaunchKernelWithHostArgs(func_handle, block_num, ctx->GetStream(), nullptr, &args, sizeof(args), nullptr, 0); return GRAPH_SUCCESS; } }; REG_OP(AddCustom) .INPUT(x, TensorType({DT_FLOAT, DT_FLOAT16})) .INPUT(y, TensorType({DT_FLOAT, DT_FLOAT16})) .OUTPUT(z, TensorType({DT_FLOAT, DT_FLOAT16})) .OP_END_FACTORY_REG(AddCustom); REG_AUTO_MAPPING_OP(AddCustom);

效果:算子可在 GE 图中运行,支持动态 shape,但每个推理 step 有 host 侧调度开销。

阶段 2:静态 shape 下沉

在阶段 1 基础上补充ShapeInferOpCompilableOp

class AddCustom : public EagerExecuteOp, public ShapeInferOp, public CompilableOp { // Execute 同阶段 1,省略... graphStatus InferShape(gert::InferShapeContext *ctx) override { *ctx->GetOutputShape(0) = *ctx->GetInputShape(0); return GRAPH_SUCCESS; } graphStatus InferDataType(gert::InferDataTypeContext *ctx) override { return ctx->SetOutputDataType(0, ctx->GetInputDataType(0)); } graphStatus Compile(gert::OpCompileContext *ctx) override { auto *input = ctx->GetInputTensor(0); auto key = BuildKey(input->GetShape()); auto source = LoadFile("add_kernel.cpp"); aclrtcProg prog; aclrtcCreateProg(&prog, source.c_str(), "add_kernel", 0, nullptr, nullptr); aclrtcCompileProg(prog, 1, options); size_t bin_size; aclrtcGetBinDataSize(prog, &bin_size); device_elves_[key].resize(bin_size); aclrtcGetBinData(prog, device_elves_[key].data()); aclrtcDestroyProg(&prog); return GRAPH_SUCCESS; } private: std::map<std::string, std::vector<uint8_t>> device_elves_; };

效果

  • 阶段 2.1(无新增交付件):静态 shape 下 kernel 下沉调度,消除 host 开销
  • 阶段 2.2:参与 shape 推导和内存复用,Compile 阶段完成算子在线编译
阶段 3:离线 OM 支持

在阶段 2 基础上补充PortableOp

class AddCustom : public EagerExecuteOp, public ShapeInferOp, public CompilableOp, public PortableOp { // Execute / InferShape / Compile 同阶段 2,省略... graphStatus Serialize(std::vector<uint8_t> &buffer) override { // 将 device_elves_ 序列化到 buffer(格式自定义,GE 只透传) return SerializeBinaryMap(device_elves_, buffer); } graphStatus Deserialize(const std::vector<uint8_t> &buffer) override { // 从 buffer 恢复 device_elves_ return DeserializeBinaryMap(buffer, device_elves_); } };

效果:编译产物随 OM 文件保存和恢复,支持AIR → ATC → OM → ACL离线部署链路。

语言公共层封装效果

上述基础设施层代码约 60-80 行。各编成语言可构建公共层进一步封装,以 Triton 为例:

// 使用 Triton 公共层后,同一个 Add 算子只需 ~10 行 TRITON_CUSTOM_OP(AddCustom) .Kernel("add_kernel") // 声明 kernel 名称 .Binary("add_kernel.npubin") // 声明 binary 路径 .Inputs({"x", "y"}) // 声明输入 .Outputs({"z"}) // 声明输出 .InferShapeSameAsInput(0) // 输出 shape = 第 0 个输入 shape .InferDataTypeSameAsInput(0) // 输出 dtype = 第 0 个输入 dtype .TilingStrategy(TilingStrategy::ElementWise) // 自动计算 block_num .Build();

封装前后对比:

重复逻辑基础设施层(手动)语言公共层(自动)
binary 加载手动aclrtBinaryLoadFromData声明.Binary()路径
args 构造手动拼装 packed struct根据 kernel 签名自动生成
block_num 计算手动CeilDiv(n, BLOCK_SIZE).TilingStrategy(ElementWise)
REG_OP 定义手动编写 proto.Inputs()/.Outputs()自动生成
InferShape手动实现.InferShapeSameAsInput(0)

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

层次职责维护方
GE 基础设施层统一接入接口、注册机制、编译/执行回调、序列化协议GE 团队
语言公共层封装特定语言的 boilerplate(binary 加载、args 构造等)各语言 SDK 团队
算子开发者只需实现 kernel 逻辑 + 少量声明算子开发者

前端接入

前端额外交付件接入方式
GE 原生REG_OP + OperatorFactory
PyTorch + TorchAirTORCH_LIBRARY + converterFX 节点映射到 GE op type
TensorFlowlibcustom_ops.so + npu_supported_ops.jsonTF Adapter 构图转换,REG_AUTO_MAPPING_OP 自动生成 GE proto
ONNXREGISTER_CUSTOM_OP 解析插件NodeProto 属性映射到 GE Operator

Open Questions(待讨论问题)

  1. 语言公共层的标准化程度:各语言的公共层是否应该由 GE 统一提供模板/SDK,还是由各语言团队独立维护?
  2. 多版本兼容:当 GE 基础设施层接口演进时,如何保证旧版本 .so 交付件在新版 GE 上仍可加载?是否需要引入算子版本字段?
  3. 编译期并行安全CustomGraphOptimizer并行回调Compile,当前要求算子实现自行保证线程安全。是否应由框架层提供锁机制?
  4. 序列化格式标准化:当前PortableOp的 buffer 格式完全由用户自定义。是否需要 GE 提供标准的序列化辅助工具?
  5. ONNX 自定义 domain 支持:当前 ONNX 解析插件需要为每个 domain::version::OpType 显式注册。是否支持通配符或自动发现机制?

Timeline(时间线)

阶段状态说明
阶段 1(动态 shape host 调度)✅ 已完成参见examples/custom_op/triton_add_custom
阶段 2.1(静态 shape 下沉 only)✅ 已完成同上 sample 验证下沉效果
阶段 2.2(下沉全量收益)✅ 已完成shape 推导、内存复用、在线编译已支持
阶段 3(离线 OM 支持)✅ 已完成参见examples/custom_op/compilable_add_custom
语言公共层🔲 规划中各语言 SDK 团队按需构建

References

  • 开发指南:custom_op_development_guide.md
  • 架构设计:custom_op_architecture.md
  • 样例代码:examples/custom_op/

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

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 10:26:17

NextUI Dashboard Template:构建现代化仪表板的终极指南

NextUI Dashboard Template&#xff1a;构建现代化仪表板的终极指南 【免费下载链接】nextui-dashboard-template Dashboard starter using NextUI V2 and Nextjs. 项目地址: https://gitcode.com/gh_mirrors/ne/nextui-dashboard-template NextUI Dashboard Template 是…

作者头像 李华
网站建设 2026/6/10 10:26:11

网易云音乐无损解析终极指南:一站式获取高品质音频的完整方案

网易云音乐无损解析终极指南&#xff1a;一站式获取高品质音频的完整方案 【免费下载链接】Netease_url 网易云无损解析 项目地址: https://gitcode.com/gh_mirrors/ne/Netease_url 对于追求极致音质的音乐爱好者来说&#xff0c;高品质音频资源往往难以获取。网易云音乐…

作者头像 李华
网站建设 2026/6/10 10:26:07

从零到戴森球:如何用3000+工厂蓝图告别布局焦虑

从零到戴森球&#xff1a;如何用3000工厂蓝图告别布局焦虑 【免费下载链接】FactoryBluePrints 游戏戴森球计划的**工厂**蓝图仓库 项目地址: https://gitcode.com/GitHub_Trending/fa/FactoryBluePrints 你是否也曾面对戴森球计划中错综复杂的生产线感到无从下手&#…

作者头像 李华
网站建设 2026/6/10 10:25:14

KKGridView单元格复用机制深度剖析:内存管理最佳实践

KKGridView单元格复用机制深度剖析&#xff1a;内存管理最佳实践 【免费下载链接】KKGridView Deprecated: Grid view library for iOS. 项目地址: https://gitcode.com/gh_mirrors/kk/KKGridView KKGridView作为iOS平台经典的网格视图库&#xff0c;其高效的单元格复用…

作者头像 李华
网站建设 2026/6/10 10:18:43

BabelDOC:终极PDF文档翻译解决方案,智能保留原格式布局

BabelDOC&#xff1a;终极PDF文档翻译解决方案&#xff0c;智能保留原格式布局 【免费下载链接】BabelDOC Yet Another Document Translator 项目地址: https://gitcode.com/GitHub_Trending/ba/BabelDOC 你是否曾为翻译PDF文档而头疼&#xff1f;传统的翻译工具总是破坏…

作者头像 李华
网站建设 2026/6/10 10:17:25

fusepy跨平台开发指南:在Linux、macOS和Windows上部署Python文件系统

fusepy跨平台开发指南&#xff1a;在Linux、macOS和Windows上部署Python文件系统 【免费下载链接】fusepy Simple ctypes bindings for FUSE 项目地址: https://gitcode.com/gh_mirrors/fu/fusepy fusepy是一个强大的Python文件系统开发工具&#xff0c;让开发者能够轻松…

作者头像 李华