Ngoài gRPC API TensorFlow ModelServer cũng hỗ trợ API RESTful. Trang này mô tả những điểm cuối API và một end-to-end ví dụ về cách sử dụng.
Yêu cầu và phản hồi là một đối tượng JSON. Thành phần của tân ngữ này phụ thuộc vào kiểu yêu cầu hoặc động từ. Xem các phần cụ thể của API bên dưới để biết chi tiết.
Trong trường hợp lỗi, tất cả các API sẽ trả về một đối tượng JSON trong cơ thể phản ứng với error
như chìa khóa và thông báo lỗi như giá trị:
{
"error": <error message string>
}
API trạng thái mô hình
API này sau chặt chẽ việc ModelService.GetModelStatus
API gRPC. Nó trả về trạng thái của một mô hình trong ModelServer.
URL
GET http://host:port/v1/models/${MODEL_NAME}[/versions/${VERSION}|/labels/${LABEL}]
Bao gồm /versions/${VERSION}
hoặc /labels/${LABEL}
là không bắt buộc. Nếu bỏ qua trạng thái cho tất cả các phiên bản được trả lại trong phản hồi.
Định dạng phản hồi
Nếu thành công, trả về một đại diện JSON của GetModelStatusResponse
protobuf.
API siêu dữ liệu mô hình
API này sau chặt chẽ việc PredictionService.GetModelMetadata
API gRPC. Nó trả về siêu dữ liệu của một mô hình trong ModelServer.
URL
GET http://host:port/v1/models/${MODEL_NAME}[/versions/${VERSION}|/labels/${LABEL}]/metadata
Bao gồm /versions/${VERSION}
hoặc /labels/${LABEL}
là không bắt buộc. Nếu bị bỏ qua, siêu dữ liệu mô hình cho phiên bản mới nhất sẽ được trả về trong phản hồi.
Định dạng phản hồi
Nếu thành công, trả về một đại diện JSON của GetModelMetadataResponse
protobuf.
API phân loại và hồi quy
API này sau chặt chẽ việc Classify
và Regress
phương pháp PredictionService
gRPC API.
URL
POST http://host:port/v1/models/${MODEL_NAME}[/versions/${VERSION}|/labels/${LABEL}]:(classify|regress)
Bao gồm /versions/${VERSION}
hoặc /labels/${LABEL}
là không bắt buộc. Nếu bỏ qua, phiên bản mới nhất sẽ được sử dụng.
Yêu cầu định dạng
Cơ thể yêu cầu cho classify
và regress
API phải là một đối tượng JSON định dạng như sau:
{
// 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>
là một số JSON (toàn bộ hoặc một chữ số thập phân), JSON chuỗi, hoặc một đối tượng JSON đại diện cho dữ liệu nhị phân (xem giá trị nhị phân Encoding phần dưới đây để biết chi tiết). <list>
là danh sách các giá trị như vậy. Định dạng này cũng tương tự như gRPC của ClassificationRequest
và RegressionRequest
protos. Cả hai phiên bản chấp nhận danh sách các Example
đối tượng.
Định dạng phản hồi
Một classify
yêu cầu trả về một đối tượng JSON trong cơ thể phản ứng, định dạng như sau:
{
"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>
là một chuỗi (mà có thể là một chuỗi rỗng ""
nếu mô hình không có một nhãn hiệu gắn liền với tỷ số). <score>
là một số thập phân (dấu phẩy động) số.
Các regress
yêu cầu trả về một đối tượng JSON trong cơ thể phản ứng, định dạng như sau:
{
// One regression value for each example in the request in the same order.
"result": [ <value1>, <value2>, <value3>, ...]
}
<value>
là một số thập phân.
Người sử dụng gRPC API sẽ nhận thấy sự giống nhau của định dạng này với ClassificationResponse
và RegressionResponse
protos.
Dự đoán API
API này sau chặt chẽ việc PredictionService.Predict
API gRPC.
URL
POST http://host:port/v1/models/${MODEL_NAME}[/versions/${VERSION}|/labels/${LABEL}]:predict
Bao gồm /versions/${VERSION}
hoặc /labels/${LABEL}
là không bắt buộc. Nếu bỏ qua, phiên bản mới nhất sẽ được sử dụng.
Yêu cầu định dạng
Yêu cầu cơ thể để predict
API phải JSON đối tượng được định dạng như sau:
{
// (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>
}
Chỉ định bộ căng đầu vào ở định dạng hàng.
Định dạng này cũng tương tự như PredictRequest
proto của gRPC API và CMLE dự đoán API . Sử dụng định dạng này nếu tất cả tensors nhập tên có cùng 0 thứ kích thước. Nếu không, hãy sử dụng định dạng cột được mô tả sau bên dưới.
Trong định dạng hàng, đầu vào được vừa khít với chính trường trong yêu cầu JSON.
Khi chỉ có một tên đầu vào, xác định giá trị của trường chính là giá trị của đầu vào:
{
// List of 3 scalar tensors.
"instances": [ "foo", "bar", "baz" ]
}
{
// List of 2 tensors each of [1, 2] shape
"instances": [ [[1, 2]], [[3, 4]] ]
}
Các hàng chục được thể hiện tự nhiên trong ký hiệu lồng nhau vì không cần phải làm phẳng danh sách theo cách thủ công.
Đối với nhiều đầu vào được đặt tên, mỗi mục được mong đợi là một đối tượng chứa cặp giá trị tên / ten đầu vào, một đối tượng cho mỗi đầu vào được đặt tên. Ví dụ, sau đây là một yêu cầu có hai phiên bản, mỗi phiên bản có một bộ ba bộ căng đầu vào được đặt tên:
{
"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]]
}
]
}
Lưu ý, mỗi tên đầu vào ( "tag", "tín hiệu", "cảm biến") được ngầm giả định có cùng 0 thứ kích thước (hai trong ví dụ trên, như có hai đối tượng trong danh sách các trường hợp). Nếu bạn đã đặt tên cho các đầu vào có thứ nguyên 0 khác nhau, hãy sử dụng định dạng cột được mô tả bên dưới.
Chỉ định bộ căng đầu vào ở định dạng cột.
Sử dụng định dạng này để chỉ định bộ căng đầu vào của bạn, nếu các đầu vào được đặt tên riêng lẻ không có cùng thứ nguyên 0 hoặc bạn muốn biểu diễn nhỏ gọn hơn. Định dạng này cũng tương tự như các inputs
lĩnh vực gRPC Predict
theo yêu cầu.
Trong các định dạng hình cây cột, đầu vào được vừa khít với chính nguyên liệu đầu vào trong yêu cầu JSON.
Giá trị cho khóa đầu vào có thể hoặc là một tensor đầu vào đơn lẻ hoặc một bản đồ của tên đầu vào tensors (được liệt kê dưới dạng lồng nhau tự nhiên của họ). Mỗi đầu vào có thể có hình dạng tùy ý và không cần chia sẻ / cùng thứ nguyên 0 (còn gọi là kích thước lô) như yêu cầu của định dạng hàng được mô tả ở trên.
Biểu diễn cột của ví dụ trước như sau:
{
"inputs": {
"tag": ["foo", "bar"],
"signal": [[1, 2, 3, 4, 5], [3, 4, 1, 2, 5]],
"sensor": [[[1, 2], [3, 4]], [[4, 5], [6, 8]]]
}
}
Lưu ý, đầu vào là một đối tượng JSON và không phải là một danh sách như trường hợp (được sử dụng trong các đại diện hàng). Ngoài ra, tất cả các đầu vào được đặt tên được chỉ định cùng nhau, trái ngược với việc cuộn chúng thành các hàng riêng lẻ được thực hiện ở định dạng hàng được mô tả trước đó. Điều này làm cho biểu diễn nhỏ gọn (nhưng có thể ít đọc hơn).
Định dạng phản hồi
Các predict
yêu cầu trả về một đối tượng JSON trong cơ thể phản ứng.
Một yêu cầu trong định dạng hàng đã đáp ứng được định dạng như sau:
{
"predictions": <value>|<(nested)list>|<list-of-objects>
}
Nếu đầu ra của mô hình chỉ chứa một tên tensor, chúng tôi bỏ qua tên và predictions
chính bản đồ đến một danh sách vô hướng hoặc danh sách các giá trị. Nếu mô hình xuất ra nhiều tensor được đặt tên, thay vào đó, chúng tôi xuất ra danh sách các đối tượng, tương tự như yêu cầu ở định dạng hàng được đề cập ở trên.
Một yêu cầu trong định dạng hình cây cột đã đáp ứng được định dạng như sau:
{
"outputs": <value>|<(nested)list>|<object>
}
Nếu đầu ra của mô hình chỉ chứa một tên tensor, chúng tôi bỏ qua tên và outputs
chính bản đồ đến một danh sách vô hướng hoặc danh sách các giá trị. Nếu mô hình xuất ra nhiều tensor được đặt tên, thay vào đó chúng ta sẽ xuất ra một đối tượng. Mỗi khóa của đối tượng này tương ứng với một tenxơ đầu ra được đặt tên. Định dạng tương tự như yêu cầu ở định dạng cột đã đề cập ở trên.
Đầu ra của các giá trị nhị phân
TensorFlow không phân biệt giữa chuỗi không nhị phân và nhị phân. Tất cả đều được DT_STRING
loại. Tensors đặt tên có _bytes
như một hậu tố trong tên của họ được xem là có giá trị nhị phân. Giá trị đó được mã hóa khác nhau như mô tả trong các giá trị nhị phân mã hóa phần dưới đây.
Ánh xạ JSON
Các API RESTful hỗ trợ mã hóa chuẩn trong JSON, giúp chia sẻ dữ liệu giữa các hệ thống dễ dàng hơn. Đối với các loại được hỗ trợ, các mã hóa được mô tả trên cơ sở từng loại trong bảng bên dưới. Các loại không được liệt kê dưới đây được ngụ ý là không được hỗ trợ.
Loại dữ liệu TF | Giá trị JSON | Ví dụ về JSON | Ghi chú |
---|---|---|---|
DT_BOOL | đúng sai | đúng sai | |
DT_STRING | chuỗi | "Chào thế giới!" | Nếu DT_STRING đại diện byte nhị phân (ví dụ byte hình ảnh đăng hoặc protobuf), mã hóa này trong Base64. Xem Encoding giá trị nhị phân để biết thêm. |
DT_INT8, DT_UINT8, DT_INT16, DT_INT32, DT_UINT32, DT_INT64, DT_UINT64 | số | 1, -10, 0 | Giá trị JSON sẽ là một số thập phân. |
DT_FLOAT, DT_DOUBLE | số | 1.1, -10.0, 0, NaN , Infinity | Giá trị JSON sẽ có một số hoặc một trong các giá trị dấu hiệu đặc biệt - NaN , Infinity , và -Infinity . Xem JSON phù hợp để biết thêm. Ký hiệu số mũ cũng được chấp nhận. |
Độ chính xác của dấu chấm động
JSON có một kiểu dữ liệu số duy nhất. Do đó, có thể cung cấp một giá trị cho đầu vào làm mất độ chính xác. Ví dụ, nếu đầu vào x
là một float
kiểu dữ liệu, và các đầu vào {"x": 1435774380}
được gửi đến mô hình chạy trên phần cứng dựa trên tiêu chuẩn IEEE 754 điểm nổi (ví dụ như Intel hay AMD), thì giá trị sẽ được âm thầm chuyển đổi bởi phần cứng underyling đến 1435774336
từ 1435774380
không thể được đại diện chính xác trong một số dấu chấm động 32-bit. Thông thường, các yếu tố đầu vào để phân phát phải cùng phân phối với đào tạo, do đó, điều này nói chung sẽ không có vấn đề vì các chuyển đổi tương tự đã xảy ra tại thời điểm đào tạo. Tuy nhiên, trong trường hợp cần độ chính xác đầy đủ, hãy đảm bảo sử dụng kiểu dữ liệu cơ bản trong mô hình của bạn có thể xử lý độ chính xác mong muốn và / hoặc cân nhắc kiểm tra phía máy khách.
Mã hóa các giá trị nhị phân
JSON sử dụng mã hóa UTF-8. Nếu bạn có tính năng hoặc tensor giá trị đầu vào mà cần phải nhị phân (giống như hình ảnh byte), bạn phải Base64 mã hóa dữ liệu và đóng gói nó trong một đối tượng JSON có b64
là chìa khóa như sau:
{ "b64": <base64 encoded string> }
Bạn có thể chỉ định đối tượng này làm giá trị cho tính năng đầu vào hoặc tensor. Định dạng tương tự cũng được sử dụng để mã hóa phản hồi đầu ra.
Một yêu cầu phân loại với image
(dữ liệu nhị phân) và caption
các tính năng được hiển thị dưới đây:
{
"signature_name": "classify_objects",
"examples": [
{
"image": { "b64": "aW1hZ2UgYnl0ZXM=" },
"caption": "seaside"
},
{
"image": { "b64": "YXdlc29tZSBpbWFnZSBieXRlcw==" },
"caption": "mountains"
}
]
}
Tuân thủ JSON
Nhiều giá trị feature hoặc tensor là số dấu phẩy động. Ngoài giá trị hữu hạn (ví dụ 3.14, 1.0, vv) này có thể có NaN
và phi hữu hạn ( Infinity
và -Infinity
) giá trị. Thật không may là đặc điểm kỹ thuật JSON ( RFC 7159 ) KHÔNG nhận ra những giá trị này (mặc dù các đặc điểm kỹ thuật JavaScript không).
API REST được mô tả trên trang này cho phép các đối tượng JSON yêu cầu / phản hồi có các giá trị như vậy. Điều này ngụ ý rằng các yêu cầu như yêu cầu sau là hợp lệ:
{
"example": [
{
"sensor_readings": [ 1.0, -3.14, Nan, Infinity ]
}
]
}
A (chặt chẽ) tiêu chuẩn JSON compliant phân tích cú pháp sẽ từ chối điều này với một lỗi phân tích cú pháp (do NaN
và Infinity
mã thông báo hỗn hợp với những con số thực tế). Để xử lý chính xác các yêu cầu / phản hồi trong mã của bạn, hãy sử dụng trình phân tích cú pháp JSON hỗ trợ các mã thông báo này.
NaN
, Infinity
, -Infinity
tokens được công nhận bởi proto3 , Python JSON mô-đun và ngôn ngữ JavaScript.
Thí dụ
Chúng tôi có thể sử dụng đồ chơi half_plus_three mô hình để xem API REST trong hành động.
Khởi động ModelServer với điểm cuối API REST
Tải half_plus_three
mô hình từ kho git :
$ mkdir -p /tmp/tfserving
$ cd /tmp/tfserving
$ git clone --depth=1 https://github.com/tensorflow/serving
Chúng tôi sẽ sử dụng Docker để chạy ModelServer. Nếu bạn muốn cài đặt ModelServer hữu trên hệ thống của bạn, hãy làm theo hướng dẫn cài đặt để cài đặt thay vào đó, và bắt đầu ModelServer với --rest_api_port
tùy chọn để xuất khẩu endpoint REST API (điều này là không cần thiết khi sử dụng 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 ...
Thực hiện lệnh gọi REST API tới ModelServer
Trong một thiết bị đầu cuối khác nhau, sử dụng curl
công cụ để thực hiện cuộc gọi REST API.
Nhận trạng thái của mô hình như sau:
$ curl http://localhost:8501/v1/models/saved_model_half_plus_three
{
"model_version_status": [
{
"version": "123",
"state": "AVAILABLE",
"status": {
"error_code": "OK",
"error_message": ""
}
}
]
}
Một predict
cuộc gọi sẽ trông như sau:
$ 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]
}
Và một regress
gọi ngoại hình như sau:
$ 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]
}
Lưu ý, regress
hiện có sẵn trên một tên chữ ký không phải mặc định và phải được xác định một cách rõ ràng. URL hoặc nội dung yêu cầu không chính xác trả về trạng thái lỗi 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)" }
$