kindle教你手把手跑通ios-tensorflow版SSD模型(一)—— 编译ios-tensorflow

来源:互联网 发布:怎么把图片上传淘宝 编辑:程序博客网 时间:2024/05/18 03:45

kindle教你手把手跑通ios-tensorflow版SSD模型(一)—— 编译ios-tensorflow

本教程主要参考JieHe96/iOS_Tensorflow_ObjectDetection_Example 提供的英文版教程,将其翻译成中文版,并补充一点自己在安装过程中积累的一些经验。再次谢谢JieHe!

本系列教程会分为3个部分,第一部分介绍“ios-tensorflow的编译”,第二部分介绍“Xcode配置”,第三部分介绍“tensorflow的模型处理”

作者:kindle

时间:2017年7月23日

声明:版权所有,转载请联系作者并注明出处

一、准备工作

1. Xcode版本 && Homebrew

You’ll need Xcode 7.3 or later.

then, install Homebrew

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

2. 下载tensorflow到本地

git clone https://github.com/tensorflow/tensorflow

3. 安装Bazel

https://docs.bazel.build/versions/master/install.html

首先要安装Java 1.8+ 可能碰到的问题:
- 直接运行brew install bazel提示如下:说明Java 1.8+没安装

Warning: You are using OS X 10.12.We do not provide support for this pre-release version.You may encounter build failures or other breakages.bazel: Java 1.8+ is required to install this formula.You can install with Homebrew Cask:  brew install Caskroom/cask/javaYou can download from:  http://www.oracle.com/technetwork/java/javase/downloads/index.html Error: An unsatisfied requirement failed this build.
  • 运行brew install Caskroom/cask/java安装Java 1.8+,提示如下:应该是OS X 10.12版本不支持的问题
Error: Unknown command: caskWarning: You are using OS X 10.12.We do not provide support for this pre-release version.You may encounter build failures or other breakages.
  • 按照Bazel官网提示,从Oracle’s JDK Page download a DMG image with an install wizard. First, double click .img file to lanch it. Then, click the .pkg file appearing in a Finder window to install the app. Last, verify java version by java -version.
  • Install Bazel Homebrew, 如果出现问题,一般是网络问题,毕竟切换成手机热点就毫无压力,流量多就是任性!刚开始可能会updating brew,而且最开始没有任何提示,但一定要耐心等待,不要没过两分钟就cut掉进程,不然这一辈子都装不好!如果实在装不了,就安装bazel官网第二种方式安装吧!
brew install bazelbazel version #确认是否安装成功
  • 准备cocoapods
sudo gem install cocoapods

4. 下载ssd目标检测模型ssd-objection-detection-ios-example到本地


5. 准备Graph(tensorflow下的模型),We only need the graph file, aka .pb file (We chose SSDMobilenet as example):

frozen_inference_graph.pb

Then download the label file for the model you chose:
https://github.com/tensorflow/models/tree/master/object_detection/data

mscoco_label_map.pbtxt

二、 开始编译

1. 编译Bazel

如果是第一次安装bazel,请安装一下教程,设置tensorflow的配置文件: https://www.tensorflow.org/install/install_sources#configure_the_installation
输出如下,目录选择默认目录,选项都选择N,若选择Y会报错,以后要用的时候再研究怎么装把。

...............................................................You have bazel 0.5.2-homebrew installed.Please specify the location of python. [Default is /Users/Alex/anaconda/bin/python]: /Users/Alex/anaconda/bin/pythonFound possible Python library paths:  /Users/Alex/anaconda/lib/python2.7/site-packagesPlease input the desired Python library path to use.  Default is [/Users/Alex/anaconda/lib/python2.7/site-packages]/Users/Alex/anaconda/lib/python2.7/site-packagesDo you wish to build TensorFlow with MKL support? [y/N] nNo MKL support will be enabled for TensorFlowPlease specify optimization flags to use during compilation when bazel option "--config=opt" is specified [Default is -march=native]: nDo you wish to build TensorFlow with Google Cloud Platform support? [y/N] nNo Google Cloud Platform support will be enabled for TensorFlowDo you wish to build TensorFlow with Hadoop File System support? [y/N] nNo Hadoop File System support will be enabled for TensorFlowDo you wish to build TensorFlow with the XLA just-in-time compiler (experimental)? [y/N] nNo XLA JIT support will be enabled for TensorFlowDo you wish to build TensorFlow with VERBS support? [y/N] nNo VERBS support will be enabled for TensorFlowDo you wish to build TensorFlow with OpenCL support? [y/N] nNo OpenCL support will be enabled for TensorFlowDo you wish to build TensorFlow with CUDA support? [y/N] nNo CUDA support will be enabled for TensorFlowDo you wish to build TensorFlow with MPI support? [y/N] nMPI support will not be enabled for TensorFlowConfiguration finished

Optional:

如果要获取 graph’s input/output name,可以运行下面第一条命令,编译summarize_graph,运行第二条语句,用--in_graph指定graph即可查看input name.

bazel build tensorflow/tools/graph_transforms:summarize_graphbazel-bin/tensorflow/tools/graph_transforms/summarize_graph --in_graph=YOUR_GRAPH_PATH/example_graph.pb

2. Change Makefile

Makefile文件在目录”tensorflow/contrib/makefile/”下,删掉所有

"-D__ANDROID_TYPES_SLIM__ " under "# Settings for iOS." for all "$(IOS_ARCH)".

至于为什么要这一步,可以参考JieHe在https://github.com/tensorflow/tensorflow/issues/9476上的评论。我的理解是这条语句会让iOS平台下一些kernel或者op错误地指向了跟android有关的路径中,从而导致提示“No OpKernel was registered to support Op ‘xxx’ with these attrs”的错误。如有理解不对的地方,欢迎指正。


3. Generate ops_to_register.h

在编译过程中,一个最大的问题是缺失各种不同的OpKernel. 可能报错如下:

Invalid argument: No OpKernel was registered to support Op 'Equal' with these attrs.  Registered devices: [CPU], Registered kernels:  <no registered kernels>

为了解决这个问题,我们用Bazel来生成一个ops_to_register.h文件,这个文件包含了所有加载一个确定graph到Xcode工程所需要的Ops(操作)。执行以下语句

bazel build tensorflow/python/tools:print_selective_registration_header bazel-bin/tensorflow/python/tools/print_selective_registration_header \    --graphs=path/to/graph.pb > ops_to_register.h

第一条语句是编译print_selective_registration_header.py,这个文件的作用是打印头文件,内部主要调用selective_registration_header_lib.py,它会生成一个头文件用于tensorflow SELECTIVE_REGISTRATION,头文件的主要功能是:Gets the ops and kernels needed from the model files(我的理解是头文件查找特定模型中用到了哪些ops和kernels,对比不同模型生成的文件会发现主要是二者框架基本一致,只是kNecessaryOpKernelClasses[]和ShouldRegisterOp(const char op[])不同)。

第二条语句是对编译好的print_selective_registration_header赋参数,告诉它graphs的路径在哪里,最后在当前目录生成一个ops_to_register.h的头文件。注意bazel-bin应该是build的时候在tensorflow同级目录下生成的文件夹,所以这时终端所在目录应该是bazel-bin所在目录

生成好头文件之后,将ops_to_register.h复制到”tensorflow/core/framework/”中,这个头文件在接下来编译tensorflow时会被selective_registration.h文件调用,在编译时还需要将-DSELECTIVE_REGISTRATION和-DSUPPORT_SELECTIVE_REGISTRATION参数传入(后文有提到)。”tensorflow/core/framework/”这个目录中selective_registration.h会调用生成好的ops_to_register.h。

Attention:

对于不同的模型,必须生成不同的ops_to_register.h文件来与模型适配;如果想在工程中包含多个模型,只要最先对不同的模型生成多个ops_to_register.h,然后合并到一起即可。这样,在同一个工程中使用多个模型时,不用每次都编译tensorflow lib。(这里我做了一个小测试,将ssd_mobilenet_v1_coco_11_06_2017模型产生的ops_to_register.h文件中的kNecessaryOpKernelClasses和ShouldRegisterOp下面的各一行元素复制到由ssd_inception_v2_coco_11_06_2017产生的ops_to_register.h文件中,以方便后续编译tf-ios-library库是否能成功)


4. Build Tensorflow iOS library

这里采用两者方式编译tf-ios-library,先讲分步骤编译,再讲傻瓜一键式编译


4.1 分步编译

  • Download the dependencies:未修改任何东西,下载文件保存在tensorflow/contrib/makefile/downloads目录下,包括五个文件夹:eigen(跟矩阵有关的库,类似于opencv的Mat)、gemmlowp(线性代数的库)、googletest(Google的开源C++单元测试框架)、protobuf(一种轻便高效的结构化数据存储格式)、re2(http://www.cnblogs.com/lanxuezaipiao/p/3423668.html)(一个正则化表达式的库),
tensorflow/contrib/makefile/download_dependencies.sh
  • Compile protobufs for iOS:(大约10min)
tensorflow/contrib/makefile/compile_ios_protobuf.sh 

未做任何修改,但提示autoreconf: command not found,因为autoconf未安装,同样的automake和libtool也需要安装,方法如下:

brew install automake #这条语句会先自动安装autoconfbrew install libtool

安装完之后,重新编译即可生成。生成路径为tensorflow/contrib/makefile/gen,下面有两个子目录“protobuf_ios”“protobuf-host”。

  • Create the libtensorflow-core.a:

tensorflow-master原始工程里是没有-03后面的命令的,至于为啥要加-DANDROID_TYPES=ANDROID_TYPES_FULL -DSELECTIVE_REGISTRATION -DSUPPORT_SELECTIVE_REGISTRATION这3条,暂时也没搞太清楚。

tensorflow/contrib/makefile/compile_ios_tensorflow.sh "-O3  -DANDROID_TYPES=ANDROID_TYPES_FULL -DSELECTIVE_REGISTRATION -DSUPPORT_SELECTIVE_REGISTRATION"

然而报错,无奈只得去官网按照如下命令重新编译:这里是指定对ARM64进行编译,同时还提供了“Universal binaries”和“Optimization”两种不同的编译方式,“Universal binaries”对各种架构都编译了,“Optimization”版提供了“-Os”和其他版本的优化方法,

make -f tensorflow/contrib/makefile/Makefile \ TARGET=IOS \ IOS_ARCH=ARM64

如果想要缩短编译时间,可以在compile_ios_tensorflow.sh文件中注释掉不需要编译的平台,比如只编译其中两种 IOS_ARCH: ARM64 and x86_64。这里我只测试了ARM64的编译,花了30min的样子,产生如下 .a 文件说明编译成功:

tensorflow/contrib/makefile/gen/lib/libtensorflow-core.atensorflow/contrib/makefile/gen/protobuf_ios/lib/libprotobuf.atensorflow/contrib/makefile/gen/protobuf_ios/lib/libprotobuf-lite.a

另外,在tensorflow/contrib/makefile/gen下还会生成一些文件夹:bin,dep,host_bin,host_obj,proto,prototext


4.2 关键步骤小结

在运行“compile_ios_tensorflow.h”编译tensorflow之前,一定记得确认以下keypoints是否进行,否则可能出现类似错误:

Invalid argument: No OpKernel was registered to support Op 'xxx' with these attrs.  Registered devices: [CPU], Registered kernels:<no registered kernels>

and

 [[Node: FeatureExtractor/InceptionV2/InceptionV2/Conv2d_1a_7x7/separable_conv2d = Conv2D[T=DT_FLOAT, data_format="NHWC", padding="VALID", strides=[1, 1, 1, 1], use_cudnn_on_gpu=true](FeatureExtractor/InceptionV2/InceptionV2/Conv2d_1a_7x7/separable_conv2d/depthwise, FeatureExtractor/InceptionV2/Conv2d_1a_7x7/pointwise_weights/read)]]

Keypoint:
1. put “ops_to_register.h” generated from your own pb file by “print_selective_registration_header” to $TF_ROOT/tensorflow/core/framework
2. In your ops_to_register.h replace the line “Conv2DOp

4.3 一键式编译

首先确保“4.2 关键步骤小结”中的4个keypoints都设置到位,如果之前编译失败,先将”tensorflow/contrib/makefile/gen”目录下的以下文件夹删除:

bin/dep/lib/obj/

然后重新编译即可:

cd $TF_ROOTtensorflow/contrib/makefile/build_all_ios_ssd.sh

本系列教程希望可以帮助大家少走弯路,最近略忙,接下来两篇我会尽快更新的,祝大家好运!小白初学,有不到位的地方请多多指正。再次感谢JieHe在issue中的耐心解答!

阅读全文
0 0