6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Object Detection APIのsaved_model出力

Last updated at Posted at 2019-01-25

TensorFlow Object Detection APIでGoogle Cloud MLのモデルサービス(モデルのデプロイ)をするためのsaved_model作成方法を書きます。調査が結構面倒でプログラムまで作成しました。
※Google Cloud MLでなければだめだった方法2 - チェックポイントファイルからエクスポートで大丈夫っぽいです。

関連記事

環境

種類 バージョン 内容
OS Ubuntu18.04.01 LTS Windows8.1からOracle VirtualBoxを使って動かしています
Python 3.5.6 Python3.5.6をpyenvで動かしています。Google Cloud MLのランタイム1.10を使うのでPythonは3.7を使いません
TensorFlow 1.10 Google Cloud MLのランタイム1.10を使うのでTensorFlowは1.12を使いません
※後で気になって調べたのですが、2019/1/5時点でもTensorFlow1.12が使えました。日本語の情報だと1.10までしかなかったのですが、英語で見ると1.12も使えました。失敗したー。

前提

  • pyenvはインストール済
  • GCPのアカウントを持っていること
  • Google Cloud SDKインストール済
  • TensorFlow Object Detection API インストール済
  • 訓練済みチェックポイントファイル作成済

記事「Object Detection APIを使って堀川君を検知」で方法を書いていますが、Google Cloud ML Engineで訓練しています。ローカルPCや他サービスを使っていてもチェックポイントファイルさえあれば大丈夫です。

手順

1. チェックポイントファイル準備

チェックポイントファイルをGoogle Cloud StorageからエクスポートされたモデルをPCにダウンロードします。model.ckpt-XXXXの3ファイルとcheckpointファイルが必要です(他は不要です)。

gsutil cp -r gs://cl-ml01/train_output/model ~/Documents/od/export/checkpoint

2. saved_model出力プログラム作成

"How to deploy an Object Detection Model with TensorFlow serving"という記事を参考にexporter.pyをコピーして変更しています。
ソース全体はGitHubに置いておきます。
改変ポイントを解説していきます。

2.1. 関数write_saved_modelのパラメータ

関数write_saved_modelのパラメータのfrozen_graph_defをtrained_checkpoint_prefixに変えます。

def write_saved_model(saved_model_path,
                      # Start of change - replace trained_checkpoint_prefix from frozen_graph_def 2019/1/13
                      #frozen_graph_def,
                      trained_checkpoint_prefix,
                      # End   of change
                      inputs,
                      outputs):

2.2. 関数write_saved_modelのセッションの開始方法

関数write_saved_modelのセッションの開始方法をfrozen_graph_defからtrained_checkpoint_prefixを使ったresotreに変更。

# Start of change - 2019/1/13
#  with tf.Graph().as_default():
#    with session.Session() as sess:
#
#      tf.import_graph_def(frozen_graph_def, name='')
  saver = tf.train.Saver()
  with session.Session() as sess:

    # restore from checkpoint
      saver.restore(sess, trained_checkpoint_prefix)
# End  of change

2.3. 関数write_saved_modelでのsignature追加

関数write_saved_modelでのsignatureを追加。

      builder.add_meta_graph_and_variables(
          sess, [tf.saved_model.tag_constants.SERVING],
          signature_def_map={
              # Start of Insertion - 2019/1/20
              'detection_signature':
                  detection_signature,
              # End   of insertion
              signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY:
                  detection_signature,
          },

2.4. 関数_export_inference_graphでの関数write_saved_model呼出パラメータ変更

1.と対応していますが、関数write_saved_modelの呼出パラメータをfrozen_graph_defからtrained_checkpoint_prefixに変えます。

# Start of change - pass trained_checkpoint_prefix 2019/1/13
#  write_saved_model(saved_model_path, frozen_graph_def,
#                    placeholder_tensor, outputs)
  write_saved_model(saved_model_path, trained_checkpoint_prefix,
                  placeholder_tensor, outputs)
# End of change

2.5. 呼出メイン部分追加

単体で呼び出せるようにメイン部分を追加。ファイルパスはパラメータにできればいいのですが、面倒なのでハードコードしています。使いまわしたい場合は適宜変更してください。

# Start of insertion - add for export 2019/1/18
from object_detection.utils.config_util import create_pipeline_proto_from_configs
from object_detection.utils.config_util import get_configs_from_pipeline_file

def main():
    # Configuration for model to be exported
    config_pathname = '/home/i348221/Documents/od/input/faster_rcnn_resnet101_coco.config'
    latest_filename = 'model.ckpt-1000'

    # Input checkpoint for the model to be exported
    # Path to the directory which consists of the saved model on disk (see above)
    trained_model_dir = '/home/i348221/Documents/od/export/checkpoint'

    # Create proto from model confguration
    configs = get_configs_from_pipeline_file(config_pathname)

    pipeline_proto = create_pipeline_proto_from_configs(configs=configs)

    # Read .ckpt and .meta files from model directory
    # checkpoint = tf.train.get_checkpoint_state(trained_model_dir, latest_filename)
    checkpoint = tf.train.get_checkpoint_state(trained_model_dir)
    input_checkpoint = checkpoint.model_checkpoint_path

    # Model Version
    model_version_id = 1

    # Output Directory
    output_directory = '/home/i348221/Documents/od/model/export/' + str(model_version_id)

    export_inference_graph(input_type='image_tensor', pipeline_config=pipeline_proto,
                                    trained_checkpoint_prefix=input_checkpoint, output_directory=output_directory)

# main関数呼び出し
if __name__ == "__main__":
    main()
# End   of insertion

3. saved_model出力

作成したプログラムをmodels/research/object_detectionフォルダに置いて実行します。

# From tensorflow/models/research/
$ export PYTHONPATH=$PYTHONPATH:`pwd`:`pwd`/slim
$ python object_detection/exporter_clml.py

これでsaved_modelとvariablesが出来ました!saved_model_cliを使って見てみます。
※saved_model_cliについては、CLI to inspect and execute SavedModel参照

# From ~/Documents/od/model/export/1/saved_model
$ saved_model_cli show --dir ./ --all
etaGraphDef with tag-set: 'serve' contains the following SignatureDefs:

signature_def['detection_signature']:
  The given SavedModel SignatureDef contains the following input(s):
    inputs['inputs'] tensor_info:
        dtype: DT_UINT8
        shape: (-1, -1, -1, 3)
        name: image_tensor:0
  The given SavedModel SignatureDef contains the following output(s):
    outputs['detection_boxes'] tensor_info:
        dtype: DT_FLOAT
        shape: (-1, 300, 4)
        name: detection_boxes:0
    outputs['detection_classes'] tensor_info:
        dtype: DT_FLOAT
        shape: (-1, 300)
        name: detection_classes:0
    outputs['detection_scores'] tensor_info:
        dtype: DT_FLOAT
        shape: (-1, 300)
        name: detection_scores:0
    outputs['num_detections'] tensor_info:
        dtype: DT_FLOAT
        shape: (-1)
        name: num_detections:0
  Method name is: tensorflow/serving/predict

signature_def['serving_default']:
  The given SavedModel SignatureDef contains the following input(s):
    inputs['inputs'] tensor_info:
        dtype: DT_UINT8
        shape: (-1, -1, -1, 3)
        name: image_tensor:0
  The given SavedModel SignatureDef contains the following output(s):
    outputs['detection_boxes'] tensor_info:
        dtype: DT_FLOAT
        shape: (-1, 300, 4)
        name: detection_boxes:0
    outputs['detection_classes'] tensor_info:
        dtype: DT_FLOAT
        shape: (-1, 300)
        name: detection_classes:0
    outputs['detection_scores'] tensor_info:
        dtype: DT_FLOAT
        shape: (-1, 300)
        name: detection_scores:0
    outputs['num_detections'] tensor_info:
        dtype: DT_FLOAT
        shape: (-1)
        name: num_detections:0
  Method name is: tensorflow/serving/predict

NG集

よく陥るNG集です。

だめだった方法1 - エクスポートされていたものをそのまま使う

事前に有効化venvの仮想環境を有効化し、環境変数の設定もします。

source cl-od/bin/activate

# From tensorflow/models/research/
export PYTHONPATH=$PYTHONPATH:`pwd`:`pwd`/slim

saved_model_cliを使ってダウンロードしたsaved_modelを見てみます。

$ saved_model_cli show --dir ./ --all
MetaGraphDef with tag-set: 'serve' contains the following SignatureDefs:

signature_def['serving_default']:
  The given SavedModel SignatureDef contains the following input(s):
    inputs['serialized_example'] tensor_info:
        dtype: DT_STRING
        shape: ()
        name: tf_example:0
  The given SavedModel SignatureDef contains the following output(s):
    outputs['detection_boxes'] tensor_info:
        dtype: DT_FLOAT
        shape: (1, 300, 4)
        name: detection_boxes:0
    outputs['detection_classes'] tensor_info:
        dtype: DT_FLOAT
        shape: (1, 300)
        name: detection_classes:0
    outputs['detection_scores'] tensor_info:
        dtype: DT_FLOAT
        shape: (1, 300)
        name: detection_scores:0
    outputs['num_detections'] tensor_info:
        dtype: DT_FLOAT
        shape: (1)
        name: num_detections:0
  Method name is: tensorflow/serving/predict

signature_def['tensorflow/serving/predict']:
  The given SavedModel SignatureDef contains the following input(s):
    inputs['serialized_example'] tensor_info:
        dtype: DT_STRING
        shape: ()
        name: tf_example:0
  The given SavedModel SignatureDef contains the following output(s):
    outputs['detection_boxes'] tensor_info:
        dtype: DT_FLOAT
        shape: (1, 300, 4)
        name: detection_boxes:0
    outputs['detection_classes'] tensor_info:
        dtype: DT_FLOAT
        shape: (1, 300)
        name: detection_classes:0
    outputs['detection_scores'] tensor_info:
        dtype: DT_FLOAT
        shape: (1, 300)
        name: detection_scores:0
    outputs['num_detections'] tensor_info:
        dtype: DT_FLOAT
        shape: (1)
        name: num_detections:0
  Method name is: tensorflow/serving/predict

残念ながらこのsaved_modelはGoogle Cloud MLで使えませんでした(筆者の技術力不足かもしれません)。
ブログ記事「Performing prediction with TensorFlow object detection models on Google Cloud Machine Learning Engine」に下記のように書かれていて、shapeがマッチしないのでこのままだとうまくいきません:disappointed_relieved:

"Note that the first dimensions of the input and output tensors should be -1 as this is required by the Cloud Machine Learning engine to support batched-inputs."

GitHub issueにも同様の記述があります。どちらも少し古いのですが、状況は変わっていないと思います。

The current object detection example only supports reading one image at a time when doing inference. However, Cloud ML engine prediction service requires the inference graph be able to accept arbitrary number of input instances.The shape of the input tensor(s) must have None as its first dimension.

だめだった方法2 - チェックポイントファイルからエクスポート

チェックポイントのファイルをダウンロードします。

gsutil cp gs://cl-ml01/train_output/model/model.ckpt-1000* ~/Documents/od/model

Exporting a trained model for inferenceに従ってsaved_modelをエクスポート。

INPUT_TYPE=image_tensor
PIPELINE_CONFIG_PATH=~/Documents/od/input/faster_rcnn_resnet101_coco.config
TRAINED_CKPT_PREFIX=~/Documents/od/model/model.ckpt-1000
EXPORT_DIR=~/Documents/od/model

python object_detection/export_inference_graph.py \
    --input_type=${INPUT_TYPE} \
    --pipeline_config_path=${PIPELINE_CONFIG_PATH} \
    --trained_checkpoint_prefix=${TRAINED_CKPT_PREFIX} \
    --output_directory=${EXPORT_DIR}
$ saved_model_cli show --dir ./saved_model --all
MetaGraphDef with tag-set: 'serve' contains the following SignatureDefs:

signature_def['serving_default']:
  The given SavedModel SignatureDef contains the following input(s):
    inputs['inputs'] tensor_info:
        dtype: DT_UINT8
        shape: (-1, -1, -1, 3)
        name: image_tensor:0
  The given SavedModel SignatureDef contains the following output(s):
    outputs['detection_boxes'] tensor_info:
        dtype: DT_FLOAT
        shape: (-1, 300, 4)
        name: detection_boxes:0
    outputs['detection_classes'] tensor_info:
        dtype: DT_FLOAT
        shape: (-1, 300)
        name: detection_classes:0
    outputs['detection_scores'] tensor_info:
        dtype: DT_FLOAT
        shape: (-1, 300)
        name: detection_scores:0
    outputs['num_detections'] tensor_info:
        dtype: DT_FLOAT
        shape: (-1)
        name: num_detections:0
  Method name is: tensorflow/serving/predict

今度はshapeは良さそうなのですが、variablesフォルダが空です。
GitHub Issueに以下のように書かれていて、変数はすべて固定値になってしまっているようです。うーん・・・

This is working as intended. The exporter script converts all variables into constants when exporting the graph.

6
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?