Tensorflowを利用したアプリをAndroid Studioで作る方法

追記３：
@84d010m08さんから表記に関して修正リクエストをいただき、マージしました。ありがとうございます。
現在はTensorFlow mobileとliteの二つの方法があるようです。
[こちらの記事](https://qiita.com/j_catfish/items/c5b8d9e035f365b62af6)を参考にしてください。

追記２：
公式からきちんとした説明が出たのでそちらを参照してください。
https://www.tensorflow.org/mobile/android_build

追記：
この記事の内容は古くなっています。
とても簡単に現在の方法を説明すると、build.gradleに以下の内容を書きます。

```build.gradle
allprojects {
    repositories {
        jcenter()
    }
}

dependencies {
    compile 'org.tensorflow:tensorflow-android:+'
}
```

そうすることで、TensorFlowInferenceInterfaceが利用できます。
(TensorFlowInferenceInterfaceについては以下の古い記事を参照)
メソッドの名前が大きく変わっているので、公式のレポジトリからメソッドを探すと確実です。
追記時点では、
・feed()で入力
・run()で学習
・fetch()で出力の取り出し
です。
https://github.com/tensorflow/tensorflow/blob/master/tensorflow/contrib/android/java/org/tensorflow/contrib/android/TensorFlowInferenceInterface.java





以下追記前の記事

-------------
TensorflowをAndroidで実行した記事がいくつかあったものの，
http://qiita.com/tomoima525/items/99a2df5cb0559c41647a
http://qiita.com/ornew/items/cf7e4478936fbf28b271
http://qiita.com/ornew/items/cf7e4478936fbf28b271
http://qiita.com/miyosuda/items/e53ad2efeed0ff040606
TensorFlowInferenceInterfaceクラスを利用してシンプルに実行する方法の日本語ドキュメントが全く無かったためメモ程度に。
この記事の方法では学習済みモデルとAndroid Studioだけでアプリを作成できます。
Deep Learningの説明やTensorflowの基本的な使い方の説明は良い記事がたくさんあるので探してください。


だいぶ雑に書いているので時間があるときに順次修正します。

#公式ドキュメント
以下の3つ。
https://github.com/tensorflow/tensorflow/blob/master/tensorflow/java/
https://github.com/tensorflow/tensorflow/tree/master/tensorflow/contrib/android
https://github.com/tensorflow/tensorflow/tree/master/tensorflow/examples/android

#準備
.jarファイルと.soファイルの準備から。
以下の公式ドキュメントの内容と同じです。
https://github.com/tensorflow/tensorflow/tree/master/tensorflow/contrib/android

bazelを入れたくない人は
https://ci.tensorflow.org/view/Nightly/job/nightly-android/
からビルド済みファイルが手に入るらしいです(未確認)

まずは

```
git clone --recurse-submodules https://github.com/tensorflow/tensorflow.git
```

でTensorflowのソースをダウンロード

次に
>tensorflow/WORKSPACE

内を変更
以下の部分のコメントアウトを消してpathを適切に指定

```
\# Uncomment and update the paths in these entries to build the Android demo.
android_sdk_repository(
    name = "androidsdk",
    api_level = 23,
    build_tools_version = "25.0.1",
    \# Replace with path to Android SDK on your system
    path = "/home/user/Android/Sdk",
)

\#Android NDK r12b is recommended (higher may cause issues with Bazel)
android_ndk_repository(
    name="androidndk",
    path="/home/user/Android/Sdk/ndk-bundle",
    api_level=14) \# This needs to be 14 or higher to compile TensorFlow.
```
次はビルドします。

```
bazel build -c opt //tensorflow/contrib/android:libtensorflow_inference.so \
   --crosstool_top=//external:android/crosstool \
   --host_crosstool_top=@bazel_tools//tools/cpp:toolchain \
   --cpu=armeabi-v7a
```
でbazelを使ってビルドしてください。
 >--cpu=armeabi-v7a

の部分はググッて
>arm64-v8a
x86
x86_64

など適切なものに変えてください。

>bazel-bin/tensorflow/contrib/android/libtensorflow_inference.so

が生成されています。

次に

```
bazel build //tensorflow/contrib/android:android_tensorflow_inference_java
```

で
>bazel-bin/tensorflow/contrib/android/libandroid_tensorflow_inference_java.jar

にjarファイルが作成されます。


# Android Studioの設定
▽libs
　　libandroid_tensorflow_inference_java.jar
　　▽armeabi-v7a
　　　　libtensorflow_inference.so
このようにファイルを配置して
app/build.gradleに

```app/build.gradle
sourceSets {
    main {
        jniLibs.srcDirs = ['libs']
    }
}
```
を追記

#コードの書き方
インポート→インスタンスの生成→入力→実行→出力を取り出す
の手順です。
##インポート

```
import org.tensorflow.contrib.android.TensorFlowInferenceInterface;
```

と

```
static {
    System.loadLibrary("tensorflow_inference");
}
```

を記述すれば利用できます。
##インスタンスの生成

```
public TensorFlowInferenceInterface inferenceInterface;
inferenceInterface = new TensorFlowInferenceInterface();
```

などでインスタンスを生成し，

```
inferenceInterface.initializeTensorFlow(getAssets(), "PATH_TO_MODEL");
```

でapp/src/main/assets/model.pbからモデルを読み込みます。model.pbと"PATH_TO_MODEL"はご自身の環境に合わせて変えてください。
##データを入力
```
inferenceInterface.fillNodeFloat("NAME_OF_INPUT", int[] shape = {1,784},float[] input);
```
で学習済みモデルにデータを入力します
"NAME_OF_INPUT"は入力部分のplaceholderの名前です
TensorflowのMNISTチュートリアルだと

```
x = tf.placeholder(tf.float32, [None, 784],name="input")
```

"input"です。
同様に int[] shape = {1,784} は[None, 784]の部分です。
また，float[] input は入力したいベクトル列，MNISTでいうと手書き文字のベクトル列です。
ご自身の環境に合わせて変えてください。

入力の配列についてはFloat以外にも
inferenceInterface.fillNodeInt()
inferenceInterface.fillNodeByte()
などいろいろあります。
https://github.com/tensorflow/tensorflow/blob/master/tensorflow/contrib/android/java/org/tensorflow/contrib/android/TensorFlowInferenceInterface.java
ここから気合で見つけてください。
##実行
```
inferenceInterface.runInference(String[]　{"NAME_OF_OUTPUT"});
```
で入力から出力を計算します。
"NAME_OF_OUTPUT"はTensorflowで
>y_conv=tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2,name="output")

などしてつけた名前です。
出力層が複数ある場合があるのでString[]になっています。

##出力の取り出し
```
inferenceInterface.readNodeFloat("NAME_OF_OUTPUT", float[] output);
```
"NAME_OF_OUTPUT"で指定した場所の出力をfloat[] outputに受け取ります。
これも入力と同様でIntやDoubleも出力可能です。


#おわりに
説明がかなり雑&サンプルコードがないのでワケが分からないと思うので時間があるときに順次修正します。
サンプルコードは用意してありますが，入力部分などコピペでやっつけで作った部分が多いので権利的な問題が発生しないように修正した後に加筆します。

Androidで実装時の公式の説明が少なすぎて筆者も勘違いしている部分もあると思うので間違いがあればコメントをよろしくお願いします。