作为我司头发储量前三的程序员

始终仗着头发多奋斗在加班的第一线

时时灵魂拷问自己

年轻人,你凭什么不加班?

虽然我没有女朋友
但是,我有代码呀

但我不明白的是,隔壁工位那个,到岗比我迟,下班比我早,天天准点儿下班接女朋友,工作还完成的不错的样子,当然,头发也还不错。除了长得比我显老,难道他有什么制胜法宝吗?趁着午休,以一礼拜咖啡为代价,我偷师了他的制胜法宝。GET了秘诀,或许我也可以事业爱情双丰收了。

aaarticlea/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==" alt="" data-src="https://res.wx.qq.com/mpres/htmledition/images/icon/common/emotion_panel/smiley/smiley_5.png" data-ratio="1" data-w="20" />

直接集成NCNN的缺点

直接集成NCNN熬老少男颜哇,想当年我一边泪流满面地集成,一边想用女友的SK2给自己的脸补补(不,你没有,both SK2和女友),咋回事儿呢,为SqueezeNet接入NCNN,把相关的模型文件,NCNN的头文件和库,JNI调用,前处理和后处理相关业务逻辑等。把这些内容都放在SqueezeNet Sample工程里。这样简单直接的集成方法,问题也很明显,和业务耦合比较多,不具有通用性,前处理后处理都和SqueezeNcnn这个Sample有关,不能很方便地提供给其他业务组件使用。深入思考一下,如果我们把AI业务,作为一个一个单独的AI组件提供给业务的同学使用,会发生这样的情况:

每个组件都要依赖和包含NCNN的库,而且每个组件的开发同学,都要去熟悉NCNN的接口,写C的调用代码,写JNI。所以我们很自然地会想到要提取一个NCNN的组件出来,提取以后呢长得顺眼了很多,大概是这个样子。

AOE SDK里的NCNN组件

有了AOE SDK,我也可以一顿操作猛如虎了!在AOE开源SDK里,我们提供了NCNN组件,下面我们从4个方面来讲一讲NCNN组件:

      ●NCNN组件的设计

      ●对SqueezeNet Sample的改造

      ●应用如何接入NCNN组件

      ●对NCNN组件的一些思考

★ NCNN组件的设计

不懂NCNN的组件设计,即使一顿操作猛如虎,你可能最后也只有两块五。那它的组件是什么嘞?NCNN组件的设计理念是组件里不包含具体的业务逻辑,只包含对NCNN接口的封装和调用。具体的业务逻辑,由业务方在外部实现。在接口定义和设计上,我们参考了TF Lite的源码和接口设计。目前提供的对外调用接口,长这个样子:

// 加载模型和param
void loadModelAndParam(...)
// 初始化是否成功
boolean isLoadModelSuccess()
// 输入rgba数据
void inputRgba(...)
// 进行推理
void run(...)
// 多输入多输出推理
void runForMultipleInputsOutputs(...)
// 得到推理结果
Tensor getOutputTensor(...)
// 关闭和清理内存
void close()

而机智骚年本人,用的是这个:

├── AndroidManifest.xml
├── cpp
│ └── ncnn
│ ├── c_api_internal.h
│ ├── include
│ ├── interpreter.cpp
│ ├── Interpreter.h
│ ├── jni_util.cpp
│ ├── jni_utils.h
│ ├── nativeinterpreterwrapper_jni.cpp
│ ├── nativeinterpreterwrapper_jni.h
│ ├── tensor_jni.cpp
│ └── tensor_jni.h
├── java
│ └── com
│ └── didi
│ └── aoe
│ └── runtime
│ └── ncnn
│ ├── Interpreter.java
│ ├── NativeInterpreterWrapper.java
│ └── Tensor.java
└── jniLibs
├── arm64-v8a
│ └── libncnn.a
└── armeabi-v7a
└── libncnn.a

●Interpreter,提供给外部调用,提供模型加载,推理这些方法。

●NativeInterpreterWrapper是具体的实现类,里面对native进行调用。

●Tensor,主要是一些数据和native层的交互。

AOE NCNN用的好,任务完成早,奥秘在此。

 ●支持多输入多输出。

     ●使用ByteBuffer来提升效率。

     ●使用Object作为输入和输出(实际支持了ByteBuffer和多维数组)。

光说不练假把式,AOE NCNN的实现过程,且听我细细道来。

 如何支持多输入多输出

为了支持多输入和多输出,我们在Native层创建了一个Tensor对象的列表,每个Tensor对象里保存了相关的输入和输出数据。Native层的Tensor对象,通过tensor_jni提供给java层调用,java层维护这个指向native层tensor的“指针”地址。这样在有多输入和多输出的时候,只要拿到这个列表里的对应的Tensor,就可以就行数据的操作了。

 ByteBuffer的使用

ByteBuffer,字节缓存区处理子节的,比传统的数组的效率要高。
DirectByteBuffer,使用的是堆外内存,省去了数据到内核的拷贝,因此效率比用ByteBuffer要高。

当然ByteBuffer的使用方法不是我们要说的重点,我们说说使用了ByteBuffer以后,给我们带来的好处:
1.接口里的字节操作更加便捷,例如里面的putInt,getInt,putFloat,getFloat,flip等一系列接口,可以很方便的对数据进行操作。
2.和native层做交互,使用DirectByteBuffer,提升了效率。我们可以简单理解为java层和native层可以直接对一块“共享”内存进行操作,减少了中间的字节的拷贝过程。

 如何使用Object作为输入和输出
目前我们只支持了ByteBuffer和MultiDimensionalArray。在实际的操作过程中,如果是ByteBuffer,我们会判断是否是direct buffer,来进行不同的读写操作。如果是MultiDimensionalArray,我们会根据不同的数据类型(例如int, float等),维度等,来对数据进行读写操作。

 对SqueezeNet Sample的改造

集成AOE NCNN组件以后,让SqueezeNet依赖NCNN Module,SqueezeNet Sample里面只包含了模型文件,前处理和后处理相关的业务逻辑,前处理和后处理可以用java,也可以用c来实现,由具体的业务实现来决定。新的代码结构变得非常简洁,目录如下:

├── AndroidManifest.xml
├── assets
│ └── squeeze
│ ├── model.config
│ ├── squeezenet_v1..bin
│ ├── squeezenet_v1..id.h
│ ├── squeezenet_v1..param.bin
│ └── synset_words.txt
└── java
└── com
└── didi
└── aoe
└── features
│ ├── squeezenet_v1..id.h
│ ├── squeezenet_v1..param.bin
│ └── synset_words.txt
└── java
└── com
└── didi
└── aoe
└── features
└── squeeze
└── SqueezeInterpreter.java

↑ 本Sample也适用于其他的AI业务组件对NCNN组件的调用。

(牛逼就完事儿)

 应用如何接入NCNN组件

对NCNN组件的接入,有两种方式

●直接接入

●通过AOE SDK接入

▲两种接入方式比较:

不BATTLE了,我单方面宣布,AOESDK完胜!

 

 对NCNN组件的总结和思考

通过对NCNN组件的封装,现在业务集成NCNN更加快捷方便了。之前我们一个新的业务集成NCNN,可能需要半天到一天的时间。使用AOE NCNN组件以后,可能只需要1-2小时的时间。当然NCNN组件目前还存在很多不完善的地方,我们对NCNN还需要去加深学习和理解。后面会通过不断的学习,持续的对NCNN组件进行改造和优化。

- - - - - - - - - - - - - - - - - - - - - - - - - - - A o E - - - - - - -  - - - - - - - - - - - - - - - - - - - -

原创不易,欢迎打赏

                  https://github.com/didi/AoE←据说点了这里的程序员们都准点下班了/

                                                欢迎添加小助手微信进入AOE开源交流群! 

												

不加班的秘诀:如何通过AOE快速集成NCNN?的更多相关文章

  1. 快速集成iOS基于RTMP的视频推流

    前言 这篇blog是iOS视频直播初窥:<喵播APP>的一个补充. 因为之前传到github上的项目中没有集成视频的推流.有很多朋友简信和微博上问我推流这部分怎么实现的. 所以, 我重新集 ...

  2. 快速集成图片浏览器快速集成图片浏览器->MJPhotoBrowser的使用

    介绍: 一个比较完整的图片浏览器,高仿了新浪微博的图片浏览效果,功能包括:下载浏览互联网图片,点击缩略图全屏显示图片.当加载较大图片时会出现圆形进度条,滑动浏览所有图片.保存图片到本地相册.GIF图片 ...

  3. iOS简单快速集成Cordova

    如果你对于什么是Cordova还不了解,可以先移步到我另一个文章:Cordoval在iOS中的运用整理 里面有详细的介绍跟如何搭建Cordova:而本文则是要介绍JiaCordova插件,如果你有一点 ...

  4. Spring Boot 揭秘与实战(三) 日志框架篇 - 如何快速集成日志系统

    文章目录 1. 默认的日志框架 logback2. 常用的日志框架 log4j 1.1. 日志级别 1.2. 日志文件 3. 源代码 Java 有很多日志系统,例如,Java Util Logging ...

  5. Android Studio快速集成讯飞SDK实现文字朗读功能

    今天,我们来学习一下怎么在Android Studio快速集成讯飞SDK实现文字朗读功能,先看一下效果图: 第一步 :了解TTS语音服务 TTS的全称为Text To Speech,即“从文本到语音” ...

  6. ShareSDK入门指南:Android 10分钟快速集成

    ShareSDK 官方已提供Android 快速集成教程,以官方教程为参考,本文重点指导大家在集成中遇到的问题. Android 快速集成官方教程:http://wiki.mob.com/Androi ...

  7. 搜狐新闻APP是如何使用HUAWEI DevEco IDE快速集成HUAWEI HiAI Engine

    6月12日,搜狐新闻APP最新版本在华为应用市场正式上线啦! 那么,这一版本的搜狐新闻APP有什么亮点呢? 先抛个图,来直接感受下—— ​ 模糊图片,瞬间清晰! 效果杠杠的吧. 而藏在这项神操作背后的 ...

  8. 如何通过Gitalk评论插件,5分钟为你的博客快速集成评论功能

    欢迎关注个人微信公众号: 小哈学Java, 文末分享阿里 P8 高级架构师吐血总结的 <Java 核心知识整理&面试.pdf>资源链接!! 个人网站: https://www.ex ...

  9. 键盘工具栏的快速集成--IQKeyboardManager

    转自:http://www.cnblogs.com/gaoxiaoniu/p/5333187.html 键盘工具栏的快速集成--IQKeyboardManager IQKeyboardManager, ...

随机推荐

  1. ganglia 客户端部署

    #!/bin/bash #配置参数 #serverIP=192.168.1.16 #network=ens32 #关闭selinux #setenforce #sed -i 's/SELINUX=en ...

  2. Stack Overflow 上 370万浏览量的一个问题:如何比较 Java 的字符串?

    在逛 Stack Overflow 的时候,发现了一些访问量像喜马拉雅山一样高的问题,比如说这个:如何比较 Java 的字符串?访问量足足有 370万+,这不得了啊!说明有很多很多的程序员被这个问题困 ...

  3. 聚类-K-Means

    1.什么是K-Means? K均值算法聚类 关键词:K个种子,均值聚类的概念:一种无监督的学习,事先不知道类别,自动将相似的对象归到同一个簇中 K-Means算法是一种聚类分析(cluster ana ...

  4. Spring(Bean)3

    bean的继承<!-- bean 的继承 作为模板来使用. 可以通过abstract="true"来指定把该bean配置为·抽象的. 通过abstract="tru ...

  5. ansible源码安装、普通用户实现批量控制

    一.ansible简介 ansible是一款自动化运维工具,基于Python开发,集合了众多运维工具(puppet.chef.func.fabric)的优点,实现了批量系统配置.批量程序部署.批量运行 ...

  6. JavaScript新手经常遇到的问题(二)

    1.Form表单只提交数据而不进行页面跳转的方法 <script type="text/javascript" src="js/jquery/jquery-1.8. ...

  7. Flink入门(二)——Flink架构介绍

    1.基本组件栈 了解Spark的朋友会发现Flink的架构和Spark是非常类似的,在整个软件架构体系中,同样遵循着分层的架构设计理念,在降低系统耦合度的同时,也为上层用户构建Flink应用提供了丰富 ...

  8. 如何在DevOps中实施连续测试

    在过去的十年中,对软件开发的需求已急剧发展.软件已成为公司获得竞争优势的关键优势,特别是如果您的公司属于SaaS范畴.通过在SDLC中实施瀑布等传统流程,组织现在正在向敏捷过渡,以便以更快的速度在市场 ...

  9. .Net Core的API网关Ocelot使用 (一)

    1.什么是API网关 API网关是微服务架构中的唯一入口,它提供一个单独且统一的API入口用于访问内部一个或多个API.它可以具有身份验证,监控,负载均衡,缓存,请求分片与管理,静态响应处理等.API ...

  10. Android 网络编程(一)

    概述 一.Android平台网络相关API接口 1.java.net.*(标准Java接口) java.net.*提供与联网有关的类,包括流.数据包套接字(socket).Internet协议.常见H ...