Se usó la API de Cloud Translation para traducir esta página.
Switch to English

API RESTful

Además de las API de gRPC, TensorFlow ModelServer también es compatible con las API RESTful. Esta página describe estos puntos finales de API y un ejemplo de un extremo a otro sobre el uso.

La solicitud y la respuesta es un objeto JSON. La composición de este objeto depende del tipo de solicitud o verbo. Consulte las secciones específicas de la API a continuación para obtener detalles.

En caso de error, todas las API devolverán un objeto JSON en el cuerpo de la respuesta con error como clave y el mensaje de error como valor:

{
  "error": <error message string>
}

API de estado del modelo

Esta API sigue de cerca la API de ModelService.GetModelStatus ModelService.GetModelStatus. Devuelve el estado de un modelo en ModelServer.

URL

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

Incluir /versions/${VERSION} o /labels/${LABEL} es opcional. Si se omite el estado de todas las versiones, se devuelve en la respuesta.

Formato de respuesta

Si tiene éxito, devuelve una representación JSON de GetModelStatusResponse protobuf.

API de metadatos del modelo

Esta API sigue de cerca la API de gRPC PredictionService.GetModelMetadata . Devuelve los metadatos de un modelo en ModelServer.

URL

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

Incluir /versions/${VERSION} o /labels/${LABEL} es opcional. Si se omite, los metadatos del modelo para la última versión se devuelven en la respuesta.

Formato de respuesta

Si tiene éxito, devuelve una representación JSON de GetModelMetadataResponse protobuf.

API de clasificación y regresión

Esta API sigue de cerca los métodos Classify y Regress de PredictionService gRPC API.

URL

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

Incluir /versions/${VERSION} o /labels/${LABEL} es opcional. Si se omite, se utiliza la última versión.

Formato de solicitud

El cuerpo de la solicitud para las API de classify y regress debe ser un objeto JSON con el siguiente formato:

{
  // 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> es un número JSON (entero o decimal) o una cadena, y <list> es una lista de dichos valores. Consulte la sección Codificación de valores binarios a continuación para obtener detalles sobre cómo representar un valor binario (flujo de bytes). Este formato es similar a los protos ClassificationRequest y RegressionRequest gRPC. Ambas versiones aceptan la lista de objetos de Example .

Formato de respuesta

Una solicitud de classify devuelve un objeto JSON en el cuerpo de la respuesta, con el siguiente formato:

{
  "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> es una cadena (que puede ser una cadena vacía "" si el modelo no tiene una etiqueta asociada con la puntuación). <score> es un número decimal (punto flotante).

La solicitud de regress devuelve un objeto JSON en el cuerpo de la respuesta, con el siguiente formato:

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

<value> es un número decimal.

Los usuarios de la API de gRPC notarán la similitud de este formato con los protos ClassificationResponse y RegressionResponse .

Predicción de API

Esta API sigue de cerca la API PredictionService.Predict gRPC.

URL

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

Incluir /versions/${VERSION} o /labels/${LABEL} es opcional. Si se omite, se utiliza la última versión.

Formato de solicitud

El cuerpo de la solicitud para la API de predict debe ser un objeto JSON con el siguiente formato:

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

Especificación de tensores de entrada en formato de fila.

Este formato es similar a PredictRequest proto de API GRPC y la CMLE predecir API . Utilice este formato si todos los tensores de entrada con nombre tienen la misma dimensión 0 . Si no es así, utilice el formato de columnas que se describe más adelante a continuación.

En el formato de fila, las entradas se asignan a la clave de instancias en la solicitud JSON.

Cuando solo hay una entrada con nombre, especifique el valor de la clave de instancias para que sea el valor de la entrada:

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

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

Los tensores se expresan de forma natural en notación anidada, ya que no es necesario aplanar manualmente la lista.

Para múltiples entradas con nombre, se espera que cada elemento sea un objeto que contenga un par de valor de tensor / nombre de entrada, uno para cada entrada con nombre. Como ejemplo, la siguiente es una solicitud con dos instancias, cada una con un conjunto de tres tensores de entrada con nombre:

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

Tenga en cuenta que cada entrada con nombre ("etiqueta", "señal", "sensor") se asume implícitamente que tiene la misma dimensión 0 ( dos en el ejemplo anterior, ya que hay dos objetos en la lista de instancias ). Si ha nombrado entradas que tienen una dimensión 0-ésima diferente, utilice el formato de columnas que se describe a continuación.

Especificar tensores de entrada en formato de columna.

Utilice este formato para especificar sus tensores de entrada, si las entradas con nombre individuales no tienen la misma dimensión 0 o si desea una representación más compacta. Este formato es similar a la inputs campo de la GRPC Predict petición.

En el formato de columnas, las entradas se asignan a la clave de entradas en la solicitud JSON.

El valor de la clave de entradas puede ser un tensor de entrada único o un mapa del nombre de entrada a los tensores (enumerados en su forma anidada natural). Cada entrada puede tener una forma arbitraria y no necesita compartir la misma dimensión 0 (también conocida como tamaño de lote) como lo requiere el formato de fila descrito anteriormente.

La representación en columnas del ejemplo anterior es la siguiente:

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

Tenga en cuenta que las entradas son un objeto JSON y no una lista como instancias (que se utilizan en la representación de filas). Además, todas las entradas con nombre se especifican juntas, en lugar de desenrollarlas en filas individuales en el formato de fila descrito anteriormente. Esto hace que la representación sea compacta (pero quizás menos legible).

Formato de respuesta

La solicitud de predict devuelve un objeto JSON en el cuerpo de respuesta.

Una solicitud en formato de fila tiene la respuesta con el siguiente formato:

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

Si la salida del modelo contiene solo un tensor con nombre, omitimos el nombre y los mapas de claves de predictions en una lista de valores escalares o de lista. Si el modelo genera varios tensores con nombre, en su lugar generamos una lista de objetos, similar a la solicitud en formato de fila mencionada anteriormente.

Una solicitud en formato de columnas tiene la respuesta con el siguiente formato:

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

Si la salida del modelo contiene solo un tensor con nombre, omitimos el nombre y las outputs claves de outputs a una lista de valores escalares o de lista. Si el modelo genera varios tensores con nombre, en su lugar generamos un objeto. Cada clave de este objeto corresponde a un tensor de salida con nombre. El formato es similar a la solicitud en formato de columna mencionado anteriormente.

Salida de valores binarios

TensorFlow no distingue entre cadenas binarias y no binarias. Todos son del tipo DT_STRING . Se _bytes que los tensores con nombre que tienen _bytes como sufijo en su nombre tienen valores binarios. Dichos valores se codifican de manera diferente como se describe en la sección de codificación de valores binarios a continuación.

Mapeo JSON

Las API RESTful admiten una codificación canónica en JSON, lo que facilita el intercambio de datos entre sistemas. Para los tipos admitidos, las codificaciones se describen tipo por tipo en la tabla siguiente. Se supone que los tipos que no se enumeran a continuación no son compatibles.

Tipo de datos TF Valor JSON Ejemplo JSON Notas
DT_BOOL verdadero Falso verdadero Falso
DT_STRING cuerda "¡Hola Mundo!" Si DT_STRING representa bytes binarios (por ejemplo, bytes de imagen serializados o protobuf), codifíquelos en Base64. Consulte Codificación de valores binarios para obtener más información.
DT_INT8, DT_UINT8, DT_INT16, DT_INT32, DT_UINT32, DT_INT64, DT_UINT64 número 1, -10, 0 El valor JSON será un número decimal.
DT_FLOAT, DT_DOUBLE número 1.1, -10.0, 0, NaN , Infinity El valor JSON será un número o uno de los valores de token especiales: NaN , Infinity e -Infinity . Consulte la conformidad con JSON para obtener más información. También se acepta la notación de exponentes.

Codificación de valores binarios

JSON usa codificación UTF-8. Si tiene una función de entrada o valores de tensor que deben ser binarios (como bytes de imagen), debe codificar los datos en Base64 y encapsularlos en un objeto JSON que tenga b64 como clave de la siguiente manera:

{ "b64": <base64 encoded string> }

Puede especificar este objeto como un valor para una característica de entrada o tensor. También se utiliza el mismo formato para codificar la respuesta de salida.

A continuación, se muestra una solicitud de clasificación con funciones de image (datos binarios) y caption :

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

Conformidad JSON

Muchos valores de función o tensor son números de punto flotante. Aparte de los valores finitos (por ejemplo, 3,14, 1,0, etc.), estos pueden tener valores NaN y no finitos ( Infinity e -Infinity ). Desafortunadamente, la especificación JSON ( RFC 7159 ) NO reconoce estos valores (aunque la especificación JavaScript sí lo hace).

La API REST descrita en esta página permite que los objetos JSON de solicitud / respuesta tengan dichos valores. Esto implica que solicitudes como la siguiente son válidas:

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

Un analizador JSON (estricto) que cumpla con los estándares rechazará esto con un error de análisis (debido a que los tokens NaN e Infinity mezclan con números reales). Para manejar correctamente las solicitudes / respuestas en su código, use un analizador JSON que admita estos tokens.

-Infinity tokens NaN , Infinity , -Infinity son reconocidos por proto3 , el módulo Python JSON y el lenguaje JavaScript.

Ejemplo

Podemos usar el modelo toy half_plus_three para ver las API REST en acción.

Inicie ModelServer con el punto final de la API REST

Descargue el modelo half_plus_three del repositorio de git :

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

Usaremos Docker para ejecutar ModelServer. Si desea instalar ModelServer de forma nativa en su sistema, siga las instrucciones de configuración para instalarlo e inicie ModelServer con la opción --rest_api_port para exportar el punto final de la API REST (esto no es necesario cuando se usa 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 ...

Realizar llamadas a la API REST a ModelServer

En una terminal diferente, use la herramienta curl para hacer llamadas a la API REST.

Obtenga el estado del modelo de la siguiente manera:

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

Una llamada de predict se vería de la siguiente manera:

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

Y una llamada de regress tiene el siguiente aspecto:

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

Tenga en cuenta que la regress está disponible en un nombre de firma no predeterminado y debe especificarse explícitamente. Un cuerpo o URL de solicitud incorrecto devuelve un estado de error 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)" }
$