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> 는 소수(부동 소수점) 숫자입니다.

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개의 명명된 입력 텐서 세트가 있는 2개의 인스턴스가 있는 요청입니다.

{
 "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에는 단일 숫자 데이터 유형이 있습니다. 따라서 정밀도가 손실되는 입력 값을 제공하는 것이 가능합니다. 예를 들어 입력 xfloat 데이터 유형이고 입력 {"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)" }
$