Android
AdventCalendar
TensorFlow
機械学習入門
TensorflowLite

この記事は ex-mixi Advent Calendar 2017 23 日目のエントリーです。

こんにちは。hnakagawa と申します。

mixiには中途で入り3年ほど在籍してました。入社当初の配属は、たんぽぽという謎チームで当時まだ黎明期だったネイティブ・アプリの開発環境の整備やフレームワーク開発を主に行っていました。
自分は組み込み畑からこの業界で仕事を始め、mixiの様なWeb系に行ったり組み込みに戻ったり、レイヤの上下を行き来するキャリアを送っていますが、アプリのスタートアップを経て去年ぐらいからMLプラットフォームの下回の仕事をするようになり、最近はex-mixiが集う人材吸引会社に吸い込まれたと噂されています?

※注 自分は研究者でもMLエンジニアでもなく、あくまで下回りの知識を活かしMLエンジニアがモデル作成に集中できるような環境を整えるのが現在の仕事

はじめに

今日はmixi時代のアプリ関係と現在の仕事であるML関係を組み合わせて、TensorFlow Liteをこちらの公式ドキュメントを元に簡単に解説したいと思います。

TensorFlow Liteとは

GoogleのMLフレームワークであるTensorFlowのモバイル環境向けtool&runtimeライブラリ群で、TensorFlowのトレーニング済みモデルをモバイル環境で実行できる形に変換します。何故モデルの変換が必要かというと、昨今のDNNなモデルはサイズが数百M〜数Gに成る事もざらでアプリで実行するためにはまずモデルサイズを小さくする必要があるためです。

現在、公式にLiteでテストされているモデルは以下の通り。

今回はDemoでリポジトリに入っているTFLiteCameraDemoを使用してInception V3のモデルを試す手順を紹介します。

※注 TensorFlow Liteは現在(2017/12/23)まだdeveloper previewの状態で、日々活発に開発が行われパラメータ等はまだまだ変わる可能性有り

アーキテクチャ概要

TensorFlow Liteのアーキテクチャは以下の図の様になっており、TensorFlowでトレーニング済みのモデルをLiteのConverterでtflite formatに変換し、その時にQuantized(量子化)を行い、DNNの内部変数を8bit以下の値に変換しモデルサイズを小さくできます。

alt

またAndroidの場合、下層のNeural Network APIとHAL(ハードウェア抽象化レイヤ)を介して、DSPやGPU等を使用できます(ハードウェア・ベンダがインテグレーションしている場合のみ)。

alt

モデル作成の流れ

  1. トレーニング済みモデルの作成(or選択
    • 独自にモデルを作成する場合はモデルをトレーニングする必要がありますが、Inception V3はpre-trainedモデルが公開されており、今回は手っ取り早くそちらを使用します。
  2. CheckPoint -> FrozenGraphDef-> TensorFlow Lite modelと変換
    • TensorFlowには用途や目的が異なる複数のフォーマットが存在する。
      • GraphDef (.pb) - Graph構造(ネットワーク)とそのオペレータ、変数定義を含むフォーマット
      • CheckPoint (.ckpt) - 内部変数の値のみのフォーマット、トレーニングの途中経過として使用できる
      • FrozenGraphDef - Graph構造(GraphDef) + 内部変数(CheckPoint)のセット
      • SavedModel - 入出力のインターフェース(signature)が定義されたGraphDef + CheckPointなフォーマット、TensorFlow Serving等で使用できる
      • TensorFlow lite model (.lite) - 今回の目的であるLite interpreterの為のフォーマット。FrozenGraphDefから変換する
    • 今回はGraphDef+CheckPointからFrozenGraphDefを作成し、その後Liteのフォーマットへ変換する。

TensorFlow Lite formatへの変換手順

Inception V3のpre-trained checkpoint
$ CHECKPOINT_DIR=/tmp/checkpoints
$ mkdir ${CHECKPOINT_DIR}
$ wget http://download.tensorflow.org/models/inception_v3_2016_08_28.tar.gz
$ tar -xvf inception_v3_2016_08_28.tar.gz
$ mv inception_v3.ckpt ${CHECKPOINT_DIR}
$ rm inception_v3_2016_08_28.tar.gz
  • Googleが公開しているpre-trained済みのCheckPointを取得
GraphDef
$ git clone https://github.com/tensorflow/models.git
$ cd models/research/slim
$ python export_inference_graph.py \
  --alsologtostderr \
  --model_name=inception_v3 \
  --output_file=/tmp/inception_v3_inf_graph.pb
  • CheckPointだけではGraph情報が無いので、tensorflow/modelsリポジトリに入っているInception V3の実装から、GraphDefを取得  
FrozenGraphDef
$ git clone https://github.com/tensorflow/tensorflow.git
$ cd tensorflow
$ bazel build tensorflow/python/tools:freeze_graph
$ bazel-bin/tensorflow/python/tools/freeze_graph \
  --input_graph=/tmp/inception_v3_inf_graph.pb \
  --input_checkpoint=/tmp/checkpoints/inception_v3.ckpt \
  --input_binary=true --output_graph=/tmp/frozen_inception_v3.pb \
  --output_node_names=InceptionV3/Predictions/Reshape_1
  • TensorFlow本体に含まれているtoolを使用し、GraphDefとCheckPointからFrozenGraphDefを作成
TensorFlow Liteフォーマット
$ bazel build tensorflow/contrib/lite/toco:toco
$ bazel-bin/tensorflow/contrib/lite/toco/toco \
  --input_file=/tmp/frozen_inception_v3.pb \
  --input_format=TENSORFLOW_GRAPHDEF \
  --output_format=TFLITE \
  --output_file=/tmp/inception-v3.tflite \
  --inference_type=QUANTIZED_UINT8 \
  --inference_input_type=QUANTIZED_UINT8 \
  --input_arrays=input \
  --output_arrays=InceptionV3/Predictions/Reshape_1 \
  --input_shapes=1,299,299,3 --default_ranges_min=0 --default_ranges_max=7
$ ls /tmp/inception-v3.tflite
-rw-r--r--  1 hnakagawa  wheel    23M 12 23 06:52 /tmp/inception-v3.tflite
  • 最後はTensorFlow Liteのtoolを使用しLiteフォーマットに変換

Androidアプリへの組み込み

TFLiteCameraDemo を取得しinception-v3.tfliteをassetsに入れ、ImageClassifier.java の以下の箇所を修正すれば動作するはず(記載にミスや間違い有りましたらコメントでお願い致します。

 /** Name of the model file stored in Assets. */
  private static final String MODEL_PATH = "inception-v3.tflite"; //<-- モデルファイル名

  /** Name of the label file stored in Assets. */
  private static final String LABEL_PATH = "labels.txt";

  /** Number of results to show in the UI. */
  private static final int RESULTS_TO_SHOW = 3;

  /** Dimensions of inputs. */
  private static final int DIM_BATCH_SIZE = 1;

  private static final int DIM_PIXEL_SIZE = 3;

  static final int DIM_IMG_SIZE_X = 299; //<-- Inception V3の入力画像サイズにする
  static final int DIM_IMG_SIZE_Y = 299; //    デフォルトではMobileNets用の224になっている

手元のNexus5xでは1cycleの推論に2000ms以上かかり精度も落ちていますが(パラメータでもう少しどうにかなる?)、改善の余地もまだまだあるので試行錯誤していきたいです。

  • だらだらと手順を書きましたが、さっさと試したい!という方向けにTensorFlowのプロジェクトがビルド済みAPKを既に準備してくれています。

参考資料

まとめ

今年はTensorFlow LiteやiOSのCoreMLの発表によって、モバイル環境でのモデル実行環境が急速に整った年でした。
プロダクトとしてはGoogle謹製の物を除いて目立った物がまだありませんが、来年はGoogle I/OとWWDCを堺にサードパーティ製のアプリが出てくると予想しています。個人的にも自分のスキルが活かせる分野なので色々考えて行きたいです。


明日はanoworlさん。強くない話とはどの様なお話なのでしょうか?
よろしくお願いします。