심심해서 하는 블로그 :: 심심해서 하는 블로그

하이퍼파라미터 최적화.. 중요한 건 알겠는데.. 일일히 하는게 번거롭네?


하이퍼파라미터의 최적화는 기계학습의 중요한 태스크 중에 하나입니다.

하이퍼파라미터를 어떻게 선택하는 가에 따라 Overfit 이 된 모델이 될 수 도 있고, Underfit 모델이 될 수 있습니다.

하지만 같은 종류의 모델을 사용하더라도 학습하는 데이터에 따라서 하이퍼파라미터의 값은 상이합니다.


우리는 최적화된 파라미터를 찾기 위해서 값을 조정하면서, 모델을 수행을 하고 모델을 검증을 합니다.

그리고 이걸 결과가 좋을 때까지 하이퍼 파라미터 값을 재변경해서 다시 학습 및 검증을 하는 과정을 반복합니다.

근데 이 과정이 생각보다 귀찮습니다.


Optuna : 하이퍼파라미터 최적화 프레임워크

Optuna는 하이퍼파라미터 최적화 태스크를 도와주는 프레임워크입니다.

파라미터의 범위를 지정해주거나, 파라미터가 될 수 있는 목록을 설정하면 매 Trial 마다 파라미터를 변경하면서, 최적의 파라미터를 찾습니다.


하이퍼파라미터의 범위나 목록은 아래의 방법으로 설정할 수 있습니다.


  • suggest_int : 범위 내의 정수형 값을 선택합니다.

n_estimators = trial.suggest_int('n_estimators',100,500)

  • suggest_categorical : List 내의 데이터 중 선택을 합니다.

criterion = trial.suggest_categorical('criterion' ,['gini', 'entropy'])

  • suggest_uniform : 범위 내의 균일 분포를 값으로 선택합니다.

subsample = trial.suggest_uniform('subsample' ,0.2,0.8)

  • suggest_discrete_uniform : 범위 내의 이산 균등 분포를 값으로 선택합니다.

max_features = trial.suggest_discrete_uniform('max_features', 0.05,1,0.05)

  • suggest_loguniform : 범위 내의 로그 함수 선상의 값을 선택합니다.

learning_rate = trial.sugget_loguniform('learning_rate' : 1e-6, 1e-3)

 

소스 코드

이전 포스팅에서 사용했던 XGBoost Regressor를 최적화 하는데 사용한 소스코드 입니다.

전체 소스코드는 https://www.kaggle.com/ssooni/xgboost-lgbm-optuna 를 참고하시면 됩니다.


매 Trial 마다 수행할 함수를 작성합니다.

함수 내부에는 하이퍼파라미터의 값을 정의하는 부분과 모델을 학습하는 부분을 작성하고 Loss Metric의 결과를 반환합니다.



이제 아래의 소스를 참고해서 optuna를 사용해서 최적의 파라미터를 찾아봅시다.

최적의 파라미터는 study.best_trial.params 에 저장되어 있습니다.



optuna는 추가적으로 학습하는 절차를 확인할 수 있는 시각화 툴도 제공합니다.

다양한 시각화 기법을 제공하지만 저는 매 Trial 마다 Loss가 어떻게 감소되었는 확인 할 수 있는 함수와

하이퍼 파라미터 별로 중요도를 확인할 수 있는 함수를 소개 합니다.



도움이 되셨으면, 아래의 공감 버튼을 눌러주세요.

공감 버튼은 작성자에게 큰 동기부여가 됩니다.

,

캐글에서 사랑받는 XGBoost

요즘 캐글에서 문제를 도전해보는 재미로 공부를 하고 있습니다.

최근에는 Tabular Playground Series - Jan 2021[ kaggle.com/c/tabular-playground-series-jan-2021 ] 를 푸는 중에 다른 사람들이 올려놓은 노트북을 참고 해보니,

대부분이 XGBoost를 사용해서 문제를 풀고 있는 것을 확인 했습니다.

왜 이렇게 사랑 받고 있는지 궁금해서 직접 사용해보고 느낀 점을 정리해서 포스팅 해보곘습니다.


앙상블 기법 : Boosting

그 전에 XGBoost에서 사용하는 Boosting이라는 앙상블 기법에 대해서 간단하게 설명을 해보겠습니다.

앙상블은 직관적으로 "집단 지성" 이라고 생각을 하면 편리합니다. 여러 개의 모델을 사용해서 각각의 예측 결과를 만들고 그 예측 결과를 기반으로 최종 예측결과를 정하는 방법이죠


그 중 Boosting이란 방법은 비교적 약한 모델들을 결합하여 하나의 강한 모델 만드는 과정입니다.

모델 A이 예측한 결과를 다음 모델인 B에서 보완하여 예측하고 최종적으로 C에서 보완을 해서 예측 결과를 만들어 내는 방식이죠.

Boosting을 사용하는 대표적인 모델은 AdaBoost, Gradient Boost 등등이 이 있고 XGBoost는 그 중 Gradient Boosting 을 사용해서 모델링을 합니다.


Gradient Boosting 설명을 수학없이 간결하게 해준 유튜브 영상이 있어서 링크를 남겨 둘게요.

이거보다 설명 잘 할 수 없을거 같아요. 꼭 보세요. 두 번 보세요.

https://www.youtube.com/watch?v=3CC4N4z3GJc


XGBoost : Extreme Gradient Boosting

장점 : 계산 속도 향상, Kaggle에서 수차례 우승한 경력

sklearn 에도 Gradient Boosting 로 Regression 또는 Classification 을 할 수 있는 매소드를 제공하고 있습니다만, 시간이 너무 오래 걸립니다.

하지만 XGBoost의 경우에는 병렬 연산을 지원하여 계산 속도를 향상 시킵니다.

또한 GPU를 사용 할 수 있는 옵션을 제공하기 때문에 학습하는데 소요되는 시간을 절약할 수 있습니다.

이것은 하이퍼파라미터 튜닝을 할 때도 특히 빛이 납니다. (CPU 만으로 50회를 돌리다 하루가 넘게 소요되서 당황스러웠던 기억이 있습니다.)

 

XGBoost는 Overfitting 을 Overfitting 을 제어 하기 위해 두 가지 방법을 제안합니다.

1. 모델의 복잡도를 제어하는 방법 : max_depth, min_child_weight, gamma 하이퍼파라미터 사용

2. 다음 모델로 Loss 를 전달할 때 Random Value를 추가하는 방법 : subsample, colsample_bytree 파라미터 사용

 

그 외에도 early_stopping_rounds 를 사용해서 눈에 띄지 않게 Loss가 감소하지 않은 경우에는 학습을 진행하지 않도록 제어도 가능합니다.

학습 성능의 경우에는 kaggle의 수차례 우승한 사례를 봤을 때, 충분히 우수하다고 판단됩니다.


 

 

단점 : Tree Based Learning, 복잡한 하이퍼 파라미터

 

모든 학습 알고리즘이 그렇듯, 장점과 단점이 있기 때문에 데이터의 분포나 상황에 알맞게 사용해야 합니다.

 

1. Tree Based Learning 를 학습할 때 학습 데이터에 예민하게 반응합니다.

학습 데이터에서 1~10 사이의 범주를 가진 라벨로 학습을 진행한 모델이 있다고 합시다.

이 모델은 데이터의 예측을 1 ~ 10 사이의 값으로 예측을 하고자 하고 10 초과, 1 미만으로 반환을 하기 어렵습니다.

 

2. 적절하게 튜닝을 하지 않은 모델은 Overfit이 쉽게 발생하는 문제 때문에 반드시 진행해야하는 절차입니다.

그런데 XGBoost는 튜닝을 할 때 손봐야할 파라미터가 너무 많습니다.

(당장 xgboost 공식 홈페이지에 가서 내용을 봐도, 파라미터가의 수가 너무 많습니다.)


소스코드

https://www.kaggle.com/ssooni/xgboost-lgbm-optuna

소스코드에는 XGBoost 외에도 LightGBM, Optuna, Stacking 앙상블을 사용한 내용도 있습니다.


,

이전 포스팅 : 2019/01/15 - [Data Mining] - [Python] 공공데이터 API 사용기 (feat 미세먼지)

GitHub : https://github.com/ssooni/data_mining_practice

소소한 근황 소개

미세먼지 API를 사용하는 것을 이후로 SVM이나 Correlation 적용하는 등의 시도를 하였으나,

생각보다 결과도 좋지 않았고 내가 알고 있는 지식의 한계가 와서... 대학원을 가버렸다(응?)

또 약간의 지식을 배웠으니까 블로그에 정리를 해봅니다.


Sequence Model

앞선 포스팅에서 매 시간마다 측정한 미세먼지 및 기상 데이터를 수집을 하였습니다.

미세먼지나 기상데이터의 특징이라고 한다면 시간에 따른 순서가 있는 데이터라는 점입니다.

이러한 종류의 데이터를 모델링하는 걸 Sequence Model이라고 하며 RNN, LSTM, 이번에 다룰 GRU 등이 있다.

Sequence Model에 주로 적용하는 데이터는 주식이나 텍스트 등이 있다.

(우리가 사용하는 언어도 어순이 있기 때문에 Sequence Model 대상이다.)


일반적으로 사용하는 신경망에서 Sequence Data 를 사용하기 어려운 이유는 2가지입니다.

입력 데이터와 출력 데이터의 길이가 가변적이다.

대표적으로 CNN은 입력값이나 출력값의 길이가 모델을 학습하거나 적용할 때 동일합니다.

하지만 우리가 주로 보는 동영상이나 책을 입력 데이터로 한다면 각각의 데이터의 길이가 다른데,

이러한 점은 일반적인 인공 신경망 알고리즘에는 적합하지 않은 데이터입니다.

(일부 논문에서는 0으로 부족한 공간을 채워서 연구한 사례가 있긴 합니다.)

 

일반적인 신경망 알고리즘에서는 데이터의 순서를 반영하지 않습니다.

데이터를 섞어도 학습 결과가 크가 변화하지 않습니다.

즉, 데이터의 선후 관계가 전혀 반영이 되지 않는다는 점이 한계입니다.


RNN의 구조

뒤에서 자꾸 무언가를 준다..

RNN의 학습하는 과정을 도식을 하면 아래와 같이 보통 표현합니다.

 

RNN 구조 도식

파란 색으로 부분을 cell 이라고 합니다.

각각의 cell은 매 단계 마다 일렬로 입력되는 input x와 이전 단계의 결과로 산출된 hidden 값 h를 입력으로 받고 출력으로 예측 값인 y 와 다음 단계로 전달할 hidden 값을 전달합니다.


매 단계마다 이전 단계에서 만들어진 hidden 값을 사용하여 y 값을 생성하기 때문에
입력 값의 순서가 다르면 hidden 값 역시 다르기 때문에 앞서 말한 선후 관계가 반영되지 않은 문제점을 해결할 수 있습니다.

또한 RNN은 다양한 Input 과 Output 의 구조를 가질 수 있습니다.
1:N, N:M, N:1 등의 다양한 구조의 데이터를 적용합니다.


GRU : Gated Recurrent Unit

RNN은 단점이 있습니다. Cell 내부에서는 실제로 소수점 단위의 계산이 이뤄지고 있고 그 결과로 h 값이 발생하는데,

Sequence가 너무 긴 데이터의 경우에 0에 가까운 값이 오고 가게 되어 컴퓨터가 계산할 수 없는 작은 수로 수렴하게 되는 문제가 있습니다.

Gradient Vanishing 으로 불리는 이 문제는 이전 단계의 정보를 선택적으로 학습을 하는 즉, "줄 건 줘" 방식으로 계산하는 LSTM이나 GRU를 통해 개선이 되었습니다.


그리고 이전 단계의 데이터의 반영과 현재 데이터에 대한 반영의 비율을 Gate 를 통해 제어를 합니다.
GRU는 Reset / Update 두 종류의 게이트를 사용해서 학습하는 모델입니다.


Reset Gate

Reset Gate 에서는 이전 단계의 Hidden status 값과 현 단계의 x 값을 Sigmoid 함수에 적용하여 0 ~ 1 사이의 값을 얻습니다.

 이 값을 이용해서 과거(이전 데이터)의 Hidden 정보를 현재의 정보를 구하는데 얼마만큼 반영 할 것인지 정합니다.


Update Gate

Update Gate 에서도 이전 단계의 Hidden status 값과 현 단계의 x 값을 Sigmoid 함수에 적용하여 0 ~ 1 사이의 값을 얻습니다.

물론 Reset Gate의 Weight 와 다른 Weight를 이용해 계산합니다. 

이 값을 이용해서 전체 데이터의 양을 1로 했을 때 현재의 정보를 반영할 비율을 $z_t$, 과거의 정보를 반영할 비율을 $1-z_t$ 로 합니다.
이제 현재의 정보를 아래의 식을 이용해서 구합니다. 

Reset Gate에서 구한 $r_t$를 이용해서 현재 정보를 얻습니다.

마지막으로 현재의 HIdden Status를 과거의 Hiddent Status와 현재의 정보를 앞서 구한 비율 $z_t$ 를 적용하여 계산 후 다음 단계로 전달합니다.

 

 

Pytorch 로 적용 해보기

전체 소스 코드 : https://github.com/ssooni/data_mining_practice/blob/master/dust_weather/GRU.ipynb

class GRU(nn.Module):
    def __init__(self, n_layers, hidden_dim, input_dim, n_classes=1, dropout_p=0.2):
        super(GRU, self).__init__()
        self.n_layers = n_layers
        self.hidden_dim = hidden_dim

        self.dropout = nn.Dropout(dropout_p)
        self.gru = nn.GRU(input_dim, self.hidden_dim, num_layers=self.n_layers, batch_first=True, dropout=dropout_p)
        self.fc = nn.Linear(self.hidden_dim, n_classes)

    def forward(self, x):
        h0 = self._init_state(x.size(0))
        out, (hn) = self.gru(x, (h0.detach()))
        out = self.fc(out[:, -1, :]) 
        return out

    def _init_state(self, batch_size=1):
        weight = next(self.parameters()).data
        return weight.new(self.n_layers, batch_size, self.hidden_dim).zero_().to(DEVICE)

 

전체 소스코드와 실행 결과를 GitHub 에 올려 두었습니다. 
매 시간 측정된 날씨 데이터와 미세 먼지 데이터를 이용해서 예측을 해보는 것을 해보았습니다.
실습용으로 사용할려고, 전처리도 간단하게 하고 프로그램도 간단하게 구현했습니다. 
참고용으로만 사용하시고, 원하는 도메인에 적절하게 적용하세요

 

> 공감 버튼은 작성자에게 큰 동기부여가 됩니다.

,