天天看點

kindle教你手把手跑通ios-tensorflow版SSD模型(一)—— 編譯ios-tensorflowkindle教你手把手跑通ios-tensorflow版SSD模型(一)—— 編譯ios-tensorflow

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/java

You 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: cask
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官網提示,從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 bazel
bazel 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/python
Found possible Python library paths:
  /Users/Alex/anaconda/lib/python2.7/site-packages
Please 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-packages
Do you wish to build TensorFlow with MKL support? [y/N] n
No MKL support will be enabled for TensorFlow
Please specify optimization flags to use during compilation when bazel option "--config=opt" is specified [Default is -march=native]: n
Do you wish to build TensorFlow with Google Cloud Platform support? [y/N] n
No Google Cloud Platform support will be enabled for TensorFlow
Do you wish to build TensorFlow with Hadoop File System support? [y/N] n
No Hadoop File System support will be enabled for TensorFlow
Do you wish to build TensorFlow with the XLA just-in-time compiler (experimental)? [y/N] n
No XLA JIT support will be enabled for TensorFlow
Do you wish to build TensorFlow with VERBS support? [y/N] n
No VERBS support will be enabled for TensorFlow
Do you wish to build TensorFlow with OpenCL support? [y/N] n
No OpenCL support will be enabled for TensorFlow
Do you wish to build TensorFlow with CUDA support? [y/N] n
No CUDA support will be enabled for TensorFlow
Do you wish to build TensorFlow with MPI support? [y/N] n
MPI support will not be enabled for TensorFlow
Configuration finished
           

Optional:

如果要擷取 graph’s input/output name,可以運作下面第一條指令,編譯summarize_graph,運作第二條語句,用

--in_graph

指定graph即可檢視input name.

bazel build tensorflow/tools/graph_transforms:summarize_graph
bazel-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 #這條語句會先自動安裝autoconf
brew 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.a
tensorflow/contrib/makefile/gen/protobuf_ios/lib/libprotobuf.a
tensorflow/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_ROOT
tensorflow/contrib/makefile/build_all_ios_ssd.sh           

本系列教程希望可以幫助大家少走彎路,最近略忙,接下來兩篇我會盡快更新的,祝大家好運!小白初學,有不到位的地方請多多指正。再次感謝JieHe在issue中的耐心解答!