如何基于香橙派AIpro开发AI推理应用

news2024/11/24 19:13:15

简介

香橙派AIpro开发板采用昇腾AI技术路线,接口丰富且具有强大的可扩展性,提供8/20TOPS澎湃算力,可广泛使用于AI边缘计算、深度视觉学习及视频流AI分析、视频图像分析、自然语言处理等AI领域。通过昇腾CANN软件栈的AI编程接口,可满足大多数AI算法原型验证、推理应用开发的需求。

AscendCL(Ascend Computing Language,昇腾计算语言)是昇腾计算开放编程框架,是对底层昇腾计算服务接口的封装,提供Device管理、Context管理、Stream管理、内存管理、模型加载与执行、算子加载与执行、媒体数据处理等API,支持C&C++、Python编程语言,能够实现深度学习推理计算、图形图像预处理、单算子加速计算等能力。

掌握了AscendCL的编程方法,就意味着可以在香橙派AIpro开发板上充分利用昇腾的算力资源,能够基于深度学习算法开发图片分类、目标检测等一系列深度学习推理计算程序。

01 开发流程

使用AscendCL开发推理应用时,开发流程大致分为以下几步:

  1. AscendCL初始化:初始化AscendCL内部资源,为运行做准备

  2. 运行管理资源申请:申请运行时相关资源,例如计算设备

  3. 媒体数据处理:可实现抠图、缩放、视频或图片的编解码等

  4. 模型推理:包括模型加载、执行、卸载

  5. 运行管理资源释放:资源使用后及时释放

  6. AscendCL去初始化:与初始化配对使用

首先,我们得先了解下,使用AscendCL时,经常会提到的“数据类型的操作接口” ,这是什么呢?为啥会存在?

在C/C++中,对用户开放的数据类型通常以Struct结构体方式定义、以声明变量的方式使用,但这种方式一旦结构体要增加成员参数,用户的代码就涉及兼容性问题,不便于维护,因此AscendCL对用户开放的数据类型,均以接口的方式操作该数据类型,例如,调用某个数据类型的Create接口创建该数据类型、调用Get接口获取数据类型内参数值、调用Set接口设置数据类型内的参数值、调用Destroy接口销毁该数据类型,用户无需关注定义数据类型的结构体长什么样,这样即使后续数据类型需扩展,只需增加该数据类型的操作接口即可,也不会引起兼容性问题。

所以,总结下,“数据类型的操作接口”就是创建数据类型、Get/Set数据类型中的参数值、销毁数据类型的一系列接口,存在的最大好处就是减少兼容性问题

接下来,进入我们今天的主题,怎么用AscendCL的接口开发网络模型推理场景下的应用。看完本文介绍的关键知识点,也可以到 “昇腾文档中心[1]”查阅详细的文档介绍。

02 AscendCL初始化与去初始化

使用AscendCL接口开发应用时,必须先初始化AscendCL ,否则可能会导致后续系统内部资源初始化出错,进而导致其它业务异常。在初始化时,还支持以下跟推理相关的配置项(例如,性能相关的采集信息配置),以json格式的配置文件传入AscendCL初始化接口。如果当前的默认配置已满足需求(例如,默认不开启性能相关的采集信息配置),无需修改,可向AscendCL初始化接口中传入NULL,或者可将配置文件配置为空json串(即配置文件中只有{})。

有初始化就有去初始化,在确定完成了AscendCL的所有调用之后,或者进程退出之前,需调用AscendCL接口实现AscendCL去初始化。

// 此处以伪代码的形式展示接口的调用流程

// 初始化
// 此处的..表示相对路径,相对可执行文件所在的目录,例如,编译出来的可执行文件存放在out目录下,此处的..就表示out目录的上一级目录
const char *aclConfigPath = "../src/acl.json";
aclError ret = aclInit(aclConfigPath);

// ......

// 去初始化
ret = aclFinalize();

03 运行管理资源申请与释放

运行管理资源包括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);

//......

04 媒体数据处理

如果模型对输入图片的宽高要求与用户提供的源图不一致,AscendCL提供了媒体数据处理的接口,可实现抠图、缩放、格式转换、视频或图片的编解码等,将源图裁剪成符合模型的要求。后续期刊中会展开说明这个功能,本期着重介绍模型推理的部分,以输入图片满足模型的要求为例。

05 模型加载

模型推理场景下,必须要有适配昇腾AI处理器的离线模型(*.om文件),我们可以使用ATC(Ascend Tensor Compiler)来构建模型。如果模型推理涉及动态Batch、动态分辨率等特性,需在构建模型增加相关配置。关于如何使用ATC来构建模型,请参见“昇腾文档中心”。

有了模型,就可以开始加载了,当前AscendCL支持以下几种方式加载模型:

  • 从*.om文件中加载模型数据,由AscendCL管理内存
  • 从*.om文件中加载模型数据,由用户自行管理内存
  • 从内存中加载模型数据,由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);

06 模型执行

在调用AscendCL接口进行模型推理时,模型推理有输入、输出数据,输入、输出数据需要按照AscendCL规定的数据类型存放。相关数据类型如下:

  • 使用aclmdlDesc类型的数据描述模型基本信息(例如输入/输出的个数、名称、数据类型、Format、维度信息等)。

模型加载成功后,用户可根据模型的ID,调用该数据类型下的操作接口获取该模型的描述信息,进而从模型的描述信息中获取模型输入/输出的个数、内存大小、维度信息、Format、数据类型等信息。

  • 使用aclDataBuffer类型的数据来描述每个输入/输出的内存地址、内存大小。

调用aclDataBuffer类型下的操作接口获取内存地址、内存大小等,便于向内存中存放输入数据、获取输出数据。

  • 使用aclmdlDataset类型的数据描述模型的输入/输出数据。

模型可能存在多个输入、多个输出,调用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支持同步模型执行、异步模型执行两种方式,这里说的同步、异步是站在调用者和执行者的角度。

  • 若调用模型执行的接口后需等待推理完成再返回,则表示模型执行是同步的。当用户调用同步模型执行接口后,可直接从该接口的输出参数中获取模型执行的结果数据,如果需要推理的输入数据量很大,同步模型执行时,需要等所有数据都处理完成后,才能获取推理的结果数据。
  • 若调用模型执行的接口后不等待推理完成完成再返回,则表示模型执行是异步的。当用户调用异步模型执行接口时,需指定Stream(Stream用于维护一些异步操作的执行顺序,确保按照应用程序中的代码调用顺序在Device上执行),另外,还需调用aclrtSynchronizeStream接口阻塞程序运行,直到指定Stream中的所有任务都完成,才可以获取推理的结果数据。如果需要推理的输入数据量很大,异步模型执行时,AscendCL提供了Callback机制,触发回调函数,在指定时间内一旦有推理的结果数据,就获取出来,达到分批获取推理结果数据的目的,提高效率。
// 此处以伪代码的形式展示同步模型执行的过程

// 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等数据类型,释放相关内存,防止内存泄露。

07 模型卸载

在模型推理结束后,还需要通过aclmdlUnload接口卸载模型,并销毁aclmdlDesc类型的模型描述信息、释放模型运行的工作内存和权值内存。

// 此处以伪代码的形式展示模型卸载的过程
// 1. 卸载模型
aclError ret = aclmdlUnload(modelId);

// 2. 释放模型描述信息
(void)aclmdlDestroyDesc(modelDesc);

// 3. 释放模型运行的工作内存和权值内存
(void)aclrtFree(modelWorkPtr);
(void)aclrtFree(modelWeightPtr);

8 更多资源 

[1]香橙派AIpro开源样例代码:https://gitee.com/ascend/EdgeAndRobotics

[2]昇腾文档中心:昇腾社区-官网丨昇腾万里 让智能无所不及

[3]香橙派AIpro学习资源一站式导航:https://www.hiascend.com/forum/thread-0285140173361311056-1-1.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1531618.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深度学习pytorch——统计属性(持续更新)

矩阵范数 vs 向量范数 向量范数 1-范数&#xff1a;所有元素的绝对值之和。 2-范数&#xff1a;所有元素的平方之和&#xff0c;在开根号。 p-范数&#xff1a;所有元素的绝对值的p次方之和&#xff0c;再求其1/p次方。 例&#xff1a;向量X[2, 3, -5, -7] &#xff0c;求向…

深入理解Linux内核页表映射分页机制原理

深入理解Linux内核页表映射分页机制原理 前言 操作系统用于处理内存访问异常的入口操作系统的核心任务是对系统资源的管理&#xff0c;而重中之重的是对CPU和内存的管理。 为了使进程摆脱系统内存的制约&#xff0c;用户进程运行在虚拟内存之上&#xff0c;每个用户进程都拥…

静态网络配置

一、查看网络命令 1.命令行查看网络配置 1、查看ip\硬件设备-网卡 ifconfig -a ifconfig ens160 网卡名称 ip addr show ip addr show ens160 nmcli device show ens160 nmcli con up ens160 2、主机名称 hostname hostname hfj.huaxia.com 3、查看路由和网关 rou…

(C++20) jthread中stop_token的基础使用

(C20) jthread中stop_token的基础使用 文章目录 (C20) jthread中stop_token的基础使用C20 jthread使用方式循环判断条件变量condition_variable_any stop回调 std::stop_callbackEND C20 jthread std::jthread - cppreference.com std::stop_token - cppreference.com std::sto…

springboot3以及上版本引入RocketMQTemplate显示could not be found.

1. 问题所在 springboot3以及上版本引入RocketMQTemplate显示could not be found&#xff1f; 在springboot3时&#xff0c;直接通过依赖来注入RocketMQTemplate会报错&#xff0c;会显示没有这个对象。 这是因为在Springboot3以前的版本&#xff0c;自动装配是通过读取所有jar…

Docker容器化技术(docker-compose安装部署案例)

docker-compose编排工具 安装docker-compose [rootservice ~]# systemctl stop firewalld [rootservice ~]# setenforce 0 [rootservice ~]# systemctl start docker[rootservice ~]# wget https://github.com/docker/compose/releases/download/v2.5.0/docker-compose-linux-…

xinput1_3.dll丢失如何修复,xinput1_3.dll的安装修复教程分享

在Windows操作系统环境下&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中之一就是“找不到xinput13.dll”。由于xinput1_3.dll是微软DirectX SDK的一部分&#xff0c;主要用于支持游戏手柄和其他外部设备的输入功能&#xff0c;缺失这一动态链接库文件可能导致某些依赖…

高顿咨询如何用国产CRM实现经验决策到数据决策的跨越

编者按 近日&#xff0c;Salesforce 移动应用在中国大陆苹果应用商店的下架&#xff0c;预示着今年CRM国产化替代即将迎来高潮。CRM作为距离业务最近的软件&#xff0c;被公认为是企业数字化转型、高质量发展的核心系统之一。“企业如何选择一款真正满足自身业务需求的本土化C…

邮件客户端 Thunderbird 简单配置

1. 基本情况介绍 原来使用的邮箱客户端是 Office 365 自带的 Outlook 365切换原因&#xff1a;新装电脑&#xff0c;发现原 Outlook 中的账号信息无法迁移&#xff0c;需要耗费大量时间手动配置邮箱使用的邮箱&#xff1a;微软 O365 邮箱、qq 邮箱、163 邮箱、公司私有邮箱 …

stable diffusion webui ubuntu 安装

1.git clone 下来 GitHub - AUTOMATIC1111/stable-diffusion-webui: Stable Diffusion web UIStable Diffusion web UI. Contribute to AUTOMATIC1111/stable-diffusion-webui development by creating an account on GitHub.https://github.com/AUTOMATIC1111/stable-diffus…

阻止默认行为 e.preventDefault()搭配passive:false才有效

正确情况 如果想阻止默认行为,那么 e.preventDefault()搭配passive:false才是正解 document.addEventListener(touchmove,(e)>{ e.preventDefault() console.log(123,123);},{passive:false}) 如果搭配 passive:false,则会报警告 e.preventDefault()搭配passive:true会报…

FREERTOS软件定时器

FreeRTOS 也提供了定时器功能&#xff0c;不过是软件定时器&#xff0c;软件定时器的精度肯定没有硬件定时器那么高&#xff0c;但是对于普通的精度要求不高的周期性处理的任务来说够了。当MCU的硬件定时器不够的时候就可以考虑使用 FreeRTOS 的软件定时器。 软件定时器允许设置…

HCIP【静态路由综合实验练习】

目录 实验要求&#xff1a; 实验过程&#xff1a; 一&#xff1a;首先设计实验 二&#xff1a;IP地址的划分&#xff08;基于192.168.1.0/24&#xff09; 在ensp中对路由器的相关命令进行配置&#xff1a; 三&#xff1a;配IP地址 &#xff08;1&#xff09;首先给所有设…

conda创建环境网络报错解决办法

文章目录 一、报错示例&#xff1a;二、解决办法&#xff1a;2.1 查看配置 conda config --show-sources2.2 修改文件 /home/XXXX/.condarc 一、报错示例&#xff1a; UnavailableInvalidChannel: HTTP 404 NOT FOUND for channel nvidia <http://mirrors.tuna.tsinghua.ed…

uniapp 开发微信小程序 出现启用组件按需注入问题如何解决

问题描述 在使用uniapp 开发微信小程序&#xff0c;进行上架发布时 代码质量栏 出现启用组件按需注入问题。 虽然现实代码上传成功&#xff0c;但是作为一个吹毛求疵的老猿人&#xff0c;肯定是无法容忍的。那么如何解决呢&#xff1f; 问题解决方案 在uniapp端&#xff0c…

[HackMyVM] Quick

kali:192.168.56.104 主机发现 arp-scan -l # arp-scan -l Interface: eth0, type: EN10MB, MAC: 00:0c:29:d2:e0:49, IPv4: 192.168.56.104 Starting arp-scan 1.10.0 with 256 hosts (https://github.com/royhills/arp-scan) 192.168.56.1 0a:00:27:00:00:05 (Un…

QT增加线程函数步骤流程

在使用线程的时候&#xff0c;不仅要关注线程开启的时机&#xff0c;同时还要关注线程安全退出&#xff0c;这样才能保证程序的健壮性&#xff0c;如果线程开启的较多&#xff0c;且开启关闭比较频繁&#xff0c;建议使用线程池来处理。开启线程有三种方式&#xff1a;第一种C的…

房屋租赁系统|基于JSP技术+ Mysql+Java+ B/S结构的房屋租赁系统设计与实现(可运行源码+数据库+设计文档)

推荐阅读100套最新项目 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 2024年56套包含java&#xff0c;ssm&#xff0c;springboot的平台设计与实现项目系统开发资源&#xff08;可…

Milvus 社区在线寻找「北辰使者」!!!

Milvus 社区的朋友们&#xff0c;大家好&#xff0c;欢迎来到 Milvus 北极星计划发布现场&#xff01; 熟悉我们的朋友都知道&#xff0c;Milvus 起源于一种学名叫“赤鸢”的鸟类&#xff0c;鸟类飞行的方向判断依靠星星、太阳、磁场&#xff0c;而北极星在人类历史上长期被视为…

24考研数学史上最难!25该怎么学?

25考研的千万不要被以前的真题卷给蒙蔽了双眼&#xff0c;现在考研的和以前真的不一样了 做过24年考研数学试卷的&#xff0c;应该都有一个感受&#xff0c;平时训练的好像都没用上。这是为啥啊。 其实是因为&#xff0c;现在的考研数学更加注重基础的考察&#xff0c;并且计…