RESTful API

Zadbaj o dobrą organizację dzięki kolekcji Zapisuj i kategoryzuj treści zgodnie ze swoimi preferencjami.

Oprócz gRPC API TensorFlow ModelServer obsługuje również relaksującego API. Ta strona opisuje te punkty końcowe API i koniec-koniec przykład zużycia.

Żądanie i odpowiedź to obiekt JSON. Skład tego obiektu zależy od typu żądania lub czasownika. Szczegółowe informacje znajdziesz w poniższych sekcjach dotyczących interfejsu API.

W przypadku wystąpienia błędu, wszystkie interfejsy API zwróci obiekt JSON w organizmie reakcji z error jako klucz i komunikat błędu jako wartości:

{
  "error": <error message string>
}

API statusu modelu

Ten interfejs API uważnie śledzi ModelService.GetModelStatus API gRPC. Zwraca status modelu w ModelServer.

URL

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

Łącznie /versions/${VERSION} lub /labels/${LABEL} jest opcjonalne. Jeśli pominięto status dla wszystkich wersji jest zwracany w odpowiedzi.

Format odpowiedzi

Jeśli się powiedzie, zwraca reprezentację JSON GetModelStatusResponse Protobuf.

Interfejs API metadanych modelu

Ten interfejs API uważnie śledzi PredictionService.GetModelMetadata API gRPC. Zwraca metadane modelu w ModelServer.

URL

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

Łącznie /versions/${VERSION} lub /labels/${LABEL} jest opcjonalne. W przypadku pominięcia w odpowiedzi zwracane są metadane modelu dla najnowszej wersji.

Format odpowiedzi

Jeśli się powiedzie, zwraca reprezentację JSON GetModelMetadataResponse Protobuf.

Klasyfikuj i regresuj API

Ten interfejs API ściśle przestrzega Classify i Regress metod PredictionService gRPC API.

URL

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

Łącznie /versions/${VERSION} lub /labels/${LABEL} jest opcjonalne. W przypadku pominięcia używana jest najnowsza wersja.

Format żądania

Ciało prośba do classify i regress API musi być obiekt JSON sformatowany w następujący sposób:

{
  // 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> szereg JSON (w całości lub po przecinku) JSON łańcuch lub obiekt JSON reprezentująca dane binarne (patrz kodowanie binarne wartości rozdział poniżej). <list> to lista tych wartości. Format ten jest podobny do gRPC za ClassificationRequest i RegressionRequest PROTOS. Obie wersje zaakceptować listę Example obiektów.

Format odpowiedzi

classify zapytanie zwraca obiekt JSON w organizmie reakcji, sformatowany w następujący sposób:

{
  "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> jest ciągiem znaków (który może być pusty ciąg "" jeśli model nie posiada etykietę powiązaną z Score). <score> jest liczbą dziesiętną (zmiennoprzecinkowy) ilość.

regress zapytanie zwraca obiekt JSON w organizmie reakcji, sformatowany w następujący sposób:

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

<value> jest liczbą dziesiętną.

Użytkownicy gRPC API zauważy podobieństwo tego formatu z ClassificationResponse i RegressionResponse PROTOS.

Przewidywanie API

Ten interfejs API uważnie śledzi PredictionService.Predict API gRPC.

URL

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

Łącznie /versions/${VERSION} lub /labels/${LABEL} jest opcjonalne. W przypadku pominięcia używana jest najnowsza wersja.

Format żądania

Ciało prośba do predict API musi być sformatowany jako obiekt JSON następująco:

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

Określanie tensorów wejściowych w formacie wiersza.

Format ten jest podobny do PredictRequest proto z gRPC API i CMLE przewidzieć API . Użyj tego formatu, jeśli wszystkie wymienione tensory wejściowe mają taką samą 0-ty wymiar. Jeśli nie, użyj formatu kolumnowego opisanego poniżej.

W formacie wiersza, wejścia są oznaczone w kluczu instancji w żądaniu JSON.

Kiedy jest tylko jedno wejście o nazwie, należy określić wartość przypadkach kluczowych być wartość na wejściu:

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

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

Tensory są wyrażane w sposób naturalny w notacji zagnieżdżonej, ponieważ nie ma potrzeby ręcznego spłaszczania listy.

W przypadku wielu nazwanych danych wejściowych oczekuje się, że każdy element będzie obiektem zawierającym parę nazwa wejściowa/wartość tensora, po jednym dla każdego nazwanego wejścia. Jako przykład poniżej przedstawiono żądanie z dwoma instancjami, z których każda zawiera zestaw trzech nazwanych tensorów wejściowych:

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

Uwaga, każda o nazwie input ( „tag”, „Sygnał”, „czujnik”) jest domyślnie zakłada się mieć taką samą 0-ty wymiar (dwa w powyższym przykładzie, ponieważ istnieją dwa obiekty na liście wystąpienia). Jeśli masz nazwane dane wejściowe, które mają inny zerowy wymiar, użyj formatu kolumnowego opisanego poniżej.

Określanie tensorów wejściowych w formacie kolumny.

Użyj tego formatu, aby określić tensory wejściowe, jeśli poszczególne nazwane dane wejściowe nie mają tego samego wymiaru zerowego lub potrzebujesz bardziej zwartej reprezentacji. Format ten jest podobny do inputs dziedzinie gRPC Predict prośbę.

W formacie tabelarycznym, wejścia są oznaczone na wejścia klucza w żądaniu JSON.

Wartość klucza może wejść albo pojedynczym tensor wejście lub mapa nazwą wejściowego do tensorów (wymienione w ich naturalnej postaci zagnieżdżonych). Każde dane wejściowe mogą mieć dowolny kształt i nie muszą dzielić tego samego/tego samego wymiaru zerowego (czyli wielkości partii), jak jest to wymagane przez format wiersza opisany powyżej.

Reprezentacja kolumnowa poprzedniego przykładu wygląda następująco:

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

Uwaga, wejścia jest obiekt JSON, a nie liście, jak przypadkach (stosowany w reprezentacji wiersza). Ponadto wszystkie nazwane dane wejściowe są określane razem, w przeciwieństwie do rozwijania ich w pojedyncze wiersze w opisanym wcześniej formacie wiersza. To sprawia, że ​​reprezentacja jest zwarta (ale może mniej czytelna).

Format odpowiedzi

predict żądania Zwraca obiekt JSON w organizmie reakcji.

Żądanie w formie wiersza jest odpowiedzią sformatowany w następujący sposób:

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

Jeśli wyjście modelu zawiera tylko jeden o nazwie tensor, pomijamy nazwę i predictions klucz mapy do listy skalarnych lub listy wartości. Jeśli model wyprowadza wiele nazwanych tensorów, zamiast tego wypisujemy listę obiektów, podobnie do żądania w formacie wiersza, o którym mowa powyżej.

Żądanie w formie kolumn jest odpowiedzią sformatowany w następujący sposób:

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

Jeśli wyjście modelu zawiera tylko jeden o nazwie tensor, pomijamy nazwę i outputs klucz mapy do listy skalarnych lub listy wartości. Jeśli model wyprowadza wiele nazwanych tensorów, zamiast tego wyprowadzamy obiekt. Każdy klucz tego obiektu odpowiada nazwanego tensora wyjściowego. Format jest podobny do żądania w formacie kolumnowym, o którym mowa powyżej.

Wyprowadzanie wartości binarnych

TensorFlow nie rozróżnia ciągów niebinarnych i binarnych. Wszystkie są DT_STRING typu. Nazwane tensory które mają _bytes jako przyrostek w nazwie są uważane mają wartości binarnych. Wartości te są kodowane w różny sposób, jak to opisano w kodującego wartości binarne sekcji poniżej.

Mapowanie JSON

Interfejsy API RESTful obsługują kodowanie kanoniczne w formacie JSON, co ułatwia udostępnianie danych między systemami. W przypadku obsługiwanych typów kodowania są opisane dla poszczególnych typów w poniższej tabeli. Typy niewymienione poniżej są dorozumiane jako nieobsługiwane.

Typ danych TF Wartość JSON Przykład JSON Uwagi
DT_BOOL prawda fałsz prawda fałsz
DT_STRING strunowy "Witaj świecie!" Jeśli DT_STRING reprezentuje bajtów binarnych (np szeregowane bajtów obraz lub Protobuf), koduje je w Base64. Zobacz Kodowanie wartości binarnych aby uzyskać więcej informacji.
DT_INT8, DT_UINT8, DT_INT16, DT_INT32, DT_UINT32, DT_INT64, DT_UINT64 numer 1, -10, 0 Wartość JSON będzie liczbą dziesiętną.
DT_FLOAT, DT_DOUBLE numer 1.1 -10.0, 0, NaN , Infinity Wartość JSON będzie liczbą lub jednym ze specjalnych wartości tokenów - NaN , Infinity i -Infinity . Zobacz JSON zgodności aby uzyskać więcej informacji. Akceptowany jest również zapis potęgowy.

Dokładność zmiennoprzecinkowa

JSON ma jednoliczbowy typ danych. W ten sposób możliwe jest podanie wartości wejściowej, która powoduje utratę precyzji. Na przykład, jeśli sygnał wejściowy x jest float typ danych, a wejście {"x": 1435774380} jest wysyłany do model działa na sprzęcie w oparciu o IEEE 754 zmiennoprzecinkowych standardu (np Intel lub AMD), to wartość będzie być cicho przekształcone przez underyling sprzętu do 1435774336 od 1435774380 nie może być dokładnie reprezentowana w 32-bitową liczbą zmiennoprzecinkową. Zazwyczaj dane wejściowe do udostępniania powinny mieć taki sam rozkład jak w przypadku uczenia, więc zazwyczaj nie będzie to problematyczne, ponieważ te same konwersje miały miejsce w czasie uczenia. Jednak w przypadku, gdy potrzebna jest pełna precyzja, należy użyć w modelu bazowego typu danych, który może obsłużyć żądaną precyzję i/lub rozważyć sprawdzanie po stronie klienta.

Kodowanie wartości binarnych

JSON używa kodowania UTF-8. Jeśli masz wejściowe funkcji lub tensora wartości, które muszą być binarny (jak obraz bajtów), musisz Base64 kodowania danych i otaczać go w obiekt JSON mający b64 jako klucz w następujący sposób:

{ "b64": <base64 encoded string> }

Możesz określić ten obiekt jako wartość dla elementu wejściowego lub tensora. Ten sam format jest używany do kodowania odpowiedzi wyjściowej.

Żądanie klasyfikacja z image (danych binarnych) i caption funkcji przedstawiono poniżej:

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

Zgodność JSON

Wiele cech lub wartości tensorów to liczby zmiennoprzecinkowe. Oprócz ograniczonej wartości (na przykład 3,14, 1,0 itd) mogą one mieć NaN i braku skończonych ( Infinity i -Infinity ) wartości. Niestety specyfikacja JSON ( RFC 7159 ) NIE uznają te wartości (choć specyfikacja JavaScript robi).

Interfejs API REST opisany na tej stronie umożliwia obiektom JSON żądanie/odpowiedź posiadanie takich wartości. Oznacza to, że wnioski takie jak poniższe są ważne:

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

A (ścisłe) normy JSON zgodny parser odrzuci to z błędu parsowania (ze względu na NaN i Infinity tokeny mieszany z liczb rzeczywistych). Aby poprawnie obsługiwać żądania/odpowiedzi w kodzie, użyj parsera JSON, który obsługuje te tokeny.

NaN , Infinity , -Infinity tokeny są rozpoznawane przez proto3 , Python JSON moduł i języka JavaScript.

Przykład

Możemy użyć zabawkę half_plus_three modelu REST API, aby zobaczyć w akcji.

Uruchom ModelServer z punktem końcowym interfejsu API REST

Pobierz half_plus_three model z git repozytorium :

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

Użyjemy Dockera do uruchomienia ModelServer. Jeśli chcesz zainstalować ModelServer natywnie w systemie, wykonaj instrukcje konfiguracji zainstalować zamiast, i rozpocząć ModelServer z --rest_api_port opcji eksportu do punktu końcowego REST API (to nie jest potrzebne do korzystania Döcker).

$ 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 ...

Wykonuj wywołania REST API do ModelServer

W innym terminalu, użyj curl narzędzie do REST wywołań API.

Uzyskaj status modelu w następujący sposób:

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

predict rozmowa będzie wyglądać następująco:

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

A regress wygląd połączeń w następujący sposób:

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

Uwaga, regress jest dostępny na inną niż domyślna nazwa i podpisu musi być określona jednoznacznie. Nieprawidłowy adres URL lub treść żądania zwraca stan błędu 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)" }
$