安卓机器学习框架学习:Android Neural Networks API (NNAPI)
Android Neural Networks API (NNAPI)
简介:
1、Android Neural Networks API (NNAPI) 是一个 Android C API,在 Android 设备上实现机器学习;
2、NNAPI 旨在为更高层级的机器学习框架(如 TensorFlow Lite 和 Caffe2)提供一个基本功能层,用来建立和训练神经网络;
3、搭载 Android 8.1(API 级别 27)或更高版本的所有 Android 设备上都提供该 API。
4、NNAPI 支持通过将 Android 设备中的数据应用到先前训练的开发者定义的模型来进行推断。
在设备上进行推断具备诸多优势:
- 延迟:您不需要通过网络连接发送请求并等待响应。例如,这对处理从相机传入的连续帧的视频应用至关重要。
- 可用性:即使在网络覆盖范围之外,应用也能运行。
- 速度:专用于神经网络处理的新硬件提供的计算速度明显快于单纯的通用 CPU。
- 隐私:数据不会离开 Android 设备。
- 费用:所有计算都在 Android 设备上执行,不需要服务器。
开发者还应在以下几个方面做出权衡取舍:
- 系统利用率:评估神经网络涉及大量的计算,而这可能会增加电池电量消耗。如果您担心自己的应用耗电量会增加(尤其是对于长时间运行的计算),应考虑监控电池运行状况。
- 应用大小:应注意模型的大小。模型可能会占用数 MB 的空间。如果在您的 APK 中绑定较大的模型会对用户造成过度影响,那么您可能需要考虑在应用安装后下载模型、使用较小的模型或在云端运行计算。NNAPI 未提供在云端运行模型的功能。
NNAPI 使用四个主要抽象概念:
-
模型:由数学运算和通过训练过程学习到的常量值构成的计算图。这些运算特定于神经网络。它们包括二维 (2D) 卷积、逻辑 (sigmoid) 激活函数、修正线性 (ReLU) 激活函数等。创建模型是一项同步操作。成功创建后,便可在线程和编译之间重用模型。在 NNAPI 中,模型表示为
ANeuralNetworksModel实例。 -
编译:表示用于将 NNAPI 模型编译到更低级别代码中的配置。创建编译是一项同步操作。成功创建后,便可在线程和执行之间重用编译。在 NNAPI 中,每个编译都表示为一个
ANeuralNetworksCompilation实例。 -
内存:表示共享内存、内存映射文件和类似内存缓冲区。使用内存缓冲区可让 NNAPI 运行时更高效地将数据传输到驱动程序。应用一般会创建一个共享内存缓冲区,其中包含定义模型所需的每个张量。您还可以使用内存缓冲区来存储执行实例的输入和输出。在 NNAPI 中,每个内存缓冲区均表示为一个
ANeuralNetworksMemory实例。 -
执行:用于将 NNAPI 模型应用到一组输入并收集结果的接口。执行可以同步执行,也可以异步执行。
对于异步执行,多个线程可以等待同一执行。此执行完成后,所有线程都被释放。在 NNAPI 中,每次执行均表示为一个
ANeuralNetworksExecution实例。
运行时:
1、**NNAPI 应由机器学习库、框架和工具调用,这样可让开发者在设备外训练他们的模型,并将其部署在 Android 设备上。2、应用一般不会直接使用 NNAPI,而会使用更高层级的机器学习框架。**这些框架进可以使用 NNAPI 在受支持的设备上执行硬件加速的推断运算。
根据应用的要求和 Android 设备的硬件功能,Android 的神经网络运行时可以在可用的**设备上处理器(包括专用的神经网络硬件、图形处理单元 (GPU) 和数字信号处理器 (DSP))**之间高效地分配计算工作负载。对于缺少专用供应商驱动程序的 Android 设备,NNAPI 运行时将在 CPU 上执行请求。
所示为 NNAPI 的简要系统架构。

编程模型:
若要使用 NNAPI 执行计算:
1、先构造一张有向图来定义要执行的计算。
2、此计算图与输入数据(例如,从机器学习框架传递过来的权重和偏差)相结合,构成 NNAPI 运行时求值的模型。

编程示例:
实现这样的计算图:

1、内存基础:
为 NNAPI 运行时提供对此类数据的高效访问途径,调用 ANeuralNetworksMemory_createFromFd() 函数并传入已打开的数据文件的文件描述符来创建 ANeuralNetworksMemory 。训练权重和偏差数据可能存储在一个文件中。
// Create a memory buffer from the file that contains the trained data
ANeuralNetworksMemory* mem1 = NULL;
int fd = open("training_data", O_RDONLY);
ANeuralNetworksMemory_createFromFd(file_size, PROT_READ, fd, 0, &mem1);
使用原生硬件缓冲区,可以将原生硬件缓冲区用于模型输入、输出和常量运算数值。在某些情况下,NNAPI 加速器可以访问 AHardwareBuffer 对象,而无需驱动程序复制数据。
// Configure and create AHardwareBuffer object
AHardwareBuffer_Desc desc = ...
AHardwareBuffer* ahwb = nullptr;
AHardwareBuffer_allocate(&desc, &ahwb);// Create ANeuralNetworksMemory from AHardwareBuffer
ANeuralNetworksMemory* mem2 = NULL;
ANeuralNetworksMemory_createFromAHardwareBuffer(ahwb, &mem2);//free
ANeuralNetworksMemory_free(mem2);
2、模型创建、编译、执行;
运算数规范:
-
添加运算数的顺序无关紧要。例如,模型输出运算数可能是添加的第一个运算数。重要的是在引用运算数时使用正确的索引值。
-
运算数具有类型。这些类型在运算数添加到模型时指定;
-
一个运算数不能同时用作模型的输入和输出;
-
每个运算数必须是一项运算的模型输入、常量或输出运算数;
运算规范:
运算指定要执行的计算。每项运算都由下面这些元素组成:
- 运算类型(例如,加法、乘法、卷积);
- 运算用于输入的运算数索引列表;
- 运算用于输出的运算数索引列表;
基本步骤:注意中间还可以进行很多配置
1、创建模型:
2、运算数添加到模型:
3、设置权重和偏差值;
4、添加运算;
5、设置输入和输出;
6、完成模型定义;
7、编译模型;
8、设置执行的设备和编译缓存;
9、执行模型;
10、最后一步,清理内存等资源;
//1、创建模型:
ANeuralNetworksModel* model = NULL;
ANeuralNetworksModel_create(&model);//2、运算数添加到模型:
// In our example, all our tensors are matrices of dimension [3][4]
ANeuralNetworksOperandType tensor3x4Type;
tensor3x4Type.type = ANEURALNETWORKS_TENSOR_FLOAT32;
tensor3x4Type.scale = 0.f; // These fields are used for quantized tensors
tensor3x4Type.zeroPoint = 0; // These fields are used for quantized tensors
tensor3x4Type.dimensionCount = 2;
uint32_t dims[2] = {3, 4};
tensor3x4Type.dimensions = dims;// We also specify operands that are activation function specifiers
ANeuralNetworksOperandType activationType;
activationType.type = ANEURALNETWORKS_INT32;
activationType.scale = 0.f;
activationType.zeroPoint = 0;
activationType.dimensionCount = 0;
activationType.dimensions = NULL;// 添加7个运算数
ANeuralNetworksModel_addOperand(model, &tensor3x4Type); // operand 0
ANeuralNetworksModel_addOperand(model, &tensor3x4Type); // operand 1
ANeuralNetworksModel_addOperand(model, &activationType); // operand 2
ANeuralNetworksModel_addOperand(model, &tensor3x4Type); // operand 3
ANeuralNetworksModel_addOperand(model, &tensor3x4Type); // operand 4
ANeuralNetworksModel_addOperand(model, &activationType); // operand 5
ANeuralNetworksModel_addOperand(model, &tensor3x4Type); // operand 6//3、设置权重和偏差值
// In our example, operands 1 and 3 are constant tensors whose values were
// established during the training process
const int sizeOfTensor = 3 * 4 * 4; // The formula for size calculation is dim0 * dim1 * elementSize
ANeuralNetworksModel_setOperandValueFromMemory(model, 1, mem1, 0, sizeOfTensor);
ANeuralNetworksModel_setOperandValueFromMemory(model, 3, mem1, sizeOfTensor, sizeOfTensor);// We set the values of the activation operands, in our example operands 2 and 5
int32_t noneValue = ANEURALNETWORKS_FUSED_NONE;
ANeuralNetworksModel_setOperandValue(model, 2, &noneValue, sizeof(noneValue));
ANeuralNetworksModel_setOperandValue(model, 5, &noneValue, sizeof(noneValue));//4、添加运算
// 两种运算,和以及乘
// The first consumes operands 1, 0, 2, and produces operand 4
uint32_t addInputIndexes[3] = {1, 0, 2};
uint32_t addOutputIndexes[1] = {4};
ANeuralNetworksModel_addOperation(model, ANEURALNETWORKS_ADD, 3, addInputIndexes, 1, addOutputIndexes);// The second consumes operands 3, 4, 5, and produces operand 6
uint32_t multInputIndexes[3] = {3, 4, 5};
uint32_t multOutputIndexes[1] = {6};
ANeuralNetworksModel_addOperation(model, ANEURALNETWORKS_MUL, 3, multInputIndexes, 1, multOutputIndexes);//5、设置输入和输出
// 输入: (0) 和 输出: (6)
uint32_t modelInputIndexes[1] = {0};
uint32_t modelOutputIndexes[1] = {6};
ANeuralNetworksModel_identifyInputsAndOutputs(model, 1, modelInputIndexes, 1 modelOutputIndexes);//6、完成模型定义
ANeuralNetworksModel_finish(model);//7、编译模型
ANeuralNetworksCompilation* compilation;
ANeuralNetworksCompilation_create(model, &compilation);//8、设置执行的设备和编译缓存
//优化低功耗
ANeuralNetworksCompilation_setPreference(compilation, ANEURALNETWORKS_PREFER_LOW_POWER);
//设置编译缓存
ANeuralNetworksCompilation_setCaching(compilation, cacheDir, token);
//完成编译
ANeuralNetworksCompilation_finish(compilation);//9、执行模型
// Run the compiled model against a set of inputs
ANeuralNetworksExecution* run1 = NULL;
ANeuralNetworksExecution_create(compilation, &run1);//指定读取输入值,可以是用户缓冲区或已分配的内存空间读取输入值。
// Set the single input to our sample model. Since it is small, we won't use a memory buffer
float32 myInput[3][4] = { ...the data... };
ANeuralNetworksExecution_setInput(run1, 0, NULL, myInput, sizeof(myInput));//设置写入输出值,写入用户缓冲区或已分配的内存空间。
float32 myOutput[3][4];
ANeuralNetworksExecution_setOutput(run1, 0, NULL, myOutput, sizeof(myOutput));//开始执行,等待可以在不同于开始执行的线程上完成。
// For our example, we have no other work to do and will just wait for the completion
ANeuralNetworksEvent_wait(run1_end);
ANeuralNetworksEvent_free(run1_end);
ANeuralNetworksExecution_free(run1);//可以选择通过使用同一编译实例将不同的输入集应用于已编译的模型,从而创建新的 ANeuralNetworksExecution 实例。//10、最后一步,清理内存等资源
// Cleanup
ANeuralNetworksCompilation_free(compilation);
ANeuralNetworksModel_free(model);
ANeuralNetworksMemory_free(mem1);
参考:
1、Neural Networks API | Android NDK | Android Developers (google.cn)
2、ndk-samples/nn-samples at main · android/ndk-samples (github.com)
相关文章:
安卓机器学习框架学习:Android Neural Networks API (NNAPI)
Android Neural Networks API (NNAPI) 简介: 1、Android Neural Networks API (NNAPI) 是一个 Android C API,在 Android 设备上实现机器学习; 2、NNAPI 旨在为更高层级的机器学习框架(如 TensorFlow Lite 和 Caffe2)…...
阿里云GPU服务器收费标准、学生价格及一个小时费用大全
阿里云GPU租用费用价格表,GPU计算卡包括NVIDIA V100计算卡、T4计算卡、A10计算卡和A100计算卡,GPU云服务器gn6i可享受3折优惠,阿里云百科分享阿里云GPU服务器学生优惠价格、GPU服务器收费价格表、GPU服务器多少钱一个小时等费用明细表&#x…...
Asp.net core 依赖注入 (带案例以及注释理解)
1.很多朋友不知道什么是依赖注入,接下来我用比较通俗易懂的话语 来帮助大家理解 依赖注入(Dependency Injection,简称DI)是一种设计模式,用于减少组件之间的耦合度。它的核心思想是,将组件之间的依赖关系从…...
【微信小程序】-- uni-app 项目-- 购物车 -- 首页 - 轮播图效果(五十二)
💌 所属专栏:【微信小程序开发教程】 😀 作 者:我是夜阑的狗🐶 🚀 个人简介:一个正在努力学技术的CV工程师,专注基础和实战分享 ,欢迎咨询! &…...
GO实现Redis:GO实现Redis集群(5)
采用一致性hash算法将key分散到不同的节点,客户端可以连接到集群中任意一个节点https://github.com/csgopher/go-redis本文涉及以下文件: consistenthash:实现添加和选择节点方法 standalone_database:单机database client&#x…...
高阶数据结构之 B树 B+树 B*树
文章目录B树B树节点的设计插入key的过程B树的验证B树的性能分析B树和B*树B树B*树总结B树、B树、B*树B树的应用做索引MySQL索引MyISAMInnoDBB树 在前面几章中我们介绍了AVL树和红黑树,简单复习一下,我们说到原本的二叉搜索树会存在缺陷(不能保…...
CSS3之动画属性
系列文章目录 前端系列文章——传送门 CSS系列文章——传送门 文章目录系列文章目录CSS3 中的动画第一步:定义一个动画第二步:执行这个动画第三步:暂停或启动这个动画过渡和动画的区别CSS3 中的动画 CSS3 动画是使元素从一种样式逐渐变化为…...
python --Matplotlib详解
安装 pip install matplotlib导包 import matplotlib.pyplot as plt绘制散点图 如果输入的是两个列表,一个表示 x 轴的值,一个表示 y 轴的值,那么就可以在直角坐标系中划出很多个点,然后将这些点用指定的线段连接起来就得到了散…...
手机(Android)刷NetHunter安装指南,无需ssh执行kali命令, NetHunter支持的无线网卡列表!
一、安装NetHunter 前提:确保手机已经root,已装上magisk。如果没有root,可用尝试magisk root 后执行此文 1、下载Nethunter:Get Kali | Kali Linux 然后push 到sdcard 里, 2、打开magisk,选择刚刚下好的…...
教育行业ChatGPT的新挑战
随着科技不断发展,AI的水平越来越高,尤其是最近火出圈的ChatGPT不仅仅可以与人类对话,而且还可以为人们提供关于各种信息帮助。 作为一个先进的“聊天”AI,无论是正苦恼,还是只是需要一些关于如何更有效地管理时间的建…...
内存泄漏 定位方法
目录 内存概念 物理内存 虚拟内存 内存泄漏 定位方法和手段 1.MemInFo MemTotal MemFree MemAvailable Cached 2 vmalloc info 3.Kmemleak 算法原理 使用方法 参考文献与链接: 如果你点进这篇文章,那么要么你是一个C\C程序员,…...
es-head插件插入查询以及条件查询(五)
es-head插件插入查询以及条件查询 1.es-head插件页面介绍 页面详细介绍 2.es-head查询语句 2.1.查询索引中的全部数据 curl命令交互,采用GET请求 语法格式: curl -XGET es地址:9200/索引名/_search?pretty [rootelaticsearch ~]# curl -XGET 192…...
安装python教程并解决Python安装完没有Scripts文件夹问题
安装python教程 并解决Python安装完没有Scripts文件夹问题 ** 一背景 **首先要了解这个出现的原因是下载安装的版本问题 系統是32 bit 的版本还是 64bit 的 web-based: 透过网络安装的,就是执行安装后才透过网络下载python executable: 可執行文件的ÿ…...
postman的断言、关联、参数化、使用newman生成测试报告
Potman 断言 Postman 断言简介 让 Postman工具 代替 人工 自动判断 预期结果 和 实际结果 是否一致断言代码 书写在 Tests 标签页中。 查看断言结果 Test Results 标签页 Postman 常用断言 1. 断言响应状态码 Status code:Code is 200 // 断言响应状态码为 200…...
春招大盘点:找工作除了招聘网站还有哪些渠道?
又是一年毕业季,估计同学们都正在写论文、找工作两头忙,很多同学和小C“诉苦”说现在找实习的渠道太少了,招聘网站都刷完了,也没看到很合适的岗位。那找工作除了招聘网站还有什么渠道呢?其实是有的,今天就为…...
eNSP 构建基本WLAN
配置项配置参数AP组 名称:hcia-group 应用模板:域管理模板hcia-domain、VAP模板hcia-vap 域管理模板 名称:hcia-domain 国家码:cn SSID模板 名称:hcia-ssid SSID名称:hcia-wlan 安全模板 名称:h…...
Python是不是被严重高估了?
Python起源一种shell的脚本语言 ,而现在已经发展成最通用的语言之一了,TIOBE指数的数据显示,Python是目前世界上最受欢迎的编程语言。 Python之所以这么受欢迎有很多原因。从Web开发到物联网编程再到AI等各个方面都能用到它。另外Python代码…...
给你一个购物车模块,你会如何设计测试用例?【测试用例设计】
测试购物车 从使用场景上,把自己想象成一个使用购物车的人,模拟流程,可以主要从两个方面进行考虑: 涉及操作:增(添加商品)删(删除商品)改(编辑、跳转商品&a…...
【wps】【毕业论文】三线表的绘制
目录 一、三线表 二、制作步骤 (1)点击“插入”——点击“表格”创建一个表格 (2)选中整个表格——鼠标右键选择“边框和底纹”,“表格属性”再点击“边框和底纹”——点击“自定义”——选择表格的边的宽度——如图…...
Spring Cloud Alibaba 多租户saas企业开发架构技术选型和设计方案
基于Spring Cloud Alibaba 分布式微服务高并发数据平台化(中台)思想多租户saas设计的企业开发架构,支持源码二次开发、支持其他业务系统集成、集中式应用权限管理、支持拓展其他任意子项目。 一、架构技术选型 核心框架 Spring Boot SOA Spring Cloud …...
Python MCP服务部署卡在step3?揭秘92%开发者忽略的config.toml权限校验机制(配置失效终极诊断指南)
第一章:Python MCP服务部署卡在step3的典型现象与问题定位当执行 Python MCP(Model Control Platform)服务自动化部署脚本时,step3(即服务容器化构建与镜像推送阶段)常出现长时间无响应、日志停滞于 Buildi…...
Graphormer图神经网络效果展示:含手性中心/立体异构体分子的预测能力验证
Graphormer图神经网络效果展示:含手性中心/立体异构体分子的预测能力验证 1. 模型概述 Graphormer是一种基于纯Transformer架构的图神经网络,专门为分子图(原子-键结构)的全局结构建模与属性预测而设计。该模型在OGB(…...
SmolVLA代码审查助手:自动检测C语言基础代码缺陷
SmolVLA代码审查助手:让C语言开发告别低级错误 写C语言代码,最怕什么?不是复杂的算法,也不是深奥的架构,而是那些不起眼却要命的基础错误。一个忘记释放的内存,一个数组越界的访问,或者一个不符…...
cobalt代码覆盖率报告:提升测试质量的关键指标
cobalt代码覆盖率报告:提升测试质量的关键指标 【免费下载链接】cobalt best way to save what you love 项目地址: https://gitcode.com/GitHub_Trending/cob/cobalt 引言:为什么代码覆盖率(Code Coverage)至关重要 在现…...
STM32驱动SG90舵机:从PWM原理到蓝牙远程控制实战
1. 认识SG90舵机与PWM控制 第一次拿到SG90这个小家伙时,我差点以为是个玩具电机。直到把它接上STM32,看到它能精准地停在指定角度,才意识到这玩意儿在机器人、智能家居里有多实用。SG90是一种微型舵机,三根线分别接电源࿰…...
AXOrderBook:打造A股市场高效订单簿处理系统的完整指南
AXOrderBook:打造A股市场高效订单簿处理系统的完整指南 【免费下载链接】AXOrderBook A股订单簿工具,使用逐笔行情进行订单簿重建、千档快照发布、各档委托队列展示等,包括python模型和FPGA HLS实现。 项目地址: https://gitcode.com/gh_mi…...
别再只用脚本了!用MATLAB OOP重构你的数据处理流程,效率翻倍
MATLAB面向对象编程:从脚本思维到工程级代码的跃迁 当你的MATLAB脚本膨胀到上千行,当每次修改都需要在数十个函数间跳转,当同事问你"这个变量在哪里定义的"而你却一时语塞——是时候告别脚本思维了。面向对象编程(OOP)不是MATLAB里…...
管道巡检软体机器人 YOLOv8 模型部署全流程(PT→ONNX→昇腾OM)
项目背景:本项目针对搭载摄像头的管道内部巡检软体机器人开发,实现管道内部缺陷、障碍物、异物的实时AI检测,完成从PC端训练到边缘端部署的完整链路。 开源仓库:AtomGit 公开仓库 适配设备:香橙派AIPro(搭…...
手把手教你用Python处理脑电信号:从MRCP到SMR的实战指南
手把手教你用Python处理脑电信号:从MRCP到SMR的实战指南 脑电信号处理一直是神经科学和脑机接口领域的热门研究方向。对于开发者而言,掌握Python处理脑电信号的技能不仅能提升科研效率,还能为医疗辅助设备开发打下坚实基础。本文将带你从零开…...
H5端微信登录实战:从配置到用户信息获取的全流程解析
1. 为什么需要H5端微信登录? 每次开发新项目时,用户注册环节总是让人头疼。传统的账号密码注册方式,不仅流程繁琐,还经常遇到用户忘记密码的问题。我在去年开发一个电商H5项目时,就发现超过60%的用户流失都发生在注册…...
