予測リクエストの形式を指定する

アプリケーションの入力に応じてリクエストを行う場合や、タイムリーな推論(リアルタイムのレスポンス)が必要な場合は、オンライン予測を使用します。

このページでは、カスタム トレーニング済みモデルのオンライン予測 API を使用してオンライン予測リクエストの形式を設定する方法について説明し、リクエストとレスポンスの例を示します。リクエストの形式を設定したら、オンライン予測を取得できます。

始める前に

オンライン予測を行うリクエストをフォーマットする前に、次の手順を行います。

  1. 予測に使用するモデル アーティファクトをエクスポートする
  2. モデルリソースをエンドポイントにデプロイする

    このアクションにより、コンピューティング リソースがモデルに関連付けられ、低レイテンシでオンライン予測を行えるようになります。

  3. モデルの DeployedModel カスタム リソースのステータスを確認し、予測リクエストを受け入れる準備ができていることを確認します。

    kubectl --kubeconfig PREDICTION_CLUSTER_KUBECONFIG get -f DEPLOYED_MODEL_NAME.yaml -o jsonpath='{.status.primaryCondition}'
    

    次のように置き換えます。

    • PREDICTION_CLUSTER_KUBECONFIG: 予測クラスタの kubeconfig ファイルのパス。
    • DEPLOYED_MODEL_NAME: DeployedModel 定義ファイルの名前。

    プライマリ条件は、DeployedModel の準備ができていることを示す必要があります。

    次の出力は、レスポンスの例を示しています。

    {"firstObservedTime":"2024-01-19T01:18:30Z","lastUpdateTime":"2024-01-19T01:35:47Z","message":"DeployedModel is ready", "observedGeneration":1, "reason":"Ready", "resourceName":"my-tf-model","type":"DeployedModel"}
    
  4. Endpoint カスタム リソースのステータスを確認し、予測リクエストを受け入れる準備ができていることを確認します。

    kubectl --kubeconfig PREDICTION_CLUSTER_KUBECONFIG get -f ENDPOINT_NAME.yaml -o jsonpath='{$.status.conditions[?(@.type == "EndpointReady")]}'
    

    次のように置き換えます。

    • PREDICTION_CLUSTER_KUBECONFIG: 予測クラスタの kubeconfig ファイルのパス。
    • ENDPOINT_NAME: Endpoint 定義ファイルの名前。

    EndpointReady 条件の status フィールドには True 値が表示されている必要があります。

    次の出力は、レスポンスの例を示しています。

    {"lastTransitionTime":"2024-01-19T05:12:26Z","message":"Endpoint Ready", "observedGeneration":1,"reason":"ResourceReady","status":"True","type":"EndpointReady"}%
    

オンライン予測の入力をフォーマットする

オンライン予測には、リクエストを送信する次の 2 つの方法があります。

  • 予測リクエスト: オンライン予測を取得するリクエストを predict メソッドに送信します。
  • 未加工の予測リクエスト: rawPredict メソッドにリクエストを送信します。これにより、JSON 形式に従うのではなく、任意の HTTP ペイロードを使用できます。

低レイテンシが必要な場合は、rawPredict がシリアル化のステップをスキップしてリクエストを予測コンテナに直接転送するため、未加工の予測を取得します。

このセクションでは、predict メソッドを使用する場合に必要な、JSON を使用して予測入力インスタンスをフォーマットしてエンコードする方法について説明します。rawPredict メソッドを使用している場合、この情報は必要ありません。

Python 用 Vertex AI SDK を使用して予測リクエストを送信する場合は、instances フィールドなしでインスタンスのリストを指定します。たとえば、{ "instances": [ ["the","quick","brown"], ... ] } ではなく [ ["the","quick","brown"], ... ] と指定します。

JSON 文字列としてインスタンスをフォーマットする

オンライン予測の基本形式はデータ インスタンスのリストです。これらは、トレーニング アプリケーションで入力を構成した方法に応じて、値のプレーンリストまたは JSON オブジェクトのメンバーのいずれかになります。TensorFlow モデルは、より複雑な入力に対応できます。

次の例は、TensorFlow モデルの入力テンソルとインスタンス キーを示しています。

 {"values": [1, 2, 3, 4], "key": 1}

次の規則に従う限り、JSON 文字列の構成は複雑になってもかまいません。

  • インスタンス データの最上位レベルは、Key-Value ペアの辞書である JSON オブジェクトでなければなりません。

  • インスタンス オブジェクト内の個々の値には、文字列、数字、またはリストを使用できます。JSON オブジェクトは埋め込めません。

  • リストには、同じ型(他のリストも含む)のアイテムのみが含まれている必要があります。文字列と数値を混在させないでください。

オンライン予測の入力インスタンスを、predict 呼び出しのメッセージ本文として渡します。詳細については、リクエスト本文のフォーマット要件をご覧ください。

各インスタンスを JSON 配列のアイテムにし、次の例のように、その配列を JSON オブジェクトの instances フィールドとして指定します。

{"instances": [
  {"values": [1, 2, 3, 4], "key": 1},
  {"values": [5, 6, 7, 8], "key": 2}
]}

予測入力のバイナリデータをエンコードする

バイナリデータを JSON がサポートする UTF-8 エンコード文字列としてフォーマットすることはできません。入力にバイナリデータがある場合は、base64 エンコーディングで表します。次の特殊なフォーマットが必要です。

  • エンコードされた文字列を、b64 という 1 つのキーを持つ JSON オブジェクトとしてフォーマットします。Python 3 では、Base64 エンコードによりバイト シーケンスが出力されます。このシーケンスを文字列に変換して、JSON シリアル化できるようにします。

    {'image_bytes': {'b64': base64.b64encode(jpeg_data).decode()}}
    
  • TensorFlow モデルのコードで、入力 / 出力テンソルのエイリアスの名前を _bytes で終わらせます。

リクエストとレスポンスの例

このセクションでは、TensorFlow と PyTorch の例を使用して、オンライン予測リクエストとレスポンスの本文の形式について説明します。

リクエスト本文の詳細

TensorFlow

リクエストの本文には、次の構造をしたデータが含まれています(JSON 表現)。

{
  "instances": [
    <value>|<simple/nested list>|<object>,
    ...
  ]
}

instances[] オブジェクトは必須であり、予測の取得対象となるインスタンスのリストをこれに含める必要があります。

インスタンスのリストに含まれる各要素の構造は、モデルの入力定義によって決まります。インスタンスには、名前付き入力を(オブジェクトとして)含めることも、ラベルなし値のみを含めることもできます。

すべてのデータに名前付き入力が含まれるわけではありません。インスタンスは、JSON 値(ブール値、数値、文字列)の場合もあれば、値のリスト、または複雑なネスト構造のリストの場合もあります。

リクエスト本文の例を次に示します。

  • 各行が文字列値としてエンコードされた CSV データ:
{"instances": ["1.0,true,\\"x\\"", "-2.0,false,\\"y\\""]}
  • 書式なしテキスト:
{"instances": ["the quick brown fox", "the lazy dog"]}
  • 単語のリスト(文字列のベクトル)としてエンコードされた文:
{
  "instances": [
    ["the","quick","brown"],
    ["the","lazy","dog"],
    ...
  ]
}
  • 浮動小数点スカラー値:
{"instances": [0.0, 1.1, 2.2]}
  • 整数のベクトル:
{
  "instances": [
    [0, 1, 2],
    [3, 4, 5],
    ...
  ]
}
  • テンソル(この場合、2 次元のテンソル):
{
  "instances": [
    [
      [0, 1, 2],
      [3, 4, 5]
    ],
    ...
  ]
}
  • 画像は、さまざまな方法で表現できます

次のエンコード スキームでは、最初の 2 つの次元は画像の行と列を表し、3 つ目の次元に各ピクセルの R、G、B 値のリスト(ベクトル)が含まれます。

{
  "instances": [
    [
      [
        [138, 30, 66],
        [130, 20, 56],
        ...
      ],
      [
        [126, 38, 61],
        [122, 24, 57],
        ...
      ],
      ...
    ],
    ...
  ]
}

データのエンコード

JSON 文字列は UTF-8 としてエンコードする必要があります。バイナリデータを送信するには、データを Base64 エンコードし、バイナリとしてマークする必要があります。JSON 文字列をバイナリとしてマークするには、b64 という名前の単一の属性の JSON オブジェクトに置き換えます。

{"b64": "..."}

次の例は、Base64 エンコードを必要とする 2 つのシリアル化された tf.Examples インスタンスを示しています(例示のための架空データ)。

{"instances": [{"b64": "X5ad6u"}, {"b64": "IA9j4nx"}]}

次の例は、base64 エンコードを必要とする、JPEG 画像の 2 つのバイト文字列を示しています(例示のための架空のデータ)。

{"instances": [{"b64": "ASa8asdf"}, {"b64": "JLK7ljk3"}]}

複数の入力テンソル

一部のモデルでは、基盤となる TensorFlow グラフで複数の入力テンソルが受け入れられます。この場合、JSON の Key-Value ペアの名前を使用して入力テンソルを識別します。

入力テンソルの別名 tag(文字列)と image(Base64 でエンコードされた文字列)を持つグラフの場合:

{
  "instances": [
    {
      "tag": "beach",
      "image": {"b64": "ASa8asdf"}
    },
    {
      "tag": "car",
      "image": {"b64": "JLK7ljk3"}
    }
  ]
}

入力テンソルの別名 tag(文字列)と image(8 ビット整数の 3 次元配列)を持つグラフの場合:

{
  "instances": [
    {
      "tag": "beach",
      "image": [
        [
          [138, 30, 66],
          [130, 20, 56],
          ...
        ],
        [
          [126, 38, 61],
          [122, 24, 57],
          ...
        ],
        ...
      ]
    },
    {
      "tag": "car",
      "image": [
        [
          [255, 0, 102],
          [255, 0, 97],
          ...
        ],
        [
          [254, 1, 101],
          [254, 2, 93],
          ...
        ],
        ...
      ]
    },
    ...
  ]
}

PyTorch

モデルが PyTorch のビルド済みコンテナを使用する場合、TorchServe のデフォルト ハンドラは、各インスタンスが data フィールドでラップされることを想定しています。次に例を示します。

{
  "instances": [
    { "data": , <value> },
    { "data": , <value> }
  ]
}

レスポンス本文の詳細

呼び出しが成功した場合、レスポンスの本文には、リクエストの本文内のインスタンスごとに、同じ順序で 1 つの予測エントリが含まれます。

{
  "predictions": [
    {
      object
    }
  ],
  "deployedModelId": string
}

いずれかのインスタンスの予測に失敗した場合、レスポンスの本文には予測が含まれません。代わりに、単一のエラーエントリが含まれています。

{
  "error": string
}

predictions[] オブジェクトには、リクエストのインスタンスごとに 1 つの予測からなるリストが含まれます。

エラーの場合、error 文字列には問題を説明するメッセージが含まれます。インスタンスの処理中にエラーが発生した場合は、予測リストではなくエラーが返されます。

インスタンスごとに 1 つの予測があっても、予測の形式はインスタンスの形式に直接関係しません。予測には、モデルに定義された出力コレクションで指定されている形式が適用されます。予測のコレクションは JSON リストで返されます。リストの各メンバーは、値、リスト、多様な複雑度の JSON オブジェクトのいずれかです。モデルに複数の出力テンソルがある場合、各予測は各出力の Key-Value ペアを含む JSON オブジェクトになります。キーはグラフの出力エイリアスを識別します。

レスポンス本文の例

次の例は、TensorFlow で考えられるレスポンスを示しています。

  • 3 つの入力インスタンスの予測セット。各予測は整数値です。

    {"predictions":
      [5, 4, 3],
      "deployedModelId": 123456789012345678
    }
    
  • より複雑な予測セット。予測のそれぞれに、出力テンソルに対応する labelscores という 2 つの名前付き値が含まれます。label の値は予測カテゴリ(car または beach)であり、scores には可能性のあるカテゴリ全体のそのインスタンスの可能性のリストが含まれます。

    {
      "predictions": [
        {
          "label": "beach",
          "scores": [0.1, 0.9]
        },
        {
          "label": "car",
          "scores": [0.75, 0.25]
        }
      ],
      "deployedModelId": 123456789012345678
    }
    
  • 入力インスタンスの処理中にエラーが発生した場合のレスポンス:

    {"error": "Divide by zero"}