API RESTful

Oltre a gRPC API tensorflow ModelServer supporta anche le API RESTful. Questa pagina descrive questi endpoint API e un end-to-end esempio consumato.

La richiesta e la risposta sono un oggetto JSON. La composizione di questo oggetto dipende dal tipo di richiesta o dal verbo. Per i dettagli, vedere le sezioni specifiche dell'API di seguito.

In caso di errore, tutte le API restituisce un oggetto JSON nel corpo della risposta con error come chiave e il messaggio di errore come valore:

{
  "error": <error message string>
}

API dello stato del modello

Questa API segue da vicino la ModelService.GetModelStatus API gRPC. Restituisce lo stato di un modello nel ModelServer.

URL

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

Compreso /versions/${VERSION} o /labels/${LABEL} è facoltativo. Se lo stato omesso per tutte le versioni viene restituito nella risposta.

Formato di risposta

In caso di successo, restituisce una rappresentazione JSON di GetModelStatusResponse protobuf.

API dei metadati del modello

Questa API segue da vicino la PredictionService.GetModelMetadata API gRPC. Restituisce i metadati di un modello nel ModelServer.

URL

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

Compreso /versions/${VERSION} o /labels/${LABEL} è facoltativo. Se omesso, nella risposta vengono restituiti i metadati del modello per l'ultima versione.

Formato di risposta

In caso di successo, restituisce una rappresentazione JSON di GetModelMetadataResponse protobuf.

API di classificazione e regressione

Questa API segue da vicino le Classify e Regress metodi di PredictionService gRPC API.

URL

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

Compreso /versions/${VERSION} o /labels/${LABEL} è facoltativo. Se omesso, viene utilizzata la versione più recente.

Formato della richiesta

Il corpo della richiesta per le classify e regress API deve essere un oggetto JSON formattato come segue:

{
  // 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> è un numero JSON (intero o decimale), stringa JSON, o un oggetto JSON che rappresenta dati binari (vedi valori binari Codifica sezione di seguito per i dettagli). <list> è un elenco di tali valori. Questo formato è simile a quello di gRPC ClassificationRequest e RegressionRequest protos. Entrambe le versioni accettano elenco di Example oggetti.

Formato di risposta

Un classify richiesta restituisce un oggetto JSON nel corpo della risposta, formattato come segue:

{
  "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> è una stringa (che può essere una stringa vuota "" se il modello non ha un'etichetta associata con il punteggio). <score> è un decimale (virgola mobile) numero.

Il regress richiesta restituisce un oggetto JSON nel corpo della risposta, formattato come segue:

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

<value> è un numero decimale.

Gli utenti di gRPC API noteranno la somiglianza di questo formato con ClassificationResponse e RegressionResponse protos.

API di previsione

Questa API segue da vicino la PredictionService.Predict API gRPC.

URL

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

Compreso /versions/${VERSION} o /labels/${LABEL} è facoltativo. Se omesso, viene utilizzata la versione più recente.

Formato della richiesta

Il corpo della richiesta per predict API deve essere oggetto JSON formattato come segue:

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

Specificare i tensori di input in formato riga.

Questo formato è simile a PredictRequest proto di gRPC API e CMLE prevedere API . Utilizzare questo formato se tutti i tensori di input di nome hanno la stessa 0-° dimensione. In caso contrario, utilizzare il formato a colonne descritto più avanti di seguito.

Nel formato di riga, ingressi corrispondono a chiave istanze nella richiesta JSON.

Quando c'è un solo nome di input, specificare il valore di istanze fondamentali di essere il valore dell'ingresso:

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

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

I tensori sono espressi naturalmente in notazione annidata poiché non è necessario appiattire manualmente l'elenco.

Per più input denominati, ogni elemento dovrebbe essere un oggetto contenente la coppia nome input/valore tensore, uno per ciascun input denominato. Ad esempio, la seguente è una richiesta con due istanze, ciascuna con un set di tre tensori di input denominati:

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

Nota, ogni ingresso chiamata ( "tag", "segnale", "sensore") è implicitamente supposto avere stessa 0-° dimensione (due nell'esempio di cui sopra, in quanto vi sono due oggetti nell'elenco istanze). Se sono stati denominati input che hanno una dimensione 0-esima diversa, utilizzare il formato a colonne descritto di seguito.

Specificare i tensori di input in formato colonna.

Usa questo formato per specificare i tensori di input, se i singoli input denominati non hanno la stessa dimensione 0-esima o se desideri una rappresentazione più compatta. Questo formato è simile al inputs campo della gRPC Predict richiesta.

Nel formato a colonne, ingressi sono calettati agli ingressi chiave nella richiesta JSON.

Il valore per la chiave ingressi possono un singolo tensore ingresso o una mappa di nome input per tensori (elencati nella loro forma naturale nested). Ciascun input può avere una forma arbitraria e non è necessario che condivida la stessa dimensione 0-esima (nota anche come dimensione batch) come richiesto dal formato di riga descritto sopra.

La rappresentazione a colonne dell'esempio precedente è la seguente:

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

Nota, ingressi è un oggetto JSON e non un elenco come istanze (usato nella rappresentazione riga). Inoltre, tutti gli input nominati vengono specificati insieme, invece di srotolarli in singole righe nel formato di riga descritto in precedenza. Questo rende la rappresentazione compatta (ma forse meno leggibile).

Formato di risposta

La predict richiesta restituisce un oggetto JSON nel corpo di risposta.

Una richiesta in formato di riga ha risposta formattato come segue:

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

Se l'uscita del modello contiene un solo nome tensore, omettiamo il nome e predictions chiave associata a un elenco di valori scalari o elencare. Se il modello emette più tensori con nome, viene invece generato un elenco di oggetti, simile alla richiesta in formato riga menzionata sopra.

Una richiesta in formato a colonne ha risposta formattato come segue:

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

Se l'uscita del modello contiene un solo nome tensore, omettiamo il nome e outputs chiave mappe per un elenco di valori scalari o elencare. Se il modello emette più tensori con nome, emettiamo invece un oggetto. Ogni chiave di questo oggetto corrisponde a un tensore di output denominato. Il formato è simile alla richiesta in formato colonna sopra menzionata.

Uscita di valori binari

TensorFlow non distingue tra stringhe non binarie e binarie. Tutti sono DT_STRING tipo. Tensori Named che hanno _bytes come suffisso nel loro nome sono considerati avere valori binari. Tali valori sono codificati in modo diverso come descritto nella codifica valori binari sezione sottostante.

Mappatura JSON

Le API RESTful supportano una codifica canonica in JSON, semplificando la condivisione dei dati tra i sistemi. Per i tipi supportati, le codifiche sono descritte tipo per tipo nella tabella seguente. Si presume che i tipi non elencati di seguito non siano supportati.

Tipo di dati TF Valore JSON Esempio JSON Appunti
DT_BOOL vero falso vero falso
DT_STRING corda "Ciao mondo!" Se DT_STRING rappresenta byte binari (ad esempio byte di immagine serializzati o protobuf), codificare questi in Base64. Vedere Codifica valori binari per maggiori informazioni.
DT_INT8, DT_UINT8, DT_INT16, DT_INT32, DT_UINT32, DT_INT64, DT_UINT64 numero 1, -10, 0 Il valore JSON sarà un numero decimale.
DT_FLOAT, DT_DOUBLE numero 1.1, -10.0, 0, NaN , Infinity Valore JSON sarà un numero o uno dei valori simbolici speciali - NaN , Infinity , e -Infinity . Vedere JSON conformità per maggiori informazioni. È accettata anche la notazione dell'esponente.

Precisione in virgola mobile

JSON ha un tipo di dati a numero singolo. Pertanto è possibile fornire un valore per un input che comporta una perdita di precisione. Ad esempio, se l'ingresso x è un float tipo di dati, e l'ingresso {"x": 1435774380} viene inviato al modello in esecuzione su hardware basato su IEEE 754 in virgola mobile standard (es Intel o AMD), allora il valore sarà essere convertito in silenzio dall'hardware underyling a 1435774336 poiché 1435774380 non può essere esattamente rappresentato in un numero in virgola mobile a 32 bit. In genere, gli input per l'elaborazione dovrebbero essere la stessa distribuzione dell'addestramento, quindi questo in genere non sarà problematico perché le stesse conversioni si sono verificate durante l'addestramento. Tuttavia, nel caso sia necessaria la massima precisione, assicurarsi di utilizzare un tipo di dati sottostante nel modello in grado di gestire la precisione desiderata e/o considerare il controllo lato client.

Codifica di valori binari

JSON utilizza la codifica UTF-8. Se si dispone di valori di caratteristiche o tensore di input che devono essere binario (come immagine byte), è necessario Base64 codificare i dati e incapsulare in un oggetto JSON avente b64 come la chiave come segue:

{ "b64": <base64 encoded string> }

È possibile specificare questo oggetto come valore per una feature di input o un tensore. Lo stesso formato viene utilizzato anche per codificare la risposta dell'output.

Una richiesta di classificazione con image (dati binari) e caption caratteristiche è la seguente:

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

Conformità JSON

Molti valori di feature o tensori sono numeri in virgola mobile. Oltre a valori finiti (ad esempio 3.14, 1.0 ecc) questi possono avere NaN e non-finito ( Infinity e -Infinity valori). Purtroppo la specifica JSON ( RFC 7159 ) NON riconosce questi valori (anche se la specifica JavaScript fa).

L'API REST descritta in questa pagina consente agli oggetti JSON di richiesta/risposta di avere tali valori. Ciò implica che sono valide richieste come la seguente:

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

A (severe) standard JSON compatibile parser rifiuterà questo con un errore di analisi (a causa di NaN e Infinity gettoni mescolato con numeri reali). Per gestire correttamente le richieste/risposte nel tuo codice, usa un parser JSON che supporti questi token.

NaN , Infinity , -Infinity gettoni sono riconosciuti da proto3 , Python JSON del modulo e il linguaggio Javascript.

Esempio

Possiamo usare il giocattolo half_plus_three modello per vedere le API REST in azione.

Avvia ModelServer con l'endpoint dell'API REST

Scarica il half_plus_three modello dalla repository git :

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

Useremo Docker per eseguire ModelServer. Se si desidera installare ModelServer nativamente sul sistema, seguire le istruzioni di configurazione per l'installazione, invece, e avviare il ModelServer con --rest_api_port opzione di esportazione API REST endpoint (questo non è necessario quando si utilizza 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 ...

Effettua chiamate API REST a ModelServer

In un terminale diverso, utilizzare il curl strumento per effettuare chiamate API REST.

Ottieni lo stato del modello come segue:

$ 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 predict chiamata apparirebbe come segue:

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

E un regress sguardi chiamata come segue:

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

Nota, regress è disponibile sul nome di firma non predefinito e deve essere specificato in modo esplicito. Un URL o un corpo della richiesta errato restituisce uno stato di errore 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)" }
$