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