当前位置: 首页 > news >正文

安卓机器学习框架学习: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&#xff09…...

阿里云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: 可執行文件的&#xff…...

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 …...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄

文|魏琳华 编|王一粟 一场大会,聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中,汇集了学界、创业公司和大厂等三方的热门选手,关于多模态的集中讨论达到了前所未有的热度。其中,…...

C++初阶-list的底层

目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...

调用支付宝接口响应40004 SYSTEM_ERROR问题排查

在对接支付宝API的时候,遇到了一些问题,记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误

HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...

服务器硬防的应用场景都有哪些?

服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...

【AI学习】三、AI算法中的向量

在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...

HashMap中的put方法执行流程(流程图)

1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...

iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈

在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...

Go 语言并发编程基础:无缓冲与有缓冲通道

在上一章节中,我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道,它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好&#xff0…...

为什么要创建 Vue 实例

核心原因:Vue 需要一个「控制中心」来驱动整个应用 你可以把 Vue 实例想象成你应用的**「大脑」或「引擎」。它负责协调模板、数据、逻辑和行为,将它们变成一个活的、可交互的应用**。没有这个实例,你的代码只是一堆静态的 HTML、JavaScript 变量和函数,无法「活」起来。 …...