こんにちは。Google I/O 行きたかった中山です。
今年の I/O もいろいろと興味深い発表がありました。
多くの発表内容を効率的に理解する上で役立つのが、あわせて公開されている Codelabs です。
実際にコードを書きながら、動きを確認することができる、大変よいコンテンツだと思います。
今回は、Android からの取り扱いが劇的に簡単になったという、TensorFlow について、この Codelabs を試しながら、理解を深めてみたいと思います。
1.Codelab:「Android & TensorFlow: Artistic Style Transfer」について
今回試しますのは、Android アプリに TensorFlow を組み込んで、「Artistic style transfer」を試してみよう、というこちらの Codelab。
「Artistic style transfer」というのは、ディープラーニングの仕組みを利用して、ある画像に、別の画像の表現スタイルだけを適用して、新しい画像を生成するもの。
具体的には、以下のように、
- 左の画像に、
- 真ん中の画像のスタイルを適用して、
- 右の画像を生成する、
この Codelab で、「Artistic style transfer」の機能を試すことで、同時に、
- TensorFlow のライブラリを、Android アプリで利用すること
- 学習済みの TensorFlow のモデルを、Android アプリに組み込んで利用すること
- 学習済みのモデルを元に「推論」のプロセスを実行すること
- TensorFlow Graph の、特定の「ノード」に、アプリからアクセスできること
あたりを、合わせて確認できるようになっているようです。
細かく見ていくには、やはり TensorFlow 自体の理解、というのが必須になってはくるのですが、まず今回は、Android アプリから、こんなにシンプルに、TensorFlow の機能を利用できるのだ、というところに焦点をあてて、触っていきたいと思います。
なおこの Codelab を試すにあたって、利用したローカル側環境は以下の通りです。
- Mac(macOS Sierra)
- Android Studio(2.3.1)
- Nexus5X
2.ソースコードの取得
ターミナルから、任意のディレクトリで以下コマンドを実行して、アプリのプロジェクトのソースコードを取得します。
git clone https://github.com/googlecodelabs/tensorflow-style-transfer-android
3.Android Studio で開く
git clone で取得してできた「tensorflow-style-transfer-android」フォルダ内にある「android」フォルダを選択して、Android Studio で開きます。
ビルドが完了後、以下のようなファイル構成となっていることが、Android Studio 上で確認できます。
なおこの時点では、まだ TensorFlow 関連の処理は実装されていない、「枠」だけの状態です。
この状態でアプリを起動すると、以下のようになります。
上半分はカメラプレビュー、下半分は、「スタイル」を適用するためのボタンと、適用対象の「スタイル」の候補が並んでいます。
4.重要なメソッド
処理の中心となるのは、プロジェクト内に用意されている「StylizeActivity」クラスのようです。
このクラスの中の、以下のメソッドが、重要な役目をになっている、とのことです。
onPreviewSizeChosen
当アプリで実装している、カメラの機能が利用可能になった際に、このメソッドが呼び出されます。
初期設定のいろいろの処理をここで実行することになります。
setStyle
適用するスタイルを指定するメソッドです。
renderDebug
スタイル適用時のデバッグ情報を出力するメソッドです。
stylizeImage
指定されたスタイルを、画像に適用するメソッドです。
ImageUtils クラスの各種メソッド
プロジェクト内に用意されている ImageUtils クラスでは、画像処理に関するヘルパーメソッドがいくつか実装されています。
これらは、パフォーマンス対策のため、C++ で実装されたものを利用しています。コードの本体は、以下のように「libtensorflow_demo.so」としてあらかじめビルドされた状態で提供されています。
StylizeActivity クラスからも、この ImageUtils クラスのメソッドを利用しています。
5.TensorFlow 学習済みモデルについて
今回利用する学習済み TensorFlow モデル、以下の「stylize_quantized.pb」が本体となっています。
構成としては、こちらのページにも解説があるとおり、以下のように表現される、とのことなのですが、
とりあえず、今回の Codelab を実行する限りにおいては、これらの詳しい仕様については、すべて把握できていなくても支障ないとのこと。
とはいえ、今後、TensorFlow をより使いこなしていくためには、このあたりの知識も必須になるのでしょう。
6.TensorFlow ライブラリの読み込み
「build.gradle」ファイルを開いて、
ファイル末尾の「dependencies」ブロック内に、以下のように、「compile ・・・」を追記し、画面右上に表示される「Sync Now」をクリックします。
android { ・・・ dependencies { compile 'org.tensorflow:tensorflow-android:1.2.0-preview' } }
なんと、build.gradle ファイルに 1行書くだけで、TensorFlow ライブラリを利用できるようになりました。
以前は、TensorFlow 自体をビルドしておいて、NDK 入れて、・・・などなど下準備が大変だったようなのですが、時代は変わりました。
7.コードの追加
「StylizeActivity」クラスに、以下の private フィールドを追加します。
// TensorFlow ライブラリが提供する、 // TensorFlow の機能を呼び出すためのインタフェースとなるクラス private TensorFlowInferenceInterface inferenceInterface; // 学習済みモデルのファイル private static final String MODEL_FILE = "file:///android_asset/stylize_quantized.pb"; // TensorFlow の「ノード」の識別名 private static final String INPUT_NODE = "input"; private static final String STYLE_NODE = "style_num"; private static final String OUTPUT_NODE = "transformer/expand/conv3/conv/Sigmoid";
また「onPreviewSizeChosen」メソッド内に、以下のように「inferenceInterface」フィールドを初期化するコードを追加します。
@Override public void onPreviewSizeChosen(final Size size, final int rotation) { ・・・ // inferenceInterface フィールドの初期化 inferenceInterface = new TensorFlowInferenceInterface(getAssets(), MODEL_FILE); }
次に、「stylizeImage」メソッドの、
// TODO: Process the image in TensorFlow here.
と書かれている部分の下側に、以下のように、inferenceInterface のメソッドを呼び出すコードを追加します。
private void stylizeImage(final Bitmap bitmap) { ・・・ // TODO: Process the image in TensorFlow here. // 元画像データを TensorFlow 側にコピー inferenceInterface.feed(INPUT_NODE, floatValues, 1, bitmap.getWidth(), bitmap.getHeight(), 3); // 適用するスタイルの画像データを、TensorFlow 側にコピー inferenceInterface.feed(STYLE_NODE, styleVals, NUM_STYLES); // TensorFlow 側で、元画像データにスタイルを適用する処理を実行 inferenceInterface.run(new String[] {OUTPUT_NODE}, isDebug()); // 適用結果を取得して配列に保存 inferenceInterface.fetch(OUTPUT_NODE, floatValues); ・・・
最後に、デバッグ用の出力を行う「renderDebug」メソッドにも一部コードを追加します。
こちらは必ずしも必要、というわけではないと思うのですが、ついでとして。
すでに実装されている、
final Vector<String> lines = new Vector<>();
というコードのすぐ下に、以下のようにコードを追加します。
private void renderDebug(final Canvas canvas) { ・・・ final Vector<String> lines = new Vector<>(); // TensorFlow の処理に関するデバッグ情報を出力 final String[] statLines = inferenceInterface.getStatString().split("\n"); Collections.addAll(lines, statLines); lines.add(""); ・・・
これでコードの追加は完了です。
なお、このアプリ、サンプルのアプリの割には、けっこういろいろなことをやっているようで、「StylizeActivity」クラスにもともと実装されているコードは、意外とボリュームがあります。
TensorFlow の機能を呼び出す部分は、数行のコード追加で行えるようですが、それをアプリとしてきれいに実装するには、やはり相応の量のコードを記述する必要があるようです。
8.アプリを実行する
作成したアプリを Android 実機で実行します。
画面上側のカメラプレビューに映るイメージが、画面下側で選択したスタイルが適用された形で、リアルタイムに描画されます。
今回、その効果を検証しましたのは、私が毎週のようにお世話になっている、たも屋林店 の「ひやかけ1.5玉とちくわの天ぷら(わかめトッピング無料) 380円」。
ここ最近は気温も高くなり、ひやかけのおいしい季節になってまいりました。
これを、今回作成したアプリを通して見ると、以下のように表示されました。
まったくおいしくなさそうな絵になっていますが、スタイルの適用、という面では想定通りの結果となっているようです。
9.まとめ
TensorFlow に関しては、どちらかというと「学習させる」ほうがメインであるようにも思えますが、しかし、これまでは、学習済みのモデルをアプリから利用するだけでも、一手間かかっていた、という状況でした。
今回の Codelab のアプリ作成で、TensorFlow をマスターできる、というわけではまったくありませんけれども、それでも、build.gradle に 1行追加するだけで、容易に TensorFlow の機能を呼び出せる、というのを体験できる、という意味では、試しがいがあるではないか、と感じました。