iOS
Keras
TensorflowLite
fine-tuning
MLKit

iOSでMLKitのカスタムモデル(MobileNetをfine-tuningして量子化)を試してみた

iOSで気軽に画像分類をやってみたかったので試してみました。
fine-tuning後のモデルはデバイス上でうまく動作しなかったので、
その直前まで参考になれば幸いです。
tf.kerasの.hdf5から.tflteをつくり量子化したのですがそこでどうやらうまく行ってないようです。

環境

GPU:GTX Geforce 1080Ti
OS:Ubuntu 16.04 LTS
iOS:12.1

OSでMLKitを動かす

サンプルアプリを動かす

ML Kit を使用して推論に TensorFlow Lite モデルを使用する(iOS)
ここのサンプルを使ってもいいのですが、iOSは初めて触るので
ファイル構成が私には難しかったので
カスタムモデルの読み込みが上手く行きませんでした。

そこで
ML Kit on iOS and how it performs against Core ML
のサンプルを使いました。
こちらの構成のほうがシンプルなのでわかりやすかったです。
最初にビルドするとエラーが何個か出ますが、ポチポチfixボタンを押していけば大丈夫です。
一箇所だけコードの修正が必要な場所が81行目の

CustomModelViewController.swift
let options = ModelOptions(
    cloudModelName: Constants.Models.cloudMobilenet,
    localModelName: Constants.Models.localMobilenet
)
interpreter = ModelInterpreter(options: options)

CustomModelViewController.swift
let options = ModelOptions(
    cloudModelName: Constants.Models.cloudMobilenet,
    localModelName: Constants.Models.localMobilenet
)
interpreter = ModelInterpreter.modelInterpreter(options: options)

に修正する必要があります。
アップデートで書き方が変わったのかな?

クラウドモデルの登録をして動かす

Firebase Console
からプロジェクトを追加します。
スクリーンショット 2019-01-08 14.43.09.png
ここではMLkitTestとしました
スクリーンショット 2019-01-08 14.47.40.png
iOSを追加するためにボタンを選択し
スクリーンショット 2019-01-08 14.48.45.png
この画面に移動します。
このiOSバンドルIDには
スクリーンショット 2019-01-08 14.49.52.png
このBundle Identiferを入力します。
スクリーンショット 2019-01-08 14.50.57.png

そのあとは画面に従ってGoogleService-Info.plist ファイルを Xcode プロジェクトのルートに移動します。
スクリーンショット 2019-01-08 14.53.57.png
そしてここからカスタムモデルをクラウド上に追加します。
スクリーンショット 2019-01-08 14.56.50.png

ここに.tfliteが置いてあるので試しにアップロードすると簡単に試せます。
List of Hosted Models

custom モデルを作る

KerasでMobileNetをファインチューニングして、サイズを落としてスマホで実行してみます。

mobile net のfine tuning を行う

Keras学習済みモデルをFine-tuningさせて精度比較
上記を参考にさせていただきました!
ここのモデルはうまく動作しています。

.hdf5 から .tfliteに変換する

変換するツールがtensorflowにありました。
まだあまり使われてないようでググってもヒットがすくなかったです。

import tensorflow as tf
# Convert to TensorFlow Lite model.
converter = tf.contrib.lite.TFLiteConverter.from_keras_model_file(model_dir + 'model_MobileNet.hdf5')
tflite_model = converter.convert()
open("converted_model.tflite", "wb").write(tflite_model)

しかし、参考のまま(コピペのまま)モデルを変換しようとするとエラーがでます。

なぜだろう??とググっていると
同じような症状にあたったというブログが!

みらいテックラボ:金魚って見分けられる? (3)
どうやらモデルの構造がおかしいから変換がうまくいかない様子。

上記をヒントにいろいろ試行錯誤すると
どうやらinput_tensorの形が指定されていなかったので、
察しの悪いコンバータが困り果てていたようです。
そこで、ベースモデルを呼び出すときに指定します。

具体的には

base_model = MobileNet(
    include_top = False,
    weights = "imagenet",
    input_shape = None
)

の部分を

# ここが大事だったようだ
input_tensor = Input(shape=(image_size, image_size, 3))

base_model = MobileNet(
    include_top = False,
    weights = "imagenet",
    input_shape = None,
    input_tensor = input_tensor
)

とします。
するとコンバートがうまくいきました!
やったね

量子化する

さて上記のモデルをスマホで実行しようとしたところ
アプリが落ちてしまいました。
どうやら重くて動作ができないようです。
そこで量子化を試みます。

量子化する方法をいろいろググっていると、
特別に他のツールを必要とせず、オプショを指定すればいいようでした。
(ドキュメントが整備されていなくて分かりづらい)
以下のコマンドを実行すると

import tensorflow as tf
converter = tf.contrib.lite.TFLiteConverter.from_keras_model_file(model_dir + 'model_MobileNet.hdf5')
converter.post_training_quantize = True
tflite_quantized_model = converter.convert()
open("quantized_model.tflite", "wb").write(tflite_quantized_model)

17MBもあったモデルが4MBに圧縮できました!

これをスマホで実行しましょう!
....
....
....
動かない。。。。なぜだ。。。

最後に

なんで動かないか調べいていくと、直近でこんな記事を書いている方が!
KerasのMobileNetモデルをTensorFlow Liteモデルファイルに変換できるように書き換える
でも私の場合は変換自体は出来ているので、この方とは症状が違うような。。。?

時間切れなので今回はここまで

所感とこれからやりたいこと

iOSでのMLKitのサンプルが少なくて困りました。
インド人youtuberがポツポツ解説してくれててるくらいで、参考になる資料が少ない印象です。
これはまだMLKitがベータ版で実運用されてないからでしょう。

iOS,Androidともに機械学習しかやってなかった私には難しかったです。
ファイル構成や、エラーの読み方、文法やコメントがぜんぜん違うので慣れる必要があります。

2019年はdeep learning はエッジでの運用が加速すると言われています。
しかし、組み込みでの開発はコストがかかるので、
Android Thingsなどのプラットフォームを利用した開発が進むと思われます。
deep learningに携わっている人もAndroidの知識が必要になるかもしれません。
iOSは出遅れてるかもしれないので、Androidを重点的にやろうと思います。

今後は
fine-tuningしたモデルをきっちりスマホで動かしたいです。
iPhone/Androidアプリ開発者のための機械学習・深層学習 実践入門
という書籍が2019/1/26に発売されるのでそれを使って学習していきたいと思います。