HiAI Foundation开发平台,加速端侧AI应用的智能革命

如果您是一名开发者,正在寻找一种高效、灵活且易于使用的端侧AI开发框架,那么HarmonyOS SDKHiAI Foundation服务(HiAI Foundation Kit)就是您的理想选择。

作为一款AI开发框架,HiAI Foundation不仅提供强大的NPU计算能力和丰富的开发工具,还提供完善的技术支持和社区资源,帮助您快速构建高质量的AI应用程序。以图像分类这种常见的AI应用为例,使用HiAI Foundation可以帮助开发者们快速实现高效的图像分类应用。HiAI Foundation面向自定义AI算法的开发者们,可以灵活地支持自有的算法,给应用带来更好的性能功耗收益。

功能演示

如果开发者对实现方式感兴趣,可以下载Demo体验,基于具体的应用场景优化。Demo支持加载离线模型,对图片中的物体进行分类。

图像分类开发步骤

1.创建项目

本章以Caffe SqueezeNet模型集成为例,说明App集成操作过程。

2.配置项目NAPI

编译HAP时,NAPI层的so需要编译依赖NDK中的libneural_network_core.so和libhiai_foundation.so。

3.头文件引用

按需引用头文件。

#include "neural_network_runtime/neural_network_core.h"
#include "hiai_foundation/hiai_options.h"

4.编写CMakeLists.txt

CMakeLists.txt中的关键代码如下:

include_directories(${HMOS_SDK_NATIVE}/sysroot/usr/lib)
FIND_LIBRARY(hiai_foundation-lib hiai_foundation)
add_library(entry SHARED Classification.cpp HIAIModelManager.cpp)
target_link_libraries(entry PUBLIC libace_napi.z.solibhilog_ndk.z.solibrawfile.z.so${hiai_foundation-lib}libneural_network_core.so)

5.集成模型

模型的加载、编译和推理主要是在native层实现,应用层主要作为数据传递和展示作用。

模型推理之前需要对输入数据进行预处理以匹配模型的输入,同样对于模型的输出也需要做处理获取自己期望的结果。另外SDK中提供了设置模型编译和运行时的配置接口,开发者可根据实际需求选择使用接口。

本节阐述同步模式下单模型的使用,从流程上分别阐述每个步骤在应用层和Native层的实现和调用,接口请参见API参考。

6.预置模型

为了让App运行时能够读取到模型文件和处理推理结果,需要先把离线模型和模型对应的结果标签文件预置到工程的"entry/src/main/resources/rawfile"目录中。

本示例所使用的离线模型转换和生成可参考Caffe模型转换,当前支持Caffe 1.0版本。

命令行中的参数说明请参见OMG参数,转换命令:

./omg --model xxx.prototxt --weight yyy.caffemodel --framework 0 --
output ./modelname

转换示例:

./omg --model deploy.prototxt --weight squeezenet_v1.1.caffemodel --framework
0 --output ./squeezenet

当看到OMG generate offline model success时,则说明转换成功,会在当前目录下生成squeezenet.om。

7.加载离线模型

在App应用创建时加载模型和读取结果标签文件。

1)调用NAPI层的"LoadModel"函数,读取模型的buffer。

2)把模型buffer传递给HIAIModelManager类的"HIAIModelManager::LoadModelFromBuffer"接口,该接口调用

OH_NNCompilation_ConstructWithOfflineModelBuffer创建模型的编译实例。

3)获取并设置模型的deviceID。

size_t deviceID = 0;
const size_t *allDevicesID = nullptr;
uint32_t deviceCount = 0;
OH_NN_ReturnCode ret = OH_NNDevice_GetAllDevicesID(&allDevicesID, &deviceCount);
if (ret != OH_NN_SUCCESS || allDevicesID == nullptr) {OH_LOG_ERROR(LOG_APP, "OH_NNDevice_GetAllDevicesID failed");return OH_NN_FAILED;
}
for (uint32_t i = 0; i < deviceCount; i++) {const char *name = nullptr;ret = OH_NNDevice_GetName(allDevicesID[i], &name);if (ret != OH_NN_SUCCESS || name == nullptr) {OH_LOG_ERROR(LOG_APP, "OH_NNDevice_GetName failed");return OH_NN_FAILED;}if (std::string(name) == "HIAI_F") {deviceID = allDevicesID[i];break;}
}
// modelData和modelSize为模型的内存地址和大小
OH_NNCompilation *compilation = OH_NNCompilation_ConstructWithOfflineModelBuffer(modelData, modelSize); 
ret = OH_NNCompilation_SetDevice(compilation, deviceID); 
if (ret != OH_NN_SUCCESS) {OH_LOG_ERROR(LOG_APP, "OH_NNCompilation_SetDevice failed");return OH_NN_FAILED;
}

4)调用OH_NNCompilation_Build,执行模型编译。

5)调用OH_NNExecutor_Construct,创建模型执行器。

6)调用OH_NNCompilation_Destroy,释放模型编译实例。

上述流程可参见Demo中"entry/src/main/cpp/Classification.cpp"文件中的"LoadModel"函数和"entry/src/main/cpp/HiAiModelManager.cpp"中的"HIAIModelManager::LoadModelFromBuffer"函数。

8.准备输入输出

1)准备输入输出

2)处理模型的输入,例如示例中模型的输入为13227*227格式Float类型的数据,需要把输入的图片转成该格式后传递到NAPI层。

3)创建模型的输入和输出Tensor,并把应用层传递的数据填充到输入的Tensor中。

// 创建输入数据
size_t inputCount = 0;
std::vector<NN_Tensor*> inputTensors;
OH_NN_ReturnCode ret = OH_NNExecutor_GetInputCount(executor, &inputCount); 
if (ret != OH_NN_SUCCESS || inputCount != inputData.size()) { // inputData为开发者构造的输入数据OH_LOG_ERROR(LOG_APP, "OH_NNExecutor_GetInputCount failed, size mismatch");return OH_NN_FAILED;
}
for (size_t i = 0; i < inputCount; ++i) {NN_TensorDesc *tensorDesc = OH_NNExecutor_CreateInputTensorDesc(executor, i); NN_Tensor *tensor = OH_NNTensor_Create(deviceID, tensorDesc); // deviceID的获取方式可参考"加载离线模型"的步骤3if (tensor != nullptr) {inputTensors.push_back(tensor);}OH_NNTensorDesc_Destroy(&tensorDesc);
}
if (inputTensors.size() != inputCount) {OH_LOG_ERROR(LOG_APP, "input size mismatch");DestroyTensors(inputTensors); // DestroyTensors为释放tensor内存操作函数return OH_NN_FAILED;
}
// 初始化输入数据
for (size_t i = 0; i < inputTensors.size(); ++i) {void *data = OH_NNTensor_GetDataBuffer(inputTensors[i]);size_t dataSize = 0;OH_NNTensor_GetSize(inputTensors[i], &dataSize);if (data == nullptr || dataSize != inputData[i].size()) { // inputData为模型的输入数据OH_LOG_ERROR(LOG_APP, "invalid data or dataSize");return OH_NN_FAILED;}memcpy(data, inputData[i].data(), inputData[i].size()); // inputData为模型的输入数据
}
// 创建输出数据,与输入数据的创建方式类似
size_t outputCount = 0;
std::vector<NN_Tensor*> outputTensors;
ret = OH_NNExecutor_GetOutputCount(executor, &outputCount); 
if (ret != OH_NN_SUCCESS) {OH_LOG_ERROR(LOG_APP, "OH_NNExecutor_GetOutputCount failed");DestroyTensors(inputTensors); // DestroyTensors为释放tensor内存操作函数return OH_NN_FAILED;
}
for (size_t i = 0; i < outputCount; i++) {NN_TensorDesc *tensorDesc = OH_NNExecutor_CreateOutputTensorDesc(executor, i); NN_Tensor *tensor = OH_NNTensor_Create(deviceID, tensorDesc); // deviceID的获取方式可参考"加载离线模型"的步骤3if (tensor != nullptr) {outputTensors.push_back(tensor);}OH_NNTensorDesc_Destroy(&tensorDesc);
}
if (outputTensors.size() != outputCount) {DestroyTensors(inputTensors); // DestroyTensors为释放tensor内存操作函数DestroyTensors(outputTensors); // DestroyTensors为释放tensor内存操作函数OH_LOG_ERROR(LOG_APP, "output size mismatch");return OH_NN_FAILED;
}

上述流程可参见Demo中"entry/src/main/cpp/Classification.cpp"文件中的"InitIOTensors"函数和"entry/src/main/cpp/HiAiModelManager.cpp"中的"HIAIModelManager::InitIOTensors"函数。

9.同步推理离线模型

调用OH_NNExecutor_RunSync,完成模型的同步推理。

可参见Demo中"entry/src/main/cpp/Classification.cpp"文件中的"RunModel"函数和"entry/src/main/cpp/HiAiModelManager.cpp"中的"HIAIModelManager::RunModel"函数。

说明:如果不更换模型,则首次编译加载完成后可多次推理,即一次编译加载,多次推理。

10.模型输出后处理

1)调用OH_NNTensor_GetDataBuffer,获取输出的Tensor,在输出Tensor中会得到模型的输出数据。

2)对输出数据进行相应的处理可得到期望的结果。

3)例如本示例demo中模型的输出是1000个label的概率,期望得到这1000个结果中概率最大的三个标签。

4)销毁实例。

调用OH_NNExecutor_Destroy,销毁创建的模型执行器实例。

调用OH_NNTensor_Destroy,销毁创建的输入输出Tensor。

上述流程可参见Demo中"entry/src/main/cpp/Classification.cpp"文件中的"GetResult"、“UnloadModel"函数和"entry/src/main/cpp/HiAiModelManager.cpp"中的"HIAIModelManager::GetResult”、"HIAIModelManager::UnloadModel"函数。

了解更多详情>>

访问HiAI Foundation服务联盟官网

获取HiAI Foundation服务开发指导文档

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

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

相关文章

C语言编程1:变量、常量与输入输出详解

C语言1&#x1f525;&#xff1a; 变量&#xff0c;赋值与初始化&#xff0c;常量&#xff0c;输入与输出 一、变量&#x1f33f; ✨1.1 定义 在C语言中变量是一个用来保存数据的地方。当我们需要在程序里保存数据时就需要用到变量。 ✨1.2 变量名称 变量名称是需要我们自…

直击2024 WAIC现场:关于大模型,热情、焦虑与冷静同在

世博展览馆内人们的热情&#xff0c;与世博中心内参与论坛的人们&#xff0c;心情似乎并不成正比。 展馆内人们看到的大模型加速落地是表象&#xff0c;也是结果&#xff1b;而论坛里的企业家和人工智能学者们则更关注大模型的未来发展方向和商业化进程&#xff0c;以及AI安全…

计算机的错误计算(二十三)

摘要 计算机的错误计算&#xff08;二十二&#xff09;阐明&#xff1a;对于结果应该为 0的算式&#xff0c;即使增加计算精度&#xff0c;也得不出0. 针对 &#xff0c;本节给出一种解决方案。 计算机的错误计算&#xff08;十九&#xff09;展示了计算机对 的错误计算&…

【0基础学爬虫】爬虫框架之 feapder 的使用

前言 大数据时代&#xff0c;各行各业对数据采集的需求日益增多&#xff0c;网络爬虫的运用也更为广泛&#xff0c;越来越多的人开始学习网络爬虫这项技术&#xff0c;K哥爬虫此前已经推出不少爬虫进阶、逆向相关文章&#xff0c;为实现从易到难全方位覆盖&#xff0c;特设【0…

Python遥感开发之时序数据的线性插值

Python遥感开发之时序数据的线性插值 0 历史博客1 实现思路2 代码实现3 效果展示 前言&#xff1a;在遇到空间数据的时候&#xff0c;尤其是哨兵、Landsat或者MODIS数据会出现局部值的空缺&#xff0c;为了解决这些值的空缺&#xff0c;通常采用插值的方法&#xff0c;本博客使…

在Ubuntu 14.04上安装和配置VNC的方法

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 简介 VNC&#xff0c;即“虚拟网络计算”&#xff0c;是一种连接系统&#xff0c;允许您使用键盘和鼠标与远程服务器上的图形桌面环境进…

Python编程学习笔记(1)--- 变量和简单数据类型

1、变量 在学习编程语言之前&#xff0c;所接触的第一个程序&#xff0c;绝大多数都是&#xff1a; print("Hello world!") 接下来尝试使用一个变量。在代码中的开头添加一行代码&#xff0c;并对第二行代码进行修改&#xff0c;如下&#xff1a; message "…

中国星坤X1224系列线对板连接器:小巧稳定,助力物联网终端高效运行

在物联网、电器和消防等领域&#xff0c;终端设备的安全稳定运行至关重要。为了满足这些领域对连接器高可靠性、小巧轻便和耐高温的需求&#xff0c;X1224系列线对板连接器应运而生。这款连接器以其独特的设计和卓越的性能&#xff0c;成为了终端设备中不可或缺的一部分。 一、…

LeetCode415-字符串相加

题目 代码 public String addStrings(String num1, String num2) {if (num1 null) {return num2;}if (num2 null) {return num1;}int min Math.min(num1.length(), num2.length());int abs Math.abs(num1.length() - num2.length());// 0.字符串对齐&#xff08;补0&…

Ubantu22.04 通过FlatPak安装微信

Ubuntu22.04 下使用Flatpak稳定安装微信&#xff01; 国际惯例&#xff0c;废话不多说&#xff0c;先上效果图。为啥使用Flatpak,因为Wechat官方只在FlatPak发布了最新的版本。之前使用了Wine以及Dock安装Wechat,效果都不是很理想&#xff0c;bug很多。所以使用了FlatPak。 Fl…

免费的鼠标连点器电脑版教程!官方正版!专业鼠标连点器用户分享教程!2024最新

电脑技术的不断发展&#xff0c;许多用户在日常工作和娱乐中&#xff0c;需要用到各种辅助工具来提升效率或简化操作&#xff0c;而电脑办公中&#xff0c;鼠标连点器作为一种能够模拟鼠标点击的软件&#xff0c;受到了广大用户的青睐。本文将为大家介绍一款官方正版的免费鼠标…

力扣第134场双周赛压轴题:子数组按位与值为K的数目

题目描述 给你一个整数数组 n u m s nums nums 和一个整数 k k k &#xff0c;请你返回 n u m s nums nums 中有多少个子数组满足&#xff1a;子数组中所有元素按位 A N D AND AND 的结果为 k k k 。 子数组是数组中连续的非空元素序列。 数据范围 1 ≤ n u m s . l e …

解释一下 Redis 的主从复制原理?

Redis 的主从复制是 Redis 实现数据冗余和高可用性的重要机制。它允许创建一个或多个 Redis 服务器&#xff08;从服务器&#xff09;来复制主服务器的数据&#xff0c;从而实现数据的备份和读写分离&#xff0c;提高系统的性能和可靠性。 主从复制的工作原理主要包括以下几个…

使用Java构建一个高性能的消息队列系统

使用Java构建一个高性能的消息队列系统 大家好&#xff0c;我是微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 消息队列系统在现代分布式系统中起着至关重要的作用&#xff0c;它能够提供异步通信、解耦系统组件、缓冲和削…

一.2.(3)放大电路的图解分析方法和微变等效电路分析方法;

放大电路的主要分析方法:图解法、微变等效电路法 这里以共射放大电路为例 (1) 图解法: 1.静态分析 首先确定静态工作点Q,然后根据电路的特点,做出直流负载线,进而画出交流负载线,最后,画出各极电流电压的波形。求出最大不失真输出电压。 估算IBQ&#xff0c;然后根据数据手册里…

09.QT控件:按钮类控件

1. QPushButton 在QT中使⽤ QPushButton 表⽰⼀个按钮。QPushButton 继承⾃ QAbstractButton&#xff0c;这个类是⼀个抽象类&#xff0c;是其他按钮的⽗类。 &#xff08;1&#xff09;QAbstractButton 中&#xff0c;和 QPushButton 相关性较⼤的属性&#xff1a; &#xf…

STM32-Unix时间戳和BKP备份寄存器以及RTC实时时钟

本内容基于江协科技STM32视频学习之后整理而得。 文章目录 1. Unix时间戳1.1 Unix时间戳简介1.2 UTC/GMT1.3 时间戳转换 2. BKP备份寄存器2.1 BKP简介2.2 BKP基本结构2.3 BKP库函数 3. RTC实时时钟3.1 RTC简介3.2 RTC框图3.3 RTC基本结构3.4 硬件电路3.5 RTC操作注意事项3.6 R…

vue事件处理v-on或@

事件处理v-on或 我们可以使用v-on指令&#xff08;简写&#xff09;来监听DOM事件&#xff0c;并在事件触发时执行对应的Javascript。用法&#xff1a;v-on:click"methodName"或click"hander" 事件处理器的值可以是&#xff1a; 内敛事件处理器&#xff1…

LocalDateTime 字符串与时间戳的相互转换

主要介绍LocalDateTime的格式化字符串与时间戳的相互转换 常见带日期时间格式&#xff1a; 字段名字段值api格式DateTimeFormatter.ISO_LOCAL_DATE_TIME字符串patternyyyy-MM-dd’T’HH:mm:ss.SSS’示例2022-06-15T22:06:29.483字符串patternyyyy-MM-dd HH:mm:ss示例2022-06-…

Golang | Leetcode Golang题解之第213题打家劫舍II

题目&#xff1a; 题解&#xff1a; func _rob(nums []int) int {first, second : nums[0], max(nums[0], nums[1])for _, v : range nums[2:] {first, second second, max(firstv, second)}return second }func rob(nums []int) int {n : len(nums)if n 1 {return nums[0]}…