Ngoài API gRPC, TensorFlow ModelServer cũng hỗ trợ API RESTful. Trang này mô tả các điểm cuối API này và ví dụ toàn diện 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 đối tượng này phụ thuộc vào loại yêu cầu hoặc động từ. Xem các phần dành riêng cho API bên dưới để biết chi tiết.
Trong trường hợp có lỗi, tất cả các API sẽ trả về một đối tượng JSON trong nội dung phản hồi với error
là khóa và thông báo lỗi là giá trị:
{
"error": <error message string>
}
API trạng thái mô hình
API này theo sát API gRPC ModelService.GetModelStatus
. 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}]
Việc bao gồm /versions/${VERSION}
hoặc /labels/${LABEL}
là tùy chọn. Nếu trạng thái bị bỏ qua 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 biểu diễn JSON của GetModelStatusResponse
protobuf.
API siêu dữ liệu mô hình
API này theo sát API PredictionService.GetModelMetadata
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
Việc bao gồm /versions/${VERSION}
hoặc /labels/${LABEL}
là tùy chọn. Nếu 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 biểu diễn JSON của GetModelMetadataResponse
protobuf.
API phân loại và hồi quy
API này theo sát các phương pháp Classify
và Regress
của API gRPC của PredictionService
.
URL
POST http://host:port/v1/models/${MODEL_NAME}[/versions/${VERSION}|/labels/${LABEL}]:(classify|regress)
Việc bao gồm /versions/${VERSION}
hoặc /labels/${LABEL}
là tùy chọn. Nếu bỏ qua phiên bản mới nhất được sử dụng.
định dạng yêu cầu
Nội dung yêu cầu cho các API classify
và regress
phải là một đối tượng JSON được đị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 thập phân), chuỗi JSON hoặc đối tượng JSON đại diện cho dữ liệu nhị phân (xem phần Mã hóa giá trị nhị phân bên dưới để biết chi tiết). <list>
là danh sách các giá trị như vậy. Định dạng này tương tự như các proto ClassificationRequest
và RegressionRequest
của gRPC. Cả hai phiên bản đều chấp nhận danh sách các đối tượng Example
.
định dạng phản hồi
Yêu cầu classify
trả về một đối tượng JSON trong nội dung phản hồi, được đị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 (có thể là chuỗi rỗng ""
nếu mô hình không có nhãn liên quan đến điểm số). <score>
là một số thập phân (dấu phẩy động).
Yêu cầu regress
trả về một đối tượng JSON trong nội dung phản hồi, được đị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 dùng API gRPC sẽ nhận thấy sự giống nhau của định dạng này với các nguyên mẫu ClassificationResponse
và RegressionResponse
.
Dự đoán API
API này theo sát API PredictionService.Predict
gRPC.
URL
POST http://host:port/v1/models/${MODEL_NAME}[/versions/${VERSION}|/labels/${LABEL}]:predict
Việc bao gồm /versions/${VERSION}
hoặc /labels/${LABEL}
là tùy chọn. Nếu bỏ qua phiên bản mới nhất được sử dụng.
định dạng yêu cầu
Nội dung yêu cầu cho API predict
phải là đối tượng JSON đượ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 tenxơ đầu vào ở định dạng hàng.
Định dạng này tương tự như nguyên mẫu PredictRequest
của API gRPC và API dự đoán CMLE . Sử dụng định dạng này nếu tất cả tenxơ đầu vào được đặt tên có cùng thứ nguyên 0 . Nếu không, hãy sử dụng định dạng cột được mô tả sau bên dưới.
Ở định dạng hàng, đầu vào được khóa thành khóa phiên bản trong yêu cầu JSON.
Khi chỉ có một đầu vào được đặt tên, hãy chỉ định giá trị của khóa phiên bản 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 thang đo được thể hiện một cách 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/tenxơ đầu vào, một cho mỗi đầu vào được đặt tên. Ví dụ, sau đây là một yêu cầu có hai trường hợp, mỗi trường hợp có một bộ ba tenxơ đầ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 đầu vào được đặt tên ("thẻ", "tín hiệu", "cảm biến") được giả định hoàn toàn có cùng thứ nguyên 0 ( hai trong ví dụ trên, vì có hai đối tượng trong danh sách phiên bản ). 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 tenxơ đầu vào ở định dạng cột.
Sử dụng định dạng này để chỉ định các tenxơ đầ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 một biểu diễn nhỏ gọn hơn. Định dạng này tương tự như trường inputs
của yêu cầu Predict
gRPC.
Ở định dạng cột, đầu vào được nhập vào khóa đầu vào trong yêu cầu JSON.
Giá trị cho khóa đầu vào có thể là một tenxơ đầu vào duy nhất hoặc ánh xạ tên đầu vào tới các tenxơ (được liệt kê ở dạng lồng nhau tự nhiên của chúng). 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 thứ 0 (còn gọi là kích thước lô) theo 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 chứ không phải danh sách như các thể hiện (được sử dụng trong biểu diễn hàng). Ngoài ra, tất cả các đầu vào đã đặt tên được chỉ định cùng nhau, trái ngược với việc hủy kiểm soát 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ể khó đọc hơn).
định dạng phản hồi
Yêu cầu predict
trả về một đối tượng JSON trong nội dung phản hồi.
Một yêu cầu ở định dạng hàng có phản hồi đượ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 tenxơ được đặt tên, thì chúng tôi sẽ bỏ qua tên và khóa predictions
ánh xạ tới danh sách các giá trị vô hướng hoặc danh sách. Nếu mô hình xuất ra nhiều tenxơ được đặt tên, thay vào đó, chúng tôi xuất ra một 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 ở định dạng cột có phản hồi đượ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 tenxơ được đặt tên, chúng tôi bỏ qua tên và outputs
các bản đồ chính thành danh sách các giá trị vô hướng hoặc danh sách. Nếu mô hình xuất ra nhiều tenxơ được đặt tên, thay vào đó, chúng tôi 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 là loại DT_STRING
. Các tenxơ được đặt tên có _bytes
làm hậu tố trong tên của chúng được coi là có giá trị nhị phân. Các giá trị như vậy được mã hóa khác nhau như được mô tả trong phần mã hóa giá trị nhị phân bên dưới.
Ánh xạ JSON
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ợ, 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ê bên dưới được ngụ ý là không được hỗ trợ.
Loại dữ liệu TF | Giá trị JSON | ví dụ JSON | ghi chú |
---|---|---|---|
DT_BOOL | đúng sai | đúng sai | |
DT_STRING | sợi dây | "Chào thế giới!" | Nếu DT_STRING biểu thị các byte nhị phân (ví dụ: byte hình ảnh được tuần tự hóa hoặc protobuf), hãy mã hóa các byte này trong Base64. Xem Mã hóa giá trị nhị phân để biết thêm thông tin. |
DT_INT8, DT_UINT8, DT_INT16, DT_INT32, DT_UINT32, DT_INT64, DT_UINT64 | con số | 1, -10, 0 | Giá trị JSON sẽ là một số thập phân. |
DT_FLOAT, DT_DOUBLE | con số | 1.1, -10.0, 0, NaN , Infinity | Giá trị JSON sẽ là một số hoặc một trong các giá trị mã thông báo đặc biệt - NaN , Infinity và -Infinity . Xem tuân thủ JSON để biết thêm thông tin. Ký hiệu số mũ cũng được chấp nhận. |
Độ chính xác của dấu phẩy độ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 dẫn đến mất độ chính xác. Chẳng hạn, nếu đầu vào x
là kiểu dữ liệu float
và đầ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 dấu phẩy động IEEE 754 (ví dụ: Intel hoặc AMD), thì giá trị sẽ được phần cứng cơ sở âm thầm chuyển đổi thành 1435774336
vì 1435774380
không thể được biểu diễn chính xác bằng số dấu phẩy động 32 bit. Thông thường, các yếu tố đầu vào để phân phối phải giống như phân phối khi đào tạo, do đó, điều này thường không có vấn đề gì vì các chuyển đổi tương tự đã xảy ra trong thời gian đà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 loại 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 việc kiểm tra phía máy khách.
Mã hóa giá trị nhị phân
JSON sử dụng mã hóa UTF-8. Nếu bạn có các giá trị đối tượng hoặc tenxơ đầu vào cần ở dạng nhị phân (như byte hình ảnh), bạn phải mã hóa dữ liệu Base64 và đóng gói nó trong một đối tượng JSON có khóa là b64
như sau:
{ "b64": <base64 encoded string> }
Bạn có thể chỉ định đối tượng này làm giá trị cho một 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à các tính năng caption
được hiển thị bên dưới:
{
"signature_name": "classify_objects",
"examples": [
{
"image": { "b64": "aW1hZ2UgYnl0ZXM=" },
"caption": "seaside"
},
{
"image": { "b64": "YXdlc29tZSBpbWFnZSBieXRlcw==" },
"caption": "mountains"
}
]
}
tuân thủ JSON
Nhiều giá trị tính năng hoặc tenxơ là số dấu phẩy động. Ngoài các giá trị hữu hạn (ví dụ: 3.14, 1.0, v.v.), chúng có thể có các giá trị NaN
và không hữu hạn ( Infinity
và -Infinity
). Thật không may, đặc tả JSON ( RFC 7159 ) KHÔNG nhận ra các giá trị này (mặc dù đặc tả JavaScript thì có).
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ư sau là hợp lệ:
{
"example": [
{
"sensor_readings": [ 1.0, -3.14, Nan, Infinity ]
}
]
}
Trình phân tích cú pháp JSON tuân thủ tiêu chuẩn (nghiêm ngặt) sẽ từ chối điều này với lỗi phân tích cú pháp (do mã thông báo NaN
và Infinity
trộn lẫn với số thực). Để 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.
Mã thông báo NaN
, Infinity
, -Infinity
được nhận dạng bởi proto3 , mô-đun JSON của Python và ngôn ngữ JavaScript.
Ví dụ
Chúng ta có thể sử dụng mô hình đồ chơi half_plus_three để xem hoạt động của các API REST.
Bắt đầu ModelServer với điểm cuối API REST
Tải xuống mô hình half_plus_three
từ kho lưu trữ 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 nguyên bản trên hệ thống của mình, hãy làm theo hướng dẫn thiết lập để cài đặt và khởi động ModelServer với tùy chọn --rest_api_port
để xuất điểm cuối API REST (điều này 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 API REST tới ModelServer
Trong một thiết bị đầu cuối khác, hãy sử dụng công cụ curl
để thực hiện lệnh gọi API REST.
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 cuộc gọi predict
sẽ 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 cuộc gọi regress
trông 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
có sẵn trên tên chữ ký không mặc định và phải được chỉ định rõ ràng. Nội dung hoặc URL yêu cầu không chính xác sẽ 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)" }
$