作者丨monkery
来源丨码上Work(codework88)
AI已经侵入我们的生活,人脸识别、语言识别、智能音响等等无处不在,但很早之前的AI数据的处理、模型推理等都在云端,随着时间和需求的变化,聪明的研究者开始把AI的推理训练放到终端(手机设备、IoT设备等)来做,MNN框架是阿里推出的端侧推理引擎
本文主要目的在于介绍下端上计算的过程,了解什么是端上计算,为移动开发者入门学习提供思路,下面我们来一起探讨学习下吧,如果对你有用记得点赞鼓励❤
注:
MNN仓库地址:
https://github.com/alibaba/MNN
简述下基本流程
终端收集数据到服务端
服务端根据收集的数据使用算法进行模型训练,最终产生可以商用的模型,然后部署
这一步就是推理阶段了,终端把用户的数据传送给服务端,服务端利用模型进行推理计算,然后返回结果给终端
终端根据结果做相应的操作
由上面的流程可知,存在几个问题
数据隐私性,需要把数据上报给服务端,而且如果用户不授权的话则收取不到
网络延迟,终端必须等待网络请求完成才能做出响应,这不适合实时操作强的任务
算力集中,完全依赖服务器的算力
端上计算其实是把推理和训练过程放在终端进行,这样做有如下优势
响应速度快,不依赖云端服务的请求,可快速做出决策,目前很多应用已经在使用,如淘宝、咸鱼、抖音等
数据隐私安全,政策对数据隐私的管控越来越严格,想把数据上传到服务端越来越难
节省服务器资源
发挥联合计算的优势,虽然一台手机/IoT设备的算力有限,但是如果把所有的设备算力集合在一起,将远远超越云服务的算力,不过这个方向还在发展中
本文以iOS平台为例进行安装,相比于其他库,MNN
的安装略微有点复杂,官方文档也不是特别健全(根据个人爱好可以参照官网的教程),总之遇到问题就解决吧
官方文档地址:
https://www.yuque.com/mnn/cn/build_ios
1git clone https://github.com/alibaba/MNN.git
第一步:
进入仓库的主目录:MNN
第二步:
基础依赖项的检查:cmake
、protobuf
、C++编译器(gcc\clang)
,如果没有安装自行查找安装
官方对依赖的版本要求及检查命令如下表:
依赖项 | 建议版本 | 检查是否安装的命令 |
---|---|---|
cmake | 理论依赖3.0以上即可,但建议版本以及测试环境中的版本都为3.10+ | cmake -v |
protobuf | version >= 3.0 is required | protoc --version |
C++编译器 | GCC 或Clang 皆可,version >= 4.9,对于macOS已经默认安装Clang |
clang -v 或者 gcc -v |
第三步:
编译模型转化器:MNNConvert
,整个编译过程需要几分钟
1cd MNN/
2./schema/generate.sh
3mkdir build
4cd build
5cmake .. -DMNN_BUILD_CONVERTER=true && make -j4
第四步:(可选)
下载demo需要的模型然后转换成MNN
支持的模型,主要用于demo工程使用,可以跳过
特别注意:这一步会经常遇到两个问题:
忘记先编译好模型转化器:MNNConvert
(第三步)
下载demo模型时,容易下载失败,可能是被墙或其他原因,如果一直失败的话可以把模型手动下载下来,然后进行转换(大致操作就是修改./tools/script/get_model.sh
脚本,注释掉下载逻辑,然后手动下载完成之后,再执行下面的命令,操作不成功的可以评论或者加微信交流)
在MNN
主目录下执行如下命令
1./tools/script/get_model.sh
第五步:
用Xcode
打开project/ios/MNN.xcodeproj
,点击编译即可,这样就把完整的MNN
库编译出来了
总结:
其实这个安装过程做了三件事
编译模型转换器MNNConvert
,主要用来把其他框架产生的模型(如:tf、caffe)转换成MNN
可用的模型
下载demo模型,并利用MNNConvert
转换成MNN模型
,这一步是为了demo工程提供模型的,所以可选步骤
编译MNN
库
总体看来,如果你是用来开发和调试源码的话,那么MNNConvert
肯定要编译好,MNN库也要编译好,如果只是想看下demo工程,那么上面的那些都不用做,直接下载下面的demo工程跑起来看下
学习一个框架直接的方式就是看它的demo如何使用,上面的安装步骤提到,由于demo用到了第三方开源的模型,所以必须要先完成上面安装操作的第四步, 然后找到路径MNN/demo
下的demo工程,打开直接run即可
在demo工程可以进行源码调试、api用法等,赶快去学习吧!
不考虑技术细节站在更高的角度看MNN
,其实MNN
主要做的事情就是推理(之后可能还会增加训练),那么猜测下需要做哪些事情如:加载模型、输入数据、输出结果等。我们以demo工程为例来研究下推理的过程
整个过程我们把它比喻成浏览器加载网页
Interpreter:模型解释器,就像浏览器的引擎则用来解释网页、分析网页结构等进行渲染
Session: 会话,网页渲染完成,总要进行会话操作的,比如请求个图片、点击button等,就是一次通信过程,而在MNN
中,Session
就是一次推理的过程,持有推理数据
所以Interpreter
加载模型,Session
负责推理数据,Session
通过Interpreter
创建,一个Interpreter
可以创建多个Session
,下面看下源码解析
声明(代码看注释)
1@interface Model : NSObject {
2 std::shared_ptr _net; // 解释器,用来持有模型数据的
3 MNN::Session *_session; // 会话,推理数据的持有者
4}
在Model
类中,声明了解释器对象_net
和会话对象_session
,这是个基类,因为不同类型的模型会创建自己的Model
,并继承Model
类
创建Interpreter
1// 获取模型所在的路径
2NSString *model = [[NSBundle mainBundle] pathForResource:@"mobilenet_v2.caffe" ofType:@"mnn"];
3// 从磁盘加载模型,当然也是支持从内存读取的
4_net = std::shared_ptr(MNN::Interpreter::createFromFile(model.UTF8String));
创建会话
1- (void)setType:(MNNForwardType)type threads:(NSUInteger)threads {
2 MNN::ScheduleConfig config; // 一些配置,暂时忽略
3 config.type = type;
4 config.numThread = (int)threads;
5 if (_session) { // 释放旧的session
6 _net->releaseSession(_session);
7 }
8 // 创建新session
9 _session = _net->createSession(config);
10}
到此模型加载和准备工作就完成了,下面介绍下如何输入数据
模型加载完成,就要开始推理了,其实不要想太复杂,就几个接口而已,作为入门先看懂骨架再看细节吧
数据容器
输入数据,自然需要容器承载这些数据,在MNN
中设计了Tensor
类用来作为数据的容器,看下面类的注释
1/**
2 * data container. 这个注释已经说明,这个类是数据的容器
3 * data for host tensor is saved in `host` field. its memory is allocated malloc directly.
4 * data for device tensor is saved in `deviceId` field. its memory is allocated by session's backend.
5 * usually, device tensors are created by engine (like net, session).
6 * meanwhile, host tensors could be created by engine or user.
7 */
8class MNN_PUBLIC Tensor {
9public:
10 struct InsideDescribe;
11
12 /** dimension type used to create tensor */
13 enum DimensionType {
14 /** for tensorflow net type. uses NHWC as data format. */
15 TENSORFLOW,
16 /** for caffe net type. uses NCHW as data format. */
17 CAFFE,
18 /** for caffe net type. uses NC4HW4 as data format. */
19 CAFFE_C4
20 };
21
22 /** handle type */
23 enum HandleDataType {
24 /** default handle type */
25 HANDLE_NONE = 0,
26 /** string handle type */
27 HANDLE_STRING = 1
28 };
29 ....
30}
输入数据&运行
数据输入返回的就是Tensor
对象,核心代码就一句(多种输入方式不多介绍,本文以入门为主)
输入数据函数getSessionInput
的定义
1Tensor* Interpreter::getSessionInput(const Session* session, const char* name){}
demo工程的示例代码
1// 输入数据,返回Tensor对象input
2auto input = _net->getSessionInput(_session, nullptr);
3MNN::Tensor tensorCache(input);
4input->copyToHostTensor(&tensorCache);
5for (int i = 0; i < cycles; i++) {
6 input->copyFromHostTensor(&tensorCache);
7 // 开始run
8 _net->runSession(_session);
9}
10...
即在推理run完成之后,我们需要获取结果,返回的也是Tensor
对象
获取结果的函数getSessionOutput
定义
1Tensor* Interpreter::getSessionOutput(const Session* session, const char* name) {}
demo工程示例代码
1// 获取结果对象output
2MNN::Tensor *output = _net->getSessionOutput(_session, nullptr);
3MNN::Tensor copy(output);
4output->copyToHostTensor(©);
5float *data = copy.host();
6...
这个过程旨在介绍整个框架的使用过程,结合demo工程理解更快,并没有过多深入,希望能快速入门
有时候会思考一些问题:其实进行智能计算,我们只需要一个合适的模型然后利用它进行推理计算,那么模型就是可以复用的,没必要每个人都要重新训练一套模型
对于这个问题,阿里就把超级成熟的模型放出来给大家用了,这些模型已经在淘宝等app上实践过,它就是MNNKit, 基于端上推理引擎MNN提供的系列应用层解决方案,目前开放了三个模型,有需要的开发者可以直接拿来玩了
MNNKit仓库地址:
https://github.com/alibaba/MNNKit
Kit SDK | 功能 |
---|---|
FaceDetection | 人脸识别 |
HandGestureDetection | 手势识别 |
PortraitSegmentation | 人像分割 |
(直接引用了GitHub库的描述)
MNN层:最核心层,提供了模型加载和推理
MNNKit Core:主要针对MNN的C++接口的封装和抽象,转化成更高级别的OC或Java实现的API,方便调用者使用
业务层:主要针对具体的算法模型的封装,主要给业务使用的
端上计算需要做什么?对于移动开发者来说初次接触AI开发很是陌生,该怎么入手AI开发呢,个人目前也在学习中,有一些深刻又吐血的经验分享:
如果你对数学有一定的熟悉的话,千万别one by one的从头开始学数学,这真的太低效了,建议先从开发者最熟悉的代码层面入手,了解AI的基本工作流程,如学学
MNN
怎么用的,你就会知道原来就是拿模型去推理然后得到结果反馈给用户然后在学会怎么训练模型,建议从简单的机器学习算法入手,根据算法需要用的数学公式,然后查这些公式的用法,边学边用更好理解
整体下来介绍了什么是端上计算及优势,对MNN库有了基本的介绍,到这相信大家已经有了基本的了解。觉得有用的帮忙点在看吧,这是对笔者最大的鼓励!
近期精彩内容推荐:
公务员和程序员,你会选哪个呢?
复工期来临,腾讯员工晒的照片引网友关注
技术总监:求求你别写这么多if...else..了
装X黑客指南:如何在小白面前秀一手
在看点这里好文分享给更多人↓↓