본문 바로가기
MLOps

6. API Serving

by 데브겸 2023. 2. 19.

- PostgreSQL DB: Backend Store로서 이용 - 모델의 accuracy, f1-score, loss, hyperparameter와 같은 수치 정보 & MLflow의 운영 정보, 메타 데이터 (run_id, run_name, experiment_name) 등을 저장할 물리적인 서버

- MinIO: Artifact Store로서 이용 - 학습된 모델을 저장하는 model registry로써 이용하기 위한 스토리지 서버 (run_id 등도 여기서 가져옴)

 

흐름: minio로 되어 있는 artifact store에서 모델을 mlflow를 통해 로컬에 다운받고 -> 파라미터 값들을 작성해서 api 호출을 하면 -> 내  로컬에서 api로 전달된 값을 바탕으로 모델 inference를 하고 -> inference 결과값을 클라이언트에 반환해주는 방식으로 만들기

 

 

1. 모델 다운로드

# download_model.py

import os
from argparse import ArgumentParser

import mlflow

# set environments
os.environ["MLFLOW_S3_ENDPOINT_URL"] = "http://localhost:9000" # minIO 접속 url
os.environ["MLFLOW_TRACKING_URI"] = "http://localhost:5001" # mlflow 접속 url
os.environ["AWS_ACCESS_KEY_ID"] = "minio"
os.environ["AWS_SECRET_ACCESS_KEY"] = "miniostorage"

def download_model(args):
  # download model artifacts
  mlflow.artifacts.download_artifacts(artifact_uri=f"runs:/{args.run_id}/{args.model_name}", dst_path=".")

if __name__ == "__main__":
  parser = ArgumentParser()
  parser.add_argument("--model-name", dest="model_name", type=str, default="sk_model")
  parser.add_argument("--run-id", dest="run_id", type=str)
  args = parser.parse_args()
  
  download_model(args)

 

Model artifacts는 MLflow에 모델이 저장될 때 함께 저장된 메타데이터와 모델 자체의 binary 파일을 의미

  • mlflow.artifacts.download_artifacts(artifact_uri=f"runs:/{args.run_id}/{args.model_name}", dst_path=".")
    • artifact_uri: URI pointing to the artifacts (Exactly one of artifact_uri or run_id must be specified)
    • run_id: ID of the MLflow Run containing the artifacts. (Exactly one of artifact_uri or run_id must be specified)
    • artifact_path: For use with run_id) If specified, a path relative to the MLflow Run’s root directory containing the artifacts to download.
    • dst_path: Path of the local filesystem destination directory to which to download the specified artifacts.
    • traking_uri: The tracking URI to be used when downloading artifacts.

 

localhost:5001로 mlflow에 접속하여 run_id 확인하기

 

확인한 run_id를 바탕으로 python 스크립트 실행하기

python download_model.py --model-name sk_model --run-id 9ddb1882473046abaa17f874908194f1

스크립트 파일 실행 후 실험 이름으로 된 폴더가 생성된 것을 볼 수 있음 (위에서 현재 폴더에 다운로드 하도록 설정함)

폴더 안에는 모델, 환경설정 파일 등이 다운로드 됨

 

 

2. 서빙에 필요한 API 구현하기

 

2-1. data validation을 위한 schema 클래스 만들기

# schemas.py

from pydantic import BaseModel


class PredictIn(BaseModel):
  mean_radius: float
  mean_texture: float
  mean_perimeter: float
  mean_area: float
  mean_smoothness: float
  mean_compactness: float
  mean_concavity: float
  mean_concave_points: float
  mean_symmetry: float
  mean_fractal_dimension: float
  radius_error: float
  texture_error: float
  perimeter_error: float
  area_error: float
  smoothness_error: float
  compactness_error: float
  concavity_error: float
  concave_points_error: float
  symmetry_error: float
  fractal_dimension_error: float
  worst_radius: float
  worst_texture: float
  worst_perimeter: float
  worst_area: float
  worst_smoothness: float
  worst_compactness: float
  worst_concavity: float
  worst_concave_points: float
  worst_symmetry: float
  worst_fractal_dimension: float


class PredictOut(BaseModel):
  target: int

 

2-2. API 구현을 위한 app.py 스크립트 파일 만들기

# app.py

import mlflow
import pandas as pd
from fastapi import FastAPI
from schemas import PredictIn, PredictOut

def get_model():
  model = mlflow.sklearn.load_model(model_uri="./sk_model")
  return model

MODEL = get_model()

# create a FastAPI instance

app = FastAPI()

@app.post("/predict", response_model=PredictOut)
def predict(data: PredictIn) -> PredictOut:
  df = pd.DataFrame([data.dict()])
  pred = MODEL.predict(df).item()
  return PredictOut(target=pred)

 

2-3. 작성한 API 실행해보고, 데이터도 날려보기

uvicorn app:app --reload

swagger UI로 확인하기 & 데이터 날려보기 => predict 결과값을 잘 반환해줌

 

 

 

 

3. Model API를 dockerize하여 컨테이너로 띄우기

 

3-1. Dockerfile 작성하기

# Dockerfile

From amd64/python:3.9-slim

WORKDIR /usr/app

RUN pip install -U pip &&\
    pip install mlflow==1.30.0 pandas scikit-learn "fastapi[all]"

COPY schemas.py schemas.py
COPY app.py app.py
COPY sk_model/ sk_model/

CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--reload"]

 

 

3-2. Docker Compose 파일 작성하기

version: "3"

services:
  api-with-model:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: api-with-model
    ports:
      - 8000:8000
    healthcheck:
      test:
        - curl -X POST http://localhost:8000/predict
        - -H
        - "Content-Type: application/json"
        - -d
        - '{"mean_radius": 13.9,"mean_texture": 23.1,"mean_perimeter": 70.34, "mean_area": 600.0,"mean_smoothness": 0.08102,"mean_compactness": 0.0532,"mean_concavity": 0.02993,"mean_concave_points": 0.0207,"mean_symmetry": 0.1622, "mean_fractal_dimension": 0.05711,"radius_error": 0.3311,"texture_error": 0.9106,"perimeter_error": 2.003,"area_error": 32.07,"smoothness_error": 0.003482,"compactness_error": 0.0193,"concavity_error": 0.0234,"concave_points_error": 0.006275,"symmetry_error": 0.01233,"fractal_dimension_error": 0.003133,"worst_radius": 16.32,"worst_texture": 27.93,"worst_perimeter": 105.5,"worst_area": 840.7,"worst_smoothness": 0.1033,"worst_compactness": 0.1711,"worst_concavity": 0.1673,"worst_concave_points": 0.0813,"worst_symmetry": 0.2344,"worst_fractal_dimension": 0.0761}'
      interval: 10s
      timeout: 5s
      retries: 5

networks:
  default:
    name: mlops-network
    external: true

 

3-3. docker compose 실행 및 확인

 

docker compose up -d

 

docker ps -a로 컨테이너 잘 돌아가는 것까지 확인

 

curl 명령어로 shell 환경에서 결과 확인하기

curl -X POST http://localhost:8000/predict -H "Content-Type: application/json" -d '{"mean_radius": 13.9,"mean_texture": 23.1,"mean_perimeter": 70.34, "mean_area": 600.0,"mean_smoothness": 0.08102,"mean_compactness": 0.0532,"mean_concavity": 0.02993,"mean_concave_points": 0.0207,"mean_symmetry": 0.1622, "mean_fractal_dimension": 0.05711,"radius_error": 0.3311,"texture_error": 0.9106,"perimeter_error": 2.003,"area_error": 32.07,"smoothness_error": 0.003482,"compactness_error": 0.0193,"concavity_error": 0.0234,"concave_points_error": 0.006275,"symmetry_error": 0.01233,"fractal_dimension_error": 0.003133,"worst_radius": 16.32,"worst_texture": 27.93,"worst_perimeter": 105.5,"worst_area": 840.7,"worst_smoothness": 0.1033,"worst_compactness": 0.1711,"worst_concavity": 0.1673,"worst_concave_points": 0.0813,"worst_symmetry": 0.2344,"worst_fractal_dimension": 0.0761}'

 

'MLOps' 카테고리의 다른 글

BentoML 시작하기 & v0와 v1 비교 (v1.0 migration 이후)  (0) 2023.08.27
5. FastAPI  (0) 2023.02.11
2. Model Development  (0) 2023.01.27