logo

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

 

하이퍼파라미터 튜닝 소개

하이퍼파라미터 튜닝은 머신러닝에서 모델의 성능을 최적화하는 중요한 과정입니다. 이 과정을 이해하기 위해서는 먼저 하이퍼파라미터와 모델 파라미터의 차이를 알아야 합니다.

하이퍼파라미터와 모델 파라미터의 차이

  • 모델 파라미터는 모델이 데이터로부터 학습하는 변수입니다. 이들은 모델 학습 과정에서 자동으로 최적화되며, 예를 들어 선형 회귀에서의 기울기와 절편, 신경망에서의 가중치가 여기에 해당합니다.
  • 하이퍼파라미터는 모델 학습 전에 설정되는 변수로, 모델의 성능과 학습 과정을 제어합니다. 예를 들어, 결정 트리의 깊이, 학습률, 배치 크기 등이 이에 해당합니다.

하이퍼파라미터 튜닝의 중요성

하이퍼파라미터의 설정은 모델의 성능에 직접적인 영향을 미칩니다. 적절히 설정되지 않은 하이퍼파라미터는 모델이 데이터를 과소적합하거나 과대적합하는 원인이 될 수 있습니다. 따라서, 적절한 하이퍼파라미터를 찾는 것은 효율적이고 정확한 모델을 구축하는 데 필수적입니다.

하이퍼파라미터 튜닝 방법 개요

하이퍼파라미터를 튜닝하는 방법에는 여러 가지가 있으며, 그 중 대표적인 두 가지 방법은 그리드 서치(Grid Search)랜덤 서치(Random Search) 입니다.

  • 그리드 서치는 사전에 정의된 하이퍼파라미터의 조합을 모두 탐색하여 최적의 조합을 찾는 방식입니다. 이 방법은 다소 시간이 많이 소요될 수 있지만, 모든 가능한 조합을 탐색하기 때문에 소규모에서 중규모의 데이터셋과 하이퍼파라미터 집합에 적합합니다.

  • 랜덤 서치는 하이퍼파라미터의 범위를 지정하고 그 안에서 무작위로 조합을 선택해 탐색하는 방식입니다. 이 방법은 그리드 서치에 비해 더 빠르게 수행될 수 있으며, 높은 차원의 공간에서 효율적으로 최적의 하이퍼파라미터를 찾을 수 있습니다.

Python을 사용하여 간단히 그리드 서치의 예를 들어보겠습니다. scikit-learn 라이브러리에서 제공하는 GridSearchCV 클래스를 사용합니다.

from sklearn.model_selection import GridSearchCV
from sklearn.ensemble import RandomForestClassifier
import numpy as np

# 예제 데이터셋 로드
from sklearn.datasets import load_digits
digits = load_digits()

# 파라미터 그리드 설정
param_grid = {
    'n_estimators': [10, 50, 100],
    'max_depth': [None, 10, 20, 30]
}

# 랜덤 포레스트 분류기 인스턴스화
rf = RandomForestClassifier()

# 그리드 서치 인스턴스화 및 수행
grid_search = GridSearchCV(estimator=rf, param_grid=param_grid, cv=5)
grid_search.fit(digits.data, digits.target)

# 최적의 파라미터와 그때의 점수
print(grid_search.best_params_)
print(grid_search.best_score_)

이 코드는 scikit-learn의 digits 데이터셋에 대해 랜덤 포레스트 분류기의 최적의 n_estimatorsmax_depth를 찾습니다. 이처럼 하이퍼파라미터 튜닝은 모델의 성능을 극대화하기 위해 필수적으로 고려해야 하는 과정입니다.


 

그리드 서치(Grid Search)

 

그리드 서치의 개념

그리드 서치(Grid Search)는 모델의 성능을 최적화하기 위해 수동으로 설정해야 하는 하이퍼파라미터를 조정하는 과정 중 하나입니다. 이 방법은 머신러닝 모델에서 사용되는 모든 하이퍼파라미터의 가능한 조합을 미리 정의된 값의 그리드(격자)에서 시도해보는 방식입니다. 각각의 파라미터 조합에 대해 교차 검증을 실시하여 최적의 파라미터 세트를 찾는 과정이 포함됩니다.

 

작동 원리

파라미터 공간의 정의

하이퍼파라미터 그리드는 모델에 사용할 하이퍼파라미터와 각 파라미터가 취할 수 있는 값의 범위를 정의합니다. 예를 들어, 결정 트리 모델의 경우 'max_depth'(트리의 최대 깊이)와 'min_samples_split'(노드를 분할하기 위한 최소 샘플 수) 파라미터에 대한 가능한 값의 그리드를 정의할 수 있습니다.

평가 지표 선택

모델의 성능 평가를 위해 하나 또는 복수의 평가 지표(metric)를 선택합니다. 이 평가 지표는 각 파라미터 조합의 성능을 평가하는 데 사용됩니다. 일반적으로 분류 문제에서는 정확도(accuracy), 정밀도(precision), 재현율(recall)과 같은 지표를, 회귀 문제에서는 평균 제곱 오차(MSE)나 평균 절대 오차(MAE)와 같은 지표를 사용할 수 있습니다.

 

장점과 단점

장점: 단순성과 전체성

그리드 서치는 구현이 쉽고 직관적이며, 하이퍼파라미터의 전체적인 탐색 공간을 체계적으로 탐색하기 때문에 가능한 최적의 조합을 찾을 수 있는 잠재력을 가집니다.

단점: 계산 비용과 차원의 저주

그리드 서치의 주요 단점은 계산 비용이 매우 높다는 것입니다. 파라미터 조합의 수가 많아질수록 필요한 계산량이 기하급수적으로 증가합니다. 또한, '차원의 저주'로 인해 파라미터의 수가 많아질수록 효과적인 탐색이 어려워지고, 최적의 결과를 찾는 데 더 많은 시간과 자원이 소요될 수 있습니다.

 

그리드 서치 구현 예시

사이킷런을 이용한 그리드 서치 구현 방법

사이킷런(scikit-learn) 라이브러리는 GridSearchCV 클래스를 통해 그리드 서치를 쉽게 구현할 수 있도록 합니다. 다음 예제는 결정 트리 분류기에 대한 그리드 서치를 실시하는 과정을 보여줍니다.

from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import GridSearchCV
from sklearn.datasets import load_iris

# 데이터 로드
iris = load_iris()
X, y = iris.data, iris.target

# 결정 트리 분류기 설정
dtree = DecisionTreeClassifier()

# 파라미터 그리드 설정
param_grid = {
    'max_depth': [3, 4, 5, 6, 7],
    'min_samples_split': [2, 3, 4, 5]
}

# 그리드 서치 설정
grid_search = GridSearchCV(estimator=dtree, param_grid=param_grid, cv=5)

# 그리드 서치 실행
grid_search.fit(X, y)

# 최적의 파라미터와 성능 출력
print("최적의 파라미터:", grid_search.best_params_)
print("최고 성능:", grid_search.best_score_)

그리드 서치 결과의 해석과 선택

위의 예제에서 GridSearchCV는 주어진 파라미터 그리드 내에서 모든 가능한 조합을 시도하고, 교차 검증을 사용하여 각 조합의 성능을 평가합니다. grid_search.best_params_ 속성을 통해 최적의 파라미터 조합을 확인할 수 있으며, grid_search.best_score_ 속성은 해당 파라미터 조합에 대한 최고 성능을 보여줍니다. 이 정보를 바탕으로 적절한 모델 세팅을 선택하여 최종 모델을 훈련할 수 있습니다.


 

랜덤 서치(Random Search) 소개

랜덤 서치는 머신러닝 모델의 하이퍼파라미터 최적화 방법 중 하나로, 고려되는 하이퍼파라미터의 범위 내에서 무작위로 파라미터 값을 선택하여 모델을 평가하는 기법입니다. 이 방법은 특히 하이퍼파라미터의 탐색 공간이 클 때 그리드 서치(Grid Search)에 비해 더 효과적일 수 있습니다.

 

작동 원리

무작위 파라미터 샘플링

랜덤 서치는 지정된 범위 또는 분포에서 하이퍼파라미터 값을 무작위로 샘플링하여 선택합니다. 이 과정은 사전에 정의된 탐색 공간에서 진행되며, 사용자는 탐색할 파라미터 및 해당 범위를 지정함으로써 탐색 공간을 제어할 수 있습니다.

평가 지표 선택

선택된 하이퍼파라미터 조합으로 모델을 훈련시킨 후, 모델의 성능을 평가하기 위해 사전에 선택된 평가 지표(예: 정확도, F1 점수, RMSE 등)를 사용합니다. 이를 통해 각 샘플링된 하이퍼파라미터 조합의 성능을 비교할 수 있습니다.

 

장점과 단점

장점

  • 계산 비용 절약: 전체 파라미터 공간을 탐색하지 않기 때문에, 그리드 서치에 비해 계산 비용이 적게 듭니다.
  • 고차원 공간에서 효율적: 일부 하이퍼파라미터는 모델 성능에 큰 변화를 주지 않는 경우가 많아, 이를 완전 탐색하는 것은 비효율적일 수 있습니다. 랜덤 서치는 이러한 고차원 공간에서 더 나은 성능의 하이퍼파라미터 조합을 빠르게 찾을 가능성이 높습니다.

단점

  • 최적화 공간의 축소가 불명확: 무작위 탐색이기 때문에, 최적의 하이퍼파라미터 조합을 찾지 못할 가능성이 있으며, 얼마나 많은 샘플링을 해야 할지 예측하기 어렵습니다.
 

랜덤 서치 구현 예시: 사이킷런을 이용한 랜덤 서치 구현 방법

사이킷런의 RandomizedSearchCV 클래스를 이용하여 랜덤 서치를 손쉽게 구현할 수 있습니다. 다음은 랜덤 서치를 이용해서 분류기의 하이퍼파라미터를 최적화하는 예시 코드입니다.

from scipy.stats import randint
from sklearn.model_selection import RandomizedSearchCV
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_digits

# 데이터 로딩
digits = load_digits()

# 모델 초기화
model = RandomForestClassifier(n_estimators=20)

# 하이퍼파라미터 분포 지정
param_dist = {"max_depth": [3, None],
              "max_features": randint(1, 11),
              "min_samples_split": randint(2, 11),
              "bootstrap": [True, False],
              "criterion": ["gini", "entropy"]}

# 랜덤 서치 객체 생성
random_search = RandomizedSearchCV(model, param_distributions=param_dist, n_iter=100, cv=5, scoring='accuracy', random_state=5)

# 랜덤 서치 수행
random_search.fit(digits.data, digits.target)

# 결과 출력
print("최적 파라미터: ", random_search.best_params_)
print("최고 점수: ", random_search.best_score_)

이 코드는 사이킷런의 RandomizedSearchCV를 사용하여 무작위로 선택된 하이퍼파라미터 조합으로 랜덤 포레스트 분류기를 여러 번 훈련시키고, 가장 성능이 좋은 조합을 찾는 예시입니다.

 

랜덤 서치 결과의 해석과 선택

랜덤 서치가 완료되면, best_params_ 속성을 통해 최적의 하이퍼파라미터 조합을 알 수 있고, best_score_를 통해 해당 하이퍼파라미터에서 달성한 최고의 성능을 확인할 수 있습니다. 또한, cv_results_ 속성을 통해 각 단계별 세부 결과를 분석할 수 있어, 탐색 과정에서의 성능 분포 및 트렌드를 파악하는 데 도움이 됩니다.


 

그리드 서치 vs 랜덤 서치

하이퍼파라미터 튜닝은 머신러닝 모델의 성능을 향상시키기 위해 모델의 구성 요소를 조정하는 과정입니다. 이 과정에서 자주 활용되는 두 가지 주요 기법은 그리드 서치(Grid Search)와 랜덤 서치(Random Search)입니다. 이 두 방법은 하이퍼파라미터의 최적 조합을 찾는 방식에서 차이가 있으며, 상황에 따라 선택적으로 사용될 수 있습니다.

비교 기준

  1. 시간 효율성

    • 그리드 서치는 사전에 정의된 모든 가능한 하이퍼파라미터 조합을 시도합니다. 이 방식은 상대적으로 높은 시간 비용이 요구되며, 하이퍼파라미터의 수나 범위가 클 경우 탐색 시간이 기하급수적으로 증가할 수 있습니다.
    • 랜덤 서치는 하이퍼파라미터의 가능한 조합 중에서 랜덤하게 선택된 조합을 시도합니다. 이 방식은 그리드 서치에 비해 탐색 시간이 단축되며, 특히 하이퍼파라미터 공간이 클 때 시간 효율성이 더욱 두드러집니다.
  2. 탐색 공간

    • 그리드 서치는 정해진 그리드(탐색 공간) 안의 모든 점들을 체계적으로 탐색합니다. 이는 그리드가 잘 정의되어 있다면 높은 정확성을 기대할 수 있지만, 하이퍼파라미터 공간이 넓을 수록 탐색에 많은 시간이 소요됩니다.
    • 랜덤 서치는 그리드를 따르지 않고 가능한 값을 랜덤하게 추출하여 탐색합니다. 이 방식은 탐색 공간에서 중요한 영역을 빠르게 식별할 수 있으며, 때로는 예상치 못한 영역에서 좋은 결과를 발견할 수도 있습니다.
  3. 최적화 가능성

    • 그리드 서치는 미리 정의된 그리드 안에서 최적의 조합을 찾는 것을 목표로 하므로, 그리드 설정에 따라 최적의 조합을 놓칠 수 있습니다.
    • 랜덤 서치는 탐색 공간 전체에서 랜덤하게 조합을 탐색하기 때문에, 예상치 못한 구역에서 좋은 성능을 발견할 가능성이 있습니다. 특히, 중요하게 작용하는 하이퍼파라미터에 대해서 유연하게 탐색할 수 있다는 장점이 있습니다.

적합한 상황

  1. 그리드 서치 사용 권장

    • 하이퍼파라미터가 적고, 그 값의 범위가 비교적 좁은 경우
    • 시간과 자원이 충분히 확보되어 정밀한 탐색이 가능한 경우
  2. 랜덤 서치 사용 권장

    • 하이퍼파라미터의 수가 많거나, 탐색해야 할 값의 범위가 넓은 경우
    • 빠른 시간 내에 합리적인 결과를 얻어야 할 때
    • 특정 하이퍼파라미터가 모델 성능에 미치는 영향이 크게 다를 때

예시 코드

# 간단한 예시 코드: Scikit-learn을 사용한 그리드 서치와 랜덤 서치
from sklearn.model_selection import GridSearchCV, RandomizedSearchCV
from sklearn.ensemble import RandomForestClassifier
from scipy.stats import randint

# 분류기 및 데이터 준비
clf = RandomForestClassifier()
X_train, y_train = ... # 훈련 데이터 준비

# 그리드 서치
param_grid = {
    'n_estimators': [10, 50, 100, 200],
    'max_depth': [None, 10, 20, 30],
}
grid_search = GridSearchCV(clf, param_grid, cv=5)
grid_search.fit(X_train, y_train)

# 랜덤 서치
param_dist = {
    'n_estimators': randint(10, 200),
    'max_depth': [None, 10, 20, 30],
}
random_search = RandomizedSearchCV(clf, param_distributions=param_dist, n_iter=100, cv=5)
random_search.fit(X_train, y_train)

이 예시에서 그리드 서치는 'n_estimators'와 'max_depth'의 모든 조합을 시도합니다. 반면, 랜덤 서치는 지정된 분포에서 랜덤하게 파라미터를 선택하여 100번의 시도를 합니다.


하이퍼파라미터 튜닝은 머신러닱 모델의 성능을 최적화하는 핵심 과정 중 하나입니다. 이 과정은 모델이 데이터에서 학습할 때 조절하는 매개변수인 하이퍼파라미터의 가장 좋은 조합을 찾는 것을 목표로 합니다. 이를 위한 최적의 접근 방법은 각 프로젝트의 특성, 데이터의 크기, 모델의 복잡도, 그리고 가용한 계산 자원을 고려하여 결정되어야 합니다.

 

모델 복잡도와 데이터 크기 고려

머신러닝 모델의 복잡도와 관련해 하이퍼파라미터 튜닝을 시작하기 전에 가장 중요한 점은 튜닝할 하이퍼파라미터의 범위와 적절한 값들을 신중하게 선택하는 것입니다. 모델이 너무 단순하면 데이터의 복잡성을 충분히 표현하지 못하고, 너무 복잡하면 과적합(overfitting)의 위험이 있습니다. 데이터 크기 또한 중요한데, 대량의 데이터를 가지고 있다면 더 복잡한 모델을 훈련시킬 수 있지만, 하이퍼파라미터 튜닝 시간도 길어질 수 있습니다.

 

병렬화와 분산 계산의 활용

계산 리소스를 최대한 활용하기 위해서는 병렬화와 분산 계산을 고려해야 합니다. 대부분의 최신 하이퍼파라미터 최적화 방법은 복수의 모델을 동시에 훈련시키면서 다양한 하이퍼파라미터 조합을 평가할 수 있도록 설계되어 있습니다. 예를 들어, 그리드 서치나 랜덤 서치를 수행할 때 여러 CPU 코어나 GPU를 사용해 동시에 여러 가지 하이퍼파라미터 설정으로 모델을 훈련시키는 것이 가능합니다.

from sklearn.model_selection import GridSearchCV, RandomizedSearchCV
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import make_classification

# 임의의 데이터셋 생성
X, y = make_classification(n_samples=1000, n_features=20, n_informative=2, random_state=42)

# 모델 정의
model = RandomForestClassifier()

# 하이퍼파라미터 설정
param_grid = {'n_estimators': [10, 50, 100], 'max_depth': [None, 10, 20, 30]}

# 그리드 서치 실행
grid_search = GridSearchCV(model, param_grid, cv=5, n_jobs=-1)  # n_jobs=-1은 모든 CPU 코어 사용을 의미함
grid_search.fit(X, y)
 

베이지안 최적화 등 고급 방법의 소개

베이지안 최적화는 특히 비용이 많이 드는 모델 평가에 유용한 고급 하이퍼파라미터 최적화 방법입니다. 이 방법은 이전의 평가 결과를 바탕으로 하여 어떤 하이퍼파라미터가 성능을 개선할 가능성이 가장 높은지 예측합니다. 그 후, 그 예측을 기반으로 새로운 하이퍼파라미터를 선택합니다. 이 과정을 반복함으로써, 베이지안 최적화는 상대적으로 적은 시도로 좋은 성능의 하이퍼파라미터 조합을 찾을 수 있습니다.

베이지안 최적화를 구현하는 라이브러리 중 하나는 scikit-optimize (skopt)입니다. 이를 이용한 간단한 예제는 다음과 같습니다.

from skopt import BayesSearchCV
from sklearn.datasets import load_iris
from sklearn.svm import SVC

# 데이터 로드
X, y = load_iris(return_X_y=True)

# 베이지안 최적화 설정
opt = BayesSearchCV(
    SVC(),
    {
        'C': (1e-6, 1e+6, 'log-uniform'),
        'gamma': (1e-6, 1e+1, 'log-uniform'),
        'kernel': ['linear', 'poly', 'rbf', 'sigmoid'],
    },
    n_iter=32,
    cv=5,
    n_jobs=-1
)

# 최적화 실행
opt.fit(X, y)

print("Best parameters found: ", opt.best_params_)

이처럼 베이지안 최적화는 효과적인 하이퍼파라미터 탐색을 위해 매우 유용한 도구로, 작은 수의 평가로도 최적의 조합을 찾는데 있어 상대적으로 높은 효율성을 보입니다.

결론적으로, 최적의 하이퍼파라미터 튜닝 방법을 선택할 때는 모델의 복잡도, 데이터의 크기와 구조, 그리고 사용 가능한 계산자원을 고려하여 다양한 방법 중 가장 적합한 것을 선택해야 합니다. 이 과정에서 실험적 접근이 중요하며, 복수의 방법을 조합하거나 새로운 기법을 시도해보는 것이 효과적일 수 있습니다.

Previous
인공신경망