Building the TensorFlow iOS libraries from source

前言

本文介绍了构建支持iOS的tensorflow静态库。

从Pod中引入tensorflow库

tensorflowpythonAndroid 的支持较好,但是在 iOS 项目中使用比较麻烦。

cocoapods 中在 TensorFlow-experimental 提供了一个tensorflow_experimental.framework,当前版本为1.1.1

TensorFlow-experimental在 cocoapods 中的最新release时间为May, 2017(2018-03-20查看)。

通过 Pod 可以快速引入 tensorflow 库。

1
$ pod 'TensorFlow-experimental'

从source中build支持iOS的tensorflow库

但是在最新的版本(version 1.1.1)中,有一个bug导致如下错误:

1
Could not create TensorFlow Graph: Not found: Op type not registered 'DecodeWav'.

原因是由于在 tensorflow/tensorflow/blob/master/tensorflow/contrib/makefile/tf_op_files.txt 中缺少了 tensorflow/core/ops/audio_ops.cc

bug详细可见here

这个 bug 在 2018-02 被修复,所以在当前最新的 tensorflow_experimental.framework 依然存在。

所以需要手动从 tensorflow 源码中编译静态库。

tensorflow 文档中提到:

if you are building for iOS, you currently need to use the Makefile.

Before you start

  • Github 中 clone tensorflow.
1
$ git clone https://github.com/tensorflow/tensorflow.git
  • 下载所有的编译依赖,官方提供了脚本,只需要运行就行。
1
2
$ cd tensorflow
$ tensorflow/contrib/makefile/download_dependencies.sh

脚本运行结束后,所有的依赖库会被下载到 tensorflow/contrib/makefile/downloads/ 文件夹下面。

Building on Mac

  • 需要Xcode 7.3及之上的版本,安装command-line tools
1
$ xcode-select --install

如果是第一安装command-line tools,需要先运行一次 XCode 并同意license。

  • 安装Homebrew,具体方法在 Homebrew 官网中,这里不详细描述。

  • 安装 automakelibtool

1
2
$ brew install automake
$ brew install libtool
  • 下载tensorflow_inception_graph

这个对于编译静态库不是必须的,tensorflow_inception_graph用来测试。

1
2
3
4
$ mkdir -p ~/graphs
$ curl -o ~/graphs/inception.zip \
https://storage.googleapis.com/download.tensorflow.org/models/inception5h.zip \
&& unzip ~/graphs/inception.zip -d ~/graphs/inception

快速编译

所有准备做好后就可以编译了,执行以下命令:

1
$ tensorflow/contrib/makefile/build_all_ios.sh

这个时间可能需要较久的时间,编译完成后会生成一个包括 iOS 平台所有架构的静态库(i386sim, x86_64sim, armv7, armv7s and arm64)。

当然,如果需要某一个架构的库,比如只需要arm64架构的静态库,可以执行以下代码。

1
$ tensorflow/contrib/makefile/build_all_ios.sh -a arm64

如果之前已经编辑过所有架构的静态库,那么就没有必要重新编译,只需要添加-T来修改已有的文件,这只需要话费几秒时间生成新的静态库。

1
$ tensorflow/contrib/makefile/build_all_ios.sh -a arm64 -T

编译结束后,在 tensorflow/contrib/makefile/gen/lib/ 中生成一个静态库 libtensorflow-core.a

创建自己的App

配置Xcode是一个坑,花了一天的时间才爬过这个坑,配置出错会一直link失败。

Xcdoe 项目里面需要设置非常多的配置,按照以下步骤一步一步来。

添加库

静态库有4个:

  • 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/downloads/nsync/builds/lipo.ios.c++11/nsync.a

系统动态库有1个:

  • Accelerate.framework

库需要通过 TARGET -> Linked Frameworks and Libraries 添加。

添加 Library Search Paths

PROJECT -> Build Settings -> Search Paths -> Library Search Paths 中添加静态库的路径。

1
2
3
tensorflow/contrib/makefile/gen/lib
tensorflow/contrib/makefile/gen/protobuf_ios/lib
tensorflow/contrib/makefile/downloads/nsync/builds/lipo.ios.c++11

Tips:
要注意必须是相对路径,可以直接用拖文件夹的方式加入。

添加头文件路径

PROJECT -> Build Settings -> Search Paths -> Header Search Paths 中添加头文件路径。

1
2
3
4
5
6
the root folder of tensorflow,
tensorflow/contrib/makefile/downloads/nsync/public
tensorflow/contrib/makefile/downloads/protobuf/src
tensorflow/contrib/makefile/downloads,
tensorflow/contrib/makefile/downloads/eigen, and
tensorflow/contrib/makefile/gen/proto.

Other Linker Flags

PROJECT -> Build Settings -> Linking -> Other Linker Flags 中对 TensorFlow 静态库添加 -force_load 标识,如下:

1
2
-force_load
"$(SRCROOT)/../tensorflow/tensorflow/contrib/makefile/gen/lib/libtensorflow-core.a"

使用 -force_load 可以指定要载入的库,避免因为使用 -all_load 导致的链接错误。

同时,需要移除所有的 -all_load,如果是为了避免 Objective-C 静态库中 categories 的问题,可以使用 -ObjC

C++支持

PROJECT -> Build Settings -> C++ Language Dialect 中选择 GNU++11GNU++14

PROJECT -> Build Settings -> C++ Standard Library 中选择 libc++

Bitcode

tensorflow 库不支持 bitcode ,所以要把 PROJECT -> Build Settings -> Build Options -> Enable Bitcode 设置为 NO

参考

  1. Building TensorFlow on iOS
  2. Building the TensorFlow iOS libraries from source
  3. iOS
  4. Creating your Own App from your source libraries