Esta página foi traduzida pela API Cloud Translation.
Switch to English

API RESTful

Além das APIs gRPC, o TensorFlow ModelServer também oferece suporte a APIs RESTful. Esta página descreve esses endpoints da API e um exemplo completo de uso.

A solicitação e a resposta são um objeto JSON. A composição deste objeto depende do tipo de solicitação ou verbo. Consulte as seções específicas da API abaixo para obter detalhes.

Em caso de erro, todas as APIs retornarão um objeto JSON no corpo da resposta com o error como chave e a mensagem de erro como o valor:

{
  "error": <error message string>
}

API de status do modelo

Esta API segue de perto a API ModelService.GetModelStatus gRPC. Ele retorna o status de um modelo no ModelServer.

URL

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

Incluir /versions/${VERSION} ou /labels/${LABEL} é opcional. Se omitido, o status de todas as versões é retornado na resposta.

Formato de resposta

Se for bem-sucedido, retorna uma representação JSON do protobuf GetModelStatusResponse .

API Model Metadata

Esta API segue de perto a PredictionService.GetModelMetadata gRPC API. Ele retorna os metadados de um modelo no ModelServer.

URL

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

Incluir /versions/${VERSION} ou /labels/${LABEL} é opcional. Se omitido, os metadados do modelo para a versão mais recente são retornados na resposta.

Formato de resposta

Se for bem-sucedido, retorna uma representação JSON do protobuf GetModelMetadataResponse .

API Classify and Regress

Esta API segue de perto os Classify e Regress métodos de PredictionService gRPC API.

URL

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

Incluir /versions/${VERSION} ou /labels/${LABEL} é opcional. Se omitido, a versão mais recente é usada.

Formato de solicitação

O corpo da solicitação para as APIs de classify e regress deve ser um objeto JSON formatado da seguinte maneira:

{
  // 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> é um número JSON (inteiro ou decimal) ou string, e <list> é uma lista de tais valores. Consulte a seção Codificando valores binários abaixo para obter detalhes sobre como representar um valor binário (fluxo de bytes). Esse formato é semelhante aos protocolos ClassificationRequest e RegressionRequest gRPC. Ambas as versões aceitam lista de objetos de Example .

Formato de resposta

Uma solicitação de classify retorna um objeto JSON no corpo da resposta, formatado da seguinte maneira:

{
  "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> é uma string (que pode ser uma string vazia "" se o modelo não tiver um rótulo associado à pontuação). <score> é um número decimal (ponto flutuante).

A solicitação de regress retorna um objeto JSON no corpo da resposta, formatado da seguinte maneira:

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

<value> é um número decimal.

Os usuários da API gRPC perceberão a semelhança desse formato com os protos ClassificationResponse e RegressionResponse .

Predict API

Esta API segue de perto a PredictionService.Predict gRPC API.

URL

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

Incluir /versions/${VERSION} ou /labels/${LABEL} é opcional. Se omitido, a versão mais recente é usada.

Formato de solicitação

O corpo da solicitação para a API de predict deve ser um objeto JSON formatado da seguinte forma:

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

Especificando tensores de entrada no formato de linha.

Este formato é semelhante ao PredictRequest proto de gRPC API eo CMLE prever API . Use este formato se todos os tensores de entrada nomeados tiverem a mesma dimensão 0 . Caso contrário, use o formato colunar descrito abaixo.

No formato de linha, as entradas são chaveadas para instâncias chave na solicitação JSON.

Quando houver apenas uma entrada nomeada, especifique o valor da chave de instâncias como o valor da entrada:

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

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

Os tensores são expressos naturalmente em notação aninhada, pois não há necessidade de nivelar a lista manualmente.

Para várias entradas nomeadas, espera-se que cada item seja um objeto contendo o par nome de entrada / valor tensor, um para cada entrada nomeada. Como exemplo, o seguinte é uma solicitação com duas instâncias, cada uma com um conjunto de três tensores de entrada nomeados:

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

Observe que cada entrada nomeada ("tag", "sinal", "sensor") é implicitamente assumida como tendo a mesma dimensão 0 ( dois no exemplo acima, pois há dois objetos na lista de instâncias ). Se você nomeou entradas que têm dimensão 0-th diferente, use o formato colunar descrito abaixo.

Especificando tensores de entrada em formato de coluna.

Use este formato para especificar seus tensores de entrada, se as entradas individuais nomeadas não tiverem a mesma dimensão 0 ou se você quiser uma representação mais compacta. Esse formato é semelhante ao campo de inputs da solicitação gRPC Predict .

No formato colunar, as entradas são chaveadas para a chave de entradas na solicitação JSON.

O valor da chave de entradas pode ser um único tensor de entrada ou um mapa de nomes de entrada para tensores (listados em sua forma aninhada natural). Cada entrada pode ter forma arbitrária e não precisa compartilhar a / mesma dimensão 0 (também conhecida como tamanho do lote) conforme exigido pelo formato de linha descrito acima.

A representação colunar do exemplo anterior é a seguinte:

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

Observe que as entradas são um objeto JSON e não uma lista como instâncias (usadas na representação de linha). Além disso, todas as entradas nomeadas são especificadas juntas, em vez de desenrolá-las em linhas individuais no formato de linha descrito anteriormente. Isso torna a representação compacta (mas talvez menos legível).

Formato de resposta

A solicitação de predict retorna um objeto JSON no corpo da resposta.

Uma solicitação em formato de linha tem resposta formatada da seguinte maneira:

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

Se a saída do modelo contém apenas um tensor nomeado, omitimos os mapas de chave de nome e predictions para uma lista de valores escalares ou de lista. Se o modelo gerar vários tensores nomeados, geraremos uma lista de objetos, semelhante à solicitação em formato de linha mencionada acima.

Uma solicitação em formato colunar tem resposta formatada da seguinte maneira:

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

Se a saída do modelo contém apenas um tensor nomeado, omitimos o nome e outputs os mapas de chave para uma lista de valores escalares ou de lista. Se o modelo gerar vários tensores nomeados, em vez disso, geraremos um objeto. Cada chave deste objeto corresponde a um tensor de saída nomeado. O formato é semelhante ao pedido em formato de coluna mencionado acima.

Saída de valores binários

O TensorFlow não faz distinção entre strings não binárias e binárias. Todos são do tipo DT_STRING . Tensores nomeados que possuem _bytes como sufixo em seus nomes são considerados valores binários. Esses valores são codificados de forma diferente, conforme descrito na seção de codificação de valores binários abaixo.

Mapeamento JSON

As APIs RESTful suportam uma codificação canônica em JSON, facilitando o compartilhamento de dados entre sistemas. Para os tipos suportados, as codificações são descritas em uma base tipo por tipo na tabela abaixo. Tipos não listados abaixo são considerados incompatíveis.

Tipo de dados TF Valor JSON Exemplo JSON Notas
DT_BOOL verdadeiro falso verdadeiro falso
DT_STRING corda "Olá Mundo!" Se DT_STRING representar bytes binários (por exemplo, bytes de imagem serializados ou protobuf), codifique-os em Base64. Consulte Codificando valores binários para obter mais informações.
DT_INT8, DT_UINT8, DT_INT16, DT_INT32, DT_UINT32, DT_INT64, DT_UINT64 número 1, -10, 0 O valor JSON será um número decimal.
DT_FLOAT, DT_DOUBLE número 1,1, -10,0, 0, NaN , Infinity O valor JSON será um número ou um dos valores de token especiais - NaN , Infinity e -Infinity . Consulte conformidade com JSON para obter mais informações. A notação de expoente também é aceita.

Codificando valores binários

JSON usa codificação UTF-8. Se você tiver recursos de entrada ou valores de tensor que precisam ser binários (como bytes de imagem), você deve codificar os dados em Base64 e encapsulá-los em um objeto JSON tendo b64 como a chave da seguinte maneira:

{ "b64": <base64 encoded string> }

Você pode especificar este objeto como um valor para um recurso de entrada ou tensor. O mesmo formato também é usado para codificar a resposta de saída.

Uma solicitação de classificação com image (dados binários) e recursos de caption é mostrada abaixo:

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

Conformidade JSON

Muitos valores de recurso ou tensor são números de ponto flutuante. Além dos valores finitos (por exemplo, 3,14, 1,0 etc.), eles podem ter valores NaN e não finitos ( Infinity e -Infinity ). Infelizmente, a especificação JSON ( RFC 7159 ) NÃO reconhece esses valores (embora a especificação JavaScript reconheça).

A API REST descrita nesta página permite que objetos JSON de solicitação / resposta tenham esses valores. Isso implica que solicitações como a seguinte são válidas:

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

Um analisador JSON compatível com padrões (estritos) rejeitará isso com um erro de análise (devido a tokens NaN e Infinity misturados com números reais). Para lidar corretamente com solicitações / respostas em seu código, use um analisador JSON que ofereça suporte a esses tokens.

-Infinity tokens NaN , Infinity , -Infinity são reconhecidos pelo proto3 , módulo Python JSON e linguagem JavaScript.

Exemplo

Podemos usar o modelo half_plus_three de brinquedo para ver as APIs REST em ação.

Inicie ModelServer com o endpoint da API REST

Baixe o modelo half_plus_three do repositório git :

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

Usaremos Docker para executar o ModelServer. Se você deseja instalar o ModelServer nativamente em seu sistema, siga as instruções de configuração para instalar e inicie o ModelServer com a opção --rest_api_port para exportar o terminal da API REST (isso não é necessário ao usar o 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 ...

Faça chamadas de API REST para ModelServer

Em um terminal diferente, use a ferramenta curl para fazer chamadas de API REST.

Obtenha o status do modelo da seguinte maneira:

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

Uma chamada de predict seria a seguinte:

$ 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 uma chamada de regress tem a seguinte aparência:

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

Observe que o regress está disponível em um nome de assinatura não padrão e deve ser especificado explicitamente. Um URL ou corpo de solicitação incorreto retorna um status de erro 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)" }
$