[MLOps] ๐Ÿฑ BentoML - 1

๊ฐ•์ฝฉ์ฝฉยท2022๋…„ 3์›” 21์ผ
0

MLOps

๋ชฉ๋ก ๋ณด๊ธฐ
1/2
post-thumbnail

โœจ ๋ชจ๋ธ์„ ์ผ๋‹จ ๋งŒ๋“ค๊ณ  ๋‚˜๋ฉด ์ฐธ์œผ๋กœ ๋ฟŒ๋“ฏํ•˜์ฃ !
๐Ÿ˜ ๊ทธ๋Ÿฐ๋ฐ, ์ด ๋ชจ๋ธ์„ ๋งค๋ฒˆ ๋กœ์ปฌ์—์„œ ๋„์šฐ๊ณ  ์ถ”๋ก ์„ ๋ฐ˜๋ณตํ•˜๋Š” ์ผ์€ ๋น„ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค.
๐Ÿ˜‰ ๊ทธ๋ฆฌ๊ณ , ๋‹ค๋ฅธ ์‹œ์Šคํ…œ์ด๋ž‘ ์—ฐ๊ณ„๋„ ์–ด๋ ต์ฃ !

โœ” ๊ทธ๋ž˜์„œ ๋ณดํ†ต, ํ•™์Šต๋œ ML model์€ ๋”ฐ๋กœ ML ์ถ”๋ก  ์„œ๋ฒ„๋ฅผ ๋„์›Œ REST API๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์„œ๋น™ํ•ฉ๋‹ˆ๋‹ค.
โœ” ๊ฐ„๋‹จํ•˜๊ฒŒ๋Š” Flask / Django ๋“ฑ์˜ Python Web Framework๋ฅผ ํ™œ์šฉํ•˜์—ฌ๋„ ML model์„ ์„œ๋น™ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ™Œ ๊ทธ๋Ÿฌ๋‚˜ ์˜ค๋Š˜์€...!

๐Ÿ˜Ž ์‚ฌ์šฉ์€ ๊ฐ„๋‹จํ•˜์ง€๋งŒ, ๊ทธ ์„ฑ๋Šฅ์€ ๊ฐ•๋ ฅํ•˜๋‹ค๊ณ  ์†Œ๋ฌธ๋‚œ ML serving framework : bentoml์„ ๊ฐ„๋‹จํžˆ ๋‹ค๋ค„๋ณด๋ ค ํ•ฉ๋‹ˆ๋‹ค :)
(์ถ”ํ›„ ๊ธฐํšŒ๊ฐ€ ๋œ๋‹ค๋ฉด Flask๋กœ ๋„์› ์„ ๋•Œ์™€ ๊ฐ„๋‹จํ•œ ์„ฑ๋Šฅ ๋น„๊ต๋„ ์ง„ํ–‰ํ•˜๋ฉด ์žฌ๋ฐŒ์„ ๊ฒƒ ๊ฐ™๋„ค์š”.)

๊ฐ€๋ณ๊ฒŒ ์‹œ์ž‘ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค :)

BentoML?

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์—์„œ ํ…Œ์ŠคํŠธ ํ•˜๋Š” ๊ฒƒ๊ณผ ๋งŽ์ด ๋‹ค๋ฆ…๋‹ˆ๋‹ค.

  • ๐Ÿ˜Ž ๋ชจ๋ธ ๋”ฑ ๋งŒ๋“ค๊ณ , Jupyter Notebook์—์„œ ๋กœ์ปฌ ์ถ”๋ก ์„ ์ˆ˜ํ–‰ํ•˜๋ฉด ๋‹ค ์ด๋ฃฌ๊ฒƒ ๊ฐ™์ง€๋งŒ...!
  • ๐Ÿคฆโ€โ™‚๏ธ ํ˜„์‹ค์€ ์กฐ๊ธˆ๋งŒ Serving ์„œ๋ฒ„์— ๋ถ€ํ•˜๊ฐ€ ๊ฐ€๋„ ํ„ฐ์ง€๊ณ .. ์‹ฌ์ง€์–ด ํ•˜๋‚˜์˜ ๋ชจ๋ธ์— ๋ถ€ํ•˜๊ฐ€ ์ง‘์ค‘๋˜๋ฉด, ์ž˜ ๋˜๋˜ ์˜† ๋ชจ๋ธ๊นŒ์ง€ ๊ฐ™์ด ๋ป—์–ด๋ฒ„๋ฆฌ๋Š”... ์ƒํ™ฉ๋„ ์ข…์ข… ๋ฐœ์ƒํ•˜๊ณค ํ•ฉ๋‹ˆ๋‹ค... ๐Ÿค”
    - ์ผ๋ก€๋กœ, ์˜ˆ์ „์— ์‚ฌ์šฉํ–ˆ๋˜ ML serving Engine ์ค‘ clipper๋ผ๋Š” ์—”์ง„์ด ์žˆ์—ˆ์ง€๋งŒ ๋ถ€ํ•˜๊ฐ€ ๋ชฐ๋ฆฌ๋ฉด ์‹ค์ œ PRODUCTION ์ƒํ™ฉ์—์„œ ์—”์ง„์ด ๋ฉˆ์ถฐ๋ฒ„๋ฆฌ๊ฑฐ๋‚˜ ํฌ๊ฒŒ ์ถ”๋ก  ์†๋„๊ฐ€ ์ €ํ•˜๋˜๋Š” ํ˜„์ƒ์ด ์—ฐ์† ๋ฐœ๊ฒฌ๋˜์–ด ๋”์ด์ƒ ํ™•์žฅ ์‚ฌ์šฉํ•˜์ง€ ๋ชปํ•œ ๊ฒฝ์šฐ๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

    https://github.com/ucbrise/clipper (์•ˆ๋…•.. ๋‹ค์‹  ๋ณด์ง€ ๋ง์ž..)

โœ” ํ•ด๋‹น ์ƒํ™ฉ์—์„œ ์™„๋ฒฝํ•œ ์—๋Ÿฌ์˜ ์›์ธ์€ ์ถ”๋ก ํ•˜์ง€ ๋ชปํ–ˆ์ง€๋งŒ (์ €๋Š” ํ•ด๋‹น ์„œ๋น„์Šค์˜ ์ด์šฉ์ž ์ž…์žฅ์ด์—ˆ๊ธฐ์—), ์–ด์ฐŒ๋˜์—ˆ๊ฑด ๋งน์ ์ธ ๋ถ€๋ถ„์€ ๋ถ€ํ•˜ ๋ถ„์‚ฐ์˜ ์‹คํŒจ ์˜€์Šต๋‹ˆ๋‹ค.
โœ” ์–ด๋–ป๊ฒŒ ๊ธธ๊ฒŒ ๊ธธ๊ฒŒ ๋งํ–ˆ์ง€๋งŒ.. BentoML์€ ๋” ๋ถ€ํ•˜๋ถ„์‚ฐ ์ชฝ์œผ๋กœ ๊ฐ•๋ ฅํ•˜๋‹ค๊ณ  ์ด์•ผ๊ธฐ ํ•˜๋‹ˆ, ๊ธฐ๋Œ€๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. ๐Ÿ™Œ

Pre-Setting

โœ” GPU ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ Workstation : nvidia GTX 1660 Ti (GPU๋Š” ์˜ค๋Š˜์€ ์—†์–ด๋„ OK!)
โœ” IDE : VScode
โœ” ๊ด€๋ จ driver ์„ค์น˜
โœ” ๋ฆฌ๋ˆ…์Šค ์ปค๋„ (WSL2 ์‚ฌ์šฉ, ํ•˜๋‹จ ์ฐธ๊ณ  ํŽ˜์ด์ง€์— WSL2 ์‚ฌ์šฉ์‹œ cuda ์„ค์น˜ ํŽ˜์ด์ง€ ์ฒจ๋ถ€)
โœ” bentoml v1.0 : ์•„์ง ์ •์‹ ๋ฐฐํฌ๋˜์ง€ ์•Š์€ pre ๋ฒ„์ „์ž…๋‹ˆ๋‹ค.
โœ” anaconda ๊ฐ€์ƒํ™˜๊ฒฝ ์‚ฌ์šฉ

Tutorial

https://docs.bentoml.org/en/latest/quickstart.html

โœจ ๊ฐ€๋ณ-๊ฒŒ bentoml์˜ quickstart๋ฅผ ๋”ฐ๋ผํ•˜๋ฉฐ ํ•ด ๋ด…๋‹ˆ๋‹ค.

anaconda ๊ฐ€์ƒํ™˜๊ฒฝ on!

linux cmd ์—์„œ bentoml ์„ค์น˜

โœ” ์•„๋ž˜ ์ฝ”๋“œ๋Š” v1.0 ๊ธฐ์ค€์œผ๋กœ, pre-release version ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

pip install bentoml --pre

๋ฐ˜์ฐฌ ๋งŒ๋“ค๊ธฐ : ๋ชจ๋ธ์„ BentoML์˜ local model store(๋กœ์ปฌ ์ €์žฅ์†Œ)์— ์ €์žฅ

๐Ÿ– ์•„๋ž˜ ์ฝ”๋“œ๋Š” 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]))

์‹œ์ œํ’ˆ ๋„์‹œ๋ฝ ๋งŒ๋“ค๊ธฐ : Service ์ƒ์„ฑ

โœ” ์•„๋ž˜ ์ฝ”๋“œ๋กœ ๊ฐ„๋‹จํžˆ 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๋ฅผ ์ง€์›ํ•œ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ ์™ธ์—๋Š” ๊ณต์‹ ๋ฌธ์„œ ์ฐธ์กฐ!

์‹œ์ œํ’ˆ ๋„์‹œ๋ฝ ๋ง›๋ณด๊ธฐ : Serving!

โœ” 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

๋„์‹œ๋ฝ ๋Œ€๋Ÿ‰ ํŒ๋งค : Build & Serve!

๐Ÿ˜Ž ๊ฐ„๋‹จํžˆ ์•„๋ž˜ 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/

  • WSL2 ์„ค์น˜

โœ” https://velog.io/@jaehyeong/WSL2-%EC%B4%88%EA%B0%84%EB%8B%A8-%EC%84%A4%EC%B9%98-%EB%B0%8F-CUDAGPU-%EC%84%A4%EC%A0%95-%EB%B0%A9%EB%B2%95

  • WSL ์‚ฌ์šฉ์‹œ Cuda ์„ค์น˜๋ฅผ ๊ฐ„๋‹จ ๋ช…๋ฃŒํžˆ ์„ค๋ช…ํ•ด ์ฃผ๋Š” ๊ณ ๋งˆ์šด ๊ฒŒ์‹œ๋ฌผ์ž…๋‹ˆ๋‹ค :)

โœ” https://zzsza.github.io/mlops/2021/04/18/bentoml-basic/

  • ๋ณ€์„ฑ์œค๋‹˜์˜ ๊ฐœ๋ฐœ ๋ธ”๋กœ๊ทธ : ์ •๋ง ์ž˜ ์ •๋ฆฌํ•ด ์ฃผ์…จ๋‹ค..!
profile
MLOps, ML Engineer. ๋ฐ์ดํ„ฐ์—์„œ ์‹œ์Šคํ…œ์œผ๋กœ, ์‹œ์Šคํ…œ์—์„œ ๊ฐ€์น˜๋กœ.

0๊ฐœ์˜ ๋Œ“๊ธ€