기계 학습(Machine Learning) 모델 개발에서 '모델을 만들고 끝'내는 것이 아니라, **'어떻게 효율적으로 실험을 반복하고 안전하게 프로덕션 환경에 배포하며 서빙(추론)할 것인가'**라는 MLOps 시스템 구축이 매우 중요해지고 있습니다.
본 기사에서는 Iris(붓꽃) 분류 모델을 주제로, 모던한 MLOps 툴들을 조합하여 원스톱 파이프라인 구축 절차를 설명합니다.
Prefect으로 Iris 분류 학습을 실행하고, MLflow에 실험 기록을 남기며, BentoML로 모델을 저장 및 서빙하고, Flask 화면/API를 통해 추론하는 샘플입니다. 각 컨테이너는 전용 디렉토리의 Dockerfile과 의존성으로 독립적으로 빌드됩니다.
먼저 소스 코드를 확보하고 애플리케이션을 실행합니다.
git clone https://github.com/minegishirei/mlops.git
cd mlops
./start.sh
Docker Desktop을 실행하고 프로젝트 디렉토리에서 실행합니다.
앱이 시작되면, Prefect 화면(http://localhost:4200)에 접속하여 Deployment로 이동합니다.
Prefect UI의 Deployments에서 Run을 생성하고, n_estimators,
test_size,
random_state를 지정하여 학습할 수 있습니다.
Run 버튼을 누르면 기계 학습 모델을 생성하는 파이프라인이 시작됩니다.
학습 처리는 모델을 MLflow의 실험 iris-classification-proxy에 기록합니다. MLflow 서버가 결과물을 대리 저장 및 배포하기 때문에, 학습 컨테이너나 BentoML과 동일한 파일 시스템을 공유할 필요는 없습니다. Model Registry에 등록은 자동으로 이루어지지 않으므로, 학습 후에 MLflow UI에서 모델을 등록하고 champion 별칭(alias)을 설정해 주세요. BentoML은 시작 시점에 모델을 로드하지 않고, 첫 예측 시점에 Registry에서 가져옵니다. 올바른 모델을 등록하여 champion을 설정하기 전까지는 예측할 수 없습니다.
MLflow의 artifact proxy 설정을 반영하려면, 프로젝트 디렉토리에서 컨테이너를 재빌드합니다.
docker compose up -d --build mlflow worker bentoml api
이전 iris-classification 실험은 로컬 경로를 결과물 저장소로 기록했기 때문에, proxy 경유로는 읽을 수 없습니다. 기존 실험은 유지되며, 새로운 학습은 iris-classification-proxy에 기록됩니다.
학습 시의 파라미터・정확도・모델은 MLflow에 기록됩니다.
최초 학습이 Prefect UI에서 완료된 후,
Models 탭에서 Create Model로 iris-classifier라는 이름으로 생성합니다.
Experiments 탭에서 생성된 모델을 선택하고, register를 통해 모델과 연결합니다.
다시 Models 탭에서 해당 모델에 main 별칭을 부여하면 완료입니다.
서버를 재시작하고 Flask 샘플 앱(http://localhost:8000)에서 동작을 확인해 봅시다.
BentoML이 중지된 상태에서는 503을 반환합니다.
- 할 수 없는 것: 학습 시작, 파라미터 변경, 모델 선택/교체.
{"features": [[5.1, 3.5, 1.4, 0.2]]}
PyTorch, TensorFlow, Scikit-Learn, XGBoost, LLM(Hugging Face 등)과 같은 다양한 프레임워크로 훈련된 모델을 Bento라고 불리는 표준화된 컨테이너 형식으로 구동합니다.
고성능 REST API 또는 gRPC 서버로 접근할 수 있습니다.
- 저장: 학습된 모델을 MLflow에 기록하고 Model Registry에 등록합니다.
- 정의:
service.py 등의 파일에서 입력 데이터 수신 및 모델 추론의 전처리/후처리(Runner와 Service 개념)를 Python 코드로 정의합니다.
- 빌드: 의존성을 포함하여 하나의 "Bento"로 아카이브화합니다.
- 실행/배포: 로컬에서 API 서버로 구동하여 테스트하거나, Docker 컨테이너화하여 프로덕션 환경에 배포합니다.
이번의 service.py는 MLflow Model Registry의 Production 모델을 읽어옵니다.
import os
from functools import cached_property
import bentoml
...
이 구성에서는 MLflow Tracking Server에서 모델을 로드합니다. 다른 구성에서는 시작 시점에 S3에서 모델을 로드하는 방법도 있습니다.
import os
import boto3
import bentoml
...
이를 구동하고 있는 컨테이너에 다음과 같이 요청을 보낼 수 있습니다.
curl -X 'POST' \
'http://localhost:3000/predict' \
-H 'accept: application/json' \
...
-
할 수 있는 것:
- BentoML의
/predict API를 직접 테스트하여 입력 및 응답 형식을 확인합니다.
- 과거에는 기계 학습된 모델을 pickle 형식으로 읽어 실행하는 경우도 있었으나, BentoML에서는 그 대체 수단이며 더 빠른 추론이 가능합니다.
-
BentoML의
-
할 수 없는 것:
- 학습 시작. MLflow UI에서 수동으로 등록/선택한 Production 모델을 사용하여 추론합니다.
실험 관리와 Model Registry 기능을 가진 것이 MLflow입니다.
기계 학습 훈련을 실행했을 때의 파라미터나 정확도를 테이블 형식이나 그래프 형식으로 비교 검토할 수 있습니다.
또한, 생성된 모델에 라벨링(labeling)/별칭(alias)을 적용함으로써 동작 환경의 모델 전환도 손쉽게 할 수 있습니다.
(앞서 언급된 BentoML 소스 코드는 MLflow URL을 호출하고 있다는 점을 기억해 주세요.)
-
http://localhost:5000
-
할 수 있는 것:
iris-classification-proxy 실험의 학습, 파라미터, 정확도, 모델 결과물을 확인하고 비교합니다.
- 학습된 모델을 Model Registry에 등록하고 버전에
champion 별칭을 설정합니다.
-
절차:
iris-classification-proxy 실험을 열고, 학습 Run의 Logged Models에 있는 iris_classifier를 열어 Register model을 선택합니다. 기존의 iris-classifier에 새로운 버전으로 등록하고, Registry의 iris-classifier에서 그 새 버전에 champion 별칭을 할당합니다. Run의 Artifacts에 표시되는 파일 경로로부터 수동으로 등록하지 말고, 반드시 Logged Model로부터 등록해야 합니다.
-
champion을 설정한 후에 예측 API를 호출해 주세요. 이미 다른 모델을 로드한 BentoML에 새로운 버전을 반영하는 경우에는, BentoML을 재시작합니다.
-
할 수 있는 것:
iris-training 배포의 시작, n_estimators, test_size, random_state
의 지정, 실행 상태 및 로그 확인. - 불가능한 작업: MLflow 실험 비교, Model Registry에 등록하거나 Production 버전을 선택하는 것. 이들은 MLflow UI에서 수행합니다.
Deployment/Worker를 사용하지 않고, 기존처럼 CLI에서 직접 학습할 경우:
docker compose --profile training run --build --rm train
예측 요청:
curl -X POST http://localhost:8000/api/predict \
-H 'Content-Type: application/json' \
-d '{"features": [[5.1, 3.5, 1.4, 0.2]]}'