RESTful API'si

GRPC API'lerine ek olarak TensorFlow ModelServer RESTful API'lerini de destekler. Bu sayfada bu API uç noktaları ve kullanıma ilişkin uçtan uca bir örnek açıklanmaktadır.

İstek ve yanıt bir JSON nesnesidir. Bu nesnenin bileşimi istek türüne veya fiile bağlıdır. Ayrıntılar için aşağıdaki API'ye özel bölümlere bakın.

Hata durumunda, tüm API'ler yanıt gövdesinde anahtar olarak error ve değer olarak hata mesajı içeren bir JSON nesnesi döndürür:

{
  "error": <error message string>
}

Model durumu API'si

Bu API, ModelService.GetModelStatus gRPC API'sini yakından takip eder. ModelServer'daki bir modelin durumunu döndürür.

URL'si

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

/versions/${VERSION} veya /labels/${LABEL} ın dahil edilmesi isteğe bağlıdır. Cevapta tüm sürümlerin atlanmış durumu döndürülür.

Yanıt formatı

Başarılı olursa GetModelStatusResponse protobuf'un JSON temsilini döndürür.

Model Meta Veri API'si

Bu API, PredictionService.GetModelMetadata gRPC API'sini yakından takip eder. ModelServer'daki bir modelin meta verilerini döndürür.

URL'si

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

/versions/${VERSION} veya /labels/${LABEL} ın dahil edilmesi isteğe bağlıdır. Atlanırsa, yanıtta en son sürümün model meta verileri döndürülür.

Yanıt formatı

Başarılı olursa GetModelMetadataResponse protobuf'un JSON temsilini döndürür.

API'yi Sınıflandır ve Regresyonla

Bu API, PredictionService gRPC API'sinin Classify ve Regress yöntemlerini yakından takip eder.

URL'si

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

/versions/${VERSION} veya /labels/${LABEL} ın dahil edilmesi isteğe bağlıdır. Atlanırsa en son sürüm kullanılır.

Talep formatı

classify ve regress API'lerine ilişkin istek gövdesi, aşağıdaki gibi biçimlendirilmiş bir JSON nesnesi olmalıdır:

{
  // 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> bir JSON numarasıdır (tam veya ondalık), JSON dizesi veya ikili verileri temsil eden bir JSON nesnesidir (ayrıntılar için aşağıdaki İkili değerleri kodlama bölümüne bakın). <list> bu tür değerlerin bir listesidir. Bu biçim, gRPC'nin ClassificationRequest ve RegressionRequest protokollerine benzer. Her iki sürüm de Example nesnelerin listesini kabul eder.

Yanıt formatı

Bir classify isteği, yanıt gövdesinde aşağıdaki gibi biçimlendirilmiş bir JSON nesnesi döndürür:

{
  "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> bir dizedir (eğer modelin puanla ilişkili bir etiketi yoksa boş bir dize "" olabilir). <score> ondalık (kayan nokta) bir sayıdır.

regress isteği, yanıt gövdesinde aşağıdaki gibi biçimlendirilmiş bir JSON nesnesi döndürür:

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

<value> ondalık bir sayıdır.

GRPC API kullanıcıları bu formatın ClassificationResponse ve RegressionResponse protokolleriyle benzerliğini fark edeceklerdir.

API'yi tahmin et

Bu API, PredictionService.Predict gRPC API'sini yakından takip eder.

URL'si

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

/versions/${VERSION} veya /labels/${LABEL} ın dahil edilmesi isteğe bağlıdır. Atlanırsa en son sürüm kullanılır.

Talep formatı

predict API'sine ilişkin istek gövdesi aşağıdaki gibi biçimlendirilmiş JSON nesnesi olmalıdır:

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

Giriş tensörlerini satır biçiminde belirtme.

Bu biçim, gRPC API'sinin PredictRequest protokolüne ve CMLE tahmin API'sine benzer. Adlandırılmış tüm giriş tensörleri aynı 0'ıncı boyuta sahipse bu formatı kullanın. Değilse, aşağıda daha sonra açıklanan sütunlu formatı kullanın.

Satır biçiminde girişler, JSON isteğindeki örnek anahtarına anahtarlanır.

Yalnızca bir adlandırılmış giriş olduğunda, örnek anahtarının değerini girişin değeri olacak şekilde belirtin:

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

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

Listeyi manuel olarak düzleştirmeye gerek olmadığından tensörler doğal olarak iç içe gösterimle ifade edilir.

Birden fazla adlandırılmış giriş için, her öğenin, her adlandırılmış giriş için bir tane olmak üzere, giriş adı/tensör değeri çiftini içeren bir nesne olması beklenir. Örnek olarak, her biri üç adlandırılmış giriş tensöründen oluşan iki örnek içeren bir istek aşağıda verilmiştir:

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

Her adlandırılmış girişin ("etiket", "sinyal", "sensör") dolaylı olarak aynı 0'ıncı boyuta sahip olduğunun varsayıldığını unutmayın ( örnek listesinde iki nesne olduğundan yukarıdaki örnekte iki ). Farklı 0'ıncı boyuta sahip girişleri adlandırdıysanız aşağıda açıklanan sütun biçimini kullanın.

Giriş tensörlerini sütun formatında belirtme.

Bireysel adlandırılmış girişler aynı 0'ıncı boyuta sahip değilse veya daha kompakt bir gösterim istiyorsanız, giriş tensörlerinizi belirtmek için bu formatı kullanın. Bu biçim, gRPC Predict isteğinin inputs alanına benzer.

Sütunlu formatta girişler, JSON isteğindeki giriş anahtarına anahtarlanır.

Giriş anahtarının değeri, tek bir giriş tensörü veya giriş adının tensörlere haritası (doğal iç içe geçmiş formlarında listelenmiştir) olabilir. Her giriş isteğe bağlı bir şekle sahip olabilir ve yukarıda açıklanan satır formatının gerektirdiği gibi aynı 0'ıncı boyutu (başka bir deyişle parti boyutunu) paylaşmaya gerek duymaz.

Önceki örneğin sütunlu gösterimi aşağıdaki gibidir:

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

Girişlerin bir JSON nesnesi olduğunu ve örneklere benzer bir liste olmadığını (satır gösteriminde kullanılan) unutmayın. Ayrıca, adlandırılmış tüm girişler, daha önce açıklanan satır formatında yapılan ayrı ayrı satırlara dönüştürülmesinin aksine, birlikte belirtilir. Bu, gösterimi kompakt hale getirir (ancak belki daha az okunabilir).

Yanıt formatı

predict isteği yanıt gövdesinde bir JSON nesnesi döndürür.

Satır biçimindeki bir isteğin yanıtı aşağıdaki şekilde biçimlendirilmiştir:

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

Modelin çıktısı yalnızca bir adlandırılmış tensör içeriyorsa, skaler veya liste değerleri listesine isim ve predictions anahtar eşlemelerini çıkarırız. Model birden fazla adlandırılmış tensör çıktısı veriyorsa, bunun yerine yukarıda bahsedilen satır formatındaki isteğe benzer şekilde bir nesne listesi çıktısı alırız.

Sütun biçimindeki bir isteğin yanıtı aşağıdaki şekilde biçimlendirilmiştir:

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

Modelin çıktısı yalnızca bir adlandırılmış tensör içeriyorsa, adı atlarız ve anahtar haritaları bir skaler veya liste değerleri listesine outputs . Model birden fazla adlandırılmış tensör çıktısı veriyorsa bunun yerine bir nesne çıktısı alırız. Bu nesnenin her anahtarı, adlandırılmış bir çıkış tensörüne karşılık gelir. Biçim, yukarıda belirtilen sütun biçimindeki isteğe benzer.

İkili değerlerin çıkışı

TensorFlow, ikili olmayan ve ikili dizeler arasında ayrım yapmaz. Hepsi DT_STRING türündedir. Adında sonek olarak _bytes bulunan adlandırılmış tensörlerin ikili değerlere sahip olduğu kabul edilir. Bu tür değerler, aşağıdaki ikili değerlerin kodlanması bölümünde açıklandığı gibi farklı şekilde kodlanır.

JSON eşlemesi

RESTful API'ler JSON'da kanonik kodlamayı destekleyerek sistemler arasında veri paylaşımını kolaylaştırır. Desteklenen türler için kodlamalar aşağıdaki tabloda tür bazında açıklanmıştır. Aşağıda listelenmeyen türlerin desteklenmediği ima edilir.

TF Veri Türü JSON Değeri JSON örneği Notlar
DT_BOOL doğru yanlış doğru yanlış
DT_STRING sicim "Selam Dünya!" DT_STRING ikili baytları temsil ediyorsa (örn. serileştirilmiş görüntü baytları veya protobuf), bunları Base64'te kodlayın. Daha fazla bilgi için İkili değerleri kodlama konusuna bakın.
DT_INT8, DT_UINT8, DT_INT16, DT_INT32, DT_UINT32, DT_INT64, DT_UINT64 sayı 1, -10, 0 JSON değeri ondalık sayı olacaktır.
DT_FLOAT, DT_DOUBLE sayı 1.1, -10.0, 0, NaN , Infinity JSON değeri bir sayı veya özel simge değerlerinden biri olacaktır ( NaN , Infinity ve -Infinity ). Daha fazla bilgi için JSON uyumluluğuna bakın. Üslü gösterim de kabul edilir.

Kayan Nokta Hassasiyeti

JSON tek sayı veri türüne sahiptir. Böylece, hassasiyet kaybıyla sonuçlanan bir girdi için bir değer sağlamak mümkündür. Örneğin, x girişi bir float nokta veri türüyse ve {"x": 1435774380} girişi IEEE 754 kayan nokta standardını temel alan donanım üzerinde çalışan modele (örn. Intel veya AMD) gönderilirse, bu durumda değer şu şekilde olacaktır: 1435774380 , 32 bitlik bir kayan nokta sayısında tam olarak temsil edilemediğinden, temeldeki donanım tarafından sessizce 1435774336 dönüştürülebilir. Genellikle, hizmete yönelik girdilerin eğitimle aynı dağılımda olması gerekir; dolayısıyla aynı dönüşümler eğitim zamanında da gerçekleştiğinden bu genellikle sorun yaratmaz. Bununla birlikte, tam hassasiyetin gerekli olması durumunda, modelinizde istenen hassasiyeti işleyebilecek ve/veya istemci tarafı kontrolünü dikkate alabilecek temel bir veri türü kullandığınızdan emin olun.

İkili değerleri kodlama

JSON, UTF-8 kodlamasını kullanır. İkili olması gereken giriş özelliği veya tensör değerleriniz varsa (görüntü baytları gibi), verileri Base64 ile kodlamanız ve bunu anahtar olarak b64 sahip bir JSON nesnesine aşağıdaki gibi kapsüllemeniz gerekir :

{ "b64": <base64 encoded string> }

Bu nesneyi bir giriş özelliği veya tensör için değer olarak belirtebilirsiniz. Aynı format, çıktı yanıtını kodlamak için de kullanılır.

image (ikili veri) ve caption özelliklerine sahip bir sınıflandırma isteği aşağıda gösterilmektedir:

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

JSON uyumluluğu

Birçok özellik veya tensör değeri kayan nokta sayılarıdır. Bunlar sonlu değerlerin dışında (örneğin 3.14, 1.0 vb.) NaN ve sonlu olmayan ( Infinity ve -Infinity ) değerlere sahip olabilirler. Ne yazık ki JSON spesifikasyonu ( RFC 7159 ) bu değerleri TANIMIYOR (ancak JavaScript spesifikasyonu öyle).

Bu sayfada açıklanan REST API, istek/yanıt JSON nesnelerinin bu tür değerlere sahip olmasına olanak tanır. Bu, aşağıdaki gibi isteklerin geçerli olduğu anlamına gelir:

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

(Katı) standartlarla uyumlu bir JSON ayrıştırıcısı bunu bir ayrıştırma hatasıyla reddeder ( NaN ve Infinity belirteçlerinin gerçek sayılarla karışması nedeniyle). Kodunuzda istekleri/yanıtları doğru şekilde işlemek için bu belirteçleri destekleyen bir JSON ayrıştırıcısı kullanın.

NaN , Infinity , -Infinity tokenları proto3 , Python JSON modülü ve JavaScript dili tarafından tanınır.

Örnek

REST API'lerini çalışırken görmek için oyuncak half_plus_third modelini kullanabiliriz.

ModelServer'ı REST API uç noktasıyla başlatın

half_plus_three modelini git deposundan indirin:

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

ModelServer'ı çalıştırmak için Docker'ı kullanacağız. ModelServer'ı sisteminize yerel olarak yüklemek istiyorsanız, bunun yerine kurulum talimatlarını izleyin ve REST API uç noktasını dışa aktarmak için ModelServer'ı --rest_api_port seçeneğiyle başlatın (Docker kullanırken bu gerekli değildir).

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

ModelServer'a REST API çağrıları yapın

Farklı bir terminalde REST API çağrıları yapmak için curl aracını kullanın.

Modelin durumunu aşağıdaki gibi alın:

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

Bir predict çağrısı aşağıdaki gibi görünecektir:

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

Ve bir regress çağrısı aşağıdaki gibi görünür:

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

regress varsayılan olmayan bir imza adında mevcut olduğunu ve açıkça belirtilmesi gerektiğini unutmayın. Yanlış bir istek URL'si veya gövdesi bir HTTP hata durumu döndürür.

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