본 포스팅은 ML Engineer를 위한 MLOps에 있는 코드들을 활용하여 진행되었습니다.
0. 환경 설정
환경 세팅부터 다시 해보고 싶어서 별도의 conda 가상환경 만들기 & 패키지 설치하기
conda create -n mlops python=3.8
pip install pandas psycopg2-binary scikit-learn joblib
1. 간단한 분류 모델 선정 및 개발
# base_train.py
from sklearn.datasets import load_breast_cancer
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
# 1. 데이터 가져오기
cancer_dataset = load_breast_cancer()
X = cancer_dataset.data
y = cancer_dataset.target
X_train, X_valid, y_train, y_valid = train_test_split(X, y, train_size=0.8, random_state=2023)
# 2. 모델 불러오기, 데이터 스케일링, 모델 학습
scaler = StandardScaler()
classifier = SVC() # decision tree는 train_acc가 1.0 나와서 버림...
scaled_X_train = scaler.fit_transform(X_train)
scaled_X_valid = scaler.transform(X_valid)
classifier.fit(scaled_X_train, y_train)
train_pred = classifier.predict(scaled_X_train)
valid_pred = classifier.predict(scaled_X_valid)
train_acc = accuracy_score(y_true=y_train, y_pred=train_pred)
valid_acc = accuracy_score(y_true=y_valid, y_pred=valid_pred)
print("Train Accuracy :", train_acc)
print("Valid Accuracy :", valid_acc)
1-1. 데이터 스케일링
Feature 별로 값의 크기가 천차만별인 경우가 많고, 그대로 모델이 학습할 경우 특징들에 대해서 고르게 학습하지 못함
따라서, 스케일러와 데이터 스케일링은 매우 중요한 요소
단, test set or valid set에 대해서 scaler를 학습하지 않도록 유의. 말 그대로 테스트와 검증을 위한 세트이므로, 그들까지 스케일러가 학습하게 되면 모델이 오버피팅 됨
1-2. 학습된 스케일러 및 모델 저장
scikit-learn에서는 모델 저장을 위해 pickle 대신 joblib 패키지를 이용하는 것을 권장하고 있음. (공식문서 link)
In the specific case of scikit-learn, it may be better to use joblib’s replacement of pickle (dump & load), which is more efficient on objects that carry large numpy arrays internally as is often the case for fitted scikit-learn estimators, but can only pickle to the disk and not to a string
import joblib
# 스케일러 및 모델 저장
joblib.dump(scaler, "scaler.joblib")
joblib.dump(classifier, "classifier.joblib")
# 스케일러 및 모델 load
scaler_load = joblib.load("scaler.joblib")
classifier_load = joblib.load("classifier.joblib")
코드 실행 시 경로에 scaler.joblib과 classifier.joblib 파일이 생성됨
1-3. 저장된 모델이 잘 불러와지는지 확인하는 파일 작성
# base_valdiate_save_model.py
import joblib
from sklearn.datasets import load_breast_cancer
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
# 1. 데이터 재현하기
cancer_dataset = load_breast_cancer()
X = cancer_dataset.data
y = cancer_dataset.target
X_train, X_valid, y_train, y_valid = train_test_split(X, y, train_size=0.8, random_state=2023)
# 2. 저장된 모델과 스케일러 불러오기
scaler_load = joblib.load("scaler.joblib")
classifier_load = joblib.load("classifier.joblib")
scaled_X_train = scaler_load.transform(X_train) # scaler가 이미 학습된 상태이기 때문에 fit 필요 없음
scaled_X_valid = scaler_load.transform(X_valid)
load_train_pred = classifier_load.predict(scaled_X_train) # classifier가 이미 학습된 상태이기 때문에 fit 필요 없음
load_valid_pred = classifier_load.predict(scaled_X_valid)
load_train_acc = accuracy_score(y_true=y_train, y_pred=load_train_pred)
load_valid_acc = accuracy_score(y_true=y_valid, y_pred=load_valid_pred)
print("Train Accuracy :", train_acc)
print("Valid Accuracy :", valid_acc)
2. Model Pileline
위의 방법으로 데이터 처리, 모델링을 하나하나 정의하며 진행할 경우 실수할 가능성이 높아짐. 예시의 경우 scaling을 한 번, 모델을 하나 이용하였지만, 수많은 스케일링과 트릭 적용, 복잡한 모델 아키텍쳐를 이용할 경우 언제 무엇을 빼먹을지 모르는 상황
(통제한 변수들을 동일하게 반복적으로 해줘야 하는데 이 과정 중 실수할 가능성도 높다)
머신러닝의 이러한 복잡한 과정을 단일 개체에 몰아넣어 재현성을 높이고 편리함을 도모하는 도구가 바로 pipeline
하나의 pipeline을 만들어 거기에 스케일러, 모델 등을 등록한 후, pipeline을 통해 한 번에 머신러닝 실험과정을 진행할 수 있음
(이렇게 될 경우 다른 파라미터들로 교차검증하기 쉬워진다는 장점도 있음)
파이프라인은 리스트로 만들어져 있고, 리스트 안에는 (모델 이름, 모델 객체)가 값으로 들어가게 됨
만약 파이프라인의 개별 요소 (ex. 파이프라인 안에서 스케일러에만 접근하고 싶은 경우) 등록한 순서에 대해서 리스트 인덱싱을 하면 됨
만약 모델 객체에 대한 파라미터 튜닝을 하고 싶다면 `등록한 이름__파라미터이름 `으로 접근하면 됨
# 예시
from sklearn.pipeline import Pipeline
from sklearn.model_selection import GridSearchCV
# 파이프라인 객체 생성 및 등록
rf_pipeline = Pipeline([("rf_classifier", RandomForestClassifier())])
# 파이프라인 학습
rf_pipeline.fit(X_train, y_train)
# 파이프라인의 요소 개별 접근을 원하는 경우 리스트 인덱싱으로 가능
rf_pipeline[0].fit(X_train, y_train)
# 교차검증
grid_param = [{"rf_classifier": [RandomForestClassifier()],
"rf_classifier__n_estimators": [10,100,1000],
"rf_classifier__max_depth": [5, 10, 15, 20],
"rf_classifier__max_leaf_nodes": [2, 4, 6]}]
gridsearch = GridSearchCV(rf_pipeline, grid_param, cv=5, verbose=0, n_jobs=-1)
best_one = gridsearch.fit(X_train, y_train)
2-1. sklearn의 pipeline을 이용한 코드 작성
성능은.... 떨어졌지만 gridsearch 이용한 교차검증까지 넣어놓기
# pipeline_train.py
import joblib
from sklearn.datasets import load_breast_cancer
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.svm import SVC
# 1. 데이터 불러오기
cancer_dataset = load_breast_cancer()
X = cancer_dataset.data
y = cancer_dataset.target
X_train, X_valid, y_train, y_valid = train_test_split(X, y, train_size=0.8, random_state=2023)
# 2. 모델 만들고 파이프라인에 등록하기
model_pipeline = Pipeline([("scaler", StandardScaler()), ("svc", SVC())])
model_pipeline.fit(X_train, y_train)
train_pred = model_pipeline.predict(X_train)
valid_pred = model_pipeline.predict(X_valid)
train_acc = accuracy_score(y_true=y_train, y_pred=train_pred)
valid_acc = accuracy_score(y_true=y_valid, y_pred=valid_pred)
print("Train Accuracy :", train_acc)
print("Valid Accuracy :", valid_acc)
# 2-1. 그리드서치로 교차검증하기
params = {
"svc": [SVC()],
"svc__C": [1, 5, 10],
"svc__kernel": ["linear", "rbf", "poly"],
"svc__gamma" : ["scale", "auto"]
}
gridsearch = GridSearchCV(model_pipeline, params)
best_one = gridsearch.fit(X_train, y_train)
print(best_one.best_estimator_)
print(best_one.score(X_valid, y_valid))
# 3. 모델 저장하기
joblib.dump(model_pipeline, "model_pipeline.joblib")
2-2. 저장된 파이프라인이 잘 불러와지는지 확인하는 파일 작성
# pipeline_validate_save_model.py
import joblib
from sklearn.datasets import load_breast_cancer
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
# 1. 데이터 재현하기
cancer_dataset = load_breast_cancer()
X = cancer_dataset.data
y = cancer_dataset.target
X_train, X_valid, y_train, y_valid = train_test_split(X, y, train_size=0.8, random_state=2023)
# 2. 파이프라인 다시 불러오기
model_pipeline_load = joblib.load("model_pipeline.joblib")
# 3. 잘 불러져왔는지 검증하기
load_train_pred = model_pipeline_load.predict(X_train)
load_valid_pred = model_pipeline_load.predict(X_valid)
load_train_acc = accuracy_score(y_true=y_train, y_pred=load_train_pred)
load_valid_acc = accuracy_score(y_true=y_valid, y_pred=load_valid_pred)
print("Load Model Train Accuracy :", load_train_acc)
print("Load Model Valid Accuracy :", load_valid_acc)
'MLOps' 카테고리의 다른 글
BentoML 시작하기 & v0와 v1 비교 (v1.0 migration 이후) (0) | 2023.08.27 |
---|---|
6. API Serving (0) | 2023.02.19 |
5. FastAPI (0) | 2023.02.11 |