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)" }
$