ML Kit for Firebase(on device)でカスタムモデルを動かす話(TensorFlowLite/Keras)

#はじめに
以前、Udemyのコース[【画像判定AI自作にチャレンジ！】TensorFlow・Keras・Python・Flaskで作る機械学習アプリ開発入門](https://www.udemy.com/tensorflow-advanced/)を受講し、カスタムモデルを作ってWEBアプリとして動作させて学びましたが、先日参加したFirebaseの[セミナー(Firebase Meetup #10 @mercari)](https://firebase-community.connpass.com/event/115709/)にて、Androidアプリでも、カスタムモデル(on device)を動作させたいと思い立ち、ML Kit for Firebaseを触ってみました。

モチベーションは三つ。

+ 実際の現場では、事前構築済みモデルではニーズを満たせないことが多いため、カスタムモデルを利用したかったこと
+ 諸々の制約（ネットワーク環境、プライバシー等）などで、WEBアプリでなく、オンデバイスで画像分類器を動作させる手法についての知見を得たかったこと
+ クイックスタートを動かすだけでなく、[自身のカスタムモデル(ラーメン二郎と中本2分類器)](https://github.com/ko-ism/datalab_keras_cnn/blob/master/datalab_keras_cnn_git.ipynb)を利用することで応用のための知見も得たかったこと

正直、クライアント側の技術は触ったことがなく、AndroidStudioを入れるところから始めたため、所々ハードルはありましたが、なんとか実装まで漕ぎつけました。


## 超ざっくりの流れ

1. 動かしたいモデル(h5ファイル)を生成しておきます。(keras)
2. モデル(h5ファイル)を、tfliteへ変換します。
3. AndroidStudioで、ML Kit for Firebaseのクイックスタートを実施します。
4. 自身のカスタムモデル(tflite)を利用するようにコードを変更します。
5. アプリを端末へ転送し、動かします。完成。


## 環境

#### サーバ
このサーバでtflite形式にモデルを変換するのに利用

+ (GoogleComputeEngine)Ubuntu16.04
+ python 3.6
+ tensorflow 1.12.0              
+ tf-nightly 1.13.0.dev20190211


#### ローカルPC
AndroidStudioを入れて、タブレットとUSB接続し、アプリをインストールする用途

+ Windows 10
+ AndroidStudio 3.2.1
+ Anaconda3


#### タブレット端末
TensorFlowLiteモデルを入れて、Androidアプリを動かす用途

+ HuaweiMediaPad
+ Android7.0


## 1. モデル(h5ファイル)を生成
kerasで作ったモデル(h5ファイル)を用意します。すでに動かしたいモデルのh5ファイルが存在している人は、ここはスキップ。

Udemyのコースの[【画像判定AI自作にチャレンジ！】TensorFlow・Keras・Python・Flaskで作る機械学習アプリ開発入門](https://www.udemy.com/tensorflow-advanced/)　が参考になりました。

今回用意したモデルの概要は以下です。

+ input shapeは、1*50*50*3　で、outputは、softmaxで2分類
+ 中本とラーメン二郎の画像をそれぞれ150枚程度学習
+ [今回利用したモデルの生成コードはgithub上にアップロード済み](https://github.com/ko-ism/datalab_keras_cnn/blob/master/datalab_keras_cnn_git.ipynb)
+ モデルサマリは以下

![モデルサマリ](https://storage.googleapis.com/permanent_koizumi/20190212_nakamotojiro_summary.png "モデルサマリ")


## 2. モデル(h5ファイル)を、tfliteへ変換
Windows環境だとtocoがサポートしていないためうまく動かなかったり、h5をpbに変換してtfliteにするとか考えたり、tflite_convertコマンドを試してエラーが出たり、紆余曲折はありましたが、最後は便利なライブラリを利用することで、ものすごく簡単に変換することができました。

+ tf.contrib.lite.TFLiteConverter

[https://www.tensorflow.org/api_docs/python/tf/contrib/lite/TFLiteConverter](https://www.tensorflow.org/api_docs/python/tf/contrib/lite/TFLiteConverter)

このライブラリで、kerasで生成したモデル(h5)から、TensorFlow Liteのモデルへ変換することができます。

```Python:siteに記載
# Converting a tf.keras model.
converter = lite.TFLiteConverter.from_keras_model_file(keras_model)
tflite_model = converter.convert()
```

今回、TensorFlow liteへ変換するために実装したコードは、以下のみ。

```Python:keras2tflite.py
import tensorflow as tf

converter = tf.contrib.lite.TFLiteConverter.from_keras_model_file("nakamoto_jiro_cnn.h5")
tflite_model = converter.convert()
open("converted_model.tflite", "wb").write(tflite_model)
```

ちなみに、最初は、この[TensorFlow LiteのConverterのサイト(https://www.tensorflow.org/lite/convert/python_api)](https://www.tensorflow.org/lite/convert/python_api)を見て、
converter = tf.lite.TFLiteConverter.from_keras_model_file("keras_model.h5")
のように書いて、エラーが発生してしまいました。

```Python:Error
AttributeError: module 'tensorflow' has no attribute 'lite'
```

ただ、これは、TensorFlowのバージョン毎に、Convertライブラリの位置や名前が変わっている模様。https://github.com/tensorflow/tensorflow/issues/24239

|TensorFlow version|Converterライブラリ名|
|:---|:---|
|1.12|tf.contrib.lite.TFLiteConverter|
|1.9〜1.11|tf.contrib.lite.TocoConverter|
|1.7〜1.8|tf.contrib.lite.toco_convert|

## 3. AndroidStudioで、ML Kit for Firebaseのクイックスタートを実施

基本的に、githubに公開されている以下のコードを利用します。
[https://github.com/firebase/quickstart-android/tree/master/mlkit](https://github.com/firebase/quickstart-android/tree/master/mlkit)

+ クイックスタートで動くモデルとしてFirebaseの顔認識やラベル判定、テキスト検出、カスタムモデルなどがあります。(MobileNetv2)
+ [参考サイトは、こちら。(ML Kit For Firebaseを使ってスマホで色々検出してみた)](https://dev.classmethod.jp/machine-learning/mlkit_detection_demo/)

1. Firebaseにプロジェクト作成
2. Android アプリに Firebase を追加

このあたりの操作も初めてだったので、デプロイ方法だとかを慣れるために、codelabをいくつかやりました。学習教材が充実していて、とても良いです。

+ [Identify objects in images using custom machine learning models with ML Kit for Firebase](https://codelabs.developers.google.com/codelabs/mlkit-android-custom-model/)
+ [Detect objects in an Image using Firebase MLKit](https://codelabs.developers.google.com/codelabs/mlkit-image-objects-android/)



## 4. 自身のカスタムモデル(tflite)を利用するようにコードを変更
前項で利用したチュートリアルコードを活用しつつ、最低限、モデル名、モデルのパス、結果の数、inputイメージサイズを変えることで、自身のカスタムモデルを利用できます。具体的には以下を変更しました。
(記載にミスや間違い等、有りましたらコメントをお願い致します。)

```Python:app/java/custommodel/CustomImageClassier.java
    //private static final String LOCAL_FLOAT_MODEL_NAME = "mobilenet_float_v2_1.0_299";
    private static final String LOCAL_FLOAT_MODEL_NAME = "nakamoto_jiro";

    //private static final String LOCAL_FLOAT_MODEL_PATH = "mobilenet_float_v2_1.0_299.tflite";
    private static final String LOCAL_FLOAT_MODEL_PATH = "nakamoto_jiro.tflite";

    //private static final int RESULTS_TO_SHOW = 3;
    private static final int RESULTS_TO_SHOW = 2;

    //private static final int DIM_IMG_SIZE_X = 299;
    //private static final int DIM_IMG_SIZE_Y = 299;
    private static final int DIM_IMG_SIZE_X = 50;
    private static final int DIM_IMG_SIZE_Y = 50;
```

次に、app/assets　に格納されている以下のファイルを修正、追加

```txt:app/assets/labels.txt
nakamoto
jiro
```

最後に、tflite自体を、app/assetsに格納(nakamoto_jiro.tflite)


## 5. あとはアプリを端末へ転送するだけ

AndroidStudioで、Runして、自分の端末を指定してアプリを転送します。


![中本二郎分類モデル](https://storage.googleapis.com/permanent_koizumi/20190212_nakamoto_jiro.png "中本二郎分類モデル")

Androidアプリでのリアルタイム分析により、二郎の画像を高い確率で二郎・中本と判定できていることを確認できました。また、クイックスタートのサンプル(Classification(float))を活用することで、お手軽に自身のローカルデバイス上でカスタムモデルが動くアプリを動かすことができました。

チュートリアルのコードをもっと読み解いて、これを機に、もっとML Kit for Firebaseを活用していきたいと思います。


## その他、つまづいたところ
+ HuaweiのUSBデバッグモード切替して、Androidへアプリ転送する方法
[参考サイトはこちら(どのようにHUAWEIで「開発者向けオプション」を表示しますか？)](https://www.imobie.jp/faq/phonerescue-for-huawei-faqs.htm)

 + 「設定」＞「タブレット情報」＞ビルド番号を７回タップ　で、開発者向けオプション表示
 + 開発者向けオプションの、USBデバッグの項を有効化
 + これで、USB接続すると、AndroidStudioが、対象端末として認識できる
（なに、この裏コマンド）

## 参考リンクまとめ

+ [ML Kit for Firebase クイックスタート](https://github.com/firebase/quickstart-android/tree/master/mlkit)
+ [ML Kit For Firebaseを使ってスマホで色々検出してみた](https://dev.classmethod.jp/machine-learning/mlkit_detection_demo/)
+ [Firebase ML Kitで自作のカスタムモデルを使って料理・非料理画像を判定できるようにした](https://techlife.cookpad.com/entry/2018/07/05/090000)
+ [TFLiteConverterドキュメント](https://www.tensorflow.org/api_docs/python/tf/contrib/lite/TFLiteConverter)
+ [(Codelabs)Identify objects in images using custom machine learning models with ML Kit for Firebase](https://codelabs.developers.google.com/codelabs/mlkit-android-custom-model/)
+ [(Codelabs)Detect objects in an Image using Firebase MLKit](https://codelabs.developers.google.com/codelabs/mlkit-image-objects-android/)
+ [どのようにHUAWEIで「開発者向けオプション」を表示しますか？](https://www.imobie.jp/faq/phonerescue-for-huawei-faqs.htm)
+ [【画像判定AI自作にチャレンジ！】TensorFlow・Keras・Python・Flaskで作る機械学習アプリ開発入門](https://www.udemy.com/tensorflow-advanced/)