不加班的秘诀:如何通过AOE快速集成NCNN?

简介: NCNN是腾讯开源的一个为手机端极致优化的高性能神经网络前向计算框架。在AOE开源工程里,我们提供了NCNN组件,本文以SqueezeNet物体识别这个Sample为例,来讲一讲 NCNN组件的设计和用法。

直接集成NCNN的缺点

直接集成NCNN相对麻烦,为SqueezeNet接入NCNN,把相关的模型文件,NCNN的头文件和库,JNI调用,前处理和后处理相关业务逻辑等。把这些内容都放在SqueezeNet Sample工程里。这样简单直接的集成方法,问题也很明显,和业务耦合比较多,不具有通用性,前处理后处理都和SqueezeNcnn这个Sample有关,不能很方便地提供给其他业务组件使用。深入思考一下,如果我们把AI业务,作为一个一个单独的AI组件提供给业务的同学使用,会发生这样的情况:

ocr_1

每个组件都要依赖和包含NCNN的库,而且每个组件的开发同学,都要去熟悉NCNN的接口,写C的调用代码,写JNI。所以我们很自然地会想到要提取一个NCNN的组件出来,提取以后如图所示:

ocr_2

AOE SDK里的NCNN组件

有了AOE SDK,就可以使操作更加简便。在AOE开源SDK里,我们提供了NCNN组件,下面我们从4个方面来讲一讲NCNN组件:

1.NCNN组件的设计
2.对SqueezeNet Sample的改造
3.应用如何接入NCNN组件
4.对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用的好,任务完成早,奥秘在此。

1.支持多输入多输出。
2.使用ByteBuffer来提升效率。
3.使用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.1.bin
│       ├── squeezenet_v1.1.id.h
│       ├── squeezenet_v1.1.param.bin
│       └── synset_words.txt
└── java
    └── com
        └── didi
            └── aoe
                └── features
                    └── squeeze
                        └── SqueezeInterpreter.java

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

应用如何接入NCNN组件
对NCNN组件的接入,有两种方式

●直接接入

_

●通过AOE SDK接入

_

▲两种接入方式比较:

_

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

对NCNN组件的总结和思考

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

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

相关文章
|
5月前
|
SQL 人工智能 自然语言处理
CodeFuse-MFTCoder提升CodeGeeX2-6B代码能力
CodeGeeX2-6B 是由智普AI开源的代码大模型。它是在自然语言大模型ChatGLM2-6B的基础上,将GLM中双向attention的部分变成单向以后(该结论由笔者分析CodeGeeX2-6B GitHub issue讨论得出),加入大量代码相关数据进行了Causal Language Model的加训,最终获取的代码大模型。
117 0
|
6月前
|
SQL 设计模式 JSON
开发期质量 节选自《闻缺陷则喜》(此书可免费下载)
开发期质量 节选自《闻缺陷则喜》(此书可免费下载)
|
11月前
|
存储 开发框架 安全
WineGometa红酒链游项目开发的核心技术
WineGometa红酒链游项目是由WineGometa团队开发的。该项目的目标是为红酒爱好者提供一个安全、透明、高效的红酒交易平台,同时推广红酒文化和品牌。 WineGometa红酒链游的核心技术是区块链技术,通过智能合约的方式确保红酒数字资产的安全和可信。用户可以在WineGometa上购买、收藏、出售红酒,同时还可以参加红酒相关的活动和游戏,获取红酒相关的奖励。
|
测试技术
深聊自动化测试之:10年小鱼给你10条建议,让你在自动化界占据一个墙角
深聊自动化测试之:10年小鱼给你10条建议,让你在自动化界占据一个墙角
99 0
|
监控 前端开发 jenkins
新来个技术总监,给团队引入了这款开发神器,同事直呼哇塞
带团队时间久了,就能发现整个 Team 都渐渐疲了。前两年老板还专门买了个系统搞 OKR,现在也不大提了;Scrum 我们也搞了,用起来也就那样;项目管理工具试了好几个,禅道、Worktile、现在用 Coding,反正有一个能用的就行;微服务化改造从去年开始在吭哧吭哧搞,我们自己搞得觉得很厉害,但业务部门那边就觉得没啥差别,搞不懂你们研发部门每天在弄些什么,赶紧做我们提的需求要紧。
新来个技术总监,给团队引入了这款开发神器,同事直呼哇塞
|
前端开发 安全 vr&ar
提升生产力,7 款好用的原型图工具推荐给你
目前有很多 UI 设计工具可以帮助您设计用户界面,码匠这里分享 7 款好用的原型图工具。
529 0
提升生产力,7 款好用的原型图工具推荐给你
|
测试技术 iOS开发 Python
热饭的测开成果盘点第二十六期:IOS自动化平台
热饭的测开成果盘点第二十六期:IOS自动化平台
热饭的测开成果盘点第二十六期:IOS自动化平台
|
测试技术 Android开发
热饭的测开成果盘点第二十七期:安卓自动化平台
热饭的测开成果盘点第二十七期:安卓自动化平台
热饭的测开成果盘点第二十七期:安卓自动化平台
|
测试技术
热饭的测开成果盘点第十五期:教程版接口测试平台
本期介绍的是接口测试平台-教程版,也就是本公众号长期连载的系列,很多同学都说想看看什么样了,今天就给大家展示下当前进度:
热饭的测开成果盘点第十五期:教程版接口测试平台
|
监控 安全 测试技术
热饭的测开成果盘点第二十期:安卓&appium自动化测试平台
本期介绍的是移动端app自动化测试平台,用的appium,可以支持多手机并发执行用例,切换环境等操作,用例自动分配等功能。
热饭的测开成果盘点第二十期:安卓&appium自动化测试平台