TensorFlowは、Googleが公開しているモバイルや、サーバなどデバイスを問わずどんな環境でもディープラーニングを動作させることができるライブラリです。

iOSアプリで識別することも、バージョン0.9.0からサポートされました。

本記事では、TensorFlowやiPhoneアプリ開発にそれほど馴染みのない方でも簡単にXcodeプロジェクトからTensorFlowのモデルを実行できるようになるまでを解説します。

TensorFlowをiOSで動作させるために必要なもの

TensorFlowをiOSプロジェクトで動作するには、以下のライブラリやソフトウェアが必要になります。

  • Xcode7.3以上
  • XcodeのCommand Line Tools
  • automake, libtool

Xcodeは、iTunesストアからダウンロードしてください。 また、XcodeのCommand Line Toolsは以下のコマンドをターミナルから入力するとインストールすることができます。

$ xcode-select --install

automakelibtoolは、Homebrew経由でインストールできます。以下のコマンドでインストールします。

$ brew install automake libtool

TensorFlowのレポジトリからライブラリをビルド

iOSプロジェクトを作成する前に、導入に必要なライブラリをビルドする必要があります。 TensorFlowレポジトリに、ライブラリをビルドするために必要なスクリプトが入っているので、まずは以下のコマンドでTensorFlowのソースコードをダウンロードします。

$ git clone git@github.com:tensorflow/tensorflow.git

クローンできたら、スクリプトのあるディレクトリに移動してユニバーサルライブラリをビルドします。

$ cd tensorflow
$ ./tensorflow/contrib/makefile/build_all_ios.sh

このビルドにはMacbook Proで10~20分くらいかかる場合があります。正常に終了していれば、ビルド成功です。

ここで発生しがちなエラー

/usr/local/Library/ENV/4.3/sed: No such file or directory というエラー

libtoolを再インストールする必要があります。Homebrewで再インストールしてビルドし直します。

$ brew reinstall -s libtool
$ ./tensorflow/contrib/makefile/build_all_ios.sh

configure: error: C compiler cannot create executables というエラー

コンパイラのgccがシステムのgccではなく、Homebrew経由でインストールしたgccとなっている可能性があります。

まずは、Makefileのgccのパスを変更します。./tensorflow/contrib/makefile/Makefileをテキストエディタで開いてHOST_CXX :=の後にあるgcc/usr/bin/gccとしましょう。

また、以下のように、コマンドの前にCC=/usr/bin/gccを付けることでシステムのコンパイラを使ってprotobufなど他の設定もしてくれるようになります。

$ CC=/usr/bin/gcc ./tensorflow/contrib/makefile/build_all_ios.sh

これでも駄目だった場合は、

./tensorflow/contrib/makefile/Makefileのコンパイラの設定部分をgccから/usr/bin/gccとして実行してみてください。

まずはサンプルを動かしてみる

ここで、サンプルが動作するか一度確認してみます。Inception-v1のモデルファイルをダウンロードして、iOSから実行するサンプルを試します。

$ mkdir -p /tmp/graphs
$ curl -o /tmp/graphs/inception5h.zip \
 https://storage.googleapis.com/download.tensorflow.org/models/inception5h.zip \
  && unzip /tmp/graphs/inception5h.zip -d /tmp/graphs/inception5h
$ cp /tmp/graphs/inception5h/* tensorflow/contrib/ios_examples/benchmark/data/
$ cp /tmp/graphs/inception5h/* tensorflow/contrib/ios_examples/camera/data/
$ cp /tmp/graphs/inception5h/* tensorflow/contrib/ios_examples/simple/data/

Xcodeのプロジェクトファイルを開きます。simpleディレクトリにあるtf_ios_makefile_example.xcodeprojファイルをダブルクリックして開くか、以下のコマンドでプロジェクトファイルをXcodeで読み込んで開くことができます。

$ open tensorflow/contrib/ios_examples/simple/tf_ios_makefile_example.xcodeproj

以下のように、Xcodeが立ち上がったかと思います。左上のRunボタンを押して実行できるかを確認します。

Xcodeが立ち上がる

シミュレーターが立ち上がって以下の画像のようなスクリーンになります。上部にあるRun Modelというボタンをタップすると、Inception-v1モデルが読み込まれて画像ファイルが何なのかを予測します。

シンプルデバッグ

予測結果は、ボタンの下部にあるデバッグログに出力されているはずです。

シンプルデバッグログ

モデルファイルが読み込まれたことと、0.51 military uniform、0.1 motorboardというログが出力されたようです。どういう意味でしょうか。実は、このアプリはこちらの画像が何なのかを予測させた結果です。

軍服画像

military uniformとは、日本語で「軍服」という意味です。この写真は、51%の確率で軍服だと判断されたということです。確かに軍服を着ていますね!

他にもカメラアプリなどがサンプルとして用意されているので、試してみると面白いでしょう。

Xcodeでプロジェクトセットアップ

新規や既存のプロジェクトでTensorFlowを使用するXcodeの設定はどうすればいいのでしょうか。ここではiOSプロジェクトを構築する場合に必要な設定を1からプロジェクトを作成しながら解説します。

プロジェクトの作成

まずはプロジェクトを作成します。メニューバーのFile → New → Projectを選択します。

プロジェクトの作成

以下のようなダイアログが出てくるので、Single View Applicationを選択してNextボタンを押します。

Single View Application

TensorFlowのライブラリはObjective-C++のインターフェースから操作するようになっています。 今回はLanguageにはObjective-Cを選択して進みます。プロジェクトの設定次第ではSwiftでプロジェクトを作ってObjective-C++のコードを読み込むこともできます。

ここで、ディレクトリはTensorFlowのレポジトリをクローンしたディレクトリに作成しておくと良いでしょう。チームで共同開発するときに、パスの設定を共有したいからです。

Objective-C++の設定

これでプロジェクトの作成は完成です。以下のようにXcodeのプロジェクトが開かれたはずです。

Xcodeのプロジェクト作成完了

Build Phasesにライブラリの追加

上部のタブにBuild Phasesという箇所があるので、クリックします。

Build Phases

すると、以下の画像のように「Link Binary with Libraries」という箇所があるので、下の+をクリックして以下のライブラリを追加してください。

Link binaries

  • libstdc++.tbd
  • Acceralate.framework
  • 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

Library Search Pathsにライブラリパスの追加

ライブラリを追加したら、ビルドに必要なので先程追加したライブラリがあるLibrary Search Pathsにパスを追加します。

Library Search Pathsは、上部タブのBuild Settingsをクリックして、検索ボックスにSearch Pathsと入力すると簡単に探すことができます。下の画像のように、左から二列目の部分をクリックすると、追加する画面が出てくるので、左下の+ボタンを押して追加していきます。

Library Search Paths

追加するライブラリのパスは以下の2つです。TensorFlowのレポジトリのパスが一階層下であることを前提としています。違うパスを利用する場合には、適宜読み替えてください。

  • $(SRCROOT)/../tensorflow/tensorflow/contrib/makefile/gen/lib
  • $(SRCROOT)/../tensorflow/tensorflow/contrib/makefile/gen/protobuf_ios/lib

Header Search Pathsにパスの追加

Header Search Pathsにヘッダファイルのあるディレクトリを追加していきます。Header Search Pathsは、Library Search Pathsの1つ上の行にあります。

追加するパスは以下の5つです。

  • $(SRCROOT)/../tensorflow
  • $(SRCROOT)/../tensorflow/tensorflow/contrib/makefile/downloads/protobuf/src
  • $(SRCROOT)/../tensorflow/tensorflow/contrib/makefile/downloads
  • $(SRCROOT)/../tensorflow/tensorflow/contrib/makefile/downloads/eigen
  • $(SRCROOT)/../tensorflow/tensorflow/contrib/makefile/gen/proto

Other Linker Flagsにオプションの追加

Other Linker Flagsに、オプションを追加します。検索ボックスに「Linking」と入力するとすぐに見つかるはずです。Linkingの中に、Other Linker Flagsがあるので下の画像の位置をクリックして、+ボタンを押して以下のオプションを追加してください。

linking

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

C++11をサポートするビルドの設定の確認

C++11に対応するビルドの設定をします。デフォルトでプロジェクトを作成していれば問題ないはずですが、既存のプロジェクトに追加する場合には気をつけてください。

Apple LLVM 8.0 - Language - C++というセクションの下に、C++ Language Dialectという行があるはずです。ここがGNU++11または、GNU++14となっていれば問題ありません。

GNU++11

その下にあるC++ Standard Libraryという行は、libc++としておきます。

libc++

BitcodeをNOに変更

最後に、TensorFlowはまだBitcodeをサポートしていないので、Enable BitcodeをNOに変更しておきます。

Enable Bitcode

これでプロジェクトの設定は終了です。

モデルファイルの読み込みと推論

グラフファイルの書き出し

TensorFlowで学習したモデルをスマホなどの端末側で利用する場合は、Pythonからよく使われるチェックポイントではなくてProtocol Buffer形式の学習済みグラフを書き出して使う必要があります。

Protocul Buffer形式の学習グラフの作り方は、

(1) 出力のノードに名前を付けて学習させる
(2) ノードの名前を使って以下のようなコードでグラフを出力する

minimal_graph = convert_variables_to_constants(sess, sess.graph_def, ["output"])
tf.train.write_graph(minimal_graph, '.', 'minimal_graph.pb', as_text=False)

で書き出すことができます。詳しくはTensorFlowのドキュメントを参考にしてください。

iPhone側からの呼び出し

iPhone側からは、Protocol Buffer形式のモデルファイルを読み込んで、識別することになります。

基本的には、Objective-C++を使ってTensorFlowのC++APIを通して操作する形になります。Objective-Cの拡張子を.mから.mmとすればObjective-CとC++を共存させることができるようになります。

使い方はサンプルプロジェクトを参考にすると分かりやすいです。

ポイントは、

(1) tensorflow::NewSession(options, &session_pointer)session->Create(graph)でSessionを作成する
(2) PortableReadFileToProto(file_name, proto)でグラフファイルとの通信
(3) session->Runで、出力を取得する

という順で実装することでiOSからでもTensorFlowのモデルを使った機械学習の実装ができます。

まとめ

TensorFlowをiOSに載せる方法を紹介しました。

TensorFlowは、Pythonを使ったサーバ側で実行する方式だけでなく、AndroidやiOSなどのクライアント側でも実行することができるようになりました!

モバイルアプリで機械学習を使ったサービスを提供する際には是非、試してみてください。