みらいテックラボ

音声・画像認識や機械学習など, 週末プログラマである管理人が興味のある技術の紹介や実際にトライしてみた様子などメモしていく.

金魚って見分けられる? (3)

Code for YAMATOKORIMAYAでは, 「アーバンデータチャレンジ2018 」への取り組みの一つとして, 金魚AI(愛)育成プロジェクトなるものに取り組んでいる.

f:id:moonlight-aska:20180729174722j:plain:w400


関連記事:
金魚って見分けられる? (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アーキテクチャ図:
f:id:moonlight-aska:20181103113419p:plain:w500


2. TensorFlow Lite Converter [2]
TensorFlow学習済モデルとTensorFlow Liteモデルは, 図のような関係にある.
f:id:moonlight-aska:20181103114623p:plain


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)


GoldFish TFLite 01


GoldFish TFLite 02

まだまだ誤認識もあるが, 一応水槽内の金魚で識別もできてる.
また, 今回の金魚データ収集イベントでは, 約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&Kerasプログラミング実装ハンドブック

TensorFlow&Kerasプログラミング実装ハンドブック


PythonとKerasによるディープラーニング

PythonとKerasによるディープラーニング


現場で使える! TensorFlow開発入門 Kerasによる深層学習モデル構築手法 (AI & TECHNOLOGY)

現場で使える! TensorFlow開発入門 Kerasによる深層学習モデル構築手法 (AI & TECHNOLOGY)