概要
Pythonで作ったtensorflowのモデルをAndroidでも使いたいと思って、色々試したが結構躓いたので、経緯を記録しておく。最終的に無事にAndroid上でtensorflowを動作させることができたが、原因はまとまってない。
<環境>
PC:mac
開発環境:AndroidStudio
tensorflowのプログラム:パラメータが格納されたmodel.pbと、Tensor.create( )、session.runner( )などが書かれたLSTM.javaがあるのみ
初動
Bazelとか使いたくなかったので、以下を参考に進めた。その上で、問題が発生してつまづいた部分を以下に記録する。
https://qiita.com/icchi_h/items/a1df9f27569714edfc5e
問題
いくつか問題が出てきたので、個別に対処していった。
問題1:model.pbが読めない
問題2:tensorflowがimportできない
問題3:アプリが以下のエラー吐いて強制終了する
No implementation found for native Lorg/tensorflow/TensorFlow;.version:()Ljava/lang/String;
Exception Ljava/lang/UnsatisfiedLinkError; thrown while initializing Lorg/tensorflow/TensorFlow;
FATAL EXCEPTION: main
java.lang.UnsatisfiedLinkError: Cannot find TensorFlow native library for OS: linux, architecture: i686.
問題1:model.pbが読み込めない
普段iOSのアプリを開発しているとこういうのは結構不便なのだが、AndroidStudioではassetsフォルダから、ローカルファイルを読み込むようになっている。
1:app/src/mainにassetsフォルダを追加(追加の仕方に注意)
追加の仕方:mainを右クリック→「New」→「Folder」→「Assets Folder」
2:作ったassetsフォルダにmodel.pbファイルを配置
3:MainActivity.javaのonCreate内で以下のコードを呼ぶ
byte[] graphDef = readByteFile(String.valueOf("model.pb"))
readFileToByteは自作関数で以下のように記述した。
byte[] readByteFile(String filePath) {
try {
byte[] b = new byte[1];
InputStream fis = this.getAssets().open(filePath);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while (fis.read(b) > 0) {
baos.write(b);
}
baos.close();
fis.close();
b = baos.toByteArray();
return b;
}catch(Exception ex){
System.out.println(ex.toString());
return null;
}
}
問題2:tensorflowがimportできない
今回使用したLSTM.javaには以下のimportが記述してあった。
import org.tensorflow.Graph;
import org.tensorflow.Session;
import org.tensorflow.Tensor;
これを読むためにapp内の「build.gradle」に以下の記述を追加した。
ちなみに、「1.2.0」と「1.2.0-preview」があるらしく、「copyTo」がpreviewしか対応していなかったため、previewを記述。その後、AndroidStudioのSyncボタンを押下。
dependencies {
...
compile 'org.tensorflow:tensorflow-android:1.2.0-preview'
//compile 'org.tensorflow:tensorflow:1.2.0'
...
}
問題3:エラーを吐いて強制終了する
No implementation found for native Lorg/tensorflow/TensorFlow;.version:()Ljava/lang/String;
Exception Ljava/lang/UnsatisfiedLinkError; thrown while initializing Lorg/tensorflow/TensorFlow;
FATAL EXCEPTION: main
java.lang.UnsatisfiedLinkError: Cannot find TensorFlow native library for OS: linux, architecture: i686.
というエラーだが、これに関する解決策が驚くほど出てこなくて困った。(私の勉強不足でもあるが)
いくつかやった事があるので以下に記すが、いらない操作もあるかもしれない。
1. soファイルを追加する
以下のリンクから、「最新成功ビルドの成果物 → out → native → (すべてのファイルをzipで)」という操作で、ファイルをダウンロードする。
http://ci.tensorflow.org/view/Nightly/job/nightly-android/
AndroidStudioでappの直下にlibsフォルダを追加する。
libsフォルダ内に先ほどダウンロードしたnativeフォルダ内の「libtensorflow_inference.so」内の全てのフォルダをlibsフォルダに追加する。ディレクトリ構成は以下のようになるはず。
-app
--libs
---arm64-v8a
----libtensorflow_inference.so
---armeabi-v7a
----libtensorflow_inference.so
---x86
----libtensorflow_inference.so
---x86_64
----libtensorflow_inference.so
2. MainAcitivityにloadLibraryの追記をする
public class MainActivity extends AppCompatActivity {
....
static {
System.loadLibrary("tensorflow_inference");
}
....
}
3. app内のbuild.gradleのsourceSetsを変更する
android {
...
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
...
}
とりあえず、これでなんとか動いた。
結局何が正解なのかは分からないが、備忘録として残しておく。