Code for YAMATOKORIMAYAでは, 「アーバンデータチャレンジ2018 」への取り組みの一つとして, 金魚AI(愛)育成プロジェクトなるものに取り組んでいる.
関連記事:
・金魚って見分けられる? (1)
・金魚って見分けられる? (2)
・金魚って見分けられる? (3)
・金魚って見分けられる? (4)
今回は, Kerasで学習したモデルをTensorFlow Liteのモデルに変換して, Androidで動かしてみようという話.
TensorFlow 1.10あたりから, tf.contrib.lite.TocoConverter.from_kears_model_fileが準備されたので, 簡単にできるかと思ったが, 結構ハマった.
1. TensroFlow Liteとは? [1]
TensorFlow Liteは, GoogleのMLフレームワークであるTensorFlowのモバイル環境向けサブセットである.
主な特徴:
・On Deviceでの機械学習推論が可能
・TensorFlowの学習済モデルをモバイル環境(Android, iOS等)で実行できる形に変換(TensorFlow Lite Converter)
・Android Neural Networks APIによりハードウェアアクセラレーションをサポート
など.
TensorFlow Liteアーキテクチャ図:
2. TensorFlow Lite Converter [2]
TensorFlow学習済モデルとTensorFlow Liteモデルは, 図のような関係にある.
3. Kerasモデルの変換
どんなモデルでもTensorFlow Liteに変換可能というわけではなく, 変換できるものには制限がある.
学習済モデルでは, InceptionV3やMobileNetなどは大丈夫なようだ.
ということは, これまで使用していたInception-ResNetV2ベースのFineTuningモデルはダメそうである.
そこで, MobileNetをベースに金魚データでFineTuningし直し, これの変換を試みる.
3.1 TocoConverter(*)の問題
まずは, TocoConverter.from_keras_model_fileで変換を試みた.
*: TensorFlow 1.12からはTFLiteConverterに改名.
import os import sys from tensorflow.contrib import lite MODEL_DIR = './model' MODEL_FILE = 'MobileNet_size224.h5' TFLITE_MODEL_FILE = 'MobileNet_size224.tflite' converter = lite.TocoConverter.from_keras_model_file(os.path.join(MODEL_DIR, MO\ DEL_FILE)) tflite_model = converter.convert() open(os.path.join(MODEL_DIR, TFLITE_MODEL_FILE), "wb").write(tflite_model)
しかし, うまく変換できず.
(tensorflow) aska@aska:~/work/GoldFish$ python conv_mobilenet_tf.py 2018-10-20 21:29:57.905622: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: SSE4.1 SSE4.2 AVX AVX2 FMA 2018-10-20 21:29:57.906884: I tensorflow/core/common_runtime/process_util.cc:69] Creating new thread pool with default inter op setting: 2. Tune using inter_op_parallelism_threads for best performance. Traceback (most recent call last): File "conv_mobilenet_tf.py", line 10, in <module> converter = lite.TocoConverter.from_keras_model_file(os.path.join(MODEL_DIR, MODEL_FILE)) File "/home/aska/anaconda3/envs/tensorflow/lib/python3.6/site-packages/tensorflow/contrib/lite/python/lite.py", line 356, in from_keras_model_file keras_model = _keras.models.load_model(model_file) File "/home/aska/anaconda3/envs/tensorflow/lib/python3.6/site-packages/tensorflow/python/keras/engine/saving.py", line 251, in load_model training_config['weighted_metrics']) KeyError: 'weighted_metrics'
ネット情報をもとに, SavedModelやFrozenGraphDefへいったん変換し, その後TFLite FlatBufferへの変換という二段階の変換を試み, 変換自体は何とかできた.
しかし, AndroidのTFLiteCameraDemo[3]に組み込むと, 起動時にアプリが落ちてしまう.
E/AndroidRuntime: FATAL EXCEPTION: main Process: android.example.com.tflitecamerademo, PID: 14151 java.lang.RuntimeException: Unable to start activity ComponentInfo{android.example.com.tflitecamerademo/com.example.android.tflitecamerademo.CameraActivity}: java.lang.IllegalArgumentException: Internal error: Cannot create interpreter: Op builtin_code out or range: 82. Are you using old TFLite binary with newer model?Registration failed. at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2416) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476) at android.app.ActivityThread.-wrap11(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:148) at android.app.ActivityThread.main(ActivityThread.java:5417) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) Caused by: java.lang.IllegalArgumentException: Internal error: Cannot create interpreter: Op builtin_code out or range: 82. Are you using old TFLite binary with newer model?Registration failed. at org.tensorflow.lite.NativeInterpreterWrapper.createInterpreter(Native Method) at org.tensorflow.lite.NativeInterpreterWrapper.<init>(NativeInterpreterWrapper.java:75) at org.tensorflow.lite.NativeInterpreterWrapper.<init>(NativeInterpreterWrapper.java:54) at org.tensorflow.lite.Interpreter.<init>(Interpreter.java:114) at com.example.android.tflitecamerademo.ImageClassifier.<init>(ImageClassifier.java:100) at com.example.android.tflitecamerademo.Camera2BasicFragment.onActivityCreated(Camera2BasicFragment.java:299) at android.app.Fragment.performActivityCreated(Fragment.java:2228) at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:992) at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1148) at android.app.BackStackRecord.run(BackStackRecord.java:793) at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1535) at android.app.FragmentController.execPendingActions(FragmentController.java:325) at android.app.Activity.performStart(Activity.java:6267) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2379) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476) at android.app.ActivityThread.-wrap11(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:148) at android.app.ActivityThread.main(ActivityThread.java:5417) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
3.2 モデル構造の問題
カスタムモデルはそれなりに変換できるのに, 学習済みモデルをベースにFine Tuningしたモデルはうまく変換できない.
試行錯誤している中, ふとモデル構造自体に問題があるのかと思い, MobileNetのTop層を変更したところ偶然にもこれがうまくいった.
[変更前]
# MobileNetのTop層(金魚22カテゴリ) top_model = Sequential() top_model.add(Reshape((1, 1, 1024), input_shape=irn_model.output_shape[1:], nam\ e='reshape1')) top_model.add(Dropout(0.4, name='dropout')) top_model.add(Conv2D(CATEGORY, (1, 1), padding='same', name='conv_preds')) top_model.add(Activation('softmax', name='act_softmax')) top_model.add(Reshape((CATEGORY,), name='reshape_2'))
[変更後]
# Top層をFCに(金魚22カテゴリ) top_model = Sequential() top_model.add(Dropout(0.4, input_shape=irn_model.output_shape[1:])) top_model.add(Dense(CATEGORY, activation='softmax', name='Logits'))
結局, 現在使用しているモデル変換コードは, こちらのStack Overflow[4]を参考にしたものを使用している.
4. フィールドテスト
本日(11/3), こちらのイベントに参加し, 実際に水槽の金魚で試してみた.
まちなか金魚生息地マップをつくろう! 〜金魚愛[ai]育成PJ Vol.2〜(UDC2018)
まだまだ誤認識もあるが, 一応水槽内の金魚で識別もできてる.
また, 今回の金魚データ収集イベントでは, 約900枚の写真データを集めることができた.
今後は,
・今回のイベントなどを通し, 現在金魚データを大量に収集しようとしているので, それらを使ってモデルの高精度化.
・1フレームの処理に200ms程度かかっているので, 今後QUANTIZED_UINT8を試してみる. (現状うまく変換できていない)
・ML Kitのカスタムモデルとして動かす.
など, やっていく予定.
----
参照URL:
[1] Introduction to TensorFlow Lite | TensorFlow Lite | TensorFlow
[2] TensorFlow Lite Converter | TensorFlow Lite | TensorFlow
[3] TensorFlow for Poets 2: TFLite Android
[4] python - Problem converting Keras model to Tensorflow-Lite using TocoConverter.from_keras_model_file - Stack Overflow
TensorFlow機械学習クックブック Pythonベースの活用レシピ60+ (impress top gear)
|
TensorFlow&Kerasプログラミング実装ハンドブック
|
|
現場で使える! TensorFlow開発入門 Kerasによる深層学習モデル構築手法 (AI & TECHNOLOGY)
|