Ta strona została przetłumaczona przez Cloud Translation API.
Switch to English

RESTful API

Oprócz interfejsów API gRPC TensorFlow ModelServer obsługuje również interfejsy API RESTful. Na tej stronie opisano te punkty końcowe interfejsu API i kompleksowy przykład użycia.

Żądanie i odpowiedź to obiekt JSON. Skład tego obiektu zależy od typu żądania lub czasownika. Szczegółowe informacje można znaleźć w sekcjach poświęconych interfejsowi API poniżej.

W przypadku błędu wszystkie interfejsy API zwrócą obiekt JSON w treści odpowiedzi z error jako kluczem i komunikatem o błędzie jako wartością:

{
  "error": <error message string>
}

Model API statusu

Ten interfejs API jest ściśle zgodny z interfejsem API ModelService.GetModelStatus gRPC. Zwraca stan modelu w ModelServer.

URL

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

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

Format odpowiedzi

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

Model Metadata API

Ten interfejs API jest ściśle zgodny z interfejsem API PredictionService.GetModelMetadata gRPC. Zwraca metadane modelu w ModelServer.

URL

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

Uwzględnienie /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 .

Klasyfikacja i regresja 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)

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

Format żądania

Treść żądania dla interfejsów API classify i regress musi być obiektem JSON sformatowanym 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> to liczba JSON (cała lub dziesiętna) lub ciąg znaków, a <list> to lista takich wartości. Zobacz sekcję Kodowanie wartości binarnych poniżej, aby uzyskać szczegółowe informacje na temat reprezentowania wartości binarnej (strumienia bajtów). Ten format jest podobny do protokołów ClassificationRequest i RegressionRequest gRPC. Obie wersje akceptują listę Example obiektów.

Format odpowiedzi

Żądanie classify zwraca obiekt JSON w treści odpowiedzi, 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> to ciąg znaków (może to być pusty ciąg "" jeśli model nie ma etykiety skojarzonej z wynikiem). <score> to liczba dziesiętna (zmiennoprzecinkowa).

Żądanie regress zwraca obiekt JSON w treści odpowiedzi, 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> to liczba dziesiętna.

Użytkownicy interfejsu API gRPC zauważą podobieństwo tego formatu z protokołami ClassificationResponse i RegressionResponse .

Predict API

Ten interfejs API jest ściśle zgodny z interfejsem API PredictionService.Predict gRPC.

URL

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

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

Format żądania

Treść żądania dla predict interfejsu API musi być obiektami JSON sformatowanymi w następujący sposób:

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

Ten format jest podobny do PredictRequest proto z gRPC API i CMLE Predict API . Użyj tego formatu, jeśli wszystkie nazwane tensory wejściowe mają ten sam zerowy wymiar . Jeśli tak nie jest, użyj formatu kolumnowego opisanego poniżej.

W formacie wiersza dane wejściowe są kluczowane do klucza instancji w żądaniu JSON.

Jeśli istnieje tylko jedno nazwane wejście, określ wartość klucza instancji jako wartość wejścia:

{
  // 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ą naturalnie wyrażane w notacji zagnieżdżonej, ponieważ nie ma potrzeby ręcznego spłaszczania listy.

W przypadku wielu nazwanych danych wejściowych każdy element powinien być obiektem zawierającym nazwę wejściową / parę wartości tensora, po jednym dla każdego nazwanego wejścia. Na przykład poniżej przedstawiono żądanie z dwoma wystąpieniami, z których każde 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]]
   }
 ]
}

Należy zauważyć, że każde nazwane wejście („znacznik”, „sygnał”, „czujnik”) domyślnie przyjmuje ten sam zerowy wymiar ( dwa w powyższym przykładzie, ponieważ na liście instancjidwa obiekty). 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 zerowego wymiaru lub chcesz uzyskać bardziej zwartą reprezentację. Format ten jest podobny do inputs dziedzinie gRPC Predict prośbę.

W formacie kolumnowym dane wejściowe są kluczowane do klucza wejściowego w żądaniu JSON.

Wartość klucza wejściowego może być pojedynczym tensorem wejściowym lub mapą nazw wejściowych na tensory (wymienione w ich naturalnie zagnieżdżonej postaci). Każde wejście może mieć dowolny kształt i nie musi mieć tego samego zerowego wymiaru (czyli rozmiaru partii), zgodnie z wymaganiami formatu wiersza opisanego powyżej.

Kolumnowa reprezentacja poprzedniego przykładu jest następująca:

{
 "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: dane wejściowe to obiekt JSON, a nie lista, jak instancje (używane w reprezentacji wierszy). Ponadto wszystkie nazwane dane wejściowe są określane razem, w przeciwieństwie do rozwijania ich do pojedynczych wierszy wykonanych w formacie wiersza opisanym wcześniej. To sprawia, że ​​reprezentacja jest zwarta (ale może mniej czytelna).

Format odpowiedzi

Żądanie predict zwraca obiekt JSON w treści odpowiedzi.

Żądanie w formacie wiersza ma odpowiedź sformatowaną w następujący sposób:

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

Jeśli wynik modelu zawiera tylko jeden nazwany tensor, pomijamy mapy kluczy nazw i predictions na liście wartości skalarnych lub list. Jeśli model generuje wiele nazwanych tensorów, zamiast tego wyprowadzamy listę obiektów, podobnie jak żądanie w formacie wiersza wspomnianym powyżej.

Żądanie w formacie kolumnowym ma odpowiedź sformatowaną w następujący sposób:

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

Jeśli wynik modelu zawiera tylko jeden nazwany tensor, pomijamy nazwę i outputs mapy kluczy do listy wartości skalarnych lub list. Jeśli model wyprowadza wiele nazwanych tensorów, zamiast tego wyprowadzamy obiekt. Każdy klucz tego obiektu odpowiada nazwanemu tensorowi wyjściowemu. Format jest podobny do żądania w formacie kolumny wspomnianym powyżej.

Wyjście wartości binarnych

TensorFlow nie rozróżnia ciągów niebinarnych i binarnych. Wszystkie są typu DT_STRING . _bytes że nazwane tensory z przyrostkiem _bytes w nazwie mają wartości binarne. Takie wartości są kodowane inaczej, jak opisano w sekcji kodowania wartości binarnych 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 w zależności od typu w poniższej tabeli. Typy niewymienione poniżej są 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 bajty binarne (np. DT_STRING bajty obrazu lub protobuf), zakoduj je w Base64. Aby uzyskać więcej informacji, zobacz Kodowanie wartości binarnych .
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 jedną ze specjalnych wartości tokenu - NaN , Infinity i -Infinity . Zobacz zgodność JSON, aby uzyskać więcej informacji. Akceptowana jest również notacja wykładników.

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

Ten obiekt można określić jako wartość elementu wejściowego lub tensora. Ten sam format jest również używany do kodowania odpowiedzi wyjściowej.

Żądanie klasyfikacji wraz z image (dane binarne) i caption jest pokazane poniżej:

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

Zgodność z JSON

Wiele wartości cech lub 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 rozpoznaje tych wartości (chociaż specyfikacja JavaScript to robi).

Interfejs API REST opisany na tej stronie umożliwia obiektom JSON żądania / odpowiedzi przyjmowanie takich wartości. Oznacza to, że żądania takie jak poniższe są ważne:

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

Parser JSON (ścisły) zgodny ze standardami odrzuci to z błędem analizy (z powodu tokenów NaN i Infinity zmieszanych z rzeczywistymi liczbami). Aby poprawnie obsługiwać żądania / odpowiedzi w kodzie, użyj parsera JSON, który obsługuje te tokeny.

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

Przykład

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

Uruchom ModelServer z punktem końcowym interfejsu API REST

Pobierz model half_plus_three z repozytorium git :

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

Będziemy używać Dockera do uruchomienia ModelServer. Jeśli chcesz zainstalować ModelServer natywnie w swoim systemie, postępuj zgodnie z instrukcjami instalacji, aby zamiast tego zainstalować, i uruchom ModelServer z opcją --rest_api_port , aby wyeksportować punkt końcowy interfejsu API REST (nie jest to potrzebne w przypadku korzystania z --rest_api_port 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 ...

Wykonuj wywołania interfejsu API REST do serwera ModelServer

Na innym terminalu użyj narzędzia curl , aby wykonać wywołania interfejsu API REST.

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

Wywołanie predict wyglądałoby 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]
}

Wywołanie regress wygląda następująco:

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

Należy zauważyć, że regress jest dostępna dla nazwy podpisu innej niż domyślna i należy ją jawnie określić. 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)" }
$