GCP AI Platformで画像認識してみる(モデルデプロイ編)

学習編に続いてモデルのデプロイと推論クライアントアプリの作成をしていきます。

f:id:xterm256color:20190507013306j:plain

目次

目標

学習済みモデルをGCP上にデプロイしてPythonのクライアントアプリを作る。

GCP上でモデルを定義する

モデルの作成

GCPのAI Platform画面を開いて「モデル」を選択する。新しいモデルを任意の名前で作る。 ここではモデルの名称(クライアントからのアクセス時に使用する)やリージョンを指定する。

f:id:xterm256color:20190507012435p:plain

バージョンの作成

つぎに、モデルの詳細画面を開いて新しいバージョンを追加する。モデルを実行する際のリソースやPythonバージョンを選択する。 またTensorFlowのバージョンも2.0は選べないが1.13.1で動くだろうということでそれを使うことにする。

f:id:xterm256color:20190507012450p:plain

注意点

  • 現在はGPUマシンタイプを選択できない
  • Pythonバージョンとして2.7と3.5のどちらかが選択できる。Python3.5ではバッチトレーニングが出来ないみたい。TensorFlowつかってるならSavedModelにした時点で、サーバーがPython2.7でも問題ないのではとも思う?とりあえず2.7で作ってみる。
  • ドキュメントでも言及されている通りモデルサイズは250MB以下にしないといけない。(これを超えるとメモリアロケーションエラーで落ちる)

クライアント環境の準備

サービスアカウント発行(GCPコンソール)

Python クライアント ライブラリの使用  |  TensorFlow 用 Cloud ML Engine  |  Google Cloudの手順に従って、サービス アカウント キーの作成 - vpn-project - Google Cloud Platform のページでサービスアカウントキーを発行する。

f:id:xterm256color:20190507012615p:plain

クライアントマシンに認証ファイルをJSON形式で保存する。

環境変数の設定(クライアントマシン)

export GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account-credential.json

Pythonライブラリのインストール(クライアントマシン)

GCPにアクセスするためのクライアントライブラリを入れる。

pip install --upgrade google-api-python-client oauth2client

また、サービスアカウントの認証ファイルへのパスを環境変数に追加しておく。 これによってクライアントアプリからOAuth2.0で認証が通るようになる。

Pythonクライアントアプリの作成

AI Platformの推論APIを叩くアプリを作る。

大まかな流れは以下の通り。それぞれかいつまんで説明する。

  1. リクエスト用のペイロードの作成
  2. プロジェクト名、モデル名、バージョン名からURLを作成
  3. リクエストを送信
  4. レスポンスをパースする

クライアントアプリの全容は cifar-10-ai-platform/inference.py at master · chmod644/cifar-10-ai-platform を参照。

なお、事前情報として、学習済みモデル(SavedModel形式)がどんな入出力をとるか知っておく必要がある。分からない場合はTensorFlowのsaved_model_cliコマンドで調べればよい。

saved_model_cli show --all --dir gs://path/to/saved_model_dir/

今回のモデルは以下のようなモデルである。signature_def['serving_default']:以降を見ると、28x28x3の画像(x)を入力して、スカラー値の推論クラス(class)と10クラス分の確率(probabilities)を出力するものとわかる ※1次元目は省いて説明している

MetaGraphDef with tag-set: 'serve' contains the following SignatureDefs:

signature_def['__saved_model_init_op']:
  The given SavedModel SignatureDef contains the following input(s):
  The given SavedModel SignatureDef contains the following output(s):
    outputs['__saved_model_init_op'] tensor_info:
        dtype: DT_INVALID
        shape: unknown_rank
        name: NoOp
  Method name is: 

signature_def['serving_default']:
  The given SavedModel SignatureDef contains the following input(s):
    inputs['x'] tensor_info:
        dtype: DT_UINT8
        shape: (-1, 28, 28, 3)
        name: serving_default_x:0
  The given SavedModel SignatureDef contains the following output(s):
    outputs['classes'] tensor_info:
        dtype: DT_INT64
        shape: (-1)
        name: StatefulPartitionedCall:0
    outputs['probabilities'] tensor_info:
        dtype: DT_FLOAT
        shape: (-1, 10)
        name: StatefulPartitionedCall:1
  Method name is: tensorflow/serving/predict

ペイロードの作成

ペイロードはdict形式で作成する。今回はCIFAR-10の各画像の中央28x28ピクセルを送るので以下のようにする。ここでは、入力imageはshape=[32, 32, 3], dtype=np.uint8の形式になっている。注意点としてはバッチの次元を入れないこと。複数のイメージを推論したい場合はリストに追加するものと思われる。

def generate_payload(image):
    image = image[2:30, 2:30, :]
    return {"instances": [{"x": image.tolist()}]}

image = something_to_parse_cifar10() # 32x32x3 uint8 image as np.ndarray
payload = generate_payload(image)

URLの作成

URLのフォーマットはprojects/<GCPのプロジェクトID>/models/<モデル名>/[versions/<バージョン名>]である。バージョン名を指定しなかった場合はデフォルトバージョンで処理される。

url = 'projects/{}/models/{}'.format(project, model)
if version is not None:
    url += '/versions/{}'.format(version)

リクエストを送信

service.projectsのpredict関数を使ってリクエストを作って処理する。

service = discovery.build('ml', 'v1')
request = service.projects().predict(
    name=url,
    body=payload
)
response = request.execute()
return response

レスポンスをパース

responseはdict型で返ってくる。predictionsというキーに対して推論結果がリストで返ってくる。なお返ってきた時点でバッチ次元(1次元目)が落とされているので、例えばresponse['predictions'][0]['classes']スカラー値となる。

probabilities = response['predictions'][0]['probabilities']
pred = response['predictions'][0]['classes']

Pythonクライアントの実行(クライアントマシン)

実際にクライアントアプリを実行してみる。

pip install git+https://github.com/chmod644/cifar-10-ai-platform.git --upgrade

cifar-10-inference --project <GCPのプロジェクトID> --model <モデル名> --version <バージョン名>

f:id:xterm256color:20190507012729p:plainf:id:xterm256color:20190507012810p:plain

きちんと画像認識が動いている。

まとめ

とりあえずクライアントアプリから推論できることは確認しました。

このやり方だとRESTful APIにアクセスすることになります(多分)。gRPCのAPIにアクセスする方法も探してみたんですが見つかりませんでした。知ってる人いたら教えてください。

参考URL

モデルをデプロイする  |  TensorFlow 用 Cloud ML Engine  |  Google Cloud

Python クライアント ライブラリの使用  |  TensorFlow 用 Cloud ML Engine  |  Google Cloud

Sample Applications  |  API Client Library for Python  |  Google Developers