RESTful API

gRPC API 외에도 TensorFlow ModelServer는 RESTful API도 지원합니다. 이 페이지에서는 이러한 API 엔드포인트와 사용법에 대한 엔드투엔드 예제를 설명합니다.

요청과 응답은 JSON 개체입니다. 이 개체의 구성은 요청 유형이나 동사에 따라 다릅니다. 자세한 내용은 아래 API 관련 섹션을 참조하세요.

오류가 발생하면 모든 API는 error 키로, 오류 메시지를 값으로 사용하여 응답 본문에 JSON 개체를 반환합니다.

{
  "error": <error message string>
}

모델 상태 API

이 API는 ModelService.GetModelStatus gRPC API를 밀접하게 따릅니다. ModelServer에서 모델의 상태를 반환합니다.

URL

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

/versions/${VERSION} 또는 /labels/${LABEL} 포함하는 것은 선택 사항입니다. 생략된 경우 모든 버전의 상태가 응답에 반환됩니다.

응답 형식

성공하면 GetModelStatusResponse protobuf의 JSON 표현을 반환합니다.

모델 메타데이터 API

이 API는 PredictionService.GetModelMetadata gRPC API를 밀접하게 따릅니다. ModelServer에서 모델의 메타데이터를 반환합니다.

URL

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

/versions/${VERSION} 또는 /labels/${LABEL} 포함하는 것은 선택 사항입니다. 생략하면 최신 버전의 모델 메타데이터가 응답으로 반환됩니다.

응답 형식

성공하면 GetModelMetadataResponse protobuf의 JSON 표현을 반환합니다.

분류 및 회귀 API

이 API는 PredictionService gRPC API의 ClassifyRegress 메서드를 밀접하게 따릅니다.

URL

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

/versions/${VERSION} 또는 /labels/${LABEL} 포함하는 것은 선택 사항입니다. 생략하면 최신 버전이 사용됩니다.

요청 형식

classifyregress API에 대한 요청 본문은 다음과 같은 형식의 JSON 객체여야 합니다.

{
  // 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> 는 JSON 숫자(정수 또는 소수), JSON 문자열 또는 이진 데이터를 나타내는 JSON 개체입니다(자세한 내용은 아래 이진 값 인코딩 섹션 참조). <list> 그러한 값의 목록입니다. 이 형식은 gRPC의 ClassificationRequestRegressionRequest proto와 유사합니다. 두 버전 모두 Example 객체 목록을 허용합니다.

응답 형식

classify 요청은 응답 본문에 다음과 같은 형식의 JSON 객체를 반환합니다.

{
  "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> 은 문자열입니다(모델에 점수와 연결된 레이블이 없는 경우 빈 문자열 "" 일 수 있음). <score> 10진수(부동 소수점) 숫자입니다.

regress 요청은 응답 본문에 다음과 같은 형식의 JSON 개체를 반환합니다.

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

<value> 은 10진수입니다.

gRPC API 사용자는 이 형식이 ClassificationResponseRegressionResponse proto와 유사하다는 것을 알게 될 것입니다.

예측 API

이 API는 PredictionService.Predict gRPC API를 밀접하게 따릅니다.

URL

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

/versions/${VERSION} 또는 /labels/${LABEL} 포함하는 것은 선택 사항입니다. 생략하면 최신 버전이 사용됩니다.

요청 형식

predict API의 요청 본문은 다음과 같은 형식의 JSON 객체여야 합니다.

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

행 형식으로 입력 텐서를 지정합니다.

이 형식은 gRPC API 및 CMLE 예측 APIPredictRequest proto와 유사합니다. 모든 명명된 입력 텐서의 0번째 차원이 동일한 경우 이 형식을 사용하세요. 그렇지 않은 경우 아래에서 나중에 설명하는 열 형식을 사용하세요.

행 형식에서 입력은 JSON 요청의 인스턴스 키로 지정됩니다.

명명된 입력이 하나만 있는 경우 인스턴스 키의 값을 입력 값으로 지정합니다.

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

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

목록을 수동으로 평면화할 필요가 없기 때문에 Tensor는 중첩 표기법으로 자연스럽게 표현됩니다.

여러 명명된 입력의 경우 각 항목은 각 명명된 입력에 대해 하나씩 입력 이름/텐서 값 쌍을 포함하는 객체일 것으로 예상됩니다. 예를 들어, 다음은 각각 3개의 명명된 입력 텐서 세트가 있는 두 개의 인스턴스가 있는 요청입니다.

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

각 명명된 입력("태그", "신호", "센서")은 동일한 0번째 차원( 인스턴스 목록에 두 개의 객체가 있으므로 위의 예에서는 2 )을 갖는 것으로 암시적으로 가정됩니다. 서로 다른 0번째 차원을 갖는 명명된 입력이 있는 경우 아래에 설명된 열 형식을 사용하십시오.

열 형식으로 입력 텐서를 지정합니다.

명명된 개별 입력의 0번째 차원이 동일하지 않거나 보다 간결한 표현을 원하는 경우 이 형식을 사용하여 입력 텐서를 지정합니다. 이 형식은 gRPC Predict 요청의 inputs 필드와 유사합니다.

열 형식에서는 입력이 JSON 요청의 입력 키로 지정됩니다.

입력 키의 값은 단일 입력 텐서이거나 텐서에 대한 입력 이름의 맵(자연스러운 중첩 형식으로 나열됨)일 수 있습니다. 각 입력은 임의의 모양을 가질 수 있으며 위에 설명된 행 형식에서 요구하는 것과 동일한 0번째 차원(일명 배치 크기)을 공유할 필요는 없습니다.

이전 예의 열 형식 표현은 다음과 같습니다.

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

입력은 JSON 개체이며 인스턴스 (행 표현에 사용됨)와 같은 목록이 아닙니다. 또한 이전에 설명한 행 형식으로 수행된 개별 행으로 펼치는 것과 달리 명명된 모든 입력은 함께 지정됩니다. 이로 인해 표현이 간결해집니다(하지만 읽기가 어려울 수도 있음).

응답 형식

predict 요청은 응답 본문에 JSON 객체를 반환합니다.

행 형식 의 요청에는 다음과 같은 형식의 응답이 있습니다.

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

모델의 출력에 이름이 지정된 텐서가 하나만 포함된 경우 스칼라 또는 목록 값 목록에 대한 이름 및 predictions 키 맵을 생략합니다. 모델이 여러 개의 명명된 텐서를 출력하는 경우 위에서 언급한 행 형식의 요청과 유사하게 객체 목록을 대신 출력합니다.

열 형식 의 요청에는 다음과 같은 형식의 응답이 있습니다.

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

모델의 출력에 이름이 지정된 텐서가 하나만 포함된 경우 이름을 생략하고 키 맵을 스칼라 또는 목록 값 목록으로 outputs . 모델이 여러 개의 명명된 텐서를 출력하는 경우 대신 객체를 출력합니다. 이 객체의 각 키는 명명된 출력 텐서에 해당합니다. 형식은 위에서 언급한 열 형식의 요청과 유사합니다.

바이너리 값 출력

TensorFlow는 이진이 아닌 문자열과 이진 문자열을 구분하지 않습니다. 모두 DT_STRING 유형입니다. 이름에 접미사로 _bytes 있는 명명된 텐서는 이진 값을 갖는 것으로 간주됩니다. 이러한 값은 아래 바이너리 값 인코딩 섹션에 설명된 대로 다르게 인코딩됩니다.

JSON 매핑

RESTful API는 JSON의 표준 인코딩을 지원하므로 시스템 간에 데이터를 더 쉽게 공유할 수 있습니다. 지원되는 유형의 경우 인코딩은 아래 표에 유형별로 설명되어 있습니다. 아래에 나열되지 않은 유형은 지원되지 않는 것으로 간주됩니다.

TF 데이터 유형 JSON 값 JSON 예 메모
DT_BOOL 사실, 거짓 사실, 거짓
DT_STRING "안녕하세요!" DT_STRING 이진 바이트(예: 직렬화된 이미지 바이트 또는 protobuf)를 나타내는 경우 이를 Base64로 인코딩합니다. 자세한 내용은 이진 값 인코딩을 참조하세요.
DT_INT8, DT_UINT8, DT_INT16, DT_INT32, DT_UINT32, DT_INT64, DT_UINT64 숫자 1, -10, 0 JSON 값은 10진수입니다.
DT_FLOAT, DT_DOUBLE 숫자 1.1, -10.0, 0, NaN , Infinity JSON 값은 숫자이거나 특수 토큰 값( NaN , Infinity-Infinity ) 중 하나입니다. 자세한 내용은 JSON 적합성을 참조하세요. 지수 표기법도 허용됩니다.

부동 소수점 정밀도

JSON에는 단일 숫자 데이터 유형이 있습니다. 따라서 정밀도가 손실되는 입력 값을 제공하는 것이 가능합니다. 예를 들어 입력 x float 데이터 유형이고 입력 {"x": 1435774380} IEEE 754 부동 소수점 표준(예: Intel 또는 AMD)을 기반으로 하는 하드웨어에서 실행되는 모델로 전송되면 값은 다음과 같습니다. 1435774380 32비트 부동 소수점 숫자로 정확하게 표현될 수 없기 때문에 기본 하드웨어에 의해 자동으로 1435774336 으로 변환됩니다. 일반적으로 제공에 대한 입력은 학습과 동일한 분포여야 하므로 학습 시 동일한 전환이 발생했기 때문에 일반적으로 문제가 되지 않습니다. 그러나 전체 정밀도가 필요한 경우에는 원하는 정밀도를 처리하거나 클라이언트 측 검사를 고려할 수 있는 모델의 기본 데이터 유형을 사용해야 합니다.

바이너리 값 인코딩

JSON은 UTF-8 인코딩을 사용합니다. 바이너리(예: 이미지 바이트)여야 하는 입력 기능 또는 텐서 값이 있는 경우 데이터를 Base64로 인코딩하고 다음과 같이 b64 키로 사용하는 JSON 객체에 캡슐화 해야 합니다 .

{ "b64": <base64 encoded string> }

이 객체를 입력 기능 또는 텐서의 값으로 지정할 수 있습니다. 출력 응답을 인코딩하는 데에도 동일한 형식이 사용됩니다.

image (바이너리 데이터) 및 caption 기능이 포함된 분류 요청은 다음과 같습니다.

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

JSON 준수

많은 특성이나 텐서 값은 부동 소수점 숫자입니다. 유한 값(예: 3.14, 1.0 등) 외에도 NaN 및 무한한 값( Infinity-Infinity )을 가질 수 있습니다. 불행하게도 JSON 사양( RFC 7159 )은 이러한 값을 인식 하지 못합니다 (JavaScript 사양은 인식하지만).

이 페이지에 설명된 REST API를 사용하면 요청/응답 JSON 개체가 이러한 값을 가질 수 있습니다. 이는 다음과 같은 요청이 유효함을 의미합니다.

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

(엄격한) 표준을 준수하는 JSON 파서는 구문 분석 오류로 이를 거부합니다(실제 숫자와 혼합된 NaNInfinity 토큰으로 인해). 코드에서 요청/응답을 올바르게 처리하려면 이러한 토큰을 지원하는 JSON 파서를 사용하세요.

NaN , Infinity , -Infinity 토큰은 proto3 , Python JSON 모듈 및 JavaScript 언어로 인식됩니다.

우리는 장난감 half_plus_3 모델을 사용하여 REST API가 실제로 작동하는 모습을 볼 수 있습니다.

REST API 엔드포인트로 ModelServer 시작

git 저장소 에서 half_plus_three 모델을 다운로드하세요:

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

Docker를 사용하여 ModelServer를 실행하겠습니다. ModelServer를 시스템에 기본적으로 설치하려면 설정 지침에 따라 대신 설치하고 --rest_api_port 옵션으로 ModelServer를 시작하여 REST API 엔드포인트를 내보냅니다(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 ...

ModelServer에 대한 REST API 호출 수행

다른 터미널에서 curl 도구를 사용하여 REST API 호출을 수행합니다.

다음과 같이 모델의 상태를 가져옵니다.

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

predict 호출은 다음과 같습니다.

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

regress 호출은 다음과 같습니다.

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

regress 기본이 아닌 서명 이름에 사용할 수 있으며 명시적으로 지정해야 합니다. 잘못된 요청 URL 또는 본문은 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)" }
$