RESTful API

gRPC APIに加えて、TensorFlow ModelServer は RESTful API もサポートします。このページでは、これらの API エンドポイントと使用方法のエンドツーエンドのについて説明します。

リクエストとレスポンスは JSON オブジェクトです。このオブジェクトの構成は、リクエストのタイプまたは動詞によって異なります。詳細については、以下の API 固有のセクションを参照してください。

エラーが発生した場合、すべての API は、キーとしてerror 、値としてエラー メッセージを含む応答本文で JSON オブジェクトを返します。

{
  "error": <error message string>
}

モデルステータスAPI

この API は、 ModelService.GetModelStatus gRPC API に厳密に従っています。 ModelServer 内のモデルのステータスを返します。

URL

GET http://host:port/v1/models/${MODEL_NAME}[/versions/${VERSION}|/labels/${LABEL}]

/versions/${VERSION}または/labels/${LABEL}を含めるかはオプションです。省略した場合は、すべてのバージョンのステータスが応答で返されます。

応答フォーマット

成功すると、 GetModelStatusResponse protobuf の JSON 表現が返されます。

モデルメタデータAPI

この API は、 PredictionService.GetModelMetadata gRPC API に厳密に従っています。 ModelServer 内のモデルのメタデータを返します。

URL

GET http://host:port/v1/models/${MODEL_NAME}[/versions/${VERSION}|/labels/${LABEL}]/metadata

/versions/${VERSION}または/labels/${LABEL}を含めるかはオプションです。省略した場合、最新バージョンのモデル メタデータが応答で返されます。

応答フォーマット

成功すると、 GetModelMetadataResponse protobuf の JSON 表現が返されます。

分類および回帰 API

この API は、 PredictionService gRPC API のClassifyメソッドとRegressメソッドに厳密に従っています。

URL

POST http://host:port/v1/models/${MODEL_NAME}[/versions/${VERSION}|/labels/${LABEL}]:(classify|regress)

/versions/${VERSION}または/labels/${LABEL}を含めるかはオプションです。省略した場合は最新バージョンが使用されます。

リクエストフォーマット

classify API とregress API のリクエスト本文は、次のようにフォーマットされた JSON オブジェクトである必要があります。

{
  // Optional: serving signature to use.
  // If unspecifed default serving signature is used.
  "signature_name": <string>,

  // Optional: Common context shared by all examples.
  // Features that appear here MUST NOT appear in examples (below).
  "context": {
    "<feature_name3>": <value>|<list>
    "<feature_name4>": <value>|<list>
  },

  // List of Example objects
  "examples": [
    {
      // Example 1
      "<feature_name1>": <value>|<list>,
      "<feature_name2>": <value>|<list>,
      ...
    },
    {
      // Example 2
      "<feature_name1>": <value>|<list>,
      "<feature_name2>": <value>|<list>,
      ...
    }
    ...
  ]
}

<value>は、JSON 数値 (整数または 10 進数)、JSON 文字列、またはバイナリ データを表す JSON オブジェクトです (詳細については、以下の「バイナリ値のエンコード」セクションを参照してください)。 <list>はそのような値のリストです。この形式は、gRPC のClassificationRequestおよびRegressionRequestプロトに似ています。どちらのバージョンもExampleオブジェクトのリストを受け入れます。

応答フォーマット

classifyリクエストは、応答本文で次の形式の JSON オブジェクトを返します。

{
  "result": [
    // List of class label/score pairs for first Example (in request)
    [ [<label1>, <score1>], [<label2>, <score2>], ... ],

    // List of class label/score pairs for next Example (in request)
    [ [<label1>, <score1>], [<label2>, <score2>], ... ],
    ...
  ]
}

<label>は文字列です (モデルにスコアに関連付けられたラベルがない場合は、空の文字列""にすることができます)。 <score>は 10 進数 (浮動小数点) です。

regressリクエストは、応答本文で次のような形式の JSON オブジェクトを返します。

{
  // One regression value for each example in the request in the same order.
  "result": [ <value1>, <value2>, <value3>, ...]
}

<value>は 10 進数です。

gRPC API のユーザーは、この形式が、 ClassificationResponseおよびRegressionResponseプロトと類似していることに気づくでしょう。

予測API

この API は、 PredictionService.Predict gRPC API に厳密に従っています。

URL

POST http://host:port/v1/models/${MODEL_NAME}[/versions/${VERSION}|/labels/${LABEL}]:predict

/versions/${VERSION}または/labels/${LABEL}を含めるかはオプションです。省略した場合は最新バージョンが使用されます。

リクエストフォーマット

predict API のリクエスト本文は、次のようにフォーマットされた JSON オブジェクトである必要があります。

{
  // (Optional) Serving signature to use.
  // If unspecifed default serving signature is used.
  "signature_name": <string>,

  // Input Tensors in row ("instances") or columnar ("inputs") format.
  // A request can have either of them but NOT both.
  "instances": <value>|<(nested)list>|<list-of-objects>
  "inputs": <value>|<(nested)list>|<object>
}

入力テンソルを行形式で指定します。

この形式は、gRPC API およびCMLE 予測 APIPredictRequestプロトに似ています。すべての名前付き入力テンソルが同じ 0 次元を持つ場合は、この形式を使用します。そうでない場合は、後述する列形式を使用してください。

行形式では、入力は JSON リクエストのインスタンスキーにキー設定されます。

名前付き入力が 1 つだけの場合は、インスタンスキーの値を入力の値として指定します。

{
  // List of 3 scalar tensors.
  "instances": [ "foo", "bar", "baz" ]
}

{
  // List of 2 tensors each of [1, 2] shape
  "instances": [ [[1, 2]], [[3, 4]] ]
}

リストを手動で平坦化する必要がないため、テンソルはネストされた表記法で自然に表現されます。

複数の名前付き入力の場合、各項目は、名前付き入力ごとに 1 つずつ、入力名とテンソル値のペアを含むオブジェクトであると想定されます。例として、以下は 2 つのインスタンスを含むリクエストで、各インスタンスには 3 つの名前付き入力テンソルのセットが含まれます。

{
 "instances": [
   {
     "tag": "foo",
     "signal": [1, 2, 3, 4, 5],
     "sensor": [[1, 2], [3, 4]]
   },
   {
     "tag": "bar",
     "signal": [3, 4, 1, 2, 5]],
     "sensor": [[4, 5], [6, 8]]
   }
 ]
}

各名前付き入力 (「タグ」、「信号」、「センサー」) は暗黙的に同じ 0 次元 (インスタンスリストに2 つのオブジェクトがあるため、上の例では2 ) を持つと想定されていることに注意してください。異なる 0 次元を持つ入力に名前を付けた場合は、以下で説明する列形式を使用してください。

入力テンソルを列形式で指定します。

個々の名前付き入力が同じ 0 次元を持たない場合、またはよりコンパクトな表現が必要な場合は、この形式を使用して入力テンソルを指定します。この形式は、gRPC Predictリクエストのinputsフィールドに似ています。

列指向形式では、入力は JSON リクエストの入力キーにキー設定されます。

inputsキーの値は、単一の入力テンソル、または入力名のテンソルへのマップ (自然なネストされた形式でリストされている) のいずれかです。各入力は任意の形状を持つことができ、上で説明した行形式で必要とされる同じ 0 番目の次元 (別名バッチ サイズ) を共有する必要はありません。

前の例の列形式の表現は次のとおりです。

{
 "inputs": {
   "tag": ["foo", "bar"],
   "signal": [[1, 2, 3, 4, 5], [3, 4, 1, 2, 5]],
   "sensor": [[[1, 2], [3, 4]], [[4, 5], [6, 8]]]
 }
}

入力はJSON オブジェクトであり、インスタンス (行表現で使用される) のようなリストではないことに注意してください。また、すべての名前付き入力は、前述の行形式で実行される個々の行に展開されるのではなく、一緒に指定されます。これにより、表現がコンパクトになります (ただし、読みにくくなる可能性があります)。

応答フォーマット

predictリクエストは、応答本文で JSON オブジェクトを返します。

行形式のリクエストには、次のような形式の応答が含まれます。

{
  "predictions": <value>|<(nested)list>|<list-of-objects>
}

モデルの出力に名前付きテンソルが 1 つだけ含まれている場合、名前とpredictionsキーはスカラーまたはリスト値のリストにマップされます。モデルが複数の名前付きテンソルを出力する場合、前述の行形式のリクエストと同様に、代わりにオブジェクトのリストを出力します。

列形式のリクエストには、次のような形式の応答が含まれます。

{
  "outputs": <value>|<(nested)list>|<object>
}

モデルの出力に名前付きテンソルが 1 つだけ含まれている場合は、名前を省略し、スカラーまたはリスト値のリストにキー マップをoutputs 。モデルが複数の名前付きテンソルを出力する場合、代わりにオブジェクトを出力します。このオブジェクトの各キーは、名前付き出力テンソルに対応します。形式は、上記の列形式のリクエストに似ています。

バイナリ値の出力

TensorFlow は、非バイナリ文字列とバイナリ文字列を区別しません。すべてDT_STRING型です。名前のサフィックスとして_bytesを持つ名前付きテンソルは、バイナリ値を持つとみなされます。このような値は、以下のバイナリ値のエンコードのセクションで説明するように、別の方法でエンコードされます。

JSONマッピング

RESTful API は JSON の正規エンコーディングをサポートしているため、システム間でのデータ共有が容易になります。サポートされているタイプのエンコーディングは、以下の表でタイプごとに説明されています。以下にリストされていないタイプは、サポートされていないことを意味します。

TF データ型JSON値JSONの例ノート
DT_BOOL真/偽真/偽
DT_STRING"こんにちは世界!" DT_STRINGバイナリ バイト (シリアル化されたイメージ バイトや protobuf など) を表す場合、これらを Base64 でエンコードします。詳細については、 「バイナリ値のエンコード」を参照してください。
DT_INT8、DT_UINT8、DT_INT16、DT_INT32、DT_UINT32、DT_INT64、DT_UINT64番号1、-10、0 JSON値は10進数になります。
DT_FLOAT、DT_DOUBLE番号1.1、-10.0、0、 NaNInfinity JSON 値は、数値、または特別なトークン値 ( NaNInfinity 、および-Infinity ) のいずれかになります。詳細については、 「JSON 準拠」を参照してください。指数表記も可能です。

浮動小数点精度

JSON には単一の数値データ型があります。したがって、精度の低下をもたらす値を入力に提供する可能性があります。たとえば、入力xfloatデータ型で、入力{"x": 1435774380} IEEE 754 浮動小数点標準 (Intel や AMD など) に基づいたハードウェアで実行されているモデルに送信される場合、値は次のようになります。 1435774380 32 ビット浮動小数点数で正確に表現できないため、基盤となるハードウェアによって暗黙的に1435774336に変換されます。通常、サービングへの入力はトレーニングと同じ分布である必要があり、トレーニング時に同じコンバージョンが発生するため、これは通常問題になりません。ただし、完全な精度が必要な場合は、必要な精度を処理できる基になるデータ型をモデルで使用するか、クライアント側のチェックを考慮してください。

バイナリ値のエンコード

JSON は UTF-8 エンコーディングを使用します。バイナリである必要がある入力フィーチャ値またはテンソル値 (画像バイトなど) がある場合は、次のようにデータを Base64 エンコードし、キーとしてb64を持つ JSON オブジェクトにカプセル化する必要があります

{ "b64": <base64 encoded string> }

このオブジェクトを入力フィーチャまたはテンソルの値として指定できます。出力応答のエンコードにも同じ形式が使用されます。

image (バイナリ データ) とcaption特徴を含む分類リクエストを以下に示します。

{
  "signature_name": "classify_objects",
  "examples": [
    {
      "image": { "b64": "aW1hZ2UgYnl0ZXM=" },
      "caption": "seaside"
    },
    {
      "image": { "b64": "YXdlc29tZSBpbWFnZSBieXRlcw==" },
      "caption": "mountains"
    }
  ]
}

JSON準拠

多くの特徴値またはテンソル値は浮動小数点数です。有限値 (例: 3.14、1.0 など) とは別に、これらはNaNおよび非有限値 ( Infinityおよび-Infinity ) を持つことができます。残念ながら、JSON 仕様 ( RFC 7159 ) はこれらの値を認識しませ(ただし、JavaScript 仕様は認識します)。

このページで説明する REST API では、リクエスト/レスポンス JSON オブジェクトにそのような値を含めることができます。これは、次のようなリクエストが有効であることを意味します。

{
  "example": [
    {
      "sensor_readings": [ 1.0, -3.14, Nan, Infinity ]
    }
  ]
}

(厳格な) 標準に準拠した JSON パーサーは、これを解析エラーで拒否します ( NaNおよびInfinityトークンと実際の数値が混在しているため)。コード内でリクエスト/レスポンスを正しく処理するには、これらのトークンをサポートする JSON パーサーを使用します。

NaNInfinity-Infinityトークンは、 proto3 、 Python JSONモジュール、および JavaScript 言語によって認識されます。

おもちゃのhalf_plus_threeモデルを使用して、REST API の動作を確認できます。

REST API エンドポイントを使用して ModelServer を起動します。

git リポジトリからhalf_plus_threeモデルをダウンロードします。

$ mkdir -p /tmp/tfserving
$ cd /tmp/tfserving
$ git clone --depth=1 https://github.com/tensorflow/serving

Docker を使用して ModelServer を実行します。 ModelServer をシステムにネイティブにインストールする場合は、代わりにセットアップ手順に従ってインストールし、 --rest_api_portオプションを使用して ModelServer を起動して REST API エンドポイントをエクスポートします (これは Docker を使用する場合には必要ありません)。

$ cd /tmp/tfserving
$ docker pull tensorflow/serving:latest
$ docker run --rm -p 8501:8501 \
    --mount type=bind,source=$(pwd),target=$(pwd) \
    -e MODEL_BASE_PATH=$(pwd)/serving/tensorflow_serving/servables/tensorflow/testdata \
    -e MODEL_NAME=saved_model_half_plus_three -t tensorflow/serving:latest
...
.... Exporting HTTP/REST API at:localhost:8501 ...

ModelServer への REST API 呼び出しを行う

別のターミナルで、 curlツールを使用して REST API 呼び出しを行います。

次のようにモデルのステータスを取得します。

$ curl http://localhost:8501/v1/models/saved_model_half_plus_three
{
 "model_version_status": [
  {
   "version": "123",
   "state": "AVAILABLE",
   "status": {
    "error_code": "OK",
    "error_message": ""
   }
  }
 ]
}

predict呼び出しは次のようになります。

$ curl -d '{"instances": [1.0,2.0,5.0]}' -X POST http://localhost:8501/v1/models/saved_model_half_plus_three:predict
{
    "predictions": [3.5, 4.0, 5.5]
}

regress呼び出しは次のようになります。

$ curl -d '{"signature_name": "tensorflow/serving/regress", "examples": [{"x": 1.0}, {"x": 2.0}]}' \
  -X POST http://localhost:8501/v1/models/saved_model_half_plus_three:regress
{
    "results": [3.5, 4.0]
}

regressデフォルト以外の署名名で使用できるため、明示的に指定する必要があることに注意してください。リクエスト URL または本文が正しくない場合は、HTTP エラー ステータスが返されます。

$ curl -i -d '{"instances": [1.0,5.0]}' -X POST http://localhost:8501/v1/models/half:predict
HTTP/1.1 404 Not Found
Content-Type: application/json
Date: Wed, 06 Jun 2018 23:20:12 GMT
Content-Length: 65

{ "error": "Servable not found for request: Latest(half)" }
$