このトピックでは、汎用プロセッサを使用する TensorFlow サービスのリクエストを作成する方法を説明します。
入力データ
EAS は、高性能を確保するため、入出力に protobuf 形式を使用する組み込み TensorFlow プロセッサを提供します。
例
EAS は、中国 (上海) リージョンの VPC 環境にパブリックテストサービスをデプロイしました。 サービス名は mnist_saved_model_example で、アクセストークンは空です。 サービスには http://pai-eas-vpc.cn-shanghai.aliyuncs.com/api/predict/mnist_saved_model_example でアクセスできます。 このサービスにアクセスする手順は、次のとおりです。
-
モデル情報の取得
GET リクエストを送信して、signature_name、name、type、shape を含むモデル情報を取得します。レスポンスは次のようになります。
$curl http://pai-eas-vpc.cn-shanghai.aliyuncs.com/api/predict/mnist_saved_model_example | python -mjson.tool { "inputs": [ { "name": "images", "shape": [ -1, 784 ], "type": "DT_FLOAT" } ], "outputs": [ { "name": "scores", "shape": [ -1, 10 ], "type": "DT_FLOAT" } ], "signature_name": "predict_images" }これは、Mixed National Institute of Standards and Technology (MNIST) データセット (Download the MNIST dataset) を使用する分類モデルです。入力データ型は DT_FLOAT です。たとえば、シェイプは [-1,784] です。第 1 次元は バッチサイズを表します。1 回のリクエストに 1 つの画像しか含まれない場合、バッチサイズは 1 です。第 2 次元は 784 次元ベクトルを表します。このモデルの入力はトレーニング時に 1 次元ベクトルへフラット化されているため、1 枚の画像入力も 28 × 28 = 784 の 1 次元ベクトルへ変換する必要があります。シェイプの値にかかわらず、入力を作成する際にフラット化する必要があります。この例では、1 枚の画像を入力する場合、入力は 1 × 784 の 1 次元ベクトルです。モデルのトレーニング時の入力 シェイプが [-1, 28, 28] の場合、1 × 28 × 28 のシェイプを持つ入力を作成する必要があります。サービスリクエストで指定した シェイプがモデルの シェイプと一致しない場合、予測リクエストはエラーを返します。
-
protobuf のインストールとサービスの呼び出し
EAS は、Python 用に事前生成された protobuf パッケージを提供します。以下のコマンドを実行してインストールできます。
$ pip install http://eas-data.oss-cn-shanghai.aliyuncs.com/sdk/pai_tf_predict_proto-1.0-py2.py3-none-any.whl次のサンプルコードに、Python 2 を使用してサービスを呼び出して予測を実行する方法を示します。
#!/usr/bin/env python # -*- coding: UTF-8 -*- import json from urlparse import urlparse from com.aliyun.api.gateway.sdk import client from com.aliyun.api.gateway.sdk.http import request from com.aliyun.api.gateway.sdk.common import constant from pai_tf_predict_proto import tf_predict_pb2 import cv2 import numpy as np with open('2.jpg', 'rb') as infile: buf = infile.read() # NumPy を使用して、バイトストリームを配列に変換します。 x = np.fromstring(buf, dtype='uint8') # 読み取った配列をデコードして、28 × 28 のマトリックスを取得します。 img = cv2.imdecode(x, cv2.IMREAD_UNCHANGED) # 予測サービス API には長さ 784 の 1 次元ベクトルが必要なため、マトリックスを長さ 784 のベクトルにリシェイプします。 img = np.reshape(img, 784) def predict(url, app_key, app_secret, request_data): cli = client.DefaultClient(app_key=app_key, app_secret=app_secret) body = request_data url_ele = urlparse(url) host = 'http://' + url_ele.hostname path = url_ele.path req_post = request.Request(host=host, protocol=constant.HTTP, url=path, method="POST", time_out=6000) req_post.set_body(body) req_post.set_content_type(constant.CONTENT_TYPE_STREAM) stat,header, content = cli.execute(req_post) return stat, dict(header) if header is not None else {}, content def demo(): # モデル情報を入力します。モデル名をクリックして取得します。 app_key = 'YOUR_APP_KEY' app_secret = 'YOUR_APP_SECRET' url = 'YOUR_APP_URL' # リクエストを構成します。 request = tf_predict_pb2.PredictRequest() request.signature_name = 'predict_images' request.inputs['images'].dtype = tf_predict_pb2.DT_FLOAT # images パラメーターの型。 request.inputs['images'].array_shape.dim.extend([1, 784]) # images パラメーターのシェイプ。 request.inputs['images'].float_val.extend(img) # データ。 request.inputs['keep_prob'].dtype = tf_predict_pb2.DT_FLOAT # keep_prob パラメーターの型。 request.inputs['keep_prob'].float_val.extend([0.75]) # デフォルト値を入力します。 # 送信するため、protobuf を文字列にシリアル化します。 request_data = request.SerializeToString() stat, header, content = predict(url, app_key, app_secret, request_data) if stat != 200: print 'Http status code: ', stat print 'Error msg in header: ', header['x-ca-error-message'] if 'x-ca-error-message' in header else '' print 'Error msg in body: ', content else: response = tf_predict_pb2.PredictResponse() response.ParseFromString(content) print(response) if __name__ == '__main__': demo()次の出力が返されます。
outputs { key: "scores" value { dtype: DT_FLOAT array_shape { dim: 1 dim: 10 } float_val: 0.0 float_val: 0.0 float_val: 1.0 float_val: 0.0 float_val: 0.0 float_val: 0.0 float_val: 0.0 float_val: 0.0 float_val: 0.0 float_val: 0.0 } }outputsフィールドには、10 カテゴリのスコアが含まれています。入力画像が 2.jpg の場合、value[2] を除くすべての値が 0 です。したがって、最終的な予測結果は 2 となり、正しい結果です。
他の言語からのサービス呼び出し
Python 以外の言語のクライアントからサービスを呼び出すには、.proto ファイルからリクエストコードを生成する必要があります。その手順を次に示します。
-
.proto ファイルの作成。たとえば、次の内容で tf.proto という名前のファイルを作成します。
syntax = "proto3"; option cc_enable_arenas = true; option java_package = "com.aliyun.openservices.eas.predict.proto"; option java_outer_classname = "PredictProtos"; enum ArrayDataType { // DataType の無効な値。DataType フィールドが設定されていないことを示すために使用されます。 DT_INVALID = 0; // すべての計算デバイスがサポートできると想定されるデータ型。 DT_FLOAT = 1; DT_DOUBLE = 2; DT_INT32 = 3; DT_UINT8 = 4; DT_INT16 = 5; DT_INT8 = 6; DT_STRING = 7; DT_COMPLEX64 = 8; // 単精度複素数。 DT_INT64 = 9; DT_BOOL = 10; DT_QINT8 = 11; // 量子化された int8。 DT_QUINT8 = 12; // 量子化された uint8。 DT_QINT32 = 13; // 量子化された int32。 DT_BFLOAT16 = 14; // 16 ビットに切り捨てられた Float32。キャスト操作専用です。 DT_QINT16 = 15; // 量子化された int16。 DT_QUINT16 = 16; // 量子化された uint16。 DT_UINT16 = 17; DT_COMPLEX128 = 18; // 倍精度複素数。 DT_HALF = 19; DT_RESOURCE = 20; DT_VARIANT = 21; // 任意の C++ データ型。 } // 配列の次元。 message ArrayShape { repeated int64 dim = 1 [packed = true]; } // 配列を表すプロトコルバッファ。 message ArrayProto { // データ型。 ArrayDataType dtype = 1; // 配列のシェイプ。 ArrayShape array_shape = 2; // DT_FLOAT。 repeated float float_val = 3 [packed = true]; // DT_DOUBLE。 repeated double double_val = 4 [packed = true]; // DT_INT32、DT_INT16、DT_INT8、DT_UINT8。 repeated int32 int_val = 5 [packed = true]; // DT_STRING。 repeated bytes string_val = 6; // DT_INT64。 repeated int64 int64_val = 7 [packed = true]; // DT_BOOL。 repeated bool bool_val = 8 [packed = true]; } // PredictRequest は、実行する TensorFlow モデル、入力をテンソルにマッピングする方法、およびユーザーに返す前に出力をフィルタリングする方法を指定します。 message PredictRequest { // 評価する名前付き署名。指定しない場合は、デフォルトの署名が使用されます。 string signature_name = 1; // 入力テンソル。 // 入力テンソルの名前はエイリアス名です。エイリアスから実際の入力テンソル名へのマッピングは、モデルエクスポートのキー「inputs」の下に名前付きの汎用署名として保存されることが想定されています。 // 「inputs」という名前の汎用署名にリストされている各エイリアスは、予測を実行するために厳密に 1 回提供される必要があります。 map<string, ArrayProto> inputs = 2; // 出力フィルター。 // 指定された名前はエイリアス名です。エイリアスから実際の出力テンソル名へのマッピングは、モデルエクスポートのキー「outputs」の下に名前付きの汎用署名として保存されることが想定されています。 // ここで指定されたテンソルのみが実行/フェッチされて返されます。ただし、何も指定されていない場合は、名前付き署名で指定されたすべてのテンソルが実行/フェッチされて返されます。 repeated string output_filter = 3; } // 実行が成功した場合の PredictRequest に対するレスポンス。 message PredictResponse { // 出力テンソル。 map<string, ArrayProto> outputs = 1; }ファイルでは、
PredictRequestが TensorFlow サービスの入力形式を、PredictResponseがサービスの出力形式を定義しています。 詳細については、「protobuf のドキュメント」をご参照ください。 -
protoc のインストール
#!/bin/bash PROTOC_ZIP=protoc-3.3.0-linux-x86_64.zip curl -OL https://github.com/google/protobuf/releases/download/v3.3.0/$PROTOC_ZIP unzip -o $PROTOC_ZIP -d ./ bin/protoc rm -f $PROTOC_ZIP -
リクエストコードファイルの生成
-
Java
$ bin/protoc --java_out=./ tf.protoコマンドを実行すると、現在のディレクトリに com/aliyun/openservices/eas/predict/proto/PredictProtos.java ファイルが生成されます。その後、このファイルをプロジェクトにインポートします。
-
Python
$ bin/protoc --python_out=./ tf.protoコマンドを実行すると、現在のディレクトリに tf_pb2.py ファイルが生成されます。
importコマンドを使用してファイルをインポートします。 -
C++
$ bin/protoc --cpp_out=./ tf.protoコマンドを実行すると、現在のディレクトリに tf.pb.cc と tf.pb.h ファイルが生成されます。コード内で
tf.pb.hを include し、tf.pb.cc を compile リストに追加します。
-