머신 러닝 - 하이퍼 파라미터 튜닝

이상해씨·2021년 11월 13일
0

머신 러닝

목록 보기
9/27

◾하이퍼파라미터 튜닝

1. 교차 검증

  • 교차 검증(Cross Validation) : 모델의 학습 과정에서 학습 / 검증데이터를 나눌때 단순히 1번 나누는게 아니라 K번 나누고 각각의 학습 모델의 성능을 비교하는 방법
    • 과적합 확인
    • 데이터에 적용한 모델의 성능을 정확히 표현하기 위해서도 유용하다.
    • hold out : train_set, test_set으로 나누는 방법
    • k-fold cross validation : train_set을 k개로 나누어 새로운 train_set, test_set으로 나누어 평균값 사용
    • stratified k-fold cross validation : 데이터의 분포가 다르다면 분포를 유지하는 방법
    • 검증(Validation)이 끝난 후 test용 데이터로 최종 평가
# simple test
import numpy as np
from sklearn.model_selection import KFold

X = np.array([[1, 2], [3, 4], [1, 2], [3, 4]])
y = np.array([1, 2, 3, 4])
# 랜덤으로 하고 싶다면
# kf = KFold(n_splits=2, random_state = val, shuffle=True)
kf = KFold(n_splits=2)

print(kf.get_n_splits)
print(kf)
for train_idx, test_idx in kf.split(X):
    print('----- idx')
    print(train_idx, test_idx)
    print('----- train idx')
    print(X[train_idx])
    print('----- val data')
    print(X[test_idx])

  • 와인 맛 분류
import pandas as pd

red_wine = pd.read_csv('winequality-red.csv', sep=';')
white_wine = pd.read_csv('winequality-white.csv', sep=';')

red_wine['color'] = 1
white_wine['color'] = 0

wine = pd.concat([red_wine, white_wine])
wine.reset_index(drop=True, inplace=True)
wine.head(2)

  • 와인 맛 분류기를 위한 데이터 정리
# 데이터 정리
wine['taste'] = [1. if grade > 5 else 0. for grade in wine['quality']]

X = wine.drop(['taste' , 'quality'], axis=1)
y = wine['taste']
# DecisionTree로 분류
# 일반 데이터
# 최선인가? 라고 한다면 확신할 수 없다.
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier, plot_tree
from sklearn.metrics import accuracy_score

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=13)

wine_tree = DecisionTreeClassifier(max_depth=2, random_state=13)
wine_tree.fit(X_train, y_train)

y_pred_tr = wine_tree.predict(X_train)
y_pred_test = wine_tree.predict(X_test)

print('Train Acc : {}'.format(accuracy_score(y_train, y_pred_tr)))
print('Test Acc : {}'.format(accuracy_score(y_test, y_pred_test)))

plt.figure(figsize=(12, 7))
plot_tree(wine_tree, feature_names = X_train.columns)
plt.show()

# DecisionTree로 분류
# 교차 검증 데이터
# KFold
# 대체적으로 5-Fold를 많이 쓴다.
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split, KFold
from sklearn.tree import DecisionTreeClassifier, plot_tree
from sklearn.metrics import accuracy_score

kFold = KFold(n_splits=5)
wine_tree_cv = DecisionTreeClassifier(max_depth=2, random_state=13)

# 각각의 fold로 학습 후 acc
cv_accuracy = []
for train_idx, test_idx in kFold.split(X):
    # train, test 데이터 구분
    X_train, X_test = X.iloc[train_idx], X.iloc[test_idx]
    y_train, y_test = y.iloc[train_idx], y.iloc[test_idx]
    # 해당 train, test로 학습
    wine_tree_cv.fit(X_train, y_train)
    # 성과(accuracy) 확인
    pred = wine_tree_cv.predict(X_test)
    cv_accuracy.append(accuracy_score(y_test, pred))
    
cv_accuracy

# acc의 분산이 크지않다면 평균을 대표값으로 한다.
np.mean(cv_accuracy), np.var(cv_accuracy), np.std(cv_accuracy)

  • StratifiedKFold의 평균이 더 낮다.
# DecisionTree로 분류
# StratifiedKFold
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split, StratifiedKFold
from sklearn.tree import DecisionTreeClassifier, plot_tree
from sklearn.metrics import accuracy_score

skFold = StratifiedKFold(n_splits=5)
wine_tree_cv = DecisionTreeClassifier(max_depth=2, random_state=13)

# 각각의 fold로 학습 후 acc
cv_accuracy = []
for train_idx, test_idx in skFold.split(X, y):
    # train, test 데이터 구분
    X_train, X_test = X.iloc[train_idx], X.iloc[test_idx]
    y_train, y_test = y.iloc[train_idx], y.iloc[test_idx]
    # 해당 train, test로 학습
    wine_tree_cv.fit(X_train, y_train)
    # 성과(accuracy) 확인
    pred = wine_tree_cv.predict(X_test)
    cv_accuracy.append(accuracy_score(y_test, pred))
    
cv_accuracy

# acc의 분산이 크지않다면 평균을 대표값으로 한다.
np.mean(cv_accuracy), np.var(cv_accuracy), np.std(cv_accuracy)

  • cross validation을 보다 간편히 하려면 cross_val_score을 사용한다.
from sklearn.model_selection import cross_val_score

skFold = StratifiedKFold(n_splits=5)
wine_tree_cv = DecisionTreeClassifier(max_depth=2, random_state=13)

cross_val_score(wine_tree_cv, X, y, scoring=None, cv=skFold)

def skfold_dt(depth):
    from sklearn.model_selection import cross_val_score

    skFold = StratifiedKFold(n_splits=5)
    wine_tree_cv = DecisionTreeClassifier(max_depth=depth, random_state=13)
    print(cross_val_score(wine_tree_cv, X, y, scoring=None, cv=skFold))
  • depth에 의해 무조건 acc가 좋아지는 것도 아니다
skfold_dt(3)

  • train score을 확인하고 싶다면(과적합도 확인하고 싶다면) cross validate 사용
    • 아래에선 첫 2개의 경우 과적합이라 볼 수 있다.
from sklearn.model_selection import cross_validate

skFold = StratifiedKFold(n_splits=5)
wine_tree_cv = DecisionTreeClassifier(max_depth=2, random_state=13)

cross_validate(wine_tree_cv, X, y, scoring=None, cv=skFold, return_train_score=True)

2. 하이퍼파라미터 튜닝

  • 하이퍼파라미터 튜닝 : 모델의 성능을 확보하기 위해 조절하는 주요 설정값
    • Feature Enginerring : 특성을 관찰하고 머신러닝 모델이 보다 학습결과를 잘 이끌어 낼 수있도록 변경하거나 새로운 특성을 찾아내는 작업
      • Training, Vailidation, Test로 데이터 구분
      • Train 데이터로 모델 생성 -> 학습 -> Valilidation 데이터로 성과 확인
      • 결과를 통해 Hyperparameter 표현 : 손(수동)으로 조정해야하는 값
    • Hyperparameter
      • 학습률
      • 학습률 스케줄링 방법
      • 활성화 함수
      • 손실 함수
      • 훈련 반복횟수
      • 가중치 초기화 방법
      • 정규화 방법
      • 적층할 계층의 수
  • 현재는 Decision Tree만 활용하고 있기 때문에 해볼만한 것은 max_depth
  • 기본적으로 반복문으로 가능하다.
import pandas as pd

red_wine = pd.read_csv('winequality-red.csv', sep=';')
white_wine = pd.read_csv('winequality-white.csv', sep=';')

red_wine['color'] = 1
white_wine['color'] = 0

wine = pd.concat([red_wine, white_wine])
wine.reset_index(drop=True, inplace=True)

# 데이터 정리
wine['taste'] = [1. if grade > 5 else 0. for grade in wine['quality']]

X = wine.drop(['taste' , 'quality'], axis=1)
y = wine['taste']
  • GridSearchCV : 그리드를 사용한 복수 하이퍼 파라미터 최적화, 모형 래퍼(Wrapper) 성격의 클래스
    • 클래스 객체에 fit 메서드를 호출하면 grid search를 사용하여 자동으로 복수개의 내부 모형을 생성하고 이를 모두 실행시켜서 최적 파라미터를 찾아준다.
    • gridscores : param_grid 의 모든 파리미터 조합에 대한 성능 결과. 각각의 원소는 다음 요소로 이루어진 튜플이다.
    • parameters: 사용된 파라미터
    • mean_validation_score: 교차 검증(cross-validation) 결과의 평균값
    • cv_validation_scores: 모든 교차 검증(cross-validation) 결과
    • bestscore : 최고 점수
    • bestparams : 최고 점수를 낸 파라미터
    • bestestimator : 최고 점수를 낸 파라미터를 가진 모형
  • validation_curve : 단일 하이퍼 파라미터 최적화
    • 최적화할 파라미터 이름과 범위, 그리고 성능 기준을 param_name, param_range, scoring 인수로 받아 파라미터 범위의 모든 경우에 대해 성능 기준을 계산
  • ParameterGrid : 복수 파라미터 최적화용 그리드
    • 파라미터를 조합하여 탐색 그리드를 생성
# GridSearchCV
# 결과를 확인하고 싶은 파라미터 정의
from sklearn.model_selection import GridSearchCV
from sklearn.tree import DecisionTreeClassifier

params = {'max_depth' : [2, 4, 7, 10]}
wine_tree = DecisionTreeClassifier(max_depth=2, random_state = 13)

# 분류기 지정, 측정할 파라미터 지정, cross validation
gridSearch = GridSearchCV(estimator=wine_tree, param_grid=params, cv=5)
# train, test는 gridSearch에서 해준다.
# n_jobs : CPU 코어를 보다 병렬로 활용한다. 따라서 높이면 속도가 빨라진다.
gridSearch.fit(X, y)

import pprint

pp = pprint.PrettyPrinter(indent = 4)
pp.pprint(gridSearch.cv_results_)

# 최적의 성능을 가진 모델
print(gridSearch.best_estimator_)
# 최적일 경우의 값
print(gridSearch.best_score_)
# 최적일 경우의 parameters
print(gridSearch.best_params_)

pipeline을 적용한 모델에 GridSearch를 적용하고 싶다면

from sklearn.pipeline import Pipeline
from sklearn.tree import DecisionTreeClassifier
from sklearn.preprocessing import StandardScaler
# Pipeline 설정
estimators = [
    ('scaler', StandardScaler()),
    ('clf', DecisionTreeClassifier(random_state=13))
]

pipe = Pipeline(estimators)
# GridSearchCV 설정
# pipeline의 옵션을 수정하기위해 __ 사용
params = [ { 'clf__max_depth' : [2, 4, 7, 10] } ]
GridSearch = GridSearchCV(estimator = pipe, param_grid = params, cv = 5)
GridSearch.fit(X, y)

# 최적 모델
print(GridSearch.best_estimator_)
print(GridSearch.best_score_)
print(GridSearch.best_params_)

# 최적 모델 트리 그리기
import matplotlib.pyplot as plt
from sklearn.tree import plot_tree

plt.figure(figsize=(12, 7))
plot_tree(GridSearch.best_estimator_['clf'], feature_names=X.columns,
          class_names=['W', 'R'],
          filled=True)
plt.show()

표로 성능 결과 정리하기

  • DataFrame으로 만들어 정리할 수 있다.
import pandas as pd

score_df = pd.DataFrame(GridSearch.cv_results_)
score_df[['params', 'rank_test_score', 'mean_test_score', 'std_test_score']]

profile
후라이드 치킨

0개의 댓글