TensorFlowの学習済みモデルを拾ってきてiOSで利用する

iOS 10でニューラルネットワークAPIのBNNS (Basic neural network subroutines) がAccelerateフレームワークに追加されたり、TensorFlowのiOSサポートが追加されたり、Prismaがオフライン対応したりと、なんとなく**あらかじめ学習させておいたモデルを使って計算するぐらいのことはiOSデバイス側でやらせてもいいんじゃないか**、という空気感も出てきたような気がしてます。[^1]

[^1]: 全部サーバー側で計算してると、ユーザーが増えればそれだけサーバー負荷も上がりますし。。

・・・いや、そんな大層な理由ではなくて、機械学習/ディープラーニングについて無知な自分が、学習用に大量のデータを集めて、Pythonスクリプトを書いて自前モデルを作成するのは一段ハードルが高いように思えてしまいます。

というわけで、先日書いた『[TensorFlowにiOSサポートが追加されたそうなので試してみた](http://qiita.com/shu223/items/ce190ea6669b2636a8a7)』の次のステップとして、**GitHubとかに落ちている学習済みモデルを拾ってきてTensorFlow/iOSで動かす**ということを試してみました。

![IMG_0003_r1_c1.jpg](https://qiita-image-store.s3.amazonaws.com/0/3180/6c3dabc5-ee07-94f1-ca73-62b9d47b73bf.jpeg)

（今回の成果の一例）

##事例1: 花を識別するモデル

GitHubで "Tensorflow iOS Models" という気になる名前のリポジトリを見つけました。

- https://github.com/jguertl/tensorflow-ios-models

**Tensorflow iOSで使えるモデルのまとめリポジトリ**にしたい、というコンセプトのようですが、2016年8月23日現在、置いてあるのは "Flowers" というモデル**1つだけ** [^2] です。

[^2]: モデルの種類を増やしていって欲しいところですが、モデルファイルは一般的にサイズが大きく、GitHubでその他ソースを公開しているプロジェクトでも、モデルファイルは別のところに置いてあって別途ダウンロードするようになっているケースも多いので、今後もそんなに集まることは期待できないかもしれませんね。。

サンプルもなかったので、これをTensorFlowの公式リポジトリの `ios_examples` 配下にある[simpleサンプル](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/contrib/ios_examples/simple)で使えるようにしてみました。

###ソースの変更点

simpleサンプルでFlowersモデルを利用するにあたってコードを書き換えた点は以下。全部 RunModelViewController の変更です。

- モデルのファイル名

```objc
NSString* network_path = FilePathForResourceName(@"tensorflow_flower_graph", @"pb");
```

- ラベルのファイル名

```objc
NSString* labels_path = FilePathForResourceName(@"flowers_comp_graph_label_strings", @"txt");
```

- テスト画像のファイル名

```objc
NSString* image_path = FilePathForResourceName(@"flowers", @"png");
```

- `tensorflow::Tensor` 作成時に利用する画像サイズやピクセル値再計算用のパラメータ

```objc
const int wanted_width = 299;
const int wanted_height = 299;
const int wanted_channels = 3;
const float input_mean = 128.0f;
const float input_std = 128.0f;
```

- `session->Run` の引数に渡す入力・出力ノードの名前

```objc++
std::string input_layer = "Mul";
std::string output_layer = "final_result";
```

ちなみにもちろん、モデルファイル（.pb）、ラベルファイル（.txt）、テスト画像への参照をプロジェクトに追加する必要はあります。

###実行結果

こういう画像を入力して、

![flowers.png](https://qiita-image-store.s3.amazonaws.com/0/3180/695b6bc7-c79f-f7b0-1506-802ab54252e2.png)


認識結果はこう出ました。

> 0.994 sunflowers

当たってますね！


##事例2: YOLOモデル

YOLOというのは"You only look once"の略みたいです。

<img src="https://qiita-image-store.s3.amazonaws.com/0/3180/15287f53-0072-39d2-34a1-c25743c71f0e.jpeg" width="400">

- [YOLO: Real-Time Object Detection](http://pjreddie.com/darknet/yolo/)

これは Pascal VOC 2012 データセットに対して物体認識を行う手法で、**20種類（クラス）のオブジェクトを分類可能**だそうです。

>
- person
- bird, cat, cow, dog, horse, sheep
- aeroplane, bicycle, boat, bus, car, motorbike, train
- bottle, chair, dining table, potted plant, sofa, tv/monitor

で、この学習済みモデルが公開されていて、それを[TensorFlowで使えるようにした](https://github.com/gliese581gg/YOLO_tensorflow)人がいて、それをさらに別の人がiOSで使えるようにしたのが下記リポジトリ。

- https://github.com/yjmade/ios_camera_object_detection

YOLOモデルの `.pb` ファイルを作成して、これをTensorFlowの公式リポジトリの `ios_examples` 配下にある[cameraサンプル](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/contrib/ios_examples/camera)で使えるようにした、というのがこのリポジトリです。

もうiOSで動くサンプルが用意されてるのでここでは利用方法については書きませんが、使ってみたところ、**メモリの使用量がエグい**です。メモリ要2GB、つまり現行機種では iPhone 6s or 6s Plusでのみ動作します。[^3]

[^3]: iPhone 6でも試してみましたが、メモリが足りず実行時に100%クラッシュしました。。

ちゃんとREADMEにもその旨が書いてあります。

> Despite I have already use YOLO tiny model, at runtime it still require at lease 850M memory, so only iPhone 6s or later which get at lease 2GB of memory can make it running, otherwise it will be killed immediately when loading the model.


###実行結果

Google画像検索で適当に牛とか馬とか犬とか猫を表示してモニタにカメラをかざして**リアルタイム認識**させてみました。以下その結果です。

![IMG_0003_r1_c1.jpg](https://qiita-image-store.s3.amazonaws.com/0/3180/6c3dabc5-ee07-94f1-ca73-62b9d47b73bf.jpeg)

(cow 0.44)


![IMG_0004_r1_c1.jpg](https://qiita-image-store.s3.amazonaws.com/0/3180/c81ab0c9-fe28-0ff9-8247-4addb4855f28.jpeg)

(horse 0.26)

![IMG_0006_r1_c1.jpg](https://qiita-image-store.s3.amazonaws.com/0/3180/211bd94a-8959-aea2-3edb-423596dc8d59.jpeg)

(dog 0.24 / cat 0.28)


##事例3: 手書き数字を識別するモデル

学習済みモデルを**Androidで実行**するという記事がありまして、

- [TesorFlow: Pythonで学習したデータをAndroidで実行 - Qiita](http://qiita.com/miyosuda/items/e53ad2efeed0ff040606)

ディープラーニングを利用した手書き数字認識のモデルを Protobuf (Protocol Buffers) 形式で作成して、その `.pb` ファイルごとGitHubにアップされていました。

- https://github.com/miyosuda/TensorFlowAndroidMNIST

冒頭のFlowersモデル同様、simpleサンプルに組み込み、

```objc
NSString* network_path = FilePathForResourceName(@"expert-graph", @"pb");
```

```objc
const int wanted_width = 28;
const int wanted_height = 28;
const int wanted_channels = 1;
```

```objc++
std::string input_layer = "input";
std::string output_layer = "output";
```

試しにMNISTのテストデータから持ってきたこういう画像を与えてみると、

<img src="https://qiita-image-store.s3.amazonaws.com/0/3180/53245345-dcce-4bc2-91da-df9443049ba3.png" width="100">

結果はこう出ました。

> Prediction: 5

ちゃんと動いてそうです。


##TensorFlowを用いないアプローチ - TensorSwift

本記事のタイトルを見て、koherさんのこの記事を思い浮かべた方も多いかもしれません。

- [TensorFlowで学習したモデルを使ってiOS/Swiftで実行する - Qiita](http://qiita.com/koher/items/2c0bfca4d6e31cde674b)

やりたいことは同じなのですが、上記記事は、TensorFlowのiOSサポートの入った0.9.0がリリースされるよりも前に書かれた記事であり、**iOS側ではTensorFlowを使っていない**、というのが大きく違う点です。TensorFlowで学習させたモデルを読み込み、**Swiftで書かれた [TensorSwift](https://github.com/qoncept/TensorSwift) という独自ライブラリでテンソルの計算を行う**、というものです。

本家TensorFlow（のiOSサポート版）を用いることと比較して、TensorSwiftのアプローチは以下の点がメリットかと思います。

- Swiftで書かれている
- 軽量である
- BLAS（Accelerate.frameworkに入っている線形代数ライブラリ）を利用した高速化がなされている

逆に、以下の点はデメリットになりそうです。

- できることが限られている

> 現状ではまだα版くらいの完成度なので TensorFlow の API のごく一部しか再現できておらず、 Deep MNIST for Experts の畳み込みニューラルネットワークが再現できるくらいの段階

- 独自の方法で書き出したモデルデータを利用する

> 本当は TensorFlow で書きだした Checkpoint ファイルを読み込めればいいのですが今のところそのような機能はありません。


##まとめと今後の展望

今回は基本的に「iOSで使えますよ」と明示して公開されている学習済みモデルを利用させていただいたわけですが、実は結構ググったりGitHub検索したにもかかわらず、そういうものはなかなか見つかりませんでした。

ただ、

- フォーマットの違う（っぽい）TensorFlow用モデルが公開されている
- 学習済みモデルは置いていないが、学習データと学習スクリプトが公開されている

というケースは多々あったので、もうちょっとちゃんとモデルについて理解して、自分でiOSでも利用可能な形で書き出すなり、学習させるなりすることができれば、できることも広がりそうです。

そんなわけで次のステップとしては、「TensorFlow iOSで使えるモデルを作成する」ということを色々参照しつつやってみたいと思っています。

##追記

TensorFlow for iOS でモデルをどのように利用しているか、コードを追ってみて記事を書きました。

- [TensorFlow for iOS のモデルについて - Qiita](http://qiita.com/shu223/items/99c39d914c32fafd4d8e)