본문으로 건너뛰기

093 모델 저장과 로드

키워드: save_model, load_model

개요

학습된 모델을 저장하고 다시 불러오는 것은 배포의 첫 단계입니다. PyCaret은 전처리 파이프라인과 모델을 함께 저장하여 재현성을 보장합니다.

실습 환경

  • Python 버전: 3.11 권장
  • 필요 패키지: pycaret[full]>=3.0

save_model 기본

from pycaret.classification import *
from pycaret.datasets import get_data

# 093 데이터 로드
data = get_data('diabetes')

# 093 환경 설정
clf = setup(data, target='Class variable', session_id=42, verbose=False)

# 093 모델 생성
rf = create_model('rf')

# 093 모델 저장
save_model(rf, 'my_first_model')
# 093 my_first_model.pkl 파일 생성됨

print("모델 저장 완료!")

load_model

from pycaret.classification import *

# 093 모델 로드
loaded_model = load_model('my_first_model')

# 093 새 데이터에 예측
from pycaret.datasets import get_data
new_data = get_data('diabetes')

predictions = predict_model(loaded_model, data=new_data.head(10))
print(predictions)

finalize_model 후 저장

from pycaret.classification import *
from pycaret.datasets import get_data

data = get_data('diabetes')
clf = setup(data, target='Class variable', session_id=42, verbose=False)

# 093 모델 생성 및 튜닝
rf = create_model('rf')
tuned_rf = tune_model(rf)

# 093 전체 데이터로 재학습 (배포용)
final_model = finalize_model(tuned_rf)

# 093 최종 모델 저장
save_model(final_model, 'production_model')

저장 파일 구조

import pickle

# 093 PyCaret 저장 파일 내용 확인
with open('production_model.pkl', 'rb') as f:
saved_obj = pickle.load(f)

print(f"저장된 객체 타입: {type(saved_obj)}")

# 093 Pipeline 객체가 저장됨
# 093 - 전처리 단계들
# 093 - 최종 모델

저장 옵션

from pycaret.classification import *

clf = setup(data, target='Class variable', session_id=42, verbose=False)
rf = create_model('rf')

# 093 기본 저장 (pickle)
save_model(rf, 'model_pickle')

# 093 압축 저장
import joblib
final = finalize_model(rf)
pipeline = get_config('pipeline')

# 093 압축률 지정
joblib.dump(pipeline, 'model_compressed.joblib', compress=3)

# 093 로드
loaded = joblib.load('model_compressed.joblib')

버전 관리

from pycaret.classification import *
from datetime import datetime
import json
import os

clf = setup(data, target='Class variable', session_id=42, verbose=False)
rf = create_model('rf')
final = finalize_model(rf)

# 093 버전 정보 생성
version_info = {
'version': '1.0.0',
'created_at': datetime.now().isoformat(),
'model_type': 'RandomForestClassifier',
'pycaret_version': '3.0.0',
'metrics': {
'accuracy': 0.78,
'f1': 0.75
}
}

# 093 메타데이터 저장
model_name = f"model_v{version_info['version']}"
save_model(final, model_name)

with open(f'{model_name}_meta.json', 'w') as f:
json.dump(version_info, f, indent=2)

print(f"모델 저장: {model_name}.pkl")
print(f"메타데이터: {model_name}_meta.json")

모델 레지스트리 패턴

import os
import json
from datetime import datetime

class ModelRegistry:
"""간단한 모델 레지스트리"""

def __init__(self, base_path='./models'):
self.base_path = base_path
os.makedirs(base_path, exist_ok=True)
self.registry_file = os.path.join(base_path, 'registry.json')
self._load_registry()

def _load_registry(self):
if os.path.exists(self.registry_file):
with open(self.registry_file, 'r') as f:
self.registry = json.load(f)
else:
self.registry = {'models': []}

def _save_registry(self):
with open(self.registry_file, 'w') as f:
json.dump(self.registry, f, indent=2)

def register(self, model, name, metrics, tags=None):
"""모델 등록"""
version = len([m for m in self.registry['models'] if m['name'] == name]) + 1
model_id = f"{name}_v{version}"

# 모델 저장
model_path = os.path.join(self.base_path, f"{model_id}.pkl")
save_model(model, model_path.replace('.pkl', ''))

# 레지스트리 업데이트
entry = {
'id': model_id,
'name': name,
'version': version,
'path': model_path,
'metrics': metrics,
'tags': tags or [],
'created_at': datetime.now().isoformat(),
'stage': 'development'
}
self.registry['models'].append(entry)
self._save_registry()

return model_id

def get_model(self, model_id):
"""모델 로드"""
for m in self.registry['models']:
if m['id'] == model_id:
return load_model(m['path'].replace('.pkl', ''))
return None

def promote(self, model_id, stage):
"""스테이지 변경"""
for m in self.registry['models']:
if m['id'] == model_id:
m['stage'] = stage
self._save_registry()

def get_production_model(self, name):
"""프로덕션 모델 가져오기"""
for m in self.registry['models']:
if m['name'] == name and m['stage'] == 'production':
return load_model(m['path'].replace('.pkl', ''))
return None

def list_models(self):
"""모델 목록"""
return self.registry['models']

# 093 사용 예
registry = ModelRegistry('./my_models')

# 093 모델 등록
from pycaret.classification import *
clf = setup(data, target='Class variable', session_id=42, verbose=False)
rf = create_model('rf')
final = finalize_model(rf)

model_id = registry.register(
final,
name='diabetes_classifier',
metrics={'accuracy': 0.78, 'f1': 0.75},
tags=['random_forest', 'diabetes']
)
print(f"등록된 모델: {model_id}")

# 093 프로덕션 승격
registry.promote(model_id, 'production')

# 093 프로덕션 모델 로드
prod_model = registry.get_production_model('diabetes_classifier')

ONNX 형식 저장

# 093 ONNX: 플랫폼 간 호환 형식
# 093 pip install skl2onnx onnxruntime

try:
from skl2onnx import convert_sklearn
from skl2onnx.common.data_types import FloatTensorType
import onnxruntime as rt
import numpy as np

from pycaret.classification import *
from pycaret.datasets import get_data

data = get_data('diabetes')
clf = setup(data, target='Class variable', session_id=42, verbose=False)

# sklearn 모델 가져오기
from sklearn.ensemble import RandomForestClassifier
rf = RandomForestClassifier(n_estimators=100, random_state=42)

X = get_config('X_train_transformed')
y = get_config('y_train_transformed')
rf.fit(X, y)

# ONNX 변환
initial_type = [('float_input', FloatTensorType([None, X.shape[1]]))]
onnx_model = convert_sklearn(rf, initial_types=initial_type)

# 저장
with open('model.onnx', 'wb') as f:
f.write(onnx_model.SerializeToString())

# ONNX 런타임으로 추론
sess = rt.InferenceSession('model.onnx')
input_name = sess.get_inputs()[0].name

# 예측
X_test = get_config('X_test_transformed')
pred_onnx = sess.run(None, {input_name: X_test.values.astype(np.float32)})
print(f"ONNX 예측 완료: {pred_onnx[0][:5]}")

except ImportError:
print("ONNX 패키지 필요: pip install skl2onnx onnxruntime")

회귀 모델 저장

from pycaret.regression import *
from pycaret.datasets import get_data

# 093 회귀 데이터
data = get_data('boston')

reg = setup(data, target='medv', session_id=42, verbose=False)

# 093 모델 생성 및 저장
rf = create_model('rf')
final = finalize_model(rf)
save_model(final, 'boston_regressor')

# 093 로드 및 예측
loaded = load_model('boston_regressor')
predictions = predict_model(loaded, data=data.head(5))
print(predictions)

모델 검증 후 저장

from pycaret.classification import *
from pycaret.datasets import get_data

data = get_data('diabetes')
clf = setup(data, target='Class variable', session_id=42, verbose=False)

rf = create_model('rf')
results = pull()

# 093 성능 검증 후 저장
min_accuracy = 0.70
accuracy = results['Accuracy'].values[0]

if accuracy >= min_accuracy:
final = finalize_model(rf)
save_model(final, 'validated_model')
print(f"모델 저장됨 (정확도: {accuracy:.4f})")
else:
print(f"성능 미달 (정확도: {accuracy:.4f} < {min_accuracy})")

다중 모델 저장

from pycaret.classification import *
from pycaret.datasets import get_data
import os

data = get_data('diabetes')
clf = setup(data, target='Class variable', session_id=42, verbose=False)

# 093 여러 모델 생성 및 저장
models_to_save = ['rf', 'xgboost', 'lightgbm']
save_dir = './saved_models'
os.makedirs(save_dir, exist_ok=True)

for model_id in models_to_save:
model = create_model(model_id, verbose=False)
final = finalize_model(model)
save_path = os.path.join(save_dir, f'{model_id}_model')
save_model(final, save_path)
print(f"저장: {save_path}.pkl")

정리

  • save_model: 파이프라인 + 모델 함께 저장
  • load_model: 저장된 모델 로드
  • finalize_model: 배포 전 전체 데이터 재학습
  • 버전 관리: 메타데이터와 함께 저장
  • ONNX: 플랫폼 간 호환성
  • 검증 후 저장: 품질 보장

다음 글 예고

다음 글에서는 FastAPI로 모델 배포를 다룹니다.


PyCaret 머신러닝 마스터 시리즈 #093