iOSでTensorFlow Liteを試してみたら思いの外ハマって、サンプルの修正PRを投げた話

## はじめに
iPhone SE(2020)を購入したので、A13 Bionicチップの実力が知りたく `TensorFlow Lite` を試してみました🙋‍♂️
最近のスマートフォンに搭載されているSoCは処理性能も高く、どの程度動くのか気になってました。
前回試したときは、僕が学生の頃だったので、２０１６年〜２０１７年くらいだったと思います。
当時は、iPad mini3で動かした記憶がありますが、あまり処理速度も高くなかった印象です。

### 僕の環境
machine：MacBook Pro (Retina, 13-inch, Early 2015) / iPhone SE(2020)
OS：macOS Catalina バージョン10.15.6 / iOS 13.5.1

XcodeやiOSを触るのも３年ぶりなので、初回の環境構築からやっていきたいと思います:muscle:

## CocoaPodsの導入
[CocoaPods](https://github.com/CocoaPods/CocoaPods)：iOS/macOS向けのライブラリマネージャーです。
今回は、2020/08/29時点で最新版の `v1.9.3` をインストールしました。
`CocoaPods` はRubyGemsなので、普段はRailsでサーバーサイドの開発をしている身としてはとても親近感があります:relaxed:

### インストール
```console
# cocoapodの導入
$ gem install cocoapods
Installing ri documentation for cocoapods-1.9.3
Done installing documentation for concurrent-ruby, i18n, thread_safe, tzinfo, activesupport, nap, fuzzy_match, algoliasearch, ffi, ethon, typhoeus, netrc, cocoapods-core, claide, cocoapods-deintegrate, cocoapods-downloader, cocoapods-plugins, cocoapods-search, cocoapods-stats, cocoapods-trunk, cocoapods-try, molinillo, atomos, CFPropertyList, colored2, nanaimo, xcodeproj, escape, fourflusher, gh_inspector, ruby-macho, cocoapods after 60 seconds
32 gems installed

# ローカル環境にcocoapodがインストールされたか確認する
$ gem list cocoapod

*** LOCAL GEMS ***

cocoapods (1.9.3)
cocoapods-core (1.9.3)
cocoapods-deintegrate (1.0.4)
cocoapods-downloader (1.4.0)
cocoapods-plugins (1.0.0)
cocoapods-search (1.0.0)
cocoapods-stats (1.1.0)
cocoapods-trunk (1.5.0)
cocoapods-try (1.2.0)

# インストールしたcocoapodのバージョンを確認（2020/08/29現在の最新版を導入した）
$ pod --version
1.9.3
```

### セットアップ
```console
# podコマンドが使用できるか確認する
$ pod
Usage:

    $ pod COMMAND

      CocoaPods, the Cocoa library package manager.

Commands:

    + cache         Manipulate the CocoaPods cache
    + deintegrate   Deintegrate CocoaPods from your project
    + env           Display pod environment
    + init          Generate a Podfile for the current directory
    + install       Install project dependencies according to versions from a
                    Podfile.lock
    + ipc           Inter-process communication
    + lib           Develop pods
    + list          List pods
    + outdated      Show outdated project dependencies
    + plugins       Show available CocoaPods plugins
    + repo          Manage spec-repositories
    + search        Search for pods
    + setup         Setup the CocoaPods environment
    + spec          Manage pod specs
    + trunk         Interact with the CocoaPods API (e.g. publishing new specs)
    + try           Try a Pod!
    + update        Update outdated project dependencies and create new Podfile.lock

Options:

    --silent        Show nothing
    --version       Show the version of the tool
    --verbose       Show more debugging information
    --no-ansi       Show output without ANSI codes
    --help          Show help banner of specified command

# pod setupコマンドで~/.cocoapods以下にCocoaPodsのリポジトリの情報を設定する
$ pod setup
Setup completed

# cocoapodの管理下にあるライブラリを確認する（初回導入時は一つも存在しないはず）
$ pod list

0 pods were found
```

## ビルド前の準備
公式の[チュートリアル](https://www.tensorflow.org/lite/performance/gpu#demo_app_tutorials)に従って導入します:point_up:
チュートリアルは、[リポジトリ内](https://github.com/tensorflow/tensorflow/blob/eed8f6c0946cd229d9b749295dd02045271b066e/tensorflow/lite/g3doc/performance/gpu.md)にも格納されています。
### TensorFlowリポジトリの取得

```console
$ git clone https://github.com/tensorflow/tensorflow
```

### モデルをダウンロード
サンプルで使用するモデルデータをダウンロードします。

```console
$ sh tensorflow/lite/examples/iosdownload_models.sh
```

### `TensorFlowLiteGpuExperimental` をインストール

`TensorFlowLiteGpuExperimental` を利用したいので、Podfileの内容を下記の形に修正します。

```diff
--- a/tensorflow/lite/examples/ios/camera/Podfile
+++ b/tensorflow/lite/examples/ios/camera/Podfile
@@ -9,5 +9,6 @@ target 'tflite_camera_example'
   # Note: TFLite GPU Delegate binary isn't released yet, but we're working
   # on it.

-  pod 'TensorFlowLite', '1.13.1'
+  # pod 'TensorFlowLite', '1.13.1'
+  pod 'TensorFlowLiteGpuExperimental', '0.0.1'
```

https://github.com/tensorflow/tensorflow/blob/eed8f6c0946cd229d9b749295dd02045271b066e/tensorflow/lite/examples/ios/camera/Podfile#L13

pod installコマンドを使って、 `TensorFlowLiteGpuExperimental` をインストールします。

```console
# pod installコマンドでライブラリを導入する
$ pod install
Analyzing dependencies
Downloading dependencies
Installing TensorFlowLiteGpuExperimental (0.0.1)
Generating Pods project
Integrating client project

[!] Please close any current Xcode sessions and use `tflite_camera_example.xcworkspace` for this project from now on.
Pod installation complete! There is 1 dependency from the Podfile and 1 total pod installed.
```

## サンプルをビルドする
pod installを走らせたときに、 `tflite_camera_example.xcworkspace` を使ってねと言われるので、こちらを開きます。

![スクリーンショット 2020-08-29 14.24.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50627/d0f771cb-4aff-10f2-6209-bffe293ca185.png)


 
Bundle identifierをユニークなものに変更します。
![スクリーンショット 2020-08-29 15.01.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50627/628d9537-4a59-0f0c-0185-caf4d037df26.png)


`Product > Scheme > Edit Scheme...` から `Run` を選択して、 `Info` タブの `Build Configuration`と `Debug executable` を下記のように変更します。

|変更前|変更後|
|----|----|
|![スクリーンショット 2020-08-29 14.38.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50627/620a46c0-c04c-312a-1447-b0c33e2e8871.png)|![スクリーンショット 2020-08-29 14.38.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50627/f12b6285-5735-3369-b910-b34c6dc54179.png)|

次に、 `Options` タブの、  `GPU Frame Capture` を `Disabled` に、 `Metal API Validation` を `Disabled`　にします。

![スクリーンショット 2020-08-29 21.18.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50627/a57a6a47-2814-4630-a975-d911b25e7ef7.png)

最後に、64ビットアーキテクチャによるリリースのみのビルドを選択します。 `Project navigator -> tflite_camera_example -> PROJECT -> tflite_camera_example -> Build Settings` の `Build Active Architecture Only > Release` をYesに設定します。

![スクリーンショット 2020-08-29 14.41.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50627/bcb46242-dc5f-2b08-16e4-d3f1218eba6d.png)

これでCPUを使う場合のビルド設定はできたので、実機を繋いでビルドします。

### CPUを使って物体認識
最初のnotebookが認識するくらいで、CPUだからなのか認識率はあまり良くないですね... :sweat: 
A13 Bionicチップとは言えども、CPUだけでは限界があるみたいですね！
![RPReplay_Final1598686901.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50627/8db77eea-94d2-d8cc-3ccc-a6e1e4bed232.gif)



### GPUデリゲートを有効にする
`TFLITE_USE_GPU_DELEGATE` の値を0から1に変更します。

```CameraExampleViewController.h
#define TFLITE_USE_GPU_DELEGATE 1
```

https://github.com/tensorflow/tensorflow/blob/eed8f6c0946cd229d9b749295dd02045271b066e/tensorflow/lite/examples/ios/camera/CameraExampleViewController.h#L22

変更したので再ビルドします。
します。しますが、ビルドが通りません！:scream:
`Unknown type name 'TFLGpuDelegateOptions'; did you mean 'GpuDelegateOptions'?` のようなエラーが出力されビルドに失敗するのです。

### GPUが使えるように修正する
このままだとやりたいことができないので、GPUが使えるように修正します。
どうやら `TFLGpuDelegateDelete` と `TFLGpuDelegateOptions` が使えなくなっているみたいです:thinking:
`TFLGpuDelegateDelete` を `DeleteGpuDelegate` に、 `TFLGpuDelegateOptions` を `GpuDelegateOptions` に変更します。
 
```diff
diff --git a/tensorflow/lite/examples/ios/camera/CameraExampleViewController.mm b/tensorflow/lite/examples/ios/camera/CameraExampleViewController.mm
index 665131195e..01c24c1838 100644
--- a/tensorflow/lite/examples/ios/camera/CameraExampleViewController.mm
+++ b/tensorflow/lite/examples/ios/camera/CameraExampleViewController.mm
@@ -387,7 +387,7 @@ void ProcessInputWithQuantizedModel(
 - (void)dealloc {
 #if TFLITE_USE_GPU_DELEGATE
   if (delegate) {
-    TFLGpuDelegateDelete(delegate);
+    DeleteGpuDelegate(delegate);
   }
 #endif
   [self teardownAVCapture];
@@ -416,10 +416,10 @@ void ProcessInputWithQuantizedModel(
   tflite::InterpreterBuilder(*model, resolver)(&interpreter);

 #if TFLITE_USE_GPU_DELEGATE
-  TFLGpuDelegateOptions options;
+  GpuDelegateOptions options;
   options.allow_precision_loss = true;
-  options.wait_type = TFLGpuDelegateWaitTypeActive;
-  delegate = TFLGpuDelegateCreate(&options);
+  options.wait_type = GpuDelegateOptions::WaitType::kActive;
+  delegate = NewGpuDelegate(&options);
   interpreter->ModifyGraphWithDelegate(delegate);
 #endif
```


該当箇所は下記URLの箇所になります。
https://github.com/tensorflow/tensorflow/blob/36d2f532a1eade7ad8b77589c85059a9ddb2f1e1/tensorflow/lite/examples/ios/camera/CameraExampleViewController.mm#L389-L391

https://github.com/tensorflow/tensorflow/blob/36d2f532a1eade7ad8b77589c85059a9ddb2f1e1/tensorflow/lite/examples/ios/camera/CameraExampleViewController.mm#L418-L424

これで、再度ビルドしてみると、ビルドが成功しました:tada: 
![スクリーンショット 2020-08-29 21.26.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50627/4f9ab492-3cba-d23b-2597-477cc0c2d48b.png)

### GPUを使って物体認識
GPUを使うことで、CPUよりも圧倒的に認識速度が向上していますね:v:
![RPReplay_Final1598686846.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50627/771df310-2ef0-fbec-ed16-541ed3d6661b.gif)

### CPU vs GPU

CPUとGPUの認識速度をGIF画像を使って見比べてみます。
CPUを使った場合に比べて、認識する物体の件数や速度が圧倒的にGPUを使った場合のほうが向上していることが分かります。
比較的安価に購入できるiPhone SE(2020)でも、11シリーズと同じA13 Bionicチップのおかげで十分に処理できているみたいですね。（10分くらい動かし続けると、ほんのり温かくなってきましたｗ）

|CPU版|GPU版|
|----|----|
|![RPReplay_Final1598686901.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50627/8db77eea-94d2-d8cc-3ccc-a6e1e4bed232.gif)|![RPReplay_Final1598686846.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50627/771df310-2ef0-fbec-ed16-541ed3d6661b.gif)|

## おわりに
TensorFlow Liteを試したきっかけは、敬愛する@shu223さんのツイートを偶然見かけたからでした:relaxed:
https://twitter.com/shu223/status/1298210477357424640?s=20

@shu223さんのQiita記事にリンクが貼られている公式の `Face Contour detection` を試してみたく、先にチュートリアルから復習しようとしたら、意外とハマりどころを見つけたという感じです。

最新の環境でもチュートリアルの内容が動くようになったので、次は `Face Contour detection` に挑戦してみようと思います:raised_hands:

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50627/d4c07125-f210-abd9-f792-916aef929b4b.png)

https://medium.com/tensorflow/tensorflow-lite-now-faster-with-mobile-gpus-developer-preview-e15797e6dee7


## おまけ
今回見つけたサンプルコードの修正箇所のPRを作ってみました:sunny:
![スクリーンショット 2020-08-29 21.48.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50627/287e1ab1-38c9-c744-4354-5334d19a41e8.png)

https://github.com/tensorflow/tensorflow/pull/42767

## 参考文献
- https://qiita.com/shu223/items/2ddcea8e949aa96749c2
- http://shu223.hatenablog.com/entry/20160720/1468969711
- https://medium.com/tensorflow/tensorflow-lite-now-faster-with-mobile-gpus-developer-preview-e15797e6dee7