API yang tenang

Selain API gRPC, TensorFlow ModelServer juga mendukung RESTful API. Halaman ini menjelaskan titik akhir API ini dan contoh penggunaan menyeluruh.

Permintaan dan respons adalah objek JSON. Komposisi objek ini bergantung pada jenis permintaan atau kata kerja. Lihat bagian khusus API di bawah untuk detailnya.

Jika terjadi kesalahan, semua API akan mengembalikan objek JSON di isi respons dengan error sebagai kunci dan pesan kesalahan sebagai nilainya:

{
  "error": <error message string>
}

API status model

API ini mengikuti API gRPC ModelService.GetModelStatus . Ini mengembalikan status model di ModelServer.

URL

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

Menyertakan /versions/${VERSION} atau /labels/${LABEL} bersifat opsional. Jika dihilangkan, status untuk semua versi dikembalikan dalam respons.

Format tanggapan

Jika berhasil, kembalikan representasi JSON dari protobuf GetModelStatusResponse .

API Metadata Model

API ini mengikuti API gRPC PredictionService.GetModelMetadata . Ini mengembalikan metadata model di ModelServer.

URL

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

Menyertakan /versions/${VERSION} atau /labels/${LABEL} bersifat opsional. Jika dihilangkan, metadata model untuk versi terbaru akan dikembalikan dalam respons.

Format tanggapan

Jika berhasil, kembalikan representasi JSON dari protobuf GetModelMetadataResponse .

Klasifikasi dan Regresi API

API ini mengikuti metode Classify dan Regress dari API gRPC PredictionService .

URL

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

Menyertakan /versions/${VERSION} atau /labels/${LABEL} bersifat opsional. Jika dihilangkan, versi terbaru yang digunakan.

Format permintaan

Isi permintaan untuk API classify dan regress harus berupa objek JSON yang diformat sebagai berikut:

{
  // 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> adalah nomor JSON (utuh atau desimal), string JSON, atau objek JSON yang mewakili data biner (lihat bagian Pengkodean nilai biner di bawah untuk detailnya). <list> adalah daftar nilai tersebut. Format ini mirip dengan proto ClassificationRequest dan RegressionRequest gRPC. Kedua versi menerima daftar objek Example .

Format tanggapan

Permintaan classify mengembalikan objek JSON di isi respons, dengan format sebagai berikut:

{
  "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> adalah string (yang dapat berupa string kosong "" jika model tidak memiliki label yang dikaitkan dengan skor). <score> adalah angka desimal (floating point).

Permintaan regress mengembalikan objek JSON di isi respons, yang diformat sebagai berikut:

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

<value> adalah angka desimal.

Pengguna API gRPC akan melihat kesamaan format ini dengan proto ClassificationResponse dan RegressionResponse .

Prediksi API

API ini mengikuti PredictionService.Predict gRPC API.

URL

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

Menyertakan /versions/${VERSION} atau /labels/${LABEL} bersifat opsional. Jika dihilangkan, versi terbaru yang digunakan.

Format permintaan

Isi permintaan untuk API predict harus berupa objek JSON yang diformat sebagai berikut:

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

Menentukan tensor masukan dalam format baris.

Format ini mirip dengan proto PredictRequest API gRPC dan API prediksi CMLE . Gunakan format ini jika semua tensor masukan bernama memiliki dimensi ke-0 yang sama . Jika tidak, gunakan format kolom yang dijelaskan nanti di bawah.

Dalam format baris, input dikunci ke kunci instance dalam permintaan JSON.

Jika hanya ada satu masukan bernama, tentukan nilai kunci instance menjadi nilai masukan:

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

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

Tensor dinyatakan secara alami dalam notasi bertingkat karena tidak perlu meratakan daftar secara manual.

Untuk beberapa masukan bernama, setiap item diharapkan berupa objek yang berisi pasangan nama masukan/nilai tensor, satu untuk setiap masukan bernama. Sebagai contoh, berikut ini adalah permintaan dengan dua instance, masing-masing dengan satu set tiga tensor masukan bernama:

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

Catatan, setiap input bernama ("tag", "sinyal", "sensor") secara implisit diasumsikan memiliki dimensi ke-0 yang sama ( dua dalam contoh di atas, karena ada dua objek dalam daftar instance ). Jika Anda memberi nama masukan yang memiliki dimensi ke-0 berbeda, gunakan format kolom yang dijelaskan di bawah.

Menentukan tensor masukan dalam format kolom.

Gunakan format ini untuk menentukan tensor masukan Anda, jika masukan bernama individual tidak memiliki dimensi ke-0 yang sama atau Anda menginginkan representasi yang lebih ringkas. Format ini mirip dengan kolom inputs pada permintaan gRPC Predict .

Dalam format kolom, masukan dikunci ke kunci masukan dalam permintaan JSON.

Nilai untuk kunci input dapat berupa tensor masukan tunggal atau peta nama masukan ke tensor (tercantum dalam bentuk bersarang aslinya). Setiap input dapat memiliki bentuk yang berubah-ubah dan tidak perlu berbagi dimensi ke-0 yang sama (alias ukuran batch) seperti yang disyaratkan oleh format baris yang dijelaskan di atas.

Representasi kolom dari contoh sebelumnya adalah sebagai berikut:

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

Catatan, inputs adalah objek JSON dan bukan contoh seperti daftar (digunakan dalam representasi baris). Selain itu, semua input bernama ditentukan bersama-sama, bukan membuka gulungannya menjadi baris individual yang dilakukan dalam format baris yang dijelaskan sebelumnya. Hal ini membuat representasi menjadi kompak (tapi mungkin kurang mudah dibaca).

Format tanggapan

Permintaan predict mengembalikan objek JSON di isi respons.

Permintaan dalam format baris memiliki format respons sebagai berikut:

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

Jika keluaran model hanya berisi satu tensor bernama, kami menghilangkan peta kunci nama dan predictions ke daftar nilai skalar atau daftar. Jika model mengeluarkan beberapa tensor bernama, kami akan menampilkan daftar objek, mirip dengan permintaan dalam format baris yang disebutkan di atas.

Permintaan dalam format kolom memiliki format respons sebagai berikut:

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

Jika keluaran model hanya berisi satu tensor bernama, kami menghilangkan nama dan outputs peta kunci ke daftar nilai skalar atau daftar. Jika model mengeluarkan beberapa tensor bernama, kami mengeluarkan objek sebagai gantinya. Setiap kunci objek ini berhubungan dengan tensor keluaran bernama. Formatnya mirip dengan permintaan dalam format kolom yang disebutkan di atas.

Output nilai biner

TensorFlow tidak membedakan antara string non-biner dan biner. Semuanya bertipe DT_STRING . Tensor bernama yang memiliki akhiran _bytes pada namanya dianggap memiliki nilai biner. Nilai tersebut dikodekan secara berbeda seperti yang dijelaskan di bagian pengkodean nilai biner di bawah.

pemetaan JSON

RESTful API mendukung pengkodean kanonik di JSON, sehingga memudahkan berbagi data antar sistem. Untuk tipe yang didukung, pengkodean dijelaskan berdasarkan tipe demi tipe pada tabel di bawah. Jenis yang tidak tercantum di bawah berarti tidak didukung.

Tipe Data TF Nilai JSON Contoh JSON Catatan
DT_BOOL benar, salah benar, salah
DT_STRING rangkaian "Halo Dunia!" Jika DT_STRING mewakili byte biner (misalnya byte gambar berseri atau protobuf), enkodekan ini di Base64. Lihat Mengkodekan nilai biner untuk informasi lebih lanjut.
DT_INT8, DT_UINT8, DT_INT16, DT_INT32, DT_UINT32, DT_INT64, DT_UINT64 nomor 1, -10, 0 Nilai JSON akan berupa angka desimal.
DT_FLOAT, DT_DOUBLE nomor 1.1, -10.0, 0, NaN , Infinity Nilai JSON akan berupa angka atau salah satu nilai token khusus - NaN , Infinity , dan -Infinity . Lihat kesesuaian JSON untuk info selengkapnya. Notasi eksponen juga diterima.

Presisi Titik Mengambang

JSON memiliki tipe data angka tunggal. Dengan demikian dimungkinkan untuk memberikan nilai pada suatu masukan yang mengakibatkan hilangnya presisi. Misalnya, jika input x adalah tipe data float , dan input {"x": 1435774380} dikirim ke model yang berjalan pada perangkat keras berdasarkan standar floating point IEEE 754 (misalnya Intel atau AMD), maka nilainya akan menjadi dikonversi secara diam-diam oleh perangkat keras yang mendasarinya menjadi 1435774336 karena 1435774380 tidak dapat direpresentasikan secara tepat dalam bilangan floating point 32-bit. Biasanya, input untuk penayangan harus memiliki distribusi yang sama dengan pelatihan, sehingga hal ini umumnya tidak akan menjadi masalah karena konversi yang sama terjadi pada waktu pelatihan. Namun, jika presisi penuh diperlukan, pastikan untuk menggunakan tipe data dasar dalam model Anda yang dapat menangani presisi yang diinginkan dan/atau mempertimbangkan pemeriksaan sisi klien.

Pengkodean nilai biner

JSON menggunakan pengkodean UTF-8. Jika Anda memiliki fitur input atau nilai tensor yang harus berupa biner (seperti byte gambar), Anda harus mengkodekan data Base64 dan merangkumnya dalam objek JSON yang memiliki b64 sebagai kunci sebagai berikut:

{ "b64": <base64 encoded string> }

Anda dapat menentukan objek ini sebagai nilai untuk fitur masukan atau tensor. Format yang sama juga digunakan untuk menyandikan respons keluaran.

Permintaan klasifikasi dengan image (data biner) dan caption ditampilkan di bawah:

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

kesesuaian JSON

Banyak nilai fitur atau tensor yang merupakan angka floating point. Selain nilai berhingga (misalnya 3.14, 1.0, dll.), nilai ini dapat memiliki nilai NaN dan tidak terbatas ( Infinity dan -Infinity ). Sayangnya spesifikasi JSON ( RFC 7159 ) TIDAK mengenali nilai-nilai ini (meskipun spesifikasi JavaScript mengenalinya).

REST API yang dijelaskan di halaman ini memungkinkan objek JSON permintaan/respons memiliki nilai tersebut. Ini menyiratkan bahwa permintaan seperti berikut ini valid:

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

Pengurai JSON (yang ketat) yang mematuhi standar akan menolak ini dengan kesalahan penguraian (karena token NaN dan Infinity tercampur dengan angka sebenarnya). Untuk menangani permintaan/tanggapan dalam kode Anda dengan benar, gunakan parser JSON yang mendukung token ini.

Token NaN , Infinity , -Infinity dikenali oleh proto3 , modul Python JSON dan bahasa JavaScript.

Contoh

Kita dapat menggunakan model mainan half_plus_three untuk melihat REST API beraksi.

Mulai ModelServer dengan titik akhir REST API

Unduh model half_plus_three dari repositori git :

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

Kami akan menggunakan Docker untuk menjalankan ModelServer. Jika Anda ingin menginstal ModelServer secara asli di sistem Anda, ikuti petunjuk pengaturan untuk menginstal, dan mulai ModelServer dengan opsi --rest_api_port untuk mengekspor titik akhir REST API (ini tidak diperlukan saat menggunakan 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 ...

Lakukan panggilan REST API ke ModelServer

Di terminal lain, gunakan alat curl untuk melakukan panggilan REST API.

Dapatkan status model sebagai berikut:

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

Panggilan predict akan terlihat sebagai berikut:

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

Dan panggilan regress terlihat sebagai berikut:

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

Catatan, regress tersedia pada nama tanda tangan non-default dan harus ditentukan secara eksplisit. URL atau isi permintaan yang salah mengembalikan status kesalahan 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)" }
$