Android への Edge のデプロイのチュートリアル

作業内容

このチュートリアルでは、AutoML Vision Edge を使用して作成した、エクスポートされたカスタム TensorFlow Lite モデルをダウンロードします。モデルを使用して花の画像を識別する既製の Android アプリを実行します。

エンド プロダクトのモバイルのスクリーンショット
画像クレジット: Felipe Venâncio、「母の庭から」CC BY 2.0、アプリに表示される画像)。

目標

この入門用のエンドツーエンドのチュートリアルでは、コードを使用して次のことを行います。

  • TFLite インタープリタを使用して、Android アプリで事前トレーニング済みモデルを実行します。

始める前に

AutoML Vision Edge からモデルをトレーニングする

Edge デバイスにモデルをデプロイする前に、Edge デバイスモデルのクイックスタートに沿って AutoML Vision Edge から TF Lite モデルをトレーニングしてエクスポートする必要があります。

クイックスタートを完了すると、以下のようにトレーニング済みのモデルファイル(TF Lite ファイル、ラベルファイル、メタデータ ファイル)がエクスポートされます。

クラウド ストレージ tf lite モデルファイル

TensorFlow をインストールする

チュートリアルを開始する前に、次のソフトウェアをインストールする必要があります。

Python がすでに動作している場合は、次のコマンドを実行して、このソフトウェアをダウンロードします。

pip install --upgrade  "tensorflow==1.7.*"
pip install PILLOW

このプロセスで問題が発生した場合は、TensorFlow の公式ドキュメントをご覧ください。

Git リポジトリのクローンを作成する

コマンドラインを使用して、次のコマンドで Git リポジトリのクローンを作成します。

git clone https://github.com/googlecodelabs/tensorflow-for-poets-2

リポジトリのローカル クローンのディレクトリ(tensorflow-for-poets-2 ディレクトリ)に移動します。このディレクトリから次のコードサンプルをすべて実行します。

cd tensorflow-for-poets-2

Android アプリを設定する

Android Studio をインストールする

必要に応じて、Android Studio 3.0 以降をインストールします。

Android Studio でプロジェクトを開く

Android Studio でプロジェクトを開くには、次の操作を行います。

  1. Android Studio Android Studio の [スタート] アイコン を開きます。読み込まれたら、このポップアップから Android Studio の [プロジェクトを開く] アイコン [Open an existing Android Studio project] を選択します。

    Android Studio の [プロジェクトを開く] ポップアップ

  2. ファイル選択画面で、作業ディレクトリから tensorflow-for-poets-2/android/tflite を選択します。

  3. 初めてプロジェクトを開く場合、Gradle ラッパーの使用について尋ねる [Gradle Sync] ポップアップが表示されます。[OK] を選択します。

    Android Studio の [プロジェクトを開く] ポップアップ

アプリのテストを行う

アプリは、実際の Android デバイスか Android Studio Emulator で実行できます。

Android デバイスを設定する

デベロッパー モードと USB デバッグを有効にしないと、アプリを Android Studio からスマートフォンに読み込めません。

一回限りの設定手順を完了するには、こちらの手順に従ってください。

カメラアクセスでエミュレータを設定する(省略可)。

実際の Android デバイスではなくエミュレータを使用する場合、エミュレータの設定は Android Studio で簡単にできます。

このアプリはカメラを使用します。そのため、デフォルトのテストパターンではなくパソコンのカメラを使用するようにエミュレータのカメラを設定します。

エミュレータのカメラを設定するには、Android Virtual Device Manager で新しいデバイスを作成する必要があります。Android Virtual Device Manager には、このボタン 仮想デバイスのマネージャー アイコン からアクセスできます。メインの AVDM ページで [Create Virtual Device] を選択します。

Android Studio で仮想デバイス オプションを作成する

次に、仮想デバイスの設定の最後のページ [Verify Configuration] ページで [Show Advanced Settings] を選択します。

Android Studio で仮想デバイス オプションを作成する

詳細設定で、ホスト コンピュータのウェブカメラを使用するように両方のカメラソースを設定できます。

Android Studio でカメラソース オプションを選択

オリジナル アプリを実行する

アプリに変更を加える前に、リポジトリに付属のバージョンを実行します。

ビルドとインストールのプロセスを開始するには、Gradle 同期を実行します。

Gradle 同期アイコン

Gradle 同期を実行したら、再生 Android Studio の再生アイコン を選択します。

再生ボタンを選択したら、次のポップアップからデバイスを選択します。

デバイス選択のポップアップ ウィンドウ

デバイスを選択したら、TensorFlow デモにカメラとファイルへのアクセスを許可する必要があります。

カメラへのアクセスを許可するのウィンドウ

アプリがインストールされたら、アプリアイコン Android Studio アプリのアイコン をクリックして起動します。このバージョンのアプリは、1,000 個の ImageNet カテゴリでトレーニング済みの、標準の MobileNet を使用しています。

次のようになります。

テストアプリの実行

カスタマイズしたアプリを実行する

デフォルトのアプリ設定では、標準の MobileNet を使用して、再トレーニングをせずに 1,000 個の ImageNet クラスのいずれか 1 つに画像を分類します。

ここで、アプリが AutoML Vision Edge で作成したモデルをカスタムの画像カテゴリに使用するように変更します。

モデルファイルをプロジェクトに追加する

デモ プロジェクトは android/tflite/app/src/main/assets/ ディレクトリの graph.litelabels.txt ファイルを検索するように構成されています。

次のコマンドを使用して、2 つのオリジナル ファイルを自身のバージョンに置き換えます。

cp [Downloads]/model.tflite android/tflite/app/src/main/assets/graph.lite
cp [Downloads]/dict.txt  android/tflite/app/src/main/assets/labels.txt

アプリに変更を加える

このアプリは浮動小数点モデルを使用していますが、AutoML Vision Edge で作成されたモデルは量子化されています。コードを変更して、アプリでこのモデルを使用できるようにします。

クラスメンバー定義と ImageClassifier イニシャライザで、labelProbArrayfilterLabelProbArray のデータ型を float から byte に変更します。

private byte[][] labelProbArray = null;
private byte[][] filterLabelProbArray = null;

labelProbArray = new byte[1][labelList.size()];
filterLabelProbArray = new byte[FILTER_STAGES][labelList.size()];

ImageClassifier イニシャライザで、int8 型に基づいて imgData を割り当てます。

    imgData =
        ByteBuffer.allocateDirect(
            DIM_BATCH_SIZE * DIM_IMG_SIZE_X * DIM_IMG_SIZE_Y * DIM_PIXEL_SIZE);

printTopKLabels() で、int8 から float へ labelProbArray データ型をキャストします。

  private String printTopKLabels() {
    for (int i = 0; i < labelList.size(); ++i) {
      sortedLabels.add(
          new AbstractMap.SimpleEntry<>(labelList.get(i), (float)labelProbArray[0][i]));
      if (sortedLabels.size() > RESULTS_TO_SHOW) {
        sortedLabels.poll();
      }
    }
    String textToShow = "";
    final int size = sortedLabels.size();
    for (int i = 0; i < size; ++i) {
      Map.Entry<String, Float> label = sortedLabels.poll();
      textToShow = String.format("\n%s: %4.2f",label.getKey(),label.getValue()) + textToShow;
    }
    return textToShow;
  }

アプリを実行する

Android Studio で Gradle 同期を実行して、ビルドシステムがファイルを検出できるようにします。

Gradle 同期アイコン

Gradle 同期を実行したあと再生 Android Studio の再生アイコン を選択し、ビルドとインストールのプロセスを開始します。

次のようになります。

エンド プロダクトのモバイルのスクリーンショット
画像クレジット: Felipe Venâncio、「母の庭から」CC BY 2.0、アプリに表示される画像)。

電源ボタンと音量小ボタンを同時に押し続けることで、スクリーンショットを撮影できます。

さまざまな花の写真にカメラを向けて画像が正しく分類されるかを確認することで、更新したアプリをテストします。

仕組み

これでアプリケーションを実行できたので、TensorFlow Lite 固有のコードを調べてみましょう。

TensorFlow-Android AAR

このアプリはコンパイル済みの TFLite Android Archive(AAR)を使用しています。この AAR は jcenter でホストされます。

モジュールの build.gradle ファイル内の以下の行には、プロジェクトの TensorFlow bintray Maven リポジトリからの最新バージョンの AAR が含められます。

build.gradle

repositories {
    maven {
        url 'https://google.bintray.com/tensorflow'
    }
}

dependencies {
    // ...
    compile 'org.tensorflow:tensorflow-lite:+'
}

次のブロックを使用して、.lite アセットや .tflite アセットを圧縮しないように Android Asset Packaging Tool に指示します。.lite ファイルはメモリマップされて、ファイルが圧縮されている場合は機能しないため、これは重要になります。

build.gradle

android {
    aaptOptions {
        noCompress "tflite"
        noCompress "lite"
    }
}

TFLite Java API の使用

TFLite に連結されたコードはすべて ImageClassifier.java に含まれます。

設定

まず注目すべきブロックは、ImageClassifier のコンストラクタです。

ImageClassifier.java

ImageClassifier(Activity activity) throws IOException {
    tflite = new Interpreter(loadModelFile(activity));
    labelList = loadLabelList(activity);
    imgData =
        ByteBuffer.allocateDirect(
            4 * DIM_BATCH_SIZE * DIM_IMG_SIZE_X * DIM_IMG_SIZE_Y * DIM_PIXEL_SIZE);
    imgData.order(ByteOrder.nativeOrder());
    labelProbArray = new float[1][labelList.size()];
    Log.d(TAG, "Created a Tensorflow Lite Image Classifier.");
}

特に注目すべき行がいくつかあります。

次の行は、TFLite インタープリタを作成します。

ImageClassifier.java

tflite = new Interpreter(loadModelFile(activity));

この行は、TFLite インタープリタをインスタンス化します。このインタープリタは tf.Session と同様に機能します(TFLite 以外の TensorFlow に詳しい方向け)。モデルを含む MappedByteBuffer をインタープリタに渡します。ローカル関数 loadModelFile は、アクティビティの graph.lite アセット ファイルを含む MappedByteBuffer を作成します。

次の行は、入力データバッファを作成します。

ImageClassifier.java

imgData = ByteBuffer.allocateDirect(
    4 * DIM_BATCH_SIZE * DIM_IMG_SIZE_X * DIM_IMG_SIZE_Y * DIM_PIXEL_SIZE);

このバイトバッファは、float に変換された画像データを格納できるサイズになっています。float 配列を入力として直接受け入れることができますが、インタープリタで余分なコピー抑えられるため、ByteBuffer のほうが効率的です。

次の行は、ラベルリストを読み込んで出力バッファを作成します。

labelList = loadLabelList(activity);
//...
labelProbArray = new float[1][labelList.size()];

出力バッファは、モデルが出力確率を書き込むラベルごとに 1 つの要素を持つ float 配列です。

モデルを実行する

次に注目すべきブロックは、classifyFrame メソッドです。このメソッドは入力として Bitmap を受け取り、モデルを実行し、アプリで印刷するテキストを返します。

ImageClassifier.java

String classifyFrame(Bitmap bitmap) {
 // ...
 convertBitmapToByteBuffer(bitmap);
 // ...
 tflite.run(imgData, labelProbArray);
 // ...
 String textToShow = printTopKLabels();
 // ...
}

このメソッドは 3 つのことを行います。まず、このメソッドはモデルへの入力用に、入力 BitmapimgData ByteBuffer に変換してコピーします。次に、このメソッドによりインタープリタの run メソッドが呼び出され、入力バッファと出力配列が引数として渡されます。インタープリタは出力配列の値をクラスごとに計算された確率に設定します。入力ノードと出力ノードは、以前に .lite モデルファイルを作成した toco コンバージョン ステップへの引数によって定義されます。

次のステップ

これで、Edge モデルを使った Android 花の分類アプリのチュートリアルを完了しました。画像分類アプリを変更してから、サンプルの注釈を取得する前に、画像分類アプリをテストしました。次に、TensorFlow Lite 固有のコードを調べて基本的な機能を理解しました。