RSVP pour votre événement TensorFlow Everywhere local dès aujourd'hui!
Cette page a été traduite par l'API Cloud Translation.
Switch to English

API RESTful

En plus des API gRPC, TensorFlow ModelServer prend également en charge les API RESTful. Cette page décrit ces points de terminaison d'API et un exemple d'utilisation de bout en bout.

La demande et la réponse sont un objet JSON. La composition de cet objet dépend du type de requête ou du verbe. Consultez les sections spécifiques à l'API ci-dessous pour plus de détails.

En cas d'erreur, toutes les API renverront un objet JSON dans le corps de la réponse avec error comme clé et le message d'erreur comme valeur:

{
  "error": <error message string>
}

API d'état du modèle

Cette API suit de près l'API ModelService.GetModelStatus ModelService.GetModelStatus. Il renvoie l'état d'un modèle dans ModelServer.

URL

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

L'inclusion de /versions/${VERSION} ou /labels/${LABEL} est facultative. En cas d'omission, l'état de toutes les versions est renvoyé dans la réponse.

Format de réponse

En cas de succès, renvoie une représentation JSON de GetModelStatusResponse protobuf.

API de métadonnées de modèle

Cette API suit de près l'API gRPC PredictionService.GetModelMetadata . Il renvoie les métadonnées d'un modèle dans le ModelServer.

URL

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

L'inclusion de /versions/${VERSION} ou /labels/${LABEL} est facultative. En cas d'omission, les métadonnées du modèle pour la dernière version sont renvoyées dans la réponse.

Format de réponse

En cas de succès, renvoie une représentation JSON de GetModelMetadataResponse protobuf.

API de classification et de régression

Cette API suit de près les Classify et Regress méthodes de PredictionService API GRPC.

URL

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

L'inclusion de /versions/${VERSION} ou /labels/${LABEL} est facultative. Si omis, la dernière version est utilisée.

Format de la demande

Le corps de la requête pour les API de classify et de regress doit être un objet JSON formaté comme suit:

{
  // 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> est un nombre JSON (entier ou décimal), une chaîne JSON ou un objet JSON qui représente des données binaires (voir la section Encodage des valeurs binaires ci-dessous pour plus de détails). <list> est une liste de ces valeurs. Ce format est similaire aux protos ClassificationRequest et RegressionRequest gRPC. Les deux versions acceptent la liste d'objets Example .

Format de réponse

Une demande de classify renvoie un objet JSON dans le corps de la réponse, formaté comme suit:

{
  "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> est une chaîne (qui peut être une chaîne vide "" si le modèle n'a pas d'étiquette associée à la partition). <score> est un nombre décimal (virgule flottante).

La demande de regress renvoie un objet JSON dans le corps de la réponse, formaté comme suit:

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

<value> est un nombre décimal.

Les utilisateurs de l'API gRPC remarqueront la similitude de ce format avec les protos ClassificationResponse et RegressionResponse .

Prédire l'API

Cette API suit de près l'API gRPC PredictionService.Predict .

URL

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

L'inclusion de /versions/${VERSION} ou /labels/${LABEL} est facultative. Si omis, la dernière version est utilisée.

Format de la demande

Le corps de demande de predict l' API doit être objet JSON formaté comme suit:

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

Spécification des tenseurs d'entrée au format ligne.

Ce format est similaire à PredictRequest proto de l' API GRPC et CMLE prédire API . Utilisez ce format si tous les tenseurs d'entrée nommés ont la même dimension 0 . Si ce n'est pas le cas, utilisez le format en colonnes décrit ci-dessous.

Dans le format de ligne, les entrées sont indexées sur la clé d' instances dans la requête JSON.

Lorsqu'il n'y a qu'une seule entrée nommée, spécifiez la valeur de la clé d' instances comme valeur de l'entrée:

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

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

Les tenseurs sont exprimés naturellement en notation imbriquée car il n'est pas nécessaire d'aplatir manuellement la liste.

Pour plusieurs entrées nommées, chaque élément est censé être un objet contenant une paire nom / valeur de tenseur d'entrée, une pour chaque entrée nommée. À titre d'exemple, voici une requête avec deux instances, chacune avec un ensemble de trois tenseurs d'entrée nommés:

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

Notez que chaque entrée nommée ("tag", "signal", "sensor") est implicitement supposée avoir la même 0-ième dimension ( deux dans l'exemple ci-dessus, car il y a deux objets dans la liste des instances ). Si vous avez nommé des entrées qui ont une 0-ième dimension différente, utilisez le format en colonnes décrit ci-dessous.

Spécification des tenseurs d'entrée au format colonne.

Utilisez ce format pour spécifier vos tenseurs d'entrée, si les entrées nommées individuelles n'ont pas la même dimension 0 ou si vous souhaitez une représentation plus compacte. Ce format est similaire au champ d' inputs de la requête gRPC Predict .

Dans le format en colonnes, les entrées sont indexées sur la clé des entrées dans la requête JSON.

La valeur de la clé des entrées peut être un seul tenseur d'entrée ou une carte du nom d'entrée en tenseurs (répertoriés dans leur forme imbriquée naturelle). Chaque entrée peut avoir une forme arbitraire et n'a pas besoin de partager la même dimension 0 (c'est-à-dire la taille du lot) comme l'exige le format de ligne décrit ci-dessus.

La représentation en colonnes de l'exemple précédent est la suivante:

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

Notez que les entrées sont un objet JSON et non une liste comme des instances (utilisées dans la représentation de ligne). En outre, toutes les entrées nommées sont spécifiées ensemble, au lieu de les dérouler dans des lignes individuelles effectuées dans le format de ligne décrit précédemment. Cela rend la représentation compacte (mais peut-être moins lisible).

Format de réponse

La demande de predict renvoie un objet JSON dans le corps de la réponse.

Une requête au format ligne a une réponse formatée comme suit:

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

Si la sortie du modèle ne contient qu'un seul tenseur nommé, nous omettons le nom et predictions clé de predictions mappe à une liste de valeurs scalaires ou de liste. Si le modèle génère plusieurs tenseurs nommés, nous générons une liste d'objets à la place, similaire à la requête au format ligne mentionnée ci-dessus.

Une demande au format colonne a une réponse formatée comme suit:

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

Si la sortie du modèle ne contient qu'un seul tenseur nommé, nous omettons le nom et les outputs clé cartes à une liste de valeurs scalaires ou liste. Si le modèle génère plusieurs tenseurs nommés, nous générons un objet à la place. Chaque clé de cet objet correspond à un tenseur de sortie nommé. Le format est similaire à la demande au format colonne mentionnée ci-dessus.

Sortie de valeurs binaires

TensorFlow ne fait pas la distinction entre les chaînes non binaires et binaires. Tous sont de type DT_STRING . Les tenseurs nommés qui ont _bytes comme suffixe dans leur nom sont considérés comme ayant des valeurs binaires. Ces valeurs sont codées différemment comme décrit dans la section de codage des valeurs binaires ci-dessous.

Cartographie JSON

Les API RESTful prennent en charge un codage canonique en JSON, ce qui facilite le partage de données entre les systèmes. Pour les types pris en charge, les encodages sont décrits type par type dans le tableau ci-dessous. Les types non répertoriés ci-dessous ne sont pas pris en charge.

Type de données TF Valeur JSON Exemple JSON Remarques
DT_BOOL vrai faux vrai faux
DT_STRING chaîne "Bonjour le monde!" Si DT_STRING représente des octets binaires (par exemple, des octets d'image sérialisés ou protobuf), codez-les en Base64. Voir Encodage des valeurs binaires pour plus d'informations.
DT_INT8, DT_UINT8, DT_INT16, DT_INT32, DT_UINT32, DT_INT64, DT_UINT64 nombre 1100 La valeur JSON sera un nombre décimal.
DT_FLOAT, DT_DOUBLE nombre 1.1, -10.0, 0, NaN , Infinity La valeur JSON sera un nombre ou l'une des valeurs de jeton spéciales - NaN , Infinity et -Infinity . Voir la conformité JSON pour plus d'informations. La notation exposant est également acceptée.

Codage des valeurs binaires

JSON utilise le codage UTF-8. Si vous avez des valeurs de fonction ou de tenseur d'entrée qui doivent être binaires (comme des octets d'image), vous devez encoder les données en Base64 et les encapsuler dans un objet JSON ayant b64 comme clé comme suit:

{ "b64": <base64 encoded string> }

Vous pouvez spécifier cet objet comme valeur pour une entité ou un tenseur en entrée. Le même format est également utilisé pour encoder la réponse de sortie.

Une demande de classification avec des fonctionnalités d' image (données binaires) et de caption est présentée ci-dessous:

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

Conformité JSON

De nombreuses valeurs d'entité ou de tenseur sont des nombres à virgule flottante. En dehors des valeurs finies (par exemple 3.14, 1.0, etc.), celles-ci peuvent avoir des valeurs NaN et non finies ( Infinity et -Infinity ). Malheureusement, la spécification JSON ( RFC 7159 ) ne reconnaît PAS ces valeurs (bien que la spécification JavaScript le fasse).

L'API REST décrite sur cette page permet aux objets JSON de demande / réponse d'avoir de telles valeurs. Cela implique que les demandes comme la suivante sont valides:

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

Un analyseur JSON conforme aux normes (strictes) rejettera cela avec une erreur d'analyse (en raison de jetons NaN et Infinity mélangés avec des nombres réels). Pour gérer correctement les demandes / réponses dans votre code, utilisez un analyseur JSON qui prend en charge ces jetons.

-Infinity jetons NaN , Infinity , -Infinity sont reconnus par proto3 , le module Python JSON et le langage JavaScript.

Exemple

Nous pouvons utiliser le modèle toy half_plus_three pour voir les API REST en action.

Démarrez ModelServer avec le point de terminaison de l'API REST

Téléchargez le modèle half_plus_three partir du référentiel git :

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

Nous utiliserons Docker pour exécuter le ModelServer. Si vous souhaitez installer ModelServer de manière native sur votre système, suivez les instructions de configuration pour l'installer à la place et démarrez ModelServer avec l'option --rest_api_port pour exporter le point de terminaison de l'API REST (cela n'est pas nécessaire lors de l'utilisation de 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 ...

Effectuer des appels d'API REST à ModelServer

Dans un autre terminal, utilisez l'outil curl pour effectuer des appels d'API REST.

Obtenez le statut du modèle comme suit:

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

Un appel de predict ressemblerait à ceci:

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

Et un appel de regress se présente comme suit:

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

Notez que la regress est disponible sur un nom de signature autre que celui par défaut et doit être spécifiée explicitement. Une URL ou un corps de requête incorrect renvoie un état d'erreur 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)" }
$