[인공지능] TensorFlow Serving - Docker Container 실행 하기, gRPC

참조


소개

  • Docker를 이용하여 TensorFlow Serving 실행하는 방법을 정리합니다.

Docker를 이용한 TensorFlow Serving 실행

  • 모델을 SavedModel 포맷으로 저장한 이후에 이를 TensorFlow Serving에서 로드해서 API 서버로 만들 수 있습니다.
  • 보통 TensorFlow Serving은 Docker를 이용해서 실행합니다.
  • Docker를 이용해서 TensorFlow Serving을 실행하는 방법은 다음과 같습니다.

TensorFlow Serving 이미지 다운로드

  • 먼저 docker hub에서 TensorFlow Serving 이미지를 다운로드 받습니다.
docker pull tensorflow/serving

TensorFlow Serving 컨테이너 실행

  • 앞서 docker hub에서 TensorFlow Serving 이미지를 다운로드 받았습니다.
  • 다음으로 TensorFlow Serving 컨테이너를 실행합니다.
docker run -t --rm  -p 8500:8500 -p 8501:8501 \
      -v "C:/src/test_data/save_model/tensorflow/Xception:/models/model" \
      tensorflow/serving \
      --model_name=mnist-model
  • 각각의 명령어 인자값에 대한 설명은 다음과 같습니다.
    • -p : 서버에서 데이터를 주고 받는데 사용할 포트를 지정합니다. (위 예시의 경우, 8501 포트)
    • -v : 불러올 모델이 SavedModel 포맷으로 저장된 전체 경로(full path)를 의미합니다. (위 예시의 경우, C:/src/test_data/save_model/tensorflow/Xception 경로에서 모델 파일을 불러 옵니다.), :뒤에는 모델을 실행할 REST API URL을 의미합니다. (위 예시의 경우, models/mnist_model)

TensorFlow Serving 서버 실행 화면

  • TensroFlow Serving 서버가 정상적으로 실행 되었다면, 다음과 같이 8501 포트로 REST API 서버가 구성되었다는 로그를 확인할 수 있습니다.
2022-03-14 02:13:03.418553: I tensorflow_serving/model_servers/server.cc:89] Building single TensorFlow model file config:  model_name: mnist-model model_base_path: /models/model
2022-03-14 02:13:03.418740: I tensorflow_serving/model_servers/server_core.cc:465] Adding/updating models.
2022-03-14 02:13:03.418771: I tensorflow_serving/model_servers/server_core.cc:591]  (Re-)adding model: mnist-model
2022-03-14 02:13:03.575600: I tensorflow_serving/core/basic_manager.cc:740] Successfully reserved resources to load servable {name: mnist-model version: 1}
2022-03-14 02:13:03.575652: I tensorflow_serving/core/loader_harness.cc:66] Approving load for servable version {name: mnist-model version: 1}
2022-03-14 02:13:03.575665: I tensorflow_serving/core/loader_harness.cc:74] Loading servable version {name: mnist-model version: 1}
2022-03-14 02:13:03.578387: I external/org_tensorflow/tensorflow/cc/saved_model/reader.cc:38] Reading SavedModel from: /models/model/1
2022-03-14 02:13:03.630984: I external/org_tensorflow/tensorflow/cc/saved_model/reader.cc:90] Reading meta graph with tags { serve }
2022-03-14 02:13:03.631036: I external/org_tensorflow/tensorflow/cc/saved_model/reader.cc:132] Reading SavedModel debug info (if present) from: /models/model/1
2022-03-14 02:13:03.632147: I external/org_tensorflow/tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations:  AVX2 FMA
To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.
2022-03-14 02:13:03.764954: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:206] Restoring SavedModel bundle.
2022-03-14 02:13:03.784500: I external/org_tensorflow/tensorflow/core/platform/profile_utils/cpu_utils.cc:114] CPU Frequency: 3600010000 Hz
2022-03-14 02:13:07.343446: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:190] Running initialization op on SavedModel bundle at path: /models/model/1
2022-03-14 02:13:07.445745: I external/org_tensorflow/tensorflow/cc/saved_model/loader.cc:277] SavedModel load for tags { serve }; Status: success: OK. Took 3867359 microseconds.
2022-03-14 02:13:07.456866: I tensorflow_serving/servables/tensorflow/saved_model_warmup_util.cc:59] No warmup data file found at /models/model/1/assets.extra/tf_serving_warmup_requests
2022-03-14 02:13:07.525380: I tensorflow_serving/core/loader_harness.cc:87] Successfully loaded servable version {name: mnist-model version: 1}
2022-03-14 02:13:07.528142: I tensorflow_serving/model_servers/server_core.cc:486] Finished adding/updating models
2022-03-14 02:13:07.528241: I tensorflow_serving/model_servers/server.cc:367] Profiler service is enabled
2022-03-14 02:13:07.528698: I tensorflow_serving/model_servers/server.cc:393] Running gRPC ModelServer at 0.0.0.0:8500 ...
[warn] getaddrinfo: address family for nodename not supported
[evhttp_server.cc : 245] NET_LOG: Entering the event loop ...
2022-03-14 02:13:07.532548: I tensorflow_serving/model_servers/server.cc:414] Exporting HTTP/REST API at:localhost:8501

gRPC를 통한 이미지 데이터 전송 및 예측 결과

  • 앞서 Docker를 이용하여 TensroFlow Serving 컨테이너를 정상적으로 실행 완료 하였습니다.
  • 이제 TensorFlow Serving 을 실행할 때 지정한 아래 URL(models/model)로 Input Data를 전송한 후, 해당 Input Data에 대한 예측 결과 값을 반환 받을 수 있습니다.
import tensorflow as tf
import matplotlib.pyplot as plt
import numpy as np
import grpc

from PIL import Image
from tensorflow_serving.apis import predict_pb2
from tensorflow_serving.apis import prediction_service_pb2_grpc

def list_chunk(list, num):
    return [list[idx:idx+num] for idx in range(0, len(list), num)]

mnist = tf.keras.datasets.mnist

(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train = x_train.reshape(x_train.shape[0], 28, 28, 1)
x_test = x_test.reshape(x_test.shape[0], 28, 28, 1)
x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train, x_test = x_train / 255.0, x_test / 255.0

test_images = x_test[0:5]

host = 'localhost'
port = 8500
model = 'mnist-model'

channel = grpc.insecure_channel(f'{host}:{port}')
stub = prediction_service_pb2_grpc.PredictionServiceStub(channel)

# Send request
# See prediction_service.proto for gRPC request/response details.
request = predict_pb2.PredictRequest()
request.model_spec.name = model
request.model_spec.signature_name = 'serving_default'

request.inputs['conv2d_input'].CopyFrom(
    tf.make_tensor_proto(test_images))

result = stub.Predict(request, 10.0)  # 10 secs timeout
response = np.array(result.outputs['dense_1'].float_val)

response = list_chunk(response.tolist(), 10)

for idx, list in enumerate(response):
    prediction = np.argmax(list)
    print('실제 값 : {} / 예측 값 : {}'.format(y_test[idx], prediction))

실행 결과

  • 정상적으로 TensorFlow Serving 과 gRPC로 통신하여 Inference 된 것을 확인할 수 있습니다.
실제 값 : 7 / 예측 값 : 7
실제 값 : 2 / 예측 값 : 2
실제 값 : 1 / 예측 값 : 1
실제 값 : 0 / 예측 값 : 0
실제 값 : 4 / 예측 값 : 4

gRPC Request Input, Ouput 파마미터 값 정보

  • 위의 gRPC 소스 코드를 보게 되면 아래와 같은 코드가 있습니다.
  • 아래 코드에서 inputs['conv2d_input'], result.outputs['dense_1'] 이라고 해서 conv2d_input, dense_1 2개의 파라미터 정보가 있습니다.
  • 해당 파라미터 정보는 모델 마다 다른 것으로 확인이 되고, 파라미터 정보를 확인 하려면 다음 주소를 통해서 Input, Output 파라미터 정보를 확인할 수 있습니다.
    • http://localhost:8501/v1/models/mnist-model/metadata 위 주소로 접속하게 되면 TensorFlow Serving 컨테이너 실행하면서 만든 model의 Metadata를 확인할 수 있고 해당 내용에 input, output 파라미터 정보를 확인할 수 있습니다.
request.inputs['conv2d_input'].CopyFrom(
    tf.make_tensor_proto(test_images))

...

response = np.array(result.outputs['dense_1'].float_val)

메타데이터 정보 예시

  • 다음은 input, output 파라미터 정보를 확인할 수 있는 메타데이터 정보 예시 입니다.
{
"model_spec":{
 "name": "mnist-model",
 "signature_name": "",
 "version": "1"
}
,
"metadata": {"signature_def": {
 "signature_def": {
  "serving_default": {
   "inputs": {
    "conv2d_input": {
     "dtype": "DT_FLOAT",
     "tensor_shape": {
      "dim": [
       {
        "size": "-1",
        "name": ""
       },
       {
        "size": "28",
        "name": ""
       },
       {
        "size": "28",
        "name": ""
       },
       {
        "size": "1",
        "name": ""
       }
      ],
      "unknown_rank": false
     },
     "name": "serving_default_conv2d_input:0"
    }
   },
   "outputs": {
    "dense_1": {
     "dtype": "DT_FLOAT",
     "tensor_shape": {
      "dim": [
       {
        "size": "-1",
        "name": ""
       },
       {
        "size": "10",
        "name": ""
       }
      ],
      "unknown_rank": false
     },
     "name": "StatefulPartitionedCall:0"
    }
   },
   "method_name": "tensorflow/serving/predict"
  },
  "__saved_model_init_op": {
   "inputs": {},
   "outputs": {
    "__saved_model_init_op": {
     "dtype": "DT_INVALID",
     "tensor_shape": {
      "dim": [],
      "unknown_rank": true
     },
     "name": "NoOp"
    }
   },
   "method_name": ""
  }
 }
}
}
}
728x90

이 글을 공유하기

댓글

Designed by JB FACTORY