SIG TFX-Addonsコミュニティに参加して、TFXをさらに改善するのを手伝ってください! SIGTFXに参加-アドオン

RESTful API

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

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

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

{
  "error": <error message string>
}

モデルステータスAPI

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

URL

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

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

応答形式

成功した場合、 GetModelStatusResponse JSON表現を返します。

モデルメタデータAPI

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

URL

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

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

応答形式

成功した場合、 GetModelMetadataResponse JSON表現を返します。

分類および回帰API

このAPIは、 PredictionService gRPCAPIの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 gRPCAPIに厳密に従います。

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>
}

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

この形式は、 PredictRequestプロトおよびCMLE予測APIに似ています。すべての名前付き入力テンソルの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]]
   }
 ]
}

注、各名前の入力(「タグ」、「信号」、「センサー」)が暗黙的に(インスタンスリスト内の2つのオブジェクトがあるように、上記の例では2つ)と同じ0番目の寸法を有するものとします。 0次元が異なる入力に名前を付けた場合は、以下で説明する列形式を使用してください。

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

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

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

入力キーの値は、単一の入力テンソル、または入力名のテンソルへのマップ(自然なネストされた形式でリストされている)のいずれかです。各入力は任意の形状にすることができ、上記の行形式で必要とされる同じ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_bytesれる名前付きテンソルは、バイナリ値を持つと見なされます。このような値は、以下のバイナリ値エンコードのセクションで説明されているように、異なる方法でエンコードされます。

JSONマッピング

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

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

浮動小数点精度

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

バイナリ値のエンコード

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仕様は認識しますが)。

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

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

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

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

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

RESTAPIエンドポイントで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へのRESTAPI呼び出しを行います

別の端末で、 curlツールを使用してRESTAPI呼び出しを行います。

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

$ 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)" }
$