[一日30分 인생승리의 학습법] [Tensorflow] Serving이용하여 REST API 만들기

IRIS예제를 이용하여 텐서플로 딥러닝 모델을 만들고

REST API를 통해 예측하는 시스템을 만들어보겠습니다.

1) 텐서플로와 텐서플로 서빙 도커 이미지를 다운받습니다

docker pull tensorflow/tensorflow:1.13.1-py3-jupyter docker pull tensorflow/serving:1.13.0

트레이닝하고 모델을 저장할 버전과 서빙할 버전의 메이저 버전이 같도록 하는 것을 권장합니다

2) 텐서플로 컨테이너를 실행합니다

docker run --name my_tf -it -p 8881-8889:8881-8889 -v C:\notebooks\:/notebooks/ tensorflow/tensorflow:1.13.1-py3-jupyter bash

호스트시스템의 경로를 C:\notebooks로 지정했는데 자신의 환경에 맞게 변경할 수 있습니다

3) 주피터 노트북을 실행합니다

cd /notebooks && jupyter notebook --allow-root --ip=0.0.0.0 --port=8881 &

참고로 주피터 노트가 아닌 vim 등을 통해 직접 소스코드를 작성하셔도 됩니다.

4) 웹 브라우저로 접속합니다

http://localhost:8881/

5) Iris 트레이닝하고 모델을 결과로 저장하는 소스코드를 작성하고 실행합니다

# 필요한 모듈을 추가로 설치한다 !pip install sklearn # 사용할 모듈을 불러온다 from os import path, listdir from shutil import copytree from sklearn import datasets from sklearn.model_selection import train_test_split import tensorflow as tf # 텐서플로 모듈을 불러온다 print('tensorflow version:', tf.__version__) from tensorflow import estimator iris = datasets.load_iris() # Iris 데이터 읽어온다 x = iris.data y = iris.target # 트레이닝셋과 검증셋으로 분리한다 x_train, x_eval, y_train, y_eval = train_test_split(x, y, test_size=0.2) model_dir = './iris/' # 모델을 저장할 디렉토리 model_name = 'iris_dnn' # 모델명 num_epochs = 20 # 에폭(입력 데이터를 몇회 순환할지) train_input_fn = estimator.inputs.numpy_input_fn(x={'x':x_train}, y=y_train, num_epochs=num_epochs, shuffle=True) train_spec = estimator.TrainSpec(input_fn=train_input_fn) eval_input_fn = estimator.inputs.numpy_input_fn(x={'x':x_eval}, y=y_eval, num_epochs=1, shuffle=False) # 서빙의 입력 메타를 정의합니다 def serving_input_receiver_fn(): receiver_tensors = { 'sepal_length': tf.placeholder(tf.float32, [None, 1]), 'sepal_width' : tf.placeholder(tf.float32, [None, 1]), 'petal_length': tf.placeholder(tf.float32, [None, 1]), 'petal_width' : tf.placeholder(tf.float32, [None, 1]), } features = { 'x': tf.concat([ receiver_tensors['sepal_length'], receiver_tensors['sepal_width'], receiver_tensors['petal_length'], receiver_tensors['petal_width'] ], axis=1) } return tf.estimator.export.ServingInputReceiver(receiver_tensors=receiver_tensors, features=features) # 최근 모델을 저장할 Exporter latest_exporter = estimator.LatestExporter(name='latest_exporter', serving_input_receiver_fn=serving_input_receiver_fn) # 가장 좋은 모델을 저장할 Exporter best_exporter = estimator.BestExporter(name='best_exporter', serving_input_receiver_fn=serving_input_receiver_fn) exporters = [latest_exporter, best_exporter] eval_spec = estimator.EvalSpec(input_fn=eval_input_fn, throttle_secs=10, exporters=exporters) classifier = estimator.DNNClassifier(config=estimator.RunConfig(model_dir=model_dir), feature_columns=[tf.feature_column.numeric_column('x', shape=[4])], hidden_units=[20], n_classes=3, model_dir=model_dir) tf.estimator.train_and_evaluate(classifier, train_spec=train_spec, eval_spec=eval_spec) def get_abs_directory_list(in_path): """입력된 경로의 (절대경로)디렉토리 목록을 가져옵니다""" out_paths = [] out_ids = [] if path.exists(in_path) and len(listdir(in_path)) >=1: for id in listdir(in_path): abs_dir = path.join(in_path, id) if path.isdir(abs_dir): out_paths.append(abs_dir) out_ids.append(id) return out_paths, out_ids # 가장 좋은 모델이 저장된 디렉토리 best_exporter_path = path.join(model_dir, 'export', 'best_exporter') src_paths, src_ids = get_abs_directory_list(best_exporter_path) # 서빙되고 있는 모델이 저장된 디렉토리 serving_exporter_path = path.join(model_dir, 'export', 'serving_exporter', model_name) _, des_ids = get_abs_directory_list(serving_exporter_path) for idx, src_path in enumerate(src_paths): # 순회 if src_ids[idx] not in des_ids: # 신규 모델이라면 copytree(src_path, path.join(serving_exporter_path, src_ids[idx])) # 복사한다 print(str(src_ids[idx]) + ' copy!')

iris 디렉토리의 트리구조입니다.

latest_exporter에 최근 모델들이 있고 가장 좋은 모델이 best_exporter에 존재합니다.

(1번만 트레이닝했을 때 best_exporter가 없을 수 있으므로 2회 이상 트레이닝을 해주세요)

best_exporter의 모델을 서빙하기 위해 serving_exporter로 복사합니다.

참고로 serving_exporter의 디렉토리 구조는 하위에 모델명 하위에 모델번호입니다.

6) 텐서플로 서빙 컨테이너를 3개 실행합니다 (운영환경에서 안정적인 운영을 위해 2개 이상을 권장합니다)

컨테이너 실행 환경변수 모델명이 iris_dnn입니다, 모델을 저장했던 serving_exporter 하위 폴더 iris_dnn과 일치합니다

docker run --rm --name serving_1 -v C:\notebooks\iris\export\serving_exporter:/models/ -p 8501:8501 -e MODEL_NAME=iris_dnn -e MODEL_BASE_PATH=/models tensorflow/serving:1.13.0 docker run --rm --name serving_2 -v C:\notebooks\iris\export\serving_exporter:/models/ -p 8502:8501 -e MODEL_NAME=iris_dnn -e MODEL_BASE_PATH=/models tensorflow/serving:1.13.0 docker run --rm --name serving_3 -v C:\notebooks\iris\export\serving_exporter:/models/ -p 8503:8501 -e MODEL_NAME=iris_dnn -e MODEL_BASE_PATH=/models tensorflow/serving:1.13.0

serving1번 컨테이너는 8501번 포트, 2번 컨테이너는 8502번 포트,

3번 컨테이너는 8503번 포트를 서비스 합니다.

기동 로그를 살펴보시면 모델번호 1560950528를 예약 > 승인 > 로딩합니다.

텐서플로 서빙이 정상 기동되었습니다

경축! 아무것도 안하여 에스천사게임즈가 새로운 모습으로 재오픈 하였습니다.
어린이용이며, 설치가 필요없는 브라우저 게임입니다.
https://s1004games.com

7) 호스트 PC 또는 호스트 서버 등에서 API를 호출해 봅니다

요청URL 형식

POST http://host:port/v1/models/${MODEL_NAME}[/versions/${MODEL_VERSION}]:(predict|classify|regress) # /versions/${MODEL_VERSION}는 생략가능하며 생략 시 가장 최신 모델이 실행됩니다 요청예시) POST http://host:port/v1/models/MY_MODEL:predict

요청메시지 형식( instances 대신 inputs형식도 가능합니다 )

{"signature_name": <string>, "instances": <value>|<(nested)list>|<list-of-objects>} 인스턴스예시) json과 유사함 "instances": [ { "f1": [1, 2, 3, 4, 5], "f2": [[1, 2], [3, 4]] }, { "f1": [3, 4, 1, 2, 5]], "f2": [[4, 5], [6, 8]] } ]

[리눅스 또는 Mac curl 명령어]

curl -X POST http://127.0.0.1:8501/v1/models/iris_dnn:predict -d '{"signature_name":"predict","instances":[{"sepal_length":[5.0],"sepal_width":[3.3],"petal_length":[1.4],"petal_width":[0.2]}]}' curl -X POST http://127.0.0.1:8501/v1/models/iris_dnn:predict -d '{"signature_name":"predict","instances":[{"sepal_length":[5.7],"sepal_width":[2.8],"petal_length":[4.1],"petal_width":[1.3]}]}' curl -X POST http://127.0.0.1:8501/v1/models/iris_dnn:predict -d '{"signature_name":"predict","instances":[{"sepal_length":[5.9],"sepal_width":[3.0],"petal_length":[5.1],"petal_width":[1.8]}]}'

[원도우 curl 명령어] (따옴표에 주의합니다)

curl -X POST http://127.0.0.1:8501/v1/models/iris_dnn:predict -d "{""signature_name"":""predict"",""instances"":[{""sepal_length"":[5.0],""sepal_width"":[3.3],""petal_length"":[1.4],""petal_width"":[0.2]}]}" curl -X POST http://127.0.0.1:8501/v1/models/iris_dnn:predict -d "{""signature_name"":""predict"",""instances"":[{""sepal_length"":[5.7],""sepal_width"":[2.8],""petal_length"":[4.1],""petal_width"":[1.3]}]}" curl -X POST http://127.0.0.1:8501/v1/models/iris_dnn:predict -d "{""signature_name"":""predict"",""instances"":[{""sepal_length"":[5.9],""sepal_width"":[3.0],""petal_length"":[5.1],""petal_width"":[1.8]}]}"

3개 명령어를 실행하면 아래와 같은 결과가 나옵니다

0번 클래스로 분류 (정답)

1번 클래스로 분류 (정답)

2번 클래스로 분류 (정답)

만약 아래와 같은 오류 메시지에 주의하십시요

Failed to connect to 127.0.0.1 port 8501: Connection refused ==> 포트가 막혀있거나 컨테이너가 제대로 기동되지 않았습니다
{ "error": "Servable not found for request: Latest(iris_dnn)" } ==> 서빙은 기동되었으나 모델 디렉토리가 잘못되었거나 모델이 없습니다

8) 5번으로 올라가서 다시 실행해봅니다(트레이딩 + 더 좋은 모델 발견)

다시 돌려보니 1560950528보다 더 좋은 1560950530가 나왔습니다.

현재 떠 있는 서빙 로그를 살펴보면 1560950530을 먼저 기동하여 정상을 확인한 후

1560950528 모델을 내리는 것을 확인할 수 있습니다.

자동으로 더 좋은 베스트모델이 서비스하고 구 모델은 종료합니다

텐서플로 서빙은 모델번호가 가장 큰 숫자의 모델을 자동으로 로딩하고 이전 모델은 종료합니다.

여기까지 IRIS예제를 이용하여 텐서플로 모델을 만들고 실제 서빙하는 실습을 해보았습니다.

끝.

[출처] https://blog.naver.com/wideeyed/221566170795

 

 

 

 

 

본 웹사이트는 광고를 포함하고 있습니다.
광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.
번호 제목 글쓴이 날짜 조회 수
» [一日30分 인생승리의 학습법] [Tensorflow] Serving이용하여 REST API 만들기 file 졸리운_곰 2021.08.07 13
1034 [一日30分 인생승리의 학습법] Amazon SageMaker는 처음이지? 누워서 머신러닝 학습부터 배포까지 file 졸리운_곰 2021.08.05 31
1033 [一日30分 인생승리의 학습법] Apache Beam (Dataflow)를 이용하여, 이미지 파일을 tfrecord로 컨버팅 하기 file 졸리운_곰 2021.08.04 4
1032 [一日30分 인생승리의 학습법] [GCP] Apache Beam 사용하기 file 졸리운_곰 2021.08.04 5
1031 [一日30分 인생승리의 학습법] Apache Beam, Apache Airflow, Apache Atlas 설명 졸리운_곰 2021.08.04 8
1030 [一日30分 인생승리의 학습법] 블레이저 웹어셈블리 (web assembly, WASM_ Awesome Blazor ) 놀라운 오픈소스 리스트 (open source) file 졸리운_곰 2021.08.04 4928
1029 MarkDown 사용법 총정리 file 졸리운_곰 2021.07.29 23
1028 [一日30分 인생승리의 학습법] [JWT/JSON Web Token] 로그인 / 인증에서 Token 사용하기 file 졸리운_곰 2021.07.24 8
1027 [一日30分 인생승리의 학습법] JWT(JSON Web Token)을 이용한 API 인증 - #1 개념 소개 file 졸리운_곰 2021.07.24 10
1026 [一日30分 인생승리의 학습법] XPath 란 무엇입니까? file 졸리운_곰 2021.07.24 5
1025 [一日30分 인생승리의 학습법] XPATH 사용법·작성법 file 졸리운_곰 2021.07.24 8
1024 [Git] Github에 잘못 올라간 파일 삭제하기 졸리운_곰 2021.07.13 16
1023 [一日30分 인생승리의 학습법]AI 한국어 자연어 처리 데이터셋 목록 file 졸리운_곰 2021.07.10 23
1022 [一日30分 인생승리의 학습법] 기계독해, MRC란 무엇일까 file 졸리운_곰 2021.07.10 37
1021 [一日30分 인생승리의 학습법] 웹어셈블리를 활용한 유망한 프로그래밍 언어 프로젝트 10가지 졸리운_곰 2021.07.02 13
1020 [一日30分 인생승리의 학습법] Windows 10에 Minikube 설치하기 file 졸리운_곰 2021.06.27 26
1019 [一日30分 인생승리의 학습법] 윈도우2016 서버에 Docker 설치하며 겪은 시행착오 기록 file 졸리운_곰 2021.06.26 11
1018 [초보용] Git 되돌리기( Reset, Revert ) file 졸리운_곰 2021.06.22 15
1017 [DOCKER] Windows Server 2016에서 도커 설치하기 졸리운_곰 2021.06.13 39
1016 [docker, windows server 2016] Installing Docker onto Windows Server 2016 file 졸리운_곰 2021.06.13 6
대표 김성준 주소 : 경기 용인 분당수지 U타워 등록번호 : 142-07-27414
통신판매업 신고 : 제2012-용인수지-0185호 출판업 신고 : 수지구청 제 123호 개인정보보호최고책임자 : 김성준 sjkim70@stechstar.com
대표전화 : 010-4589-2193 [fax] 02-6280-1294 COPYRIGHT(C) stechstar.com ALL RIGHTS RESERVED