Treten Sie der SIG TFX-Addons-Community bei und helfen Sie mit, TFX noch besser zu machen! SIG TFX-Addons beitreten

RESTful API

Neben gRPC-APIs unterstützt TensorFlow ModelServer auch RESTful-APIs. Diese Seite beschreibt diese API-Endpunkte und ein End-to-End- Beispiel zur Verwendung.

Die Anforderung und Antwort ist ein JSON-Objekt. Die Zusammensetzung dieses Objekts hängt vom Anforderungstyp oder Verb ab. Weitere Informationen finden Sie in den API-spezifischen Abschnitten unten.

Im Fehlerfall geben alle APIs ein JSON-Objekt im Antworttext mit dem error als Schlüssel und der Fehlermeldung als Wert zurück:

{
  "error": <error message string>
}

Modellstatus-API

Diese API folgt eng der gRPC-API ModelService.GetModelStatus . Es gibt den Status eines Modells im ModelServer zurück.

URL

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

Das Einschließen von /versions/${VERSION} oder /labels/${LABEL} ist optional. Wenn der Status für alle Versionen weggelassen wird, wird er in der Antwort zurückgegeben.

Antwortformat

Bei Erfolg wird eine JSON-Darstellung von GetModelStatusResponse protobuf zurückgegeben.

Modell-Metadaten-API

Diese API folgt genau der PredictionService.GetModelMetadata gRPC-API. Es gibt die Metadaten eines Modells im ModelServer zurück.

URL

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

Das Einschließen von /versions/${VERSION} oder /labels/${LABEL} ist optional. Wenn nicht angegeben, werden die Modellmetadaten für die neueste Version in der Antwort zurückgegeben.

Antwortformat

Bei Erfolg wird eine JSON-Darstellung von GetModelMetadataResponse protobuf zurückgegeben.

API klassifizieren und regressieren

Diese API folgt genau den Classify und Regress Methoden der PredictionService gRPC-API.

URL

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

Das Einschließen von /versions/${VERSION} oder /labels/${LABEL} ist optional. Wenn nicht angegeben, wird die neueste Version verwendet.

Anforderungsformat

Der Anforderungshauptteil für die classify und regress APIs muss ein JSON-Objekt sein, das wie folgt formatiert ist:

{
  // 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> ist eine JSON-Zahl (ganz oder dezimal), eine JSON-Zeichenfolge oder ein JSON-Objekt, das Binärdaten darstellt (Einzelheiten finden Sie im Abschnitt Codieren von Binärwerten weiter unten). <list> ist eine Liste solcher Werte. Dieses Format ähnelt den Prototypen ClassificationRequest und RegressionRequest von gRPC. Beide Versionen akzeptieren eine Liste von Example .

Antwortformat

Eine classify gibt ein JSON-Objekt im Antworttext zurück, das wie folgt formatiert ist:

{
  "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> ist eine Zeichenfolge (die eine leere Zeichenfolge "" wenn dem Modell keine Bezeichnung zugeordnet ist). <score> ist eine Dezimalzahl (Gleitkommazahl).

Die regress gibt ein JSON-Objekt im Antworttext zurück, das wie folgt formatiert ist:

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

<value> ist eine Dezimalzahl.

Benutzer der gRPC-API werden die Ähnlichkeit dieses Formats mit den Protokollen ClassificationResponse und RegressionResponse bemerken.

API vorhersagen

Diese API folgt eng der PredictionService.Predict gRPC-API.

URL

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

Das Einschließen von /versions/${VERSION} oder /labels/${LABEL} ist optional. Wenn nicht angegeben, wird die neueste Version verwendet.

Anforderungsformat

Der Anforderungshauptteil für die predict API muss wie folgt im JSON-Objekt formatiert sein:

{
  // (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>
}

Angeben von Eingangstensoren im Zeilenformat.

Dieses Format ähnelt dem PredictRequest Proto der gRPC-API und der CMLE-Vorhersage-API . Verwenden Sie dieses Format, wenn alle benannten Eingangstensoren dieselbe 0-te Dimension haben . Wenn dies nicht der Fall ist, verwenden Sie das später beschriebene Spaltenformat.

Im Zeilenformat werden Eingaben Instanzen Schlüssel in der JSON - Anforderung eingegeben.

Wenn nur eine benannte Eingabe vorhanden ist, geben Sie den Wert des Instanzschlüssels als Wert der Eingabe an:

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

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

Tensoren werden natürlich in verschachtelter Notation ausgedrückt, da die Liste nicht manuell reduziert werden muss.

Bei mehreren benannten Eingaben wird erwartet, dass jedes Element ein Objekt ist, das ein Paar aus Eingabename und Tensorwert enthält, eines für jede benannte Eingabe. Das folgende Beispiel ist eine Anforderung mit zwei Instanzen mit jeweils drei benannten Eingangstensoren:

{
 "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]]
   }
 ]
}

Beachten Sie , jeweils genannte Eingang ( „tag“, „Signal“, „Sensor“) wird implizit angenommen haben gleiche 0-ten Dimension (zwei in obigem Beispiel, da es zwei Objekte in der Instanzen - Liste). Wenn Sie Eingaben mit einer anderen 0-ten Dimension benannt haben, verwenden Sie das unten beschriebene Spaltenformat.

Angeben von Eingangstensoren im Spaltenformat.

Verwenden Sie dieses Format, um Ihre Eingabetensoren anzugeben, wenn einzelne benannte Eingaben nicht dieselbe 0-te Dimension haben oder Sie eine kompaktere Darstellung wünschen. Dieses Format ist ähnlich der inputs Feld der gRPC Predict Anfrage.

Im Spaltenformat werden Eingaben mit Eingabeschlüsseln in der JSON-Anforderung verknüpft.

Der Wert für die Eingänge Schlüssel kann entweder ein einzelner Eingang Tensor oder eine Karte von Eingang Namen Tensor (in ihrer natürlichen verschachtelten Form aufgeführt). Jede Eingabe kann eine beliebige Form haben und muss nicht dieselbe 0-te Dimension (auch als Stapelgröße bezeichnet) gemeinsam haben, wie dies für das oben beschriebene Zeilenformat erforderlich ist.

Die spaltenweise Darstellung des vorherigen Beispiels lautet wie folgt:

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

Beachten Sie, dass Eingaben ein JSON-Objekt und keine Liste wie Instanzen sind (in der Zeilendarstellung verwendet). Außerdem werden alle benannten Eingaben zusammen angegeben, anstatt sie in einzelne Zeilen abzuwickeln, die im zuvor beschriebenen Zeilenformat erstellt wurden. Dies macht die Darstellung kompakt (aber möglicherweise weniger lesbar).

Antwortformat

Die predict gibt ein JSON-Objekt im Antworttext zurück.

Eine Anfrage im Zeilenformat hat die Antwort wie folgt formatiert:

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

Wenn die Ausgabe des Modells nur einen benannten Tensor enthält, lassen wir die Schlüsselzuordnungen für Name und predictions einer Liste von Skalar- oder Listenwerten weg. Wenn das Modell mehrere benannte Tensoren ausgibt, geben wir stattdessen eine Liste von Objekten aus, ähnlich der oben erwähnten Anforderung im Zeilenformat.

Eine Anfrage im Spaltenformat hat die Antwort wie folgt formatiert:

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

Wenn die Ausgabe des Modells nur einen benannten Tensor enthält, lassen wir den Namen outputs und geben Schlüsselzuordnungen zu einer Liste von Skalar- oder Listenwerten aus. Wenn das Modell mehrere benannte Tensoren ausgibt, geben wir stattdessen ein Objekt aus. Jeder Schlüssel dieses Objekts entspricht einem benannten Ausgangstensor. Das Format ähnelt der oben erwähnten Anforderung im Spaltenformat.

Ausgabe von Binärwerten

TensorFlow unterscheidet nicht zwischen nicht-binären und binären Zeichenfolgen. Alle sind DT_STRING Typ DT_STRING . Benannte Tensoren, deren Name _bytes als Suffix enthält, haben Binärwerte. Solche Werte werden unterschiedlich codiert, wie im folgenden Abschnitt zum Codieren von Binärwerten beschrieben.

JSON-Zuordnung

Die RESTful-APIs unterstützen eine kanonische Codierung in JSON, wodurch der Datenaustausch zwischen Systemen vereinfacht wird. Für unterstützte Typen werden die Codierungen in der folgenden Tabelle typweise beschrieben. Typen, die unten nicht aufgeführt sind, werden nicht unterstützt.

TF-Datentyp JSON-Wert JSON-Beispiel Anmerkungen
DT_BOOL wahr falsch wahr falsch
DT_STRING Zeichenfolge "Hallo Welt!" Wenn DT_STRING binäre Bytes darstellt (z. B. serialisierte Bildbytes oder Protobuf), codieren Sie diese in Base64. Weitere Informationen finden Sie unter Codieren von Binärwerten .
DT_INT8, DT_UINT8, DT_INT16, DT_INT32, DT_UINT32, DT_INT64, DT_UINT64 Nummer 1, -10, 0 Der JSON-Wert ist eine Dezimalzahl.
DT_FLOAT, DT_DOUBLE Nummer 1,1, -10,0, 0, NaN , Infinity Der JSON-Wert ist eine Zahl oder einer der speziellen Token-Werte - NaN , Infinity und -Infinity . Weitere Informationen finden Sie unter JSON-Konformität . Die Exponentenschreibweise wird ebenfalls akzeptiert.

Gleitkomma-Präzision

JSON hat einen Datentyp mit einer einzelnen Nummer. Somit ist es möglich, einen Wert für eine Eingabe bereitzustellen, der zu einem Genauigkeitsverlust führt. Zum Beispiel, wenn der Eingang x a float Datentyp und der Eingang {"x": 1435774380} wird an das Modell läuft auf der Hardware auf der Basis des IEEE 754 Gleitkomma - Standard (zB Intel oder AMD) gesendet wird , dann wird der Wert von der Underyling-Hardware stillschweigend in 1435774336 1435774336 da 1435774380 nicht genau in einer 32-Bit-Gleitkommazahl dargestellt werden kann. In der Regel sollten die Eingaben für das Servieren dieselbe Verteilung wie für das Training haben, sodass dies im Allgemeinen nicht problematisch ist, da zum Zeitpunkt des Trainings dieselben Conversions stattfanden. Wenn jedoch volle Genauigkeit erforderlich ist, stellen Sie sicher, dass Sie in Ihrem Modell einen zugrunde liegenden Datentyp verwenden, der die gewünschte Genauigkeit verarbeiten kann, und / oder eine clientseitige Überprüfung in Betracht ziehen.

Binärwerte codieren

JSON verwendet die UTF-8-Codierung. Wenn Sie Eingabemerkmale oder Tensorwerte haben, die binär sein müssen (wie Bildbytes), müssen Sie Base64 die Daten codieren und sie wie folgt in ein JSON-Objekt mit b64 als Schlüssel kapseln:

{ "b64": <base64 encoded string> }

Sie können dieses Objekt als Wert für ein Eingabe-Feature oder einen Tensor angeben. Das gleiche Format wird auch zum Codieren der Ausgabeantwort verwendet.

Eine Klassifizierungsanforderung mit image (Binärdaten) und caption wird unten gezeigt:

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

JSON-Konformität

Viele Merkmals- oder Tensorwerte sind Gleitkommazahlen. Abgesehen von endlichen Werten (z. B. 3,14, 1,0 usw.) können diese NaN und nicht endliche Werte ( Infinity und -Infinity ) haben. Leider erkennt die JSON-Spezifikation ( RFC 7159 ) diese Werte NICHT (obwohl die JavaScript-Spezifikation dies tut).

Die auf dieser Seite beschriebene REST-API ermöglicht es Anforderungs- / Antwort-JSON-Objekten, solche Werte zu haben. Dies bedeutet, dass Anforderungen wie die folgende gültig sind:

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

Ein (strenger) standardkonformer JSON-Parser lehnt dies mit einem Analysefehler ab (aufgrund von NaN und Infinity Token, die mit tatsächlichen Zahlen gemischt sind). Verwenden Sie einen JSON-Parser, der diese Token unterstützt, um Anforderungen / Antworten in Ihrem Code korrekt zu verarbeiten.

NaN , Infinity , -Infinity Tokens von erkannt werden proto3 , Python JSON - Modul und JavaScript - Sprache.

Beispiel

Wir können das Modell toy half_plus_three verwenden, um REST-APIs in Aktion zu sehen.

Starten Sie ModelServer mit dem REST-API-Endpunkt

Laden Sie das Modell half_plus_three aus dem Git-Repository herunter:

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

Wir werden Docker verwenden, um den ModelServer auszuführen. Wenn Sie Modelserver nativ auf Ihrem System installieren mögen, Installationsanweisungen statt, zu installieren und den Modelserver mit starten --rest_api_port Option Export REST API - Endpunkt (dies ist nicht erforderlich , bei der Verwendung von 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 ...

Führen Sie REST-API-Aufrufe an ModelServer durch

Verwenden Sie in einem anderen Terminal das curl Tool, um REST-API-Aufrufe durchzuführen.

Erhalten Sie den Status des Modells wie folgt:

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

Ein predict würde wie folgt aussehen:

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

Und ein regress sieht wie folgt aus:

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

Hinweis: regress ist für einen nicht standardmäßigen Signaturnamen verfügbar und muss explizit angegeben werden. Eine falsche Anforderungs-URL oder ein falscher Text gibt einen HTTP-Fehlerstatus zurück.

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