茨城エンジニアのPython開発日記

茨城のITベンチャー企業ではたらく2年目エンジニア。Pythonで色々なものを作成中。

AIをARに応用するぞ会 → (第3回) ~スマホでAI作動2~


ブログから記事を見つけたい場合はこちら

ブログ地図 - 茨城エンジニアのPython開発日記

こんにちは。

開発メンバーのKです。
GWは田植えをしました。
体がなまっていたので、ひどい筋肉痛になりました。
全自動で田植えをする機械が欲しい。

さて今回は、前回に引き続きスマホでAIを動かすことにチャレンジしました。


以下、目次です。

1. 前回詰まったところ

前回、Android上でClassificationするために、Android studio上のjavaでTensorflow liteを動かそうとしました。
しかし、学習済みモデルをうまくreadできてない状態でした。
(我々はjava初心者なので、わからないことだらけで大変です...)

↓前回のブログ
tottorisnow33.hatenablog.com

2. MappedByteBuffer形式でうまくreadできた

tensorflow liteの公式ページを見ると、モデルのリード及び実行は Interpreter クラスを使用するそうです。
リード方法は、Fileクラスの変数を入れるか、MappedByteBufferクラスの変数を入れるかのどちらかです。
https://www.tensorflow.org/lite/guide/inference?hl=ja


ネットで具体的にリードのやり方を調べていると、MappedByteBufferクラスを使ったやり方を見つけました。
以下、その見つけたページです。大変助かりました。
note.com

MappedByteBuffer形式でファイルを取得するのに、
このページの

private MappedByteBuffer loadModel(String modelPath)

関数を使わせていただきました。
実際には、この関数の引数に
Context context
追加して、関数内のthis.contextを、引数でもらったcontextになるように書き換えました。

そのうえで、以下のように関数を呼び出してMappedByteBufferを取得して、
それからInterpreterインスタンス化をしました。

String ModelPath = "model_img_recog_ramen_pan_bn.tflite";
Context context = MainActivity.this;
MappedByteBuffer MyModel = loadModel(context, ModelPath);
Interpreter interpreter = new Interpreter(MyModel)


普通、リードをするだけなら、ファイルパスを指定して、適当なリード関数を使えばいいんじゃない?と思っていましたが、
そんな簡単ではありませんでした。
ここでポイントとなるのは、

  • activityを取得してcontextに入れる(3節)
  • Android Studioでファイルをリードするときはassetsフォルダを使う(4節)

ということです。

3. activityを取得してcontextに入れる

そもそもcontextとは(まだよく理解してないですが)、アプリケーション周りのインターフェースの情報を使うのに利用するクラスのようです。
以下のページが参考になるかと思います。
developer.android.com
qiita.com



そのcontextにActivityを代入するために、
MainActivity.this
を参照しました。
MainActivityは、自分たちがモデルファイルをリードしようとしているクラスのクラス名です。

4. Android Studioでファイルをリードするときはassetsフォルダを使う

自分たちは最初、FileクラスをInterpreterの引数にしてリードしようとしました。
しかし、Fileのexsists関数で読み込めているかを確認すると、Falseが帰ってきてしまいました。
つまり、Interpreter クラス以前に、File クラスでのリードができていなかったのです。
これの原因はまだよくわかっていなのですが、おそらく、直接ファイルパスを指定してリードしようとしたのがダメなのかと思います。
本来、Android studioでファイルをリードするときは、assetsフォルダに入れてそこから決まった手順でリードするべきなようです。


assetsを使ってリードする方法はいくつかあるようなのですが、
今回自分たちはcontextを使ってリードしています。


実際にやった手順は以下の通りです。
(1) 事前に、リードしたいファイルをassetsフォルダに入れる。
(2) ソース上で、activityを取得してcontextに入れる(3節)
(3) 以下のソースでAssetFileDescriptorを取得

context.getAssets().openFd("リードしたいファイル名")

(3)以降の手順は先ほど紹介した以下のページの
private MappedByteBuffer loadModel(String modelPath)
関数を参照してください。
note.com

以上の手順でassetsフォルダのファイルを、
MappedByteBuffer 形式でリードすることができます。


5. リードはできたけどまた壁が

以上でtffileをリードすることはできたようなので、
さっそくinterpreter.runを実行しました。
すると以下のようなエラーが、、、

E/libc: Access denied finding property "ro.hardware.chipname"
A/libc: Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0 in tid 12027 (pplication_test), pid 12027 (pplication_test)

ハードを使うのに何か必要な手順でもあるのでしょうか?



また、Interpreterインスタンス化するソースで、下のような感じでnew の後のInterpreterに謎の横線が出ました。(ちょっと見づらいですが)
Interpreter interpreter = new Interpreter(MyModel)

Android studio上で勝手にやってくれていることのようなのですが、なんでこうなっているかさっぱり。
問題あるのかないのか良くわかっていません。


次回はこれらの解決から始めることになりそうです。