一文教你如何调用Ascend C算子
本文分享自华为云社区《一文教你如何调用Ascend C算子》,作者: 昇腾CANN。
Ascend C是CANN针对算子开发场景推出的编程语言,原生支持C和C++标准规范,兼具开发效率和运行性能。基于Ascend C编写的算子程序,通过编译器编译和运行时调度,运行在昇腾AI处理器上。使用Ascend C,开发者可以基于昇腾AI硬件高效实现自定义的创新算法。
本文重点介绍基于Ascend C算子编程语言完成自定义算子的开发和部署后,如何调用自定义算子验证算子功能。
三种常见的算子调用方式
目前,Ascend C算子有三种常见的调用方式:
- Kernel直调:完成算子核函数开发和Tiling实现后,可基于内核调用符方式进行完成算子的调用,用来快速验证算法逻辑。
- 单算子调用:相比于Kernel直调,单算子调用是一种较为标准的调用方式。开发者在完成所有算子交付件开发、编译部署之后,一般通过单算子调用方式验证单算子功能以满足交付条件,包括两种调用方式:
- 单算子API执行:基于C语言的API执行算子,直接调用单算子API接口,无需提供单算子描述文件进行离线模型的转换。
- 单算子模型执行:基于图IR执行算子,先编译算子(例如,使用ATC工具将Ascend IR定义的单算子描述文件编译成算子om模型文件),再调用AscendCL接口加载算子模型,最后调用AscendCL接口执行算子。
- 在PyTorch、ONNX、TensorFlow等三方框架中调用算子:需要完成框架适配开发,即可从第三方框架实现算子调用。
当然,除了可以调用自定义算子进行功能验证外,开发者也可以通过单算子调用方式直接调用昇腾算子库中预制的算子,使用昇腾算力。
通过单算子API执行方式调用算子
通过单算子API执行方式调用算子,是算子交付阶段最重要的一种调用方式,也是Ascend C算子开发人员必须掌握的算子调用手段,下面做重点讲解。开发者若想了解其他方式,可以移至文末查阅“Ascend C一站式学习资源”[1]。
Ascend C算子开发并编译部署完成后,会在算子包安装目录下的op_api目录下会自动生成单算子API,以默认安装场景为例,单算子调用的头文件.h和动态库libcust_opapi.so所在的目录结构为:
├── opp //算子库目录
│ ├── vendors //自定义算子所在目录
│ ├── config.ini
│ └── vendor_name1 // 存储对应厂商部署的自定义算子,此名字为编译自定义算子安装包时配置的vendor_name,若未配置,默认值为customize
│ ├── op_api
│ │ ├── include
│ │ │ └── aclnn_xx.h
│ │ └── lib
│ │ └── libcust_opapi.so
...
aclnn_xx.h中的算子API形式一般定义为“两段式接口”,形如:
aclnnStatus aclnnXxxGetWorkspaceSize(const aclTensor *src, ..., aclTensor *out, uint64_t workspaceSize, aclOpExecutor **executor);
aclnnStatus aclnnXxx(void* workspace, int64 workspaceSize, aclOpExecutor* executor, aclrtStream stream);
单算子API可以直接在应用程序中调用,大致过程为:
- 使用第一段接口aclnnXxxGetWorkspaceSize计算本次API调用计算过程中需要多少的workspace内存
- 获取到本次API计算需要的workspace大小后,按照workspaceSize大小申请Device侧内存
- 调用第二段接口aclnnXxx,调用对应的单算子二进制执行计算
完整调用流程如下:

下面提供单算子调用的关键代码示例,供开发者参考:
// 1.AscendCL初始化
aclRet = aclInit("../scripts/acl.json"); // 2.运行管理资源申请
int deviceId = 0;
aclRet = aclrtSetDevice(deviceid);
// 获取软件栈的运行模式,不同运行模式影响后续的接口调用流程(例如是否进行数据传输等)
aclrtRunMode runMode;
bool g_isDevice = false;
aclError aclRet = aclrtGetRunMode(&runMode);
g_isDevice = (runMode == ACL_DEVICE); // 3.申请内存存放算子的输入输出
// ...... // 4.传输数据
if (aclrtMemcpy(devInputs_[i], size, hostInputs_[i], size, kind) != ACL_SUCCESS) {
return false;
} // 5.计算workspace大小并申请内存
size_t workspaceSize = 0;
aclOpExecutor *handle = nullptr;
auto ret = aclnnAddCustomGetWorkspaceSize(inputTensor_[0], inputTensor_[1], outputTensor_[0],
&workspaceSize, &handle);
// ...
void *workspace = nullptr;
if (workspaceSize != 0) {
if (aclrtMalloc(&workspace, workspaceSize, ACL_MEM_MALLOC_NORMAL_ONLY) != ACL_SUCCESS) {
ERROR_LOG("Malloc device memory failed");
}
} // 6.执行算子
if (aclnnAddCustom(workspace, workspaceSize, handle, stream) != ACL_SUCCESS) {
(void)aclrtDestroyStream(stream);
ERROR_LOG("Execute Operator failed. error code is %d", static_cast<int32_t>(ret));
return false;
} // 7.同步等待
aclrtSynchronizeStream(stream); // 8.处理执行算子后的输出数据,例如在屏幕上显示、写入文件等,由用户根据实际情况自行实现
// ...... // 9.释放运行管理资源
aclRet = aclrtResetDevice(deviceid);
// .... // 10.AscendCL去初始化
aclRet = aclFinalize();
运行一个完整的算子调用程序
昇腾的gitee仓中提供了完整的样例工程LINK,工程目录结构如下:
├──input // 存放脚本生成的输入数据目录
├──output // 存放算子运行输出数据和真值数据的目录
├── inc // 头文件目录
│ ├── common.h // 声明公共方法类,用于读取二进制文件
│ ├── operator_desc.h // 算子描述声明文件,包含算子输入/输出,算子类型以及输入描述与输出描述
│ ├── op_runner.h // 算子运行相关信息声明文件,包含算子输入/输出个数,输入/输出大小等
├── src
│ ├── CMakeLists.txt // 编译规则文件
│ ├── common.cpp // 公共函数,读取二进制文件函数的实现文件
│ ├── main.cpp // 单算子调用应用的入口
│ ├── operator_desc.cpp // 构造算子的输入与输出描述
│ ├── op_runner.cpp // 单算子调用主体流程实现文件
├── scripts
│ ├── verify_result.py // 真值对比文件
│ ├── gen_data.py // 输入数据和真值数据生成脚本文件
│ ├── acl.json // acl配置文件
步骤1 增加头文件引用。
安装部署完成后,会在算子包安装目录下的op_api目录生成单算子调用的头文件aclnn_xx.h和动态库libcust_opapi.so,编写单算子的调用代码时,要包含自动生成的单算子API执行接口头文件:
#include "aclnn_add_custom.h"
步骤2 修改CMakeLists文件。
编译算子调用程序时,需要在头文件的搜索路径include_directories中增加算子包安装目录下的op_api/include目录,便于找到该头文件;同时需要链接cust_opapi动态库。
- 设置CUST_PKG_PATH变量为算子包安装目录下的op_api目录,以下样例仅为参考,请根据算子包部署的实际目录位置进行设置。
if (NOT DEFINED ENV{DDK_PATH})
set(INC_PATH "/usr/local/Ascend/ascend-toolkit/latest")
message(STATUS "set default INC_PATH: ${INC_PATH}")
else ()
message(STATUS "env INC_PATH: ${INC_PATH}")
endif()
set(CUST_PKG_PATH "${INC_PATH}/opp/vendors/customize/op_api")
- 在头文件的搜索路径include_directories中增加算子包安装目录下的op_api/include目录。
include_directories(
${INC_PATH}/runtime/include
${INC_PATH}/atc/include
../inc
${CUST_PKG_PATH}/include
)
- 链接cust_opapi链接库。
target_link_libraries(execute_add_op
ascendcl
cust_opapi
acl_op_compiler
nnopbase
stdc++
)
步骤3 生成测试数据。
在样例工程目录下,执行如下命令:
python3 scripts/gen_data.py
会在工程目录下input目录中生成两个shape为(8,2048),数据类型为float16的数据文件input_0.bin与input_1.bin,用于进行AddCustom算子的验证。代码样例如下:
import numpy as np
a = np.random.randint(100, size=(8, 2048,)).astype(np.float16)
b = np.random.randint(100, size=(8, 2048,)).astype(np.float16)
a.tofile('input_0.bin')
b.tofile('input_1.bin')
步骤4 程序编译与运行。
1. 开发环境上,设置环境变量,配置AscendCL单算子验证程序编译依赖的头文件与库文件路径,如下为设置环境变量的示例。${INSTALL_DIR}表示CANN软件安装目录,例如,$HOME/Ascend/ascend-toolkit/latest。{arch-os}为运行环境的架构和操作系统,arch表示操作系统架构,os表示操作系统,例如x86_64-linux。
export DDK_PATH=${INSTALL_DIR}
export NPU_HOST_LIB=${INSTALL_DIR}/{arch-os}/lib64
2. 编译样例工程,生成单算子验证可执行文件。
a. 切换到样例工程根目录,然后在样例工程根目录下执行如下命令创建目录用于存放编译文件,例如,创建的目录为“build”。
mkdir -p build
b. 进入build目录,执行cmake编译命令,生成编译文件,命令示例如下所示:
cd build
cmake ../src
c. 执行如下命令,生成可执行文件。
make
会在工程目录的output目录下生成可执行文件execute_add_op。
3. 执行单算子。
a. 以运行用户(例如HwHiAiUser)拷贝开发环境中样例工程output目录下的execute_add_op到运行环境任一目录。
说明: 若您的开发环境即为运行环境,此拷贝操作可跳过。
b. 在运行环境中,执行execute_add_op:
chmod +x execute_add_op
./execute_add_op
会有如下屏显信息:
[INFO] Set device[0] success
[INFO] Get RunMode[1] success
[INFO] Init resource success
[INFO] Set input success
[INFO] Copy input[0] success
[INFO] Copy input[1] success
[INFO] Create stream success
[INFO] Execute aclnnAddCustomGetWorkspaceSize success, workspace size 0
[INFO] Execute aclnnAddCustom success
[INFO] Synchronize stream success
[INFO] Copy output[0] success
[INFO] Write output success
[INFO] Run op success
[INFO] Reset Device success
[INFO] Destory resource success
如果有Run op success,表明执行成功,会在output目录下生成输出文件output_z.bin。
4. 比较真值文件。
切换到样例工程根目录,然后执行如下命令:
python3 scripts/verify_result.py output/output_z.bin output/golden.bin
会有如下屏显信息:
test pass
可见,AddCustom算子验证结果正确。
更多学习资源
[1]Ascend C一站式学习资源:https://www.hiascend.com/ascend-c
一文教你如何调用Ascend C算子的更多相关文章
- Ascend Pytorch算子功能验证
Ascend Pytorch算子功能验证 编写测试用例 以add算子为例,测试脚本文件命名为:add_testcase.py.以下示例仅为一个简单的用例实现,具体算子的实现,需要根据算子定义进行完整的 ...
- Ascend Pytorch算子适配层开发
Ascend Pytorch算子适配层开发 适配方法 找到和PyTorch算子功能对应的NPU TBE算子,根据算子功能计算出输出Tensor的size,再根据TBE算子原型构造对应的input/ou ...
- 手把手教你使用LabVIEW人工智能视觉工具包快速实现传统Opencv算子的调用(含源码)
前言 今天我们一起来使用LabVIEW AI视觉工具包快速实现图像的滤波与增强:图像灰度处理:阈值处理与设定:二值化处理:边缘提取与特征提取等基本操作.工具包的安装与下载方法可见之前的博客. 一.图像 ...
- 【OpenCV新手教程之十二】OpenCV边缘检測:Canny算子,Sobel算子,Laplace算子,Scharr滤波器合辑
本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/25560901 作者:毛星云(浅墨) ...
- [OpenCV入门教程之十二】OpenCV边缘检测:Canny算子,Sobel算子,Laplace算子,Scharr滤波器合辑
http://blog.csdn.net/poem_qianmo/article/details/25560901 本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog ...
- 学习 opencv---(11)OpenC 边缘检测:Canny算子,Sobel算子,Laplace算子,Scharr滤波器
本篇文章中,我们将一起学习OpenCV中边缘检测的各种算子和滤波器——Canny算子,Sobel算子,Laplace算子以及Scharr滤波器.文章中包含了五个浅墨为大家准备的详细注释的博文配套源代码 ...
- 边缘检测:Canny算子,Sobel算子,Laplace算子
1.canny算子 Canny边缘检测算子是John F.Canny于 1986 年开发出来的一个多级边缘检测算法.更为重要的是 Canny 创立了边缘检测计算理论(Computational the ...
- 大数据学习day24-------spark07-----1. sortBy是Transformation算子,为什么会触发Action 2. SparkSQL 3. DataFrame的创建 4. DSL风格API语法 5 两种风格(SQL、DSL)计算workcount案例
1. sortBy是Transformation算子,为什么会触发Action sortBy需要对数据进行全局排序,其需要用到RangePartitioner,而在创建RangePartitioner ...
- 大数据学习day23-----spark06--------1. Spark执行流程(知识补充:RDD的依赖关系)2. Repartition和coalesce算子的区别 3.触发多次actions时,速度不一样 4. RDD的深入理解(错误例子,RDD数据是如何获取的)5 购物的相关计算
1. Spark执行流程 知识补充:RDD的依赖关系 RDD的依赖关系分为两类:窄依赖(Narrow Dependency)和宽依赖(Shuffle Dependency) (1)窄依赖 窄依赖指的是 ...
- opencv6.3-imgproc图像处理模块之边缘检测
接opencv6.2-improc图像处理模块之图像尺寸上的操作 本文大部分都是来自于转http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutori ...
随机推荐
- spark 计算前后两条记录之间的差(diff),时间差等
有时候会遇到这样的场景:有一个datafram,我们需要计算同一组对象中,前后两条记录之间的差值,此处并不仅限于时间,还可以是其他的数据类型 需要用到两个工具:spark窗口函数Window对对象分组 ...
- SVM三则
硬间隔SVM SVM被提出来, 解决模式识别中, 数据的分类问题,属于有监督算法中的一种, 如上图所示, 于其他的线性回归方式不同, SVM企图去寻找一个最完美的超平面, 因为能正确分类样本的线, 它 ...
- nginx重新整理——————编译nginx[二]
前言 简单编译一下nginx. 正文 为什么我们要去编译nginx. 系统安装,比如yum安装,会把nginx 模块直接编译进来. 这意味着,我们无法使用第三方的包.如果我们需要使用第三方包,那么需要 ...
- mysql 重新整理——配置文件[一]
前言 对mysql 进行从新整理一下,仅做参考,如有任何不对望指出. 正文 mysql 一般分windows和linux,但是他们的运行配置其实是一样的,所以在此不做区分. 直接上一个大体的图: 我个 ...
- This version of Android Studio cannot open this project, please retry with Android Studio 4.0 or newer.
前言 遇到的问题,This version of Android Studio cannot open this project, please retry with Android Studio 4 ...
- MMdeploy TensorRT 模型实时监控桌面,PyQt5实现
本项目遵从:GNU General Public License v3.0 个人博客『 gy77 』: GitHub仓库 :代码源码详见仓库 demo_qt.py 我的CSDN博客 我的博客园 简介: ...
- JVM简明笔记2:运行时数据区
1 内存布局总体结构 根据 JVM 规范,JVM 内存共分为虚拟机栈(Virtual Machine Stacks).堆(Heap).方法区(Method Area).程序计数器(Program Co ...
- 力扣67(java)-二进制求和(简单)
题目: 给你两个二进制字符串,返回它们的和(用二进制表示). 输入为 非空 字符串且只包含数字 1 和 0. 示例 1: 输入: a = "11", b = "1&quo ...
- 开源数据库PolarDB为什么能捕获娃哈哈的心?
简介: 在10月25日由阿里云开发者社区.PolarDB开源社区.infoQ联合举办的「开源人说」第三期--<数据库PolarDB专场>沙龙上,中启乘数科技(杭州)有限公司联合创始人唐成带 ...
- EasyNLP发布融合语言学和事实知识的中文预训练模型CKBERT
简介: 本⽂简要介绍CKBERT的技术解读,以及如何在EasyNLP框架.HuggingFace Models和阿里云机器学习平台PAI上使⽤CKBERT模型. 导读 预训练语言模型在NLP的各个应用 ...