API RESTful

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 ClassifyRegress 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 classifyregress 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 ClassificationRequestRegressionRequest 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 ClassificationResponseRegressionResponse 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-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 NaNInfinity 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)" }
$