Tensorflowで作った学習モデルをandroidで利用する

物体検出を勉強中です。Tensorflowにはネットワークのグラフ情報やパラメータなどを保存するcheckpointというものがありますよね。
checkpointファイルをロードすれば一旦学習をストップして、再度学習を続行することもできて非常に便利。
それとは別でcheckpointファイルからProtocolBufferと呼ばれるグラフ情報とパラメータが格納されたファイルを作成できるらしく、それを使ってAndroid上で動かしてみた。

まずはProtocolBufferファイルの作成から。コードはいつも通りここにあげた。
出力結果でネットワークに使用したConv2dなどのパラメータが出てきているのがわかります。
利用としてはtf.Sessionでの初期化をProtocolBufferファイルに入っているグラフ情報で初期化して使うという感じかな?
モルガンさんのこの記事を参照した。

ProtocolBufferファイルの作成もできたので、Android上で読み込んで使ってみる。
アプリの設計としては

  • OpenCVのライブラリを導入して、カメラのフレームを入力にする。
  • カメラのフレームを取得して、その画像でOpenCVライブラリにあるテンプレートマッチングを行う。
  • マッチングしたところを切り抜きリサイズしてProtocolBufferファイルを読み込み、学習にかける

こんな感じ こちらのコードはここ
Androidアプリの開発はそんな経験はなくThreadやListenerなどはあまりわかってないので、頭悪いコードになってしまった。
ProtocolBufferファイルが400MBとデカすぎるのでSDカードから読み込むことに。それでもかなり重いが。。
結果としては以下のようになった
f:id:Owatank:20170729151250p:plain
欠点として、端末の電池の減りが早くなるのと、端末自体が激アツになってしまう。

作るにおいて躓いたのは、OpenCVの導入だった。
android用のTensorflowの導入は簡単だったけど、OpenCVを手順通りにやるとLinkerErrorが出てしまい困った。
原因としては、OpenCVの導入の手順では「sdk > native > libs」の libs を 自プロジェクトの jniLibs に置くと書いてある。
libsの中身としては、armeabix86とかAndroid端末のCPU?の名前のディレクトリが何個かある。
自分のプロジェクトにはTensorflowを利用するために、「jniLibs -> armeabi-v7a -> libtensorflow_inference.so」ファイルが置いてある。
jniLibsに armeabi-v7a以外のx86などのディレクトリを置いてしまうと、Tensorflowのライブラリを読み込むときに、libtensorflow_inference.soをx86とかから参照してしまいエラーが出るということだった。OpenCVを利用するためには libsのarmeabi-v7aだけをコピーして置けば解決した。
f:id:Owatank:20170729152341p:plain

RCNNも作ってみたかったけどjavaでのSelectiveSearchのライブラリが見つからなかったので諦めた。
ProtocolBufferファイルの利用例が作れたのでよしとする。