Serve MLflow model with BentoML
BentoML คือ model serving ตัวหนึ่ง ที่มี feature ทั้งการ registry model, build API, model versioning หรือแม้กระทั่งสร้าง docker file(หรือเราจะเรียกมันว่า bento) ซึ่งเป็นเครื่องมือที่สามารถนำ model ของเราไปใช้งานจริง เรียกได้ว่า “ทุกอย่างจบภายในตัวเดียว” ทั้งนี้ feature registry model จะคล้ายๆตัว MLflow Model Registry แต่ bentoml ก็สามารถใช้งานร่วมกับ MLflow ได้อย่างไร้รอยต่อ นั่นหมายความว่า เราไปพัฒนา model บน MLflow แล้วมาทำ API บน bentoml ก็ไม่มีปัญหา ในบทความนี้จะแนะนำการใช้ BentoML อย่างง่ายกับ model ที่เรามีแล้วบน MLflow เพื่อ build API endpoint บน local
BentoML แบบดั้งเดิมจะมี feature ของ BentoML Model Registry โดยจะต้อง save model ใน BentoML แล้ว load มาใช้อีกที(ซึ่งคล้ายกับ MLflow Model Registry) ปกติแล้ว การสร้าง API บน BentoML จะมีตัว runner เพื่อช่วย scale ในการทำ computation worker ซึ่งถ้าเรา save model เป็น BentoML model แล้ว จะเรียกใช้งานค่อนข้างง่าย(Pre-built model runners) แต่ในขณะเดียวกันถ้าเป็น model ที่มาจาก MLflow อาจจะมีปัญหาในกรณีที่เราไปเปลี่ยน stage model ใน MLflow Model Registry มันจะต้องมาลงทะเบียนใหม่ใน BentoML model เพื่อ update model ทำให้เกิดงานที่ซ้ำซ้อน แต่ไม่เป็นไร BentoML เองก็มีวิธีการทำ Custom runner เหมือนกัน แต่อาจจะมีการเขียนเพิ่มเติมจากเดิมเล็กน้อย
Prerequisites:
- อ่านบทความ เก็บ Model ของคุณไว้ใช้งานด้วย MLflow และ MLflow custom model flavor
- install bentoml library
- registry model บทความ MLflow custom model flavor แล้วตั้งชื่อเป็น bentoml-mlflow และ set stage เป็น Staging
step 1: สร้าง directory สำหรับเขียน BentoML framework ซึ่งประกอบด้วยไฟล์ดังต่อไปนี้
- some_directory
|- service.py
|- bentofile.yaml
|- requirements.txt
step 2: สร้างไฟล์ service.py เพื่อเขียน API
import bentoml
from bentoml.io import Image,NumpyNdarray
import PIL
import mlflow
import numpy as np
mlflow.set_tracking_uri('http://localhost:5000')
model_url = 'models:/bentoml-mlflow/Staging'
class ClothingClassificationRunner(bentoml.Runnable):
SUPPORTED_RESOURCES = ("cpu",)
SUPPORTS_CPU_MULTI_THREADING = False
def __init__(self):
self.model = mlflow.pyfunc.load_model(model_uri=model_url)
@bentoml.Runnable.method(batchable=False)
def predict(self, input_image: Image) -> list:
img = PIL.ImageOps.grayscale(input_image)
img = img.resize((28,28))
np_img = np.array(img).astype(np.uint8)
tensor_input = np.expand_dims(np_img, axis = 0)
result = self.model.predict(tensor_input)
return result
#create runner
clothing_classification_runner = bentoml.Runner(ClothingClassificationRunner)
classification = bentoml.Service(
#service_name
"cloting_classification_service",
#set runner
runners=[clothing_classification_runner],
)
#build api
#set input to image file and output to array
@classification.api(input=Image(), output=NumpyNdarray())
def image_classify(input_data: PIL.Image) -> np.array:
predict_result = clothing_classification_runner.predict.run(input_data)
return np.array(predict_result)
- class ClothingClassificationRunner ใน method predict จะ load model จาก MLflow และ implement predict function โดยแปลง image เป็น input tensor ตาม input format ของ model
- สร้าง runner จาก class ClothingClassificationRunner
- ในตัว API path เราตั้งชื่อว่า image_classification (ตามชื่อ function) ซึ่งไปเรียก predict ของ ClothingClassificationRunner
step 3: สร้างไฟล์สำหรับ build bento(docker file) ที่ชื่อว่า bentofile.yaml ใน directory เดียวกับ service.py
service: "service:classification" # Same as the argument passed to bentoml
labels:
owner: janebhop
stage: dev
include:
- "*.py" # A pattern for matching which files to include in the bento
python:
requirements_txt: ./requirements.txt
step 4: สร้าง requirements.txt สำหรับ python environment
mlflow==2.7.1
numpy==1.23.5
tensorflow-cpu==2.10.0
step 5: หลังจากได้ครบทั้ง 3 ไฟล์แล้วให้เราเปิด command prompt แล้ว cd ไปยัง directory ดังกล่าวและใช้คำสั่งต่อไปนี้เพื่อให้ BentoML build docker file(bento)
$ bentoml build
step 6: หลังจาก build สำเร็จจะปรากฎ output ดังภาพทที่ 2 จะเป็นชื่อ service และ tag โดยสามารถใช้คำสั่ง $ bentoml list
ใน cmd เพื่อดู bento ที่เราเคย build ทั้งหมดได้
step 7: serve API บน local โดยใช้คำสั่งต่อไปนี้ ซึ่งเลือกเป็น tag id หรือถ้าอยากใช้ tag ล่าสุดก็ใส่เป็น latest
$ bentoml serve cloting_classification_service:latest
step 8: BentoML จะสร้าง local endpoint ที่ http://localhost:3000 เป็นหน้า Swagger ซึ่งสามารถเข้าไป post api โดยใส่ test input image เป็นไฟล์ภาพ ตัว API จะส่งคำตอบเป็น ชื่อ class และความน่าจะเป็นของ class ออกมา ดังภาพที่ 3
หรือใช้คำสั่ง $ bentoml containerize cloting_classification_service:latest
ก็จะเป็นการสร้าง container จาก bento (docker file) ของเราได้เหมือนกัน
code
ถ้าอ่านจนถึงตรงนี้แล้วไม่ติดขั้นตอนไหนเลยเราก็สามารถใช้ MLflow ร่วมกับ BentoML ได้อย่างไร้ปัญหาแล้ว ขอบคุณทุกท่านที่ติดตามซีรี่ย์นี้ครับ