学习MACE也有一个月了,将其划分三步来学习。本文是MACE学习的第一步即MACE环境的搭建。之后还有两步mace的编译和mace工程化。

  MACE(2)-----模型编译:https://www.cnblogs.com/missidiot/p/9509831.html

  MACE(3)-----工程化:https://www.cnblogs.com/missidiot/p/9717633.html

文章内容翻译自 MACE 官方手册,记录本人阅读与开发过程,力求不失原意,但推荐阅读原文。

  MACE官方文档:https://media.readthedocs.org/pdf/mace/latest/mace.pdf

  小米MACE Github地址:https://github.com/xiaomi/mace

  小米MACE安装说明:https://mace.readthedocs.io/en/latest/

  

MACE

目录

  介绍

  环境搭建

  实例运行

一、简介(Introduction)

  MACE(移动AI计算引擎)是小米开发的一款针对移动异构计算平台优化的深度学习推理框架。MACE覆盖了常见的移动端计算设备(CPU,GPU和DSP),并且提供了完整的工具链和文档,帮助用户将深度学习模型部署到手机,平板电脑,个人电脑和物联网设备。MACE已经在小米内部广泛使用并且被充分验证具有业界领先的性能和稳定性。

框架(Architecture)

MACE(1)-----环境搭建-LMLPHP

  上图描述了MACE的基本框架。

1. MACE Model

  MACE定义了自有的模型格式(类似于Caffe2),通过MACE提供的工具可以将Caffe和TensorFlow的模型 转为MACE模型。

2. MACE Interpreter

  MACE Interpreter主要负责解析运行神经网络图(DAG)并管理网络中的Tensors。

3. Run Time

  CPU/GPU/DSP Runtime对应于各个计算设备的算子实现。

使用流程

MACE(1)-----环境搭建-LMLPHP

1. 配置模型部署文件(model.yml)

  模型部署文件详细描述了需要部署的模型以及生成库的信息,MACE根据该文件最终生成对应的库文件。

2. 编译MACE库

  编译MACE的静态库或者动态库。

3. 模型转换

  将TensorFlow 或者 Caffe的模型转为MACE的模型。

4.1 部署

  根据不同使用目的集成Build阶段生成的库文件,然后调用MACE相应的接口执行模型。

4.2 命令行运行

  MACE提供了命令行工具,可以在命令行运行模型,可以用来测试模型运行时间,内存占用和正确性。

4.3 Benchmark

  MACE提供了命令行benchmark工具,可以细粒度的查看模型中所涉及的所有算子的运行时间。

总结 

  以上步骤是基于官方文档,以下为博主理解:最初我们设计算法为python文件(model.py)训练完成后生成model.pb模型文件。再将model.pb文件部署在model.yml文件中,之后经过编译转换将model.yml文件经过converter.py转换生成库文件。最终进入第四步按需求去调用这些库文件即可。

二、环境搭建

  环境要求:本文基于Ubuntu 16.04搭建,所需安装的软件主要包括docker,bazel和Android jdk,以及python的依赖库,Cmake在构建工程时候Android stdio会自动更新下载。当这些所需的库安装好后便可以在MACE官方pull mace镜像了。

  下图为所需的依赖库:

MACE(1)-----环境搭建-LMLPHP

MACE(1)-----环境搭建-LMLPHP

1. 在Ubuntu16.04下安装Docker 

1.1 安装docker:sudo apt-get install docker.io
1.2 检查版本: docker version 当出现client和service表面安装成功
1.3 启动docker:systemctl start docker.service
1.4 更新docker 

  1.需要使用apt-get来升级,借助阿里的docker-ce源
    sudo add-apt-repository "deb [arch=amd64] http://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"
  2.sudo apt-get update
  3.搜索源
    apt-cache madison docker-ce

  会出现版本,选择一个
  4.sudo apt-get -y install docker-ce=17.09.0~ce-0~ubuntu --allow-unauthenticated
  5.查看是否更新
    sudo docker version

 1.5 设置开机自启动
    sudo systemctl enable docker

  然后再重启:
    systemctl restart docker

2. python库的安装(python2.7)  

库的安装需要加 --user
比如:
  pip install -I --user filelock==3.0.0
或者:
  pip install tensorflow

3.安装Android NDK(r15b, r15c and r16b )

  注:不要下载最新版的,博主下的17b出现问题。

3.1 由于挂载在/opt文件夹下面,需要权限,所以首先进入到管理员状态
  sudo su
3.2 进入到/opt文件下面
  cd opt
3.3 执行下面命令下载(博主采用的是r15c的版本,测试可用)
  wget -q https://dl.google.com/android/repository/android-ndk-r15c-linux-x86_64.zip
3.4 在此目录下面进行解压
  unzip -q android-ndk-r15c-linux-x86_64.zip
3.5 导入环境变量(红色版本根据自己下载更改)
  export ANDROID_NDK_VERSION=r15c
  export ANDROID_NDK=/opt/android-ndk-${ANDROID_NDK_VERSION}
  export ANDROID_NDK_HOME=${ANDROID_NDK}
  # add to PATH
  export PATH=${PATH}:${ANDROID_NDK_HOME}
3.6 变量生效:source /etc/profile
3.7 验证是否生效:ndk-build
  注:若出现以下这些表明安装成功。
  Android NDK: Could not find application project directory !  
Android NDK: Please define the NDK_PROJECT_PATH variable to point to it.   
  /home/weilong/android/android-ndk-r16b/build/core/build-local.mk:151: *** Android NDK: Aborting . Stop.

4. 在Linux下面安装bazel

4.1安装Jdk8
  sudo apt-get install openjdk-8-jdk
4.2在包资源中增加Bazel的发布源
  4.2.1 echo "deb [arch=amd64] http://storage.googleapis.com/bazel-apt stable jdk1.8" | sudo tee /etc/apt/sources.list.d/bazel.list
  4.2.2 curl https://bazel.build/bazel-release.pub.gpg | sudo apt-key add -
4.3 安装Bazel
  sudo apt-get update && s get install bazel
如果这一步出错:
由于没有公钥,无法验证下列签名: NO_PUBKEY 7EA0A9C3F273FCD8
W: 仓库 “http://mirrors.aliyun.com/docker-ce/linux/ubuntu xenial InRelease” 没有数字签名。
N: 无法认证来自该源的数据,所以使用它会带
解决办法:(红色字符串是PUBKEY的后八位)
  sudo apt-key adv --recv-keys --keyserver keyserver.Ubuntu.com F273FCD8
4.4 更新Bazel
  sudo apt-get upgrade bazel
4.5 导入路径(红色版本号根据自己查看的写)
  查看版本:bazel version
  export BAZEL_VERSION=0.13.1
4.6 创建bazel环境
  创建一个bazel目录: sudo mkdir /bazel
进入到该目录: cd /bazel
下载bazel安装文件: wget https://github.com/bazelbuild/bazel/releases/download/$BAZEL_VERSION/bazel-$BAZEL_VERSION-installer-linux-x86_64.sh
赋予执行权限: chmod +x bazel-*.sh
执行该安装文件: ./bazel-$BAZEL_VERSION-installer-linux-x86_64.sh
进入根目录: cd /
移除该源文件: rm -f /bazel/bazel-$BAZEL_VERSION-installer-linux-x86_64.sh

5. 构建MACE镜像

  MACE提供已安装依赖项的docker镜像以及用于构建镜像的Dockerfiles,您可以直接拉取现有的镜像或从Dockerfiles构建它们。在大多数情况下,镜像可以满足开发人员的基本需求。

 5.1.创建镜像

  MACE镜像已经在docker环境创建好了,有两种创建方式,pull或者build。官方提供的MACE镜像有两种,lite版和full版。官方强烈建议pull来构建镜像到本地,建议读者在docker的学习上花一点时间。

  1.1 lite版本    

# Pull lite edition docker image
docker pull registry.cn-hangzhou.aliyuncs.com/xiaomimace/mace-dev-lite
# Build lite edition docker image
docker build -t registry.cn-hangzhou.aliyuncs.com/xiaomimace/mace-dev-lite ./docker/mace-dev-lite

  1.2 full版本

# Pull full edition docker image
docker pull registry.cn-hangzhou.aliyuncs.com/xiaomimace/mace-dev
# Build full edition docker image
docker build -t registry.cn-hangzhou.aliyuncs.com/xiaomimace/mace-dev ./docker/mace-dev

 5.2 使用镜像

启动docker
2.1 创建一个mace-dev的容器
docker run -it --privileged -d --name mace-dev \
-v /dev/bus/usb:/dev/bus/usb --net=host \
-v /local/path:/container/path \
-v /usr/bin/docker:/usr/bin/docker \
-v /var/run/docker.sock:/var/run/docker.sock \
registry.cn-hangzhou.aliyuncs.com/xiaomimace/mace-dev
2.2 执行该容器 docker exec -it mace-dev /bin/bash

  本文直接pull的mace-dev版本。如下图所示构建的镜像为mace-dev为13.4GB,并开启了一个容器,ID为12899***。

MACE(1)-----环境搭建-LMLPHP

  至此,MACE环境就搭建起来了,下一节内容为构建一个实例,演示如何通过MACE来转模型文件。

现在开启一个容器,在容器中pull mace项目:

1.sudo docker ps -a  #c查看镜像,会看见一个id
2. sudo docker start id #id为上条命令的id号码
3. sudo docker exec -it id bash #同理id为镜像的id

三、构建并运行实例模型

  我们以mobilenet-v2模型为例。

1. Pull MACE项目

git clone https://github.com/XiaoMi/mace.git

2. pull MACE Model Zoo 项目

git clone https://github.com/XiaoMi/mace-models.git

MACE(1)-----环境搭建-LMLPHP

3. 编译MACE Library(后期发现这一步其实不用,当打开容器时候资源可以通用,在本地的都可以用,模型git到本地即可。这块后期再改)

  Question?如何在文件夹下找到容器中创建的文件?

  Answer!通过查看容器的Id找到位置。

  3.1 进入到mace路径下

3.1.1 首先对docker文件全部解锁,在cd /var/lib下执行命令:chmod -R 777 docker
3.1.2 方法一:通过ID在docker文件下找,
3.1.3 方法二:在docker下面直接搜索mace文件即可,mace文件已经在容器中了。

MACE(1)-----环境搭建-LMLPHP

如上图所示就进入到了容器中的mace路径下,注意该操作得另起一个终端操作。

  3.2 进行编译

bash tools/build-standalone-lib.sh

MACE(1)-----环境搭建-LMLPHP

MACE(1)-----环境搭建-LMLPHP

  如上图所示即编译完成。

4. 模型转换成C++代码,防止反编译有效保护模型。有两种方法

  1. 将模型图转换为代码,将模型权重转换为文件
model_graph_format: code 
model_data_format: file
  2. 将模型图和模型权重都转换为代码
model_graph_format: code
model_data_format: code

  以mobilenet-v2为例子,将mace-models/mobilenet-v2 文件夹下的mobilenet-v2.yml和mobilenet-v2-host.yml都修改为code。

MACE(1)-----环境搭建-LMLPHP

5. 将mobilenet-v2.yml模型转换为MACE格式

在mace路径下:cd /mace
python tools/converter.py convert --config=/var/lib/docker/aufs/diff/b1e110a3c38e93df0e36c475a137d390c6c44dc4299da4895494453d88f21e65/mace-models/
mobilenet-v2/mobilenet-v2.yml

  MACE(1)-----环境搭建-LMLPHP

MACE(1)-----环境搭建-LMLPHP

  以上图片为转换过程,若出现则表明转换工作完成。

  以上的步骤已经将model.yml文件转换完毕形成库,之后的步骤就是将这些库加载到工程中形成model.apk文件部署在安卓终端中。

  在转换后所生成的库在mace/builds/文件夹下面;

MACE(1)-----环境搭建-LMLPHP

  mace中的android工程路径;/mace/mcae/examples/android/这在后期用Android studio直接加载此工程即可。

MACE(1)-----环境搭建-LMLPHP

  在加载之前我么需要将转换生成的库挂载到工程中。

  在android项目中的macelibrary/src/main/cpp 文件夹下,如下图所示
    -- 新建include/mace/public文件夹
    -- 新建lib文件夹
    -- 新建model文件夹
MACE(1)-----环境搭建-LMLPHP

  1. 将builds/include/mace/public/ 下的mace.h 以及 mace_runtime.h拷贝进去macelibrary/src/main/cpp/include/mace/public中

  2. 将builds/mobilenet-v2/include/mace/public/ 下的mace_engine_factory.h 以及 mobilenet_v2.h拷贝至 macelibrary/src/main/cpp/include/mace/public中

   3. 将builds/mobilenet-v2/model 下的mobilenet-v2.a 拷贝至 macelibrary/src/main/cpp/model中,并修改mobilenet-v2.a 为 mobilenet.a

    4. 将builds/lib下的文件都拷贝至macelibrary/src/main/cpp/lib中,里面有三个文件夹,分别是arm64-v8a,armeabi-v7a和linux-x86-64。

    这三个文件是针对的终端硬件结构也不一致,读者自己百度,当往终端部署时候首先会找v8a的so文件,如果没有则向下兼容找v7a文件。arm是cpu的一种体系结构,x86用于平板或者电脑cpu结构。

    4.1 我们需要将各个版本的下的/cpu_gpu下的文件复制到与此同级别目录,还有个dsp体系结构,本例子暂不介绍。

    4.2 将model下的mobilenet.a文件同样复制到各个体系结构下。如下图所示:

MACE(1)-----环境搭建-LMLPHP

MACE(1)-----环境搭建-LMLPHP

  5. macelibrary/src/main/cpp/include/mace/public下所有.h文件都要被引入,如下图,总共有四个.h文件

    mace.h不需要引入

    mace_runtime需要引入mace.h

    mace_mobilenet.h需要引入mace.h 和mace_runtime.h

    mace_engine_factory.h需要引入mace.h 和mace_runtime.h,同理如下图所示

MACE(1)-----环境搭建-LMLPHP

MACE(1)-----环境搭建-LMLPHP

  至此以上的工作模型经过编译转换,并且将生成的库加载在工程文件中,这个工作已经完成,下一步将在Android studio中加载工程 ,并运行生成apk文件在终端。

  打开Android stdio,在File下找到Project Structure加载NDK路径。

MACE(1)-----环境搭建-LMLPHP

  在Android studio加载在/var/lib/docker/aufs/diff/b1e110a3c38e93df0e36c475a137d390c6c44dc4299da4895494453d88f21e65/mace/mace/examples下的android工程

由于这个测试的app默认是使用mobilenet_v1的模型的,所以我们更改一下代码让他使用mobilenet_v2,修改com.xiaomi.mace.demo.result下的InitData.java文件中的
model = MODELS[0];改为:model = MODELS[];即可MACE(1)-----环境搭建-LMLPHP

运行后的结果如下图所示,该实例功能是物体实时识别;下篇博文会会针对mobilenet_v2.pb文件分析网络结构。

如果遇到卡退问题,原因是权限要读写外部存储卡,权限不够导致,在客户端apk设置下赋予权限即可。

MACE(1)-----环境搭建-LMLPHP

本文仅用于学习研究,非商业用途,欢迎大家指出错误一起学习,文章内容翻译自 MACE 官方手册,记录本人阅读与开发过程,力求不失原意,但推荐阅读原文。

MACE官方文档:https://media.readthedocs.org/pdf/mace/latest/mace.pdf

小米MACE Github地址:https://github.com/xiaomi/mace

小米MACE安装说明:https://mace.readthedocs.io/en/latest/

  

05-11 20:19