一、背景

1.1 AoE是什么

AoE (AI on Edge) 是一个滴滴开源的终端侧AI集成运行时环境(IRE)。以 “稳定性、易用性、安全性” 为设计原则,帮助开发者将不同框架的深度学习算法轻松部署到终端高效执行,Github 地址是 https://github.com/didi/aoe

为什么要做一个 AI 终端集成运行时框架,原因有两个:

一是随着人工智能技术快速发展,这两年涌现出了许多运行在终端的推理框架,在给开发者带来更多选择的同时,也增加了将AI布署到终端的成本;

二是通过推理框架直接接入AI的流程比较繁琐,涉及到动态库接入、资源加载、前处理、后处理、资源释放、模型升级,以及如何保障稳定性等问题。

目前AoE SDK已经在滴滴银行卡OCR上应用使用,想更加清晰地理解 AoE 和推理框架、宿主 App 的关系,可以通过下面的业务集成示意图来了解它。

1.2 终端推理框架一览

下面是终端运行的8种主流推理框架(排名不分先后)。

序号 名称 开发者 开源时间 描述
1 TensorFlow Lite Google 2017 TensorFlow Lite使用Android Neural Networks API,默认调用CPU,目前最新的版本已经支持GPU。
2 Core ML Apple 2017 Core ML是2017年Apple公司在WWDC上与iOS11同时发布的移动端机器学习框架,底层使用Accelerate和Metal分别调用CPU和GPU。Core ML需要将你训练好的模型转化为Core ML model
3 Caffe2 Facebook 2017 Caffe2是facebook在2017年发布的一个跨平台的框架,不仅仅支持Windows,Linux,Macos三大桌面系统,也支持移动端iOS,Android,可以说是集训练和推理于一身。
4 NCNN 腾讯 2017 NCNN是2017年腾讯优图实验室开源的移动端框架,使用C++ 实现,支持Android和iOS两大平台。
5 Paddle-Mobile 百度 2017 Paddle-Mobile是2017年百度PaddlePaddle组织下的移动端深度学习开源框架,当时叫做mobile-deep-learning(MDL)。支持安卓和iOS平台,CPU和GPU使用,提供量化工具。
6 QNNPACK Facebook 2018 QNNPACK是Facebook在2018年发布的int8量化低精度高性能开源框架,全称Quantized Neural Network PACKage,用于手机端神经网络计算的加速,已经被整合到PyTorch 1.0中,在Caffe2里就能直接使用。
7 MACE 小米 2018 MACE是2018年小米在开源中国开源世界高峰论坛中宣布开源的移动端框架,以OpenCL和汇编作为底层算子,提供了异构加速可以方便在不同的硬件上运行模型,同时支持各种框架的模型转换。
8 MNN 阿里巴巴 2019 MNN是2019年阿里开源的移动端框架,不依赖第三方计算库,使用汇编实现核心运算,支持Tensorflow、Caffe、ONNX等主流模型文件格式,支持CNN、RNN、GAN等常用网络。

1.3 AoE 如何支持各种推理框架

从本质上来说,无论是什么推理框架,都必然包含下面 5 个处理过程,对这些推理过程进行抽象,是 AoE 支持各种推理框架的基础。

目前,AoE 实现了两种推理框架 NCNN 和 TensorFlow Lite 的支持,以这两种推理框架为例,说明一下 5 个推理过程在各自推理框架里的形式。

推理框架 初使化 前处理 执行推理 后处理 释放资源
NCNN int load_param(const unsigned char* mem);int load_model(const unsigned char* mem); ... int input(const char* blob_name, const Mat& in);int extract(const char* blob_name, Mat& feat); ... void release();
TF Lite public Interpreter(@NonNull ByteBuffer byteBuffer, Interpreter.Options options) ... public void run(Object input, Object output) ... public void close();

1.4 AoE 支持哪些平台

目前,AoE 已经开源的运行时环境 SDK 包括 Android 和 iOS 平台,此外 Linux 平台运行时环境 SDK也已和大家正式见面。

二、工作原理

2.1 抽象推理框架的处理过程

前面已经介绍了,不同推理框架包含着共性的过程,它们分别是初使化、前处理、执行推理、后处理、释放资源。对 AoE 集成运行环境来说,最基本的便是抽象推理操作,通过 依赖倒置 的设计,使得业务只依赖AoE的上层抽象,而不用关心具体推理框架的接入实现。这种设计带来的最大的好处是开发者随时可以添加新的推理框架,而不用修改框架实现,做到了业务开发和 AoE SDK 开发完全解耦。

在 AoE SDK 中这一个抽象是 InterpreterComponent(用来处理模型的初使化、执行推理和释放资源)和 Convertor(用来处理模型输入的前处理和模型输出的后处理),InterpreterComponent 具体实现如下:

  1. /**
  2. * 模型翻译组件
  3. */
  4. interface InterpreterComponent<TInput, TOutput> extends Component {
  5. /**
  6. * 初始化,推理框架加载模型资源
  7. *
  8. * @param context 上下文,用与服务绑定
  9. * @param modelOptions 模型配置列表
  10. * @return 推理框架加载
  11. */
  12. boolean init(@NonNull Context context, @NonNull List<AoeModelOption> modelOptions);
  13.  
  14. /**
  15. * 执行推理操作
  16. *
  17. * @param input 业务输入数据
  18. * @return 业务输出数据
  19. */
  20. @Nullable
  21. TOutput run(@NonNull TInput input);
  22.  
  23. /**
  24. * 释放资源
  25. */
  26. void release();
  27.  
  28. /**
  29. * 模型是否正确加载完成
  30. *
  31. * @return true,模型正确加载
  32. */
  33. boolean isReady();
  34. }

  

Convertor的具体实现如下:

  1. interface Convertor<TInput, TOutput, TModelInput, TModelOutput> {
  2. /**
  3. * 数据预处理,将输入数据转换成模型输入数据
  4. *
  5. * @param input 业务输入数据
  6. * @return 模型输入数据
  7. */
  8. @Nullable
  9. TModelInput preProcess(@NonNull TInput input);
  10.  
  11. /**
  12. * 数据后处理,将模型输出数据转换成业务输出数据
  13. *
  14. * @param modelOutput 模型输出数据
  15. * @return
  16. */
  17. @Nullable
  18. TOutput postProcess(@Nullable TModelOutput modelOutput);
  19. }

 

2.2 稳定性保障

众所周知,Android平台开发的一个重要的问题是机型适配,尤其是包含大量Native操作的场景,机型适配的问题尤其重要,一旦应用在某款机型上面崩溃,造成的体验损害是巨大的。有数据表明,因为性能问题,移动App每天流失的活跃用户占比5%,这些流失的用户,6 成的用户选择了沉默,不再使用应用,3 成用户改投竞品,剩下的用户会直接卸载应用。因此,对于一个用户群庞大的移动应用来说,保证任何时候App主流程的可用性是一件最基本、最重要的事。结合 AI 推理过程来看,不可避免地,会有大量的操作发生在 Native 过程中,不仅仅是推理操作,还有一些前处理和资源回收的操作也比较容易出现兼容问题。为此,AoE 运行时环境 SDK 为 Android 平台上开发了独立进程的机制,让 Native 操作运行在独立进程中,同时保证了推理的稳定性(偶然性的崩溃不会影响后续的推理操作)和主进程的稳定性(主进程任何时候不会崩溃)。

具体实现过程主要有三个部分:注册独立进程、异常重新绑定进程以及跨进程通信优化。

第一个部分,注册独立进程,在 Manifest 中增加一个 RemoteService 组件,代码如下:

  1. <application>
  2. <service
  3. android:name=".AoeProcessService"
  4. android:exported="false"
  5. android:process=":aoeProcessor" />
  6.  
  7. </application>

第二个部分,异常重新绑定独立进程,在推理时,如果发现 RemoteService 终止了,执行 “bindService()” 方法,重新启动 RemoteService。

  1. @Override
  2. public Object run(@NonNull Object input) {
  3. if (isServiceRunning()) {
  4. ...(代码省略)//执行推理
  5. } else {
  6. bindService();//重启独立进程
  7. }
  8. return null;
  9. }

第三个部分,跨进程通信优化,因为独立进程,必然涉及到跨进程通信,在跨进程通信里最大的问题是耗时损失,这里,有两个因素造成了耗时损失:

  • 传输耗时
  • 序列化/反序列化耗时

相比较使用binder机制的传输耗时,序列化/反序列化占了整个通信耗时的90%以上。由此可见,对序列化/反序列化的优化是跨进程通信优化的重点。

对比了当下主流的序列化/反序列化工具,最终AoE集成运行环境使用了kryo库进行序列化/反序列。 以下是对比结果,数据参考oschina的文章《各种 Java 的序列化库的性能比较测试结果》。

三、MNIST集成示例

3.1 对TensorFlowLiteInterpreter的继承

当我们要接入一个新的模型时,首先要确定的是这个模型运行在哪一个推理框架上,然后继承这个推理框架的InterpreterComponent实现,完成具体的业务流程。MNIST是运行在TF Lite框架上的模型,因此,**我们实现AoE的TF Lite的Interpreter抽象类,将输入数据转成模型的输入,再从模型的输出读取业务需要的数据。**初使化、推理执行和资源回收沿用TensorFlowLiteInterpreter的默认实现。

  1. public class MnistInterpreter extends TensorFlowLiteInterpreter<float[], Integer, float[], float[][]> {
  2.  
  3. @Nullable
  4. @Override
  5. public float[] preProcess(@NonNull float[] input) {
  6. return input;
  7. }
  8.  
  9. @Nullable
  10. @Override
  11. public Integer postProcess(@Nullable float[][] modelOutput) {
  12. if (modelOutput != null && modelOutput.length == 1) {
  13. for (int i = 0; i < modelOutput[0].length; i++) {
  14. if (Float.compare(modelOutput[0][i], 1f) == 0) {
  15. return i;
  16. }
  17. }
  18. }
  19. return null;
  20. }
  21. }

  

3.2 运行时环境配置

接入MNIST的第二个步骤是配置推理框架类型和模型相关参数,代码如下:

  1. mClient = new AoeClient(requireContext(), "mnist",
  2. new AoeClient.Options()
  3. .setInterpreter(MnistInterpreter.class)/*
  4. .useRemoteService(false)*/,
  5. "mnist");

  

3.3 推理执行

以下是MINST初使化推理框架、推理执行和资源回收的实现:

  1. //初使化推理框架
  2. int resultCode = mClient.init();
  3. //推理执行
  4. Object result = mClient.process(mSketchModel.getPixelData());
  5. if (result instanceof Integer) {
  6. int num = (int) result;
  7. Log.d(TAG, "num: " + num);
  8. mResultTextView.setText((num == -1) ? "Not recognized." : String.valueOf(num));
  9. }
  10. //资源回收
  11. if (mClient != null) {
  12. mClient.release();
  13. }

  

四、加入我们

帮助AI在终端落地,开源AoE集成运行环境是我们走出的第一步!未来,为终端的开发者提供更多推理框架的支持,提供更多有价值的特性,是我们不懈追求的目标。如果您对这个项目感兴趣,如果您在终端AI运行环境方面有想法,如果您在使用时有疑问,诚挚邀请您加入我们。

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

一文读懂AOE到底是什么!的更多相关文章

  1. 一文读懂HTTP/2及HTTP/3特性

    摘要: 学习 HTTP/2 与 HTTP/3. 前言 HTTP/2 相比于 HTTP/1,可以说是大幅度提高了网页的性能,只需要升级到该协议就可以减少很多之前需要做的性能优化工作,当然兼容问题以及如何 ...

  2. 一文读懂高性能网络编程中的I/O模型

    1.前言 随着互联网的发展,面对海量用户高并发业务,传统的阻塞式的服务端架构模式已经无能为力.本文(和下篇<高性能网络编程(六):一文读懂高性能网络编程中的线程模型>)旨在为大家提供有用的 ...

  3. 从HTTP/0.9到HTTP/2:一文读懂HTTP协议的历史演变和设计思路

    本文原作者阮一峰,作者博客:ruanyifeng.com. 1.引言 HTTP 协议是最重要的互联网基础协议之一,它从最初的仅为浏览网页的目的进化到现在,已经是短连接通信的事实工业标准,最新版本 HT ...

  4. [转帖]一文读懂 HTTP/2

    一文读懂 HTTP/2 http://support.upyun.com/hc/kb/article/1048799/ 又小拍 • 发表于:2017年05月18日 15:34:45 • 更新于:201 ...

  5. [转帖]从HTTP/0.9到HTTP/2:一文读懂HTTP协议的历史演变和设计思路

    从HTTP/0.9到HTTP/2:一文读懂HTTP协议的历史演变和设计思路   http://www.52im.net/thread-1709-1-2.html     本文原作者阮一峰,作者博客:r ...

  6. 一文读懂Java动态代理

    作者 :潘潘 日期 :2020-11-22 事实上,对于很多Java编程人员来说,可能只需要达到从入门到上手的编程水准,就能很好的完成大部分研发工作.除非自己强主动获取,或者工作倒逼你学习,否则我们好 ...

  7. 一文读懂AI简史:当年各国烧钱许下的愿,有些至今仍未实现

    一文读懂AI简史:当年各国烧钱许下的愿,有些至今仍未实现 导读:近日,马云.马化腾.李彦宏等互联网大佬纷纷亮相2018世界人工智能大会,并登台演讲.关于人工智能的现状与未来,他们提出了各自的观点,也引 ...

  8. 一文读懂 深度强化学习算法 A3C (Actor-Critic Algorithm)

    一文读懂 深度强化学习算法 A3C (Actor-Critic Algorithm) 2017-12-25  16:29:19   对于 A3C 算法感觉自己总是一知半解,现将其梳理一下,记录在此,也 ...

  9. [转帖]MerkleDAG全面解析 一文读懂什么是默克尔有向无环图

    MerkleDAG全面解析 一文读懂什么是默克尔有向无环图 2018-08-16 15:58区块链/技术 MerkleDAG作为IPFS的核心数据结构,它融合了Merkle Tree和DAG的优点,今 ...

随机推荐

  1. [ch04-05] 梯度下降的三种形式

    系列博客,原文在笔者所维护的github上:https://aka.ms/beginnerAI, 点击star加星不要吝啬,星越多笔者越努力. 4.5 梯度下降的三种形式 我们比较一下目前我们用三种方 ...

  2. 「Python 编程」编码实现网络请求库中的 URL 解析器

    摘要:怎么写出更短的代码并不是这次要讨论的话题.今天我们来研究一下:运行代码的计算机是如何找到目标服务器的? 相信各位 Python 开发者都用过 Requests 库,有些朋友还用过 WebSock ...

  3. ZooKeeper初步

    ZooKeeper 简介: 顾名思义 zookeeper 就是动物园管理员,他是用来管 hadoop(大象).Hive(蜜蜂).pig(小猪)的管理员, Apache Hbase 和 Apache S ...

  4. nitacm第十六届浙江大学宁波理工学院程序设计大赛总结

    校赛时间:2019.11.30周六下午12:00-16:00 重现赛链接:https://ac.nowcoder.com/acm/contest/2995#question 体验: 11点多到达石鳞大 ...

  5. leetcode字节跳动专题(持续更新)

    挑战字符串 无重复字符的最长子串 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度. 示例 1: 输入: "abcabcbb" 输出: 3 解释: 因为无重复字符的最 ...

  6. 这十道经典Python笔试题,全做对算我输

    经常有小伙伴学了Python不知道是否能去找工作,可以来看下这十道题检验你的成果: 1.常用的字符串格式化方法有哪些?并说明他们的区别 a. 使用%,语法糖 print("我叫%s,今年%d ...

  7. ARTS-S c++调用pytorch接口

    想跑通第1个参考资料上讲的例子,一定要注意gcc和gperftools的版本.因为LibTorch用了c++17的over-aligned新特性. centos默认的gcc是4.8.5不支持这个新特性 ...

  8. JS页面跳转和打开新窗口方式

    1.window.location.href=URL : 在本窗体打开一个新的页面,也是最常用的一种方法: 2.window.open(URL)  :  在一个新的窗口打开一个新的页面: 3.loca ...

  9. 【JS】395-重温基础:事件

    本文是 重温基础 系列文章的第二十篇. 这是第三个基础系列的第一篇,欢迎持续关注呀!重温基础 系列的[初级]和[中级]的文章,已经统一整理到我的[Cute-JavaScript](http://js. ...

  10. 【JS】302- 回调地狱解决方案之Promise

    为什么出现Promise 在javascript开发过程中,代码是单线程执行的,同步操作,彼此之间不会等待,这可以说是它的优势,但是也有它的弊端,如一些网络操作,浏览器事件,文件等操作等,都必须异步执 ...