- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
摘要: 本文介绍了昇腾计算语言AscendCL的基本概念,并以示例代码的形式介绍了如何基于AscendCL开发AI推理应用,最后配以实际的操作演示说明如何编译运行应用。
本文分享自华为云社区《 基于昇腾计算语言AscendCL开发AI推理应用 》,作者:昇腾CANN.
AscendCL(Ascend Computing Language,昇腾计算语言)是昇腾计算开放编程框架,是对底层昇腾计算服务接口的封装,它提供运行时资源(例如设备、内存等)管理、模型加载与执行、算子加载与执行、图片数据编解码/裁剪/缩放处理等API库,实现在昇腾CANN平台上进行深度学习推理计算、图形图像预处理、单算子加速计算等能力。简单来说, 就是统一的API框架,实现对所有资源的调用.
首先,我们得先了解下,使用AscendCL时, 经常会提到的“数据类型的操作接口” ,这是什么呢?为啥会存在?
在C/C++中,对用户开放的数据类型通常以Struct结构体方式定义、以声明变量的方式使用,但这种方式一旦结构体要增加成员参数,用户的代码就涉及兼容性问题,不便于维护,因此AscendCL对用户开放的数据类型,均以接口的方式操作该数据类型,例如,调用某个数据类型的Create接口创建该数据类型、调用Get接口获取数据类型内参数值、调用Set接口设置数据类型内的参数值、调用Destroy接口销毁该数据类型,用户无需关注定义数据类型的结构体长什么样,这样即使后续数据类型需扩展,只需增加该数据类型的操作接口即可,也不会引起兼容性问题.
所以,总结下, “数据类型的操作接口”就是创建数据类型、Get/Set数据类型中的参数值、销毁数据类型的一系列接口,存在的最大好处就是减少兼容性问题.
接下来,进入我们今天的主题,怎么用AscendCL的接口开发网络模型推理场景下的应用。看完本文介绍的关键知识点,也可以到 “昇腾文档中心[1]”查阅详细的文档介绍.
使用AscendCL接口开发应用时,必须先初始化AscendCL ,否则可能会导致后续系统内部资源初始化出错,进而导致其它业务异常。在初始化时,还支持以下跟推理相关的配置项(例如,性能相关的采集信息配置),以json格式的配置文件传入AscendCL初始化接口。如果当前的默认配置已满足需求(例如,默认不开启性能相关的采集信息配置),无需修改,可向AscendCL初始化接口中传入NULL,或者可将配置文件配置为空json串(即配置文件中只有{}).
有初始化就有去初始化,在确定完成了AscendCL的所有调用之后,或者进程退出之前,需调用AscendCL接口实现AscendCL去初始化.
// 此处以伪代码的形式展示接口的调用流程 // 初始化 // 此处的..表示相对路径,相对可执行文件所在的目录,例如,编译出来的可执行文件存放在out目录下,此处的..就表示out目录的上一级目录 const char *aclConfigPath = " ../src/acl.json " ; aclError ret = aclInit(aclConfigPath); // ...... // 去初始化 ret = aclFinalize();
运行管理资源包括Device、Context、Stream、Event等,此处重点介绍Device、Context、Stream,其基本概念如下图所示 .
您需要按顺序依次申请如下运行管理资源: Device、Context、Stream ,确保可以使用这些资源执行运算、管理任务。所有数据处理都结束后,需要按顺序依次释放运行管理资源: Stream、Context、Device .
在申请运行管理资源时,Context、Stream支持隐式创建和显式创建两种申请方式.
// 此处以伪代码的形式展示接口的调用流程,以显式创建Context和Stream为例 // 运行管理资源申请 // 1、指定运算的Device aclError ret = aclrtSetDevice(deviceId); // 2、显式创建一个Context,用于管理Stream对象 ret = aclrtCreateContext(context, deviceId); // 3、显式创建一个Stream,用于维护一些异步操作的执行顺序,确保按照应用程序中的代码调用顺序执行任务 ret = aclrtCreateStream(stream); // ...... // 运行管理资源释放 // 1、销毁Stream ret = aclrtDestroyStream(stream); // 2、销毁Context ret = aclrtDestroyContext(context); // 3、释放Device资源 ret = aclrtResetDevice(deviceId); // ......
如果模型对输入图片的宽高要求与用户提供的源图不一致,AscendCL提供了媒体数据处理的接口,可实现抠图、缩放、格式转换、视频或图片的编解码等,将源图裁剪成符合模型的要求。后续期刊中会展开说明这个功能,本期着重介绍模型推理的部分,以输入图片满足模型的要求为例.
模型推理场景下,必须要有适配昇腾AI处理器的离线模型(*.om文件),我们可以使用ATC(Ascend Tensor Compiler)来构建模型。如果模型推理涉及动态Batch、动态分辨率等特性,需在构建模型增加相关配置。关于如何使用ATC来构建模型,请参见“昇腾文档中心[1]”.
有了模型,就可以开始加载了,当前AscendCL支持以下几种方式加载模型:
由用户自行管理内存时,需关注工作内存、权值内存。工作内存用于存放模型执行过程中的临时数据,权值内存用于存放权值数据。这个时候,是不是有疑问了,我怎么知道工作内存、权值内存需要多大?不用担心,AscendCL不仅提供了加载模型的接口,同时也提供了“根据模型文件获取模型执行时所需的工作内存和权值内存大小”的接口,方便用户使用 .
// 此处以伪代码的形式展示接口的调用流程,以“由用户管理内存”为例 // 1.根据om模型文件获取模型执行时所需的权值内存大小、工作内存大小。 aclError ret = aclmdlQuerySize(omModelPath, & modelWorkSize, & modelWeightSize); // 2.根据工作内存大小,申请Device上模型执行的工作内存。 ret = aclrtMalloc(& modelWorkPtr, modelWorkSize, ACL_MEM_MALLOC_HUGE_FIRST); // 3.根据权值内存的大小,申请Device上模型执行的权值内存。 ret = aclrtMalloc(& modelWeightPtr, modelWeightSize, ACL_MEM_MALLOC_HUGE_FIRST); // 4.以从om模型文件加载模型、由用户管理工作内存和权值内存为例 // 模型加载成功,返回标识模型的ID。 ret = aclmdlLoadFromFileWithMem(modelPath, & modelId, modelWorkPtr, modelWorkSize, modelWeightPtr, modelWeightSize);
在调用AscendCL接口进行模型推理时,模型推理有输入、输出数据,输入、输出数据需要按照AscendCL规定的数据类型存放。相关数据类型如下:
模型加载成功后,用户可根据模型的ID,调用该数据类型下的操作接口获取该模型的描述信息,进而从模型的描述信息中获取模型输入/输出的个数、内存大小、维度信息、Format、数据类型等信息.
调用aclDataBuffer类型下的操作接口获取内存地址、内存大小等,便于向内存中存放输入数据、获取输出数据.
模型可能存在多个输入、多个输出,调用aclmdlDataset类型的操作接口添加多个aclDataBuffer类型的数据.
// 此处以伪代码的形式展示如何准备模型的输入、输出数据结构 // 1.根据加载成功的模型的ID,获取该模型的描述信息 aclmdlDesc *modelDesc = aclmdlCreateDesc(); aclError ret = aclmdlGetDesc(modelDesc, modelId); // 2.准备模型推理的输入数据结构 // (1)申请输入内存 // 当前示例代码中的模型只有一个输入,所以index为0,如果模型有多个输入,则需要先调用aclmdlGetNumInputs接口获取模型输入的数量 void *modelInputBuffer = nullptr; size_t modelInputSize = aclmdlGetInputSizeByIndex(modelDesc, 0 ); ret = aclrtMalloc(& modelInputBuffer, modelInputSize, ACL_MEM_MALLOC_NORMAL_ONLY); // (2)准备模型的输入数据结构 // 创建aclmdlDataset类型的数据,描述模型推理的输入 aclmdlDataset *input = aclmdlCreateDataset(); aclDataBuffer *inputData = aclCreateDataBuffer(modelInputBuffer, modelInputSize); ret = aclmdlAddDatasetBuffer(input, inputData); // 3.准备模型推理的输出数据结构 // (1)创建aclmdlDataset类型的数据output,描述模型推理的输出 aclmdlDataset *output = aclmdlCreateDataset(); // (2)获取模型的输出个数. size_t outputSize = aclmdlGetNumOutputs(modelDesc); // (3)循环为每个输出申请内存,并将每个输出添加到aclmdlDataset类型的数据中 for (size_t i = 0 ; i < outputSize; ++ i) { size_t buffer_size = aclmdlGetOutputSizeByIndex(modelDesc, i); void *outputBuffer = nullptr; ret = aclrtMalloc(& outputBuffer, buffer_size, ACL_MEM_MALLOC_NORMAL_ONLY); aclDataBuffer *outputData = aclCreateDataBuffer(outputBuffer, buffer_size); ret = aclmdlAddDatasetBuffer(output, outputData); }
准备好模型执行所需的输入和输出数据类型、且存放好模型执行的输入数据后,可以执行模型推理了,如果模型的输入涉及动态Batch、动态分辨率等特性,则在模型执行前,还需要调用AscendCL接口告诉模型本次执行时需要用的Batch数、分辨率等.
当前AscendCL支持同步模型执行、异步模型执行两种方式,这里说的同步、异步是站在调用者和执行者的角度.
// 此处以伪代码的形式展示同步模型执行的过程 // 1. 由用户自行编码,将模型所需的输入数据读入内存 // 如果模型推理之前先进行媒体数据处理,则此处可以将媒体数据处理后的输出内容作为模型推理的输入内存, // ...... // 2. 执行模型推理 // modelId表示模型ID,在模型加载成功后,会返回标识模型的ID // input、output分别表示模型推理的输入、输出数据,在准备模型推理的输入、输出数据结构时已定义 aclError ret = aclmdlExecute(modelId, input, output) // 3. 处理模型推理的输出数据 for (size_t i = 0 ; i < aclmdlGetDatasetNumBuffers(output); ++ i) { // 获取每个输出的内存地址和内存大小 aclDataBuffer* dataBuffer = aclmdlGetDatasetBuffer(output, i); void * data = aclGetDataBufferAddr(dataBuffer); size_t len = aclGetDataBufferSizeV2(dataBuffer); // 获取到输出数据后,由用户自行编码,处理输出数据 // ...... } // 4.销毁模型输入、输出数据结构 // 释放输入资源,包括数据结构和内存 ( void )aclDestroyDataBuffer(dataBuffer); ( void )aclmdlDestroyDataset(mdlDataset); // 5.释放内存资源,防止内存泄露 // ......
推理结束后,如果需要获取并进一步处理推理结果数据,则由用户自行编码实现。最后,别忘了,我们还要销毁aclmdlDataset、aclDataBuffer等数据类型,释放相关内存,防止内存泄露.
在模型推理结束后,还需要通过aclmdlUnload接口卸载模型,并销毁aclmdlDesc类型的模型描述信息、释放模型运行的工作内存和权值内存.
// 此处以伪代码的形式展示模型卸载的过程 // 1. 卸载模型 aclError ret = aclmdlUnload(modelId); // 2. 释放模型描述信息 ( void )aclmdlDestroyDesc(modelDesc); // 3. 释放模型运行的工作内存和权值内存 ( void )aclrtFree(modelWorkPtr); ( void )aclrtFree(modelWeightPtr);
以上就是基于AscendCL开发基础推理应用的相关知识点,您也可以在“昇腾社区在线课程[2]”板块学习视频课程,学习过程中的任何疑问,都可以在“昇腾论坛[3]”互动交流! 。
是不是意犹未尽,想自己操作一把呢,来吧!您可以从 昇腾CANN样例仓 获取该样例以及详细的使用说明.
[1]昇腾文档中心: https://www.hiascend.com/zh/document 。
[2]昇腾社区在线课程: https://www.hiascend.com/zh/edu/courses 。
[3]昇腾论坛: https://www.hiascend.com/forum 。
。
点击关注,第一时间了解华为云新鲜技术~ 。
最后此篇关于基于昇腾计算语言AscendCL开发AI推理应用的文章就讲到这里了,如果你想了解更多关于基于昇腾计算语言AscendCL开发AI推理应用的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
SQL 和一般开发的新手,我有一个表(COUNTRIES),其中包含字段(INDEX、NAME、POPULATION、AREA) 通常我添加一个客户端(Delphi)计算字段(DENSITY)和 On
我想使用 calc(100%-100px),但在我的 demo 中不起作用由于高度只接受像素,因此如何将此百分比值转换为像素。 最佳答案 以下将为您提供高度: $(window).height();
我正在尝试在 MySQL 中添加列并动态填充其他列。 例如我有一张表“数字”并具有第 1 列、第 2 列、第 3 列,这些总数应填充在第 4 列中 最佳答案 除非我误解了你的问题,否则你不只是在寻找:
我想返回简单计算的结果,但我不确定如何执行此操作。我的表格如下: SELECT COUNT(fb.engineer_id) AS `total_feedback`, SUM(fb.ra
我一直在尝试做这个程序,但我被卡住了,我仍然是一个初学者,任何帮助将不胜感激。我需要程序来做 打印一个 10 X 10 的表格,其中表格中的每个条目都是行号和列号的总和 包含一个累加器,用于计算所有表
这个计算背后一定有一些逻辑。但我无法得到它。普通数学不会导致这种行为。谁能帮我解释一下原因 printf ("float %f\n", 2/7 * 100.0); 结果打印 1.000000 为什么会
我想计算从 0 到 (n)^{1/2} - 1 的数字的 AND每个数字从 0 到 (n)^{1/2} - 1 .我想在 O(n) 中执行此操作时间,不能使用 XOR、OR、AND 运算。 具体来说,
如何在 Excel 中将公式放入自定义数字格式?例如(出于说明目的随机示例), 假设我有以下数据: 输入 输出 在不编辑单元格中的实际数据的情况下,我想显示单元格中的值除以 2,并保留两位小数: 有没
每次我在 Flutter 应用程序中调用计算()时,我都会看到内存泄漏,据我所知,这基本上只是一种生成隔离的便捷方法。我的应用程序内存占用增加并且在 GC 之后永远不会减少。 我已将我的代码简化为仅调
我有数字特征观察 V1通过 V12用于目标变量 Wavelength .我想计算 Vx 之间的 RMSE列。数据格式如下。 每个变量“Vx”以 5 分钟的间隔进行测量。我想计算所有 Vx 变量的观测值
我正在寻找一种使用 C 语言计算文件中未知字符数的简单方法。谢谢你的帮助 最佳答案 POSIX 方式(可能是您想要的方式): off_t get_file_length( FILE *file ) {
我正在使用 Postgres,并且我正试图围绕如何在连续日期跨度中得出第一个开始日期的问题进行思考。例如 :- ID | Start Date | End Date =================
我有一个订单表格,我在其中使用 jQuery 计算插件来汇总总数。 此求和工作正常,但生成的“总和”存在问题。总之,我希望用逗号替换任何点。 代码的基础是; function ($this) {
我在使用 double 变量计算简单算术方程时遇到问题。 我有一个具有 double 属性 Value 的组件,我将此属性设置为 100。 然后我做一个简单的减法来检查这个值是否真的是 100: va
我在这里看到了一些关于 CRC 32 计算的其他问题。但没有一个让我满意,因此是这样。 openssl 库是否有任何用于计算 CRC32 的 api 支持?我已经在为 SHA1 使用 openssl,
当我在PHP日期计算中遇到问题时,我感到惊讶。 $add = '- 30 days'; echo date('Y-m-01', strtotime($add)); // result is 2017-
我正在使用 javascript 进行练习,我编写了这个脚本来计算 2 个变量的总和,然后在第三个方程中使用这个总和!关于如何完成这项工作的任何想法都将非常有用! First Number:
我有一个来自EAC的提示单和一个包含完整专辑的FLAC文件。 我正在尝试制作一些python脚本来播放文件,因为我需要能够设置在flac文件中开始的位置。 如何从CueSheet格式MM:SS:FF转
这个问题已经有答案了: Adding two numbers concatenates them instead of calculating the sum (24 个回答) 已关闭去年。 我有一个
4000 我需要上面字段 name="quantity" 和 id="price" 中的值,并使用 javascript 函数进行计算,并将其显示在字段 id= 中仅当我单击计算按钮时才显示“总
我是一名优秀的程序员,十分优秀!