papermaill을 사용하여 ipynb에서 웹 서버 구축
TL;DR
기계 학습에 관한 시스템 개발은jupyter에서 모델을 개발한 후 활용할 때python 파일로 바꾸는 상황을 볼 수 있다.
이번에는 다시 쓰지 않아도 활용할 수 있도록 ipynb 파일에 공유해 웹 서버를 구축하는 방법입니다.
ipynb 파일의 실행은papermaill이라는 프로그램 라이브러리를 사용합니다.
또한 이 문서에 기재된 모든 코드는 아래 창고에 저장됩니다.
단계
최종 파일 구성
최종적으로 다음 파일 구조를 만듭니다.
./
├── model # ステップ1で作成
├── requirements.txt # ステップ2で作成
├── main.ipynb # ステップ2で作成
├── docker-compose.yml # ステップ3で作成
└── dockerfile # ステップ3で作成
1. 테스트용 모델 구축
아이리스 데이터 세트를 사용하여 간단한 SVC 모델을 만듭니다.
import pickle
import numpy as np
from sklearn.svm import SVC
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
iris_dataset = load_iris()
x = iris_dataset["data"]
y = iris_dataset["target"]
x_train, x_test, y_train, y_test = train_test_split(
x,
y,
test_size = 0.2,
train_size = 0.8,
shuffle = True)
clf = SVC(gamma='scale')
clf.fit(x_train, y_train)
y_pred = clf.predict(x_test)
print(accuracy_score(y_test, y_pred))
filename = 'model'
pickle.dump(clf, open(filename, 'wb'))
clf = pickle.load(open(filename, 'rb'))
y_pred = clf.predict(x_test)
print(accuracy_score(y_test, y_pred))
2. 노트북으로 제작 예측
papermaill에서 호출된 Requirements.txt 파일과 ipynb 파일을 만듭니다.python 서버라면
WSGI와 ASGI가 있어 참고로 양측을 준비했다.
또한 이번 WSGI는 wsgiref를, ASGI는 uvicorn을 사용했으니 좋아하는 사람을 이용할 수 있을 것 같다.
WSGI의 경우
# requirements.txt
sklearn
numpy
papermill
# main.ipynb
import json
import pickle
import numpy as np
from datetime import datetime
from wsgiref.util import setup_testing_defaults
from wsgiref.simple_server import make_server
PORT = 8000
class ModelPredictor:
def __init__(self):
self.model = pickle.load(open('model', 'rb'))
def main(self,data):
return json.dumps({"val": self.predict(self.prep(data))} ,cls = NumpyEncoder).encode()
def prep(self,data):
return [[ data['sepal length (cm)'],
data['sepal width (cm)'],
data['petal length (cm)'],
data['petal width (cm)']]]
def predict(self,data):
return self.model.predict(data)[0]
class NumpyEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, np.integer):
return int(obj)
elif isinstance(obj, np.floating):
return float(obj)
elif isinstance(obj, np.ndarray):
return obj.tolist()
else:
return super(NumpyEncoder, self).default(obj)
prd_controller = ModelPredictor()
prd_controller.predict(
{"sepal length (cm)": 1,
"sepal width (cm)": 1,
"petal length (cm)": 1,
"petal width (cm)":1})
def simple_app(environ, start_response):
setup_testing_defaults(environ)
wsgi_input = environ["wsgi.input"]
content_length = int(environ["CONTENT_LENGTH"])
data = json.loads(wsgi_input.read(content_length))
print(wsgi_input)
print(data)
status = '200 OK'
headers = [('Content-type', 'text/plain; charset=utf-8')]
ret = [prd_controller.main(data)]
start_response(status, headers)
return ret
with make_server('0.0.0.0', PORT, simple_app) as httpd:
print(f"Serving on port {PORT}...")
httpd.serve_forever()
ASGI의 경우
# requirements.txt
sklearn
numpy
papermill
uvicorn
# main.ipynb
import json
import pickle
import uvicorn
import numpy as np
import nest_asyncio
from datetime import datetime
nest_asyncio.apply()
PORT = 8000
class ModelPredictor:
def __init__(self):
self.model = pickle.load(open('model', 'rb'))
def predict(self,body):
rt_val = self.model.predict([[
body['sepal length (cm)'],
body['sepal width (cm)'],
body['petal length (cm)'],
body['petal width (cm)']]])
return json.dumps({"val": rt_val[0]}, cls=NumpyEncoder).encode()
class NumpyEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, np.integer):
return int(obj)
elif isinstance(obj, np.floating):
return float(obj)
elif isinstance(obj, np.ndarray):
return obj.tolist()
else:
return super(NumpyEncoder, self).default(obj)
prd_controller = ModelPredictor()
prd_controller.predict(
{"sepal length (cm)": 1,
"sepal width (cm)": 1,
"petal length (cm)": 1,
"petal width (cm)":1})
async def read_body(receive):
body = b''
more_body = True
while more_body:
message = await receive()
body += message.get('body', b'')
more_body = message.get('more_body', False)
return json.loads(body)
async def app(scope, receive, send):
body = await read_body(receive)
ret = prd_controller.predict(body)
await send({
'type': 'http.response.start',
'status': 200,
'headers': [
[b'content-type', b'text/plain'],
]
})
await send({
'type': 'http.response.body',
'body': ret,
})
uvicorn.run(app, host="0.0.0.0", port=PORT, log_level="info")
3. 서버용 docker 이미지 만들기
예측 웹 서버의 docker 이미지를 만들기 위해 dockerfile을 기술합니다.
main
papermill main.ipynb out.ipynb
에서ipynb 파일을 실행한 결과out입니다.ipynb로 출력합니다.이번에는 컨테이너의 운행에 docker-compose, docker-compose를 사용하기 위해서입니다.제작도 가능합니다.
# dockerfile
FROM jupyter/datascience-notebook:latest
WORKDIR /home/jovyan
COPY model ./
COPY main.ipynb ./
COPY requirements.txt ./
RUN pip install -r requirements.txt
ENTRYPOINT [ "papermill","main.ipynb","out.ipynb"]
# docker-compose.yml
version: '3'
services:
notebook_server:
build: .
container_name: notebook_server
hostname: notebook_server
restart: always
ports:
- 8000:8000
4. 동작 확인
다음 명령을 실행하여 구축 후curl을 통해 동작을 확인합니다.{"val": INTEGER} 형식으로 데이터를 반환하면 성공합니다.
$ docker-compose up -d
$ curl -X POST -H "Content-Type: application/json" -d '{ "sepal length (cm)": 1, "sepal width (cm)": 1, "petal length (cm)": 1, "petal width (cm)":1}' localhost:8000
{"val": 0}
감상
소개는 했지만 다음과 같은 몇 가지 점에서 추천하지 않습니다.
Reference
이 문제에 관하여(papermaill을 사용하여 ipynb에서 웹 서버 구축), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/uniocto/articles/696883e30f7c0eca46f9텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)