โจ ๋ชจ๋ธ์ ์ผ๋จ ๋ง๋ค๊ณ ๋๋ฉด ์ฐธ์ผ๋ก ๋ฟ๋ฏํ์ฃ !
๐ ๊ทธ๋ฐ๋ฐ, ์ด ๋ชจ๋ธ์ ๋งค๋ฒ ๋ก์ปฌ์์ ๋์ฐ๊ณ ์ถ๋ก ์ ๋ฐ๋ณตํ๋ ์ผ์ ๋นํจ์จ์ ์
๋๋ค.
๐ ๊ทธ๋ฆฌ๊ณ , ๋ค๋ฅธ ์์คํ
์ด๋ ์ฐ๊ณ๋ ์ด๋ ต์ฃ !
โ ๊ทธ๋์ ๋ณดํต, ํ์ต๋ ML model์ ๋ฐ๋ก ML ์ถ๋ก ์๋ฒ๋ฅผ ๋์ REST API๋ฅผ ํ์ฉํ์ฌ ์๋นํฉ๋๋ค.
โ ๊ฐ๋จํ๊ฒ๋ Flask / Django ๋ฑ์ Python Web Framework๋ฅผ ํ์ฉํ์ฌ๋ ML model์ ์๋นํ ์ ์์ต๋๋ค.
๐ ๊ทธ๋ฌ๋ ์ค๋์...!
๐ ์ฌ์ฉ์ ๊ฐ๋จํ์ง๋ง, ๊ทธ ์ฑ๋ฅ์ ๊ฐ๋ ฅํ๋ค๊ณ ์๋ฌธ๋ ML serving framework : bentoml์ ๊ฐ๋จํ ๋ค๋ค๋ณด๋ ค ํฉ๋๋ค :)
(์ถํ ๊ธฐํ๊ฐ ๋๋ค๋ฉด Flask๋ก ๋์ ์ ๋์ ๊ฐ๋จํ ์ฑ๋ฅ ๋น๊ต๋ ์งํํ๋ฉด ์ฌ๋ฐ์ ๊ฒ ๊ฐ๋ค์.)
๊ฐ๋ณ๊ฒ ์์ํด๋ณด๊ฒ ์ต๋๋ค :)
BentoML is an open platform that simplifies ML model deployment and enables you to serve your models at production scale in minutes.
https://docs.bentoml.org/en/latest/index.html
โ ๊ฐ๋จํ๊ฒ! PRODUCTION SCALE์ model serving์ ๊ฐ๋ฅํ๊ฒ ํ๋ ํ๋ซํผ!
โ ์ค์ ๋ก ML ๋ชจ๋ธ์ ์ด์ ์๋น์ค์ ์๋นํ๋ค ๋ณด๋ฉด, production์ ์ ์ฉํ๋ค๋ ๊ฒ์ ์ค์ local์์ ํ
์คํธ ํ๋ ๊ฒ๊ณผ ๋ง์ด ๋ค๋ฆ
๋๋ค.
https://github.com/ucbrise/clipper (์๋ .. ๋ค์ ๋ณด์ง ๋ง์..)
โ ํด๋น ์ํฉ์์ ์๋ฒฝํ ์๋ฌ์ ์์ธ์ ์ถ๋ก ํ์ง ๋ชปํ์ง๋ง (์ ๋ ํด๋น ์๋น์ค์ ์ด์ฉ์ ์
์ฅ์ด์๊ธฐ์), ์ด์ฐ๋์๊ฑด ๋งน์ ์ธ ๋ถ๋ถ์ ๋ถํ ๋ถ์ฐ์ ์คํจ ์์ต๋๋ค.
โ ์ด๋ป๊ฒ ๊ธธ๊ฒ ๊ธธ๊ฒ ๋งํ์ง๋ง.. BentoML์ ๋ ๋ถํ๋ถ์ฐ ์ชฝ์ผ๋ก ๊ฐ๋ ฅํ๋ค๊ณ ์ด์ผ๊ธฐ ํ๋, ๊ธฐ๋๊ฐ ๋ฉ๋๋ค. ๐
โ GPU ์ฌ์ฉ ๊ฐ๋ฅํ Workstation : nvidia GTX 1660 Ti (GPU๋ ์ค๋์ ์์ด๋ OK!)
โ IDE : VScode
โ ๊ด๋ จ driver ์ค์น
โ ๋ฆฌ๋
์ค ์ปค๋ (WSL2 ์ฌ์ฉ, ํ๋จ ์ฐธ๊ณ ํ์ด์ง์ WSL2 ์ฌ์ฉ์ cuda ์ค์น ํ์ด์ง ์ฒจ๋ถ)
โ bentoml v1.0 : ์์ง ์ ์ ๋ฐฐํฌ๋์ง ์์ pre ๋ฒ์ ์
๋๋ค.
โ anaconda ๊ฐ์ํ๊ฒฝ ์ฌ์ฉ
โจ ๊ฐ๋ณ-๊ฒ bentoml์ quickstart๋ฅผ ๋ฐ๋ผํ๋ฉฐ ํด ๋ด ๋๋ค.
โ ์๋ ์ฝ๋๋ v1.0 ๊ธฐ์ค์ผ๋ก, pre-release version ์ฝ๋์ ๋๋ค.
pip install bentoml --pre
๐ ์๋ ์ฝ๋๋ iris dataset์ผ๋ก sklearn framework ๊ธฐ๋ฐ์ SVM ๋ชจ๋ธ์ ํ์ตํ๊ณ , BentoML ๋ก์ปฌ ์ ์ฅ์์ ์ ์ฅํ๋ ์ฝ๋์
๋๋ค.
๐ฃ ์ํ! ์ด๋ ๊ฒ ๋ณด๋ ์ง์ง ๋ฒค๋(๋์๋ฝ)์ ๋ชจ๋ธ์ ์ ์ฅํ๋ ๋๋์ด๋ค์ :)
import bentoml
from sklearn import svm
from sklearn import datasets
# Load predefined training set to build an example model
iris = datasets.load_iris()
X, y = iris.data, iris.target
# Model Training
clf = svm.SVC(gamma='scale')
clf.fit(X, y)
# Call to bentoml.<FRAMEWORK>.save(<MODEL_NAME>, model)
# In order to save to BentoML's standard format in a local model store
# bentoml.sklearn.save("iris_clf", clf)
# 03/21/22 22:43:57 INFO [cli] Successfully saved
# Model(tag="iris_clf:6tmyatnjdsg5kaav", path="/home/kang/bentoml/models/iris_clf/6tmyatnjdsg5kaav/")
โ ์ ๋ ์์ ์ฝ๋๋ฅผ ์ ์ํฌ์คํ ์ด์ ์์ ์ํํ๊ณ , ์๋์ ๊ฐ์ ์ ์์ ์ผ๋ก save ๋์๋ค๋ ๊ฒฐ๊ณผ๋ฅผ ๋ฆฌํด๋ฐ์์ต๋๋ค.
โ "latest"๋ผ๋ tag๋ฅผ ํ์ฉํ์ฌ ๋ฒ์ ๊ด๋ฆฌ๋ฅผ ํ๋ ๊ฒ์ผ๋ก ๋ณด์ ๋๋ค. (๋์ปค ์ด๋ฏธ์ง์ ์ ์ฌ)
import bentoml
import numpy as np
iris_clf_runner = bentoml.sklearn.load_runner("iris_clf:latest")
iris_clf_runner.run(np.array([5.9, 3. , 5.1, 1.8]))
โ ์๋ ์ฝ๋๋ก ๊ฐ๋จํ ML Serving ์๋ฒ๋ฅผ ๋์ธ ์ ์์ต๋๋ค :)
# service.py
import numpy as np
import bentoml
from bentoml.io import NumpyNdarray
# ์ด์ ํ์ต์ ์งํํ ๋ชจ๋ธ์ ๋ก๋ํด์ฃผ๊ณ ,
iris_clf_runner = bentoml.sklearn.load_runner("iris_clf:latest")
# ์์ ๋ชจ๋ธ์ "runner"๋ก ์ฌ์ฉํ๋ "bentoml service"๋ฅผ ์์ฑํฉ๋๋ค.
# ๋ง์ฝ, runner๊ฐ ์ฌ๋ฌ๊ฐ๋ฉด, runners ์ธ์์ list ์์ ๋ชจ๋ ์ ์ํ์ฌ์ผ ํฉ๋๋ค.
# ๋ชจ๋ ๋ชจ๋ธ์ ๊ฐ์ง๊ณ , "๋์๋ฝ์ ์ธ๋ ๊ฑฐ์ฃ !"
svc = bentoml.Service("iris_classifier", runners=[iris_clf_runner])
# ๊ทธ๋ฆฌ๊ณ , ์์์ ์ ์ํ "bentoml service"๋ฅผ ์ด๋
ธํ
์ด์
์ผ๋ก ์ฌ์ฉํ์ฌ, ์ถ๋ก ํจ์๋ฅผ ์ ์ํฉ๋๋ค.
# pre / post processing ๋ก์ง๋ ์ ์ํฉ๋๋ค.
@svc.api(input=NumpyNdarray(), output=NumpyNdarray())
def classify(input_series: np.ndarray) -> np.ndarray:
# Define pre-processing logic
result = iris_clf_runner.run(input_series)
# Define post-processing logic
return result
โจ ๋ง ๊ทธ๋๋ก, ์ฌ๋ฌ ๋ชจ๋ธ์ "๋์๋ฝ์ผ๋ก ์ธ๊ณ ", ๊ทธ ๋์๋ฝ์ ์ธ๋ค๊ณ ์ด๋
ธํ
์ด์
์ผ๋ก "๋ง๋๊ฒ ์๋นํ๋ฉด" ๋๋ค์ :)
๐ input๊ณผ output type์ ์์ ์์์ฒ๋ผ numpy.ndarray๋ฅผ ๊ธฐ๋ณธ์ ์ผ๋ก ์ง์ํ๋ฉฐ, ๊ทธ ์ธ์ pandas.DataFrame / PIL.Image๋ฅผ ์ง์ํ๋ค๊ณ ํฉ๋๋ค. ๊ทธ ์ธ์๋ ๊ณต์ ๋ฌธ์ ์ฐธ์กฐ!
โ service.py๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์๋น!
โ --reload ์ต์
์ ์์ค์ ๋ณํ๊ฐ ์๊ธฐ๋ฉด ์ฌ์์ ์์ด ๋ฐ์ํ๋ ์ต์
์
๋๋ค :)
bentoml serve ./service.py:svc --reload
๐ ๊ฐ๋จํ ๊ฒฐ๊ณผ๊น์ง ํ์ธ!
import requests
res = requests.post(
"http://127.0.0.1:3000/classify",
headers={"content-type": "application/json"},
data="[5,4,3,2]").text
print(res)
# 1
๐ ๊ฐ๋จํ ์๋ yaml file์ ์์ฑํ๊ณ ,
# bentofile.yaml
service: "service.py:svc" # A convention for locating your service: <YOUR_SERVICE_PY>:<YOUR_SERVICE_ANNOTATION>
description: "file: ./README.md"
labels:
owner: bentoml-team
stage: demo
include:
- "*.py" # A pattern for matching which files to include in the bento
python:
packages:
- scikit-learn # Additional libraries to be included in the bento
- pandas
โ README.md ํ์ผ์ bentofile.yaml ํ์ผ๊ณผ ๊ฐ์ ์์น์ ์ ์ฅํด์ค๋๋ค.
touch README.md
๐ ๊ทธ๋ฆฌ๊ณ , CLI์์ bento๋ฅผ ๋น๋ํฉ๋๋ค!
bento build
โ bento list ๋ช
๋ น์ด๋ก ์์ฑ๋ bento๋ฅผ ํ์ธํ ์ ์์ฃ :)
โจ ๋์ปค ์ด๋ฏธ์ง ๋น๋์ ๊ฐ์ ๋๋!
bento list
Tag Service Path Size Creation Time
iris_classifโฆ service:svc /home/kang/bโฆ 15.42 KiB 2022-03-21
15:23:23
๐ ๋๋์ด ์์ฑ๋ Bento(์ด๋ฏธ์ง)๋ก production serving์ ์์ํฉ๋๋ค!
bentoml serve iris_classifier:latest --production
๐ ๊ฐ๋จํ ๊ฒฐ๊ณผ๊น์ง ํ์ธ!
import requests
res = requests.post(
"http://127.0.0.1:3000/classify",
headers={"content-type": "application/json"},
data="[5,4,3,2]").text
print(res)
# 1
๐ ์ค๋์ ๊ฐ๋จํ์ ์ด์ ์ ๋ ๊น๊ฒ ๋ BentoML ํํ ๋ฆฌ์ผ์ ์งํํด ๋ณด์์ต๋๋ค.
๐ "๋์๋ฝ"์ด๋ผ๋ ์๋ฏธ ๊ทธ๋๋ก ์ฅ์ฅ ์ธ์ ๊ทธ๋๋ก Serving(ํ๋งค)๊น์ง ์์ํ ์งํํ ์ ์๋ ์ ๊ทผ์ฑ ์ข์ ํ๋ ์์ํฌ์์ ํ๋ฆผ์์ด ๋ณด์
๋๋ค :)
๐ ๋ค์ ๊ธ์๋ ์ค์ ์๋ฏธ๊ฐ ์๋ ๋ชจ๋ธ์ ๊ฐ์ ธ์์, ์ฑ๋ฅ ๋น๊ต๋ ํด๋ณด๊ณ
(๋ก์ปฌ์ด๋ผ์ ๊ฐ๋ฅํ ์ง๋ ๋ชจ๋ฅด๊ฒ ์ต๋๋ค๋ง...ใ
) ์ข ๋ Advancedํ ๊ธฐ๋ฅ๋ ์ฌ์ฉํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค!
โ https://www.lainyzine.com/ko/article/how-to-install-wsl2-and-use-linux-on-windows-10/
โ https://zzsza.github.io/mlops/2021/04/18/bentoml-basic/