My Data Story

[딥러닝] 인공 신경망 - 신경망 하이퍼파라미터 튜닝하기 본문

Deep Learning

[딥러닝] 인공 신경망 - 신경망 하이퍼파라미터 튜닝하기

Hwasss 2021. 9. 5. 01:42
728x90

◈  '인공 신경망' 목차 

1. 퍼셉트론

2. 다층 퍼셉트론

3. 케라스 API 소개

4. 시퀀셜 API 구현

5. 함수형 API 구현

6. 서브클래싱 API 구현

7. 모델 저장과 복원, 콜백, 텐서보드

8. 신경망 하이퍼파라미터 튜닝하기

    최적의 신경망 구축하기 위해 적절한 하이퍼파라미터를 선정하는 방법에 대해 살펴보자.


신경망의 유연성은 단점이기도 하다. 조정할 하이퍼파라미터가 많기 때문이다. 

아주 복잡한 네트워크 구조에서 뿐만 아니라 간단한 다층 퍼셉트론에서도 층의 개수, 층마다 있는 뉴런의 개수, 각 층에서 사용하는 활성화 함수, 가중치 초기화 전략 등 많은 것을 바꿀 수 있다. 

 

그렇다면 어떻게 어떤 하이퍼파라미터 조합이 주어진 문제에 최적인지 알 수 있을 까요?

1. GridSearchCV/RandomSearchCV

한 가지 방법은 많은 하이퍼파라미터 조합을 시도해보고 어떤 것이 검정 세트에서 (또는 K폴드 교차 검증으로) 가장 좋은 점수를 내는 지 확인하는 것이다. 예를 들어 GridSearchCV나 RandomSearchCV를 사용해 하이퍼파라미터 공간을 탐색할 수 있다. 

이렇게 하려면 케라스 모델을 사이킷런 추정기처럼 보이도록 바꾸어야 한다. 

 

우선 일련의 하이퍼파라미터로 케라스 모델을 만들고 컴파일하는 함수를 만든다.

 

def build_model(n_hidden=1, n_neurons=30, learning_rate=3e-3, input_shape=[8]) :
    model=keras.models.Sequentail()
    model.add(keras.layers.InputLayer(input_shape=input_shape))
    
    for layer in range(n_hidden) :
        model.add(keras.layers.Dense(n_neurons, activation='relu'))
        
    model.add(keras.layers.Dense(1))
    
    optimizer=keras.optimizers.SGD(lr=learning_rate)
    model.compile(loss='mse', optimizer=optimizer)
    
    return model

 

build_model() 함수로 만들어진 케라스 모델을 감싸는 간단한 wrapper인 KerasRegressor 객체를 생성한다.

 

keras_reg = keras.wrapper.scikit_learn.KerasRegressor(build_model)

 

KerasRegressor 객체 생성 시, 어떤 하이퍼파라미터도 지정하지 않았으므로 기본 하이퍼파라미터를 사용할 것이다.

KerasRegressor는 fit()로 훈련하고 socre()로 평가하고 predict() 로 예측할 수 있다.

 

fit()을 통해 지정한 모든 매개 변수를 케라스 모델로 전달된다.

사이킷런은 손실이 아니라 점수를 계산하기 때문에 출력 점수는 음의 MSE이다. 

 

keras_reg.fit(X_train, y_train, epochs=100,
              validation_data=(X_valid, y_valid),
              calllbacks=[keras.callbacks.EarlyStopping(patience=10)])

mse_test = keras_reg.score(X_test, y_test)
y_pred = keras_reg.predict(X_new)

 

모델 하나를 훈련하고 평가하는 것이 아니라 수백 개의 모델을 훈련하고 검증 세트에서 최상의 모델을 선택해야 하므로 GridSearchCV 보다 RandomizedSearchCV 를 사용하는 것이 더 좋을 것 같다.

 

from scipy.stats import reciprocal
from sklearn.model_selection import RandomizedSearchCV

param_distribs = {
     'n_hidden' : [0,1,2,3],
     'n_neurons' : np.arange(1,100),
     'learning_rate' : reciprocal(3e-4, 3e-2).
   }
   
rnd_search_cv = RandomizedSearchCV(keras_reg, param_distribs, n_iter=10, cv=3)
rnd_search_cv.fit(X_train, y_train, epochs=100,
                  validation_data=(X_valid, y_valid),
                  callbacks=[keras.callbacks.EarlyStopping(patience=10)]))

 

이때 RandomizedSearchCV 는 k-겹 교차 검증을 사용하기 때문에 X_valid와 y_valid 를 사용하지 않는다.

이 데이터는 조기 종료에만 사용된다. 

 

랜덤 탐색은 하드웨어와 데이터셋의 크기, 모델의 복잡도, n_iter, cv 매개 변수에 따라 몇 시간 걸릴 수 있다. 

실행이 끝나면 다음처럼 랜덤 탐색이 찾은 최상의 하이퍼파라미터와 훈련된 케라스 모델을 얻을 수 있다.

 

print(rnd_search_cv.best_params_)
print(rnd_search_cv.best_score_)

model = rnd_search_cv.best_estimator_model

 

 

2. 하이퍼파라미터 튜닝 라이브러리

랜덤 탐색을 사용하는 것은 크게 어렵지 않으며 간단한 문제에서 잘 동작한다.

하지만 훈련에 시간이 많이 걸리면 탐색할 수 있는 하이퍼파라미터 공간에 제약이 생긴다. 

 

탐색 과정을 수동으로 부조하여 이 문제를 부분적으로 완화할 수 있다. 

하이퍼파라미터 범위를 크게 하여 빠르게 첫 번째랜덤 탐색을 수행하고,

첫 번째 탐색에서 찾은 하이퍼파라미터 값을 중심으로 더 좁은 범위를 탐색한다. 

 

훨씬 더 효율적으로 파라미터 공간을 탐색하는 기법이 있다. 

탐색 지역이 좋다고 판명될 때 더 탐색을 수행하는 것이다. 

이 기법은 수동으로 탐색 영역을 좁혔던 작업을 대신 관리하여 훨씬 적은 시간 내에 더 나은 솔루션을 만든다.

하이퍼파라미터 최적화에 사용할 수 있는 몇몇 파이썬 라이브러리는 다음과 같다.

 

˙ Hyperopt

 학습률과 같은 실수와 층의 개수 같은 이산적인 값을 포함하여 모든 종류의 복잡한 탐색 공간에 대해 최적화를 수행할 수 있는 잘 알려진 라이브러리이다.

 

˙ Hyperas, kpot, Talos

케라스 모델을 위한 하이퍼파라미터 최적화 라이브러리이다. (처음 두개는 Hyperopt 기반이다.)

 

˙ 케라스 튜너

사용하기 쉬운 켈스 하이퍼파라미터 최적화 라이브러리이다. 구글이 만들었고, 시각화와 분석을 포함한 클라우드 서비스로도 제공될 예정이다.

 

˙ Scikit-Optimize(skopt)

범용 최적화 라이브러리이다. BayesSearchCV 클래스는 GridSearchCV와 비슷한 인터페이스를 사용하여 베이즈 최적화를 수행한다. 

 

˙ Spearmint

베이즈 최적화 라이브러이다.

 

˙ Hyperband

리샤 리 등의 최근 Hyperband 논문을 기반으로 구축된 빠른 하이퍼파라미터 튜닝 라이브러리이다.

 

˙ Sklearn-Deap

GridSearchCV와 비슷한 인터페이스를 가진 진화 알고리즘 기반의 하이퍼파라미터 최적화 라이브러리이다. 

 

하이퍼파라미터 튜닝은 아직 활발히 연구되는 영역이다. 

 

이 분야에 진화 알고리즘이 다시 등장한다. 2017년 발표된 딥마인드의 훌륭한 논문에서는 모델의 개체군과 하이퍼파라미터를 함께 최적화했다.구글도 하이퍼파라미터 탐색 뿐만 아니라 문제에 최적인 신경망 구조를 찾기 위해 진화 전략을 사용한다. 구글의 AutoML 서비스는 이미 클라우드로 제공된다. 

 

사실 진화 알고리즘은 흔한 경사 하강법을 대체하여 개별 신경망을 성공적으로 훈련해왔다. 예를 들어 심층 신경 진화 기법을 소개한 2017년 우버의 포스트(https://homl.info/neuroevol) 를 확인해보길 바란다.

 

이런 놀라운 발전과 도구와 서비스가 있더라도 신속한 프로토타입을 만들고 탐색 공간을 제한하기 위해 각 하이퍼파라미터에 어떤 값이 적절할 지 생각해보는 것은 도움이 된다. 퍼셉트론에 있는 은닉층의 개수와 뉴런의 개수를 고르고 주요 하이퍼파라미터에서 좋은 값을 선택하는 가이드라인에 대해 살펴보자.

 

 

3. 하이퍼파라미터 적정 기준

3.1 은닉층 개수

은닉층 하나로 시작해도 많은 문제에서 납득할 만한 결과를 얻을 수 있다. 이론적으로 하나의 MLP 더라도 뉴런 개수가 충분하면 아주 복잡한 함수도 모델링할 수 있다.하지만 복잡한 문제에서는 심층 신경망이 얕은 신경망보다 파라미터 효율성이 훨씬 좋다. 

 

실제 데이터는 계층 구조를 가진 경우가 많아 심층 신경망이 더 유리하다.즉 아래쪽 은닉층은 저수준의 구조를 모델링하고 (ex. 여러 방향이나 모양의 선)중간 은닉층은 저수준의 구조를 연결해 중간 수준의 구조를 모델링하고 (ex. 사각형, 원)가장 위쪽 은닉층과 출력층은 중간 수준의 구조를 연결해 고수준의 구조를 모델링하기 때문이다. (ex. 얼굴)

 

복잡한 문제라면 훈련 세트에 과대적합이 생길 때까지 점진적으로 은닉층의 수를 늘릴 수 있다. 

 

3.2 은닉층의 뉴런 개수

은닉층의 구성 방식은 일반적으로 각 층의 뉴런을 점점 줄여서 깔때기처럼 구성한다.저수준의 많은 특성이 고수준의 적은 특성으로 합쳐지기 때문이다. 

 

하지만 대부분의 경우 모든 은닉층에 같은 크기를 사용해도 동일하거나 더 나은 성능을 내기도 한다.또한 튜닝할 하이퍼파라미터가 층마다 한 개씩이 아니라 전체를 통들어 한 개가 된다. 데이터셋에 따라 다르지만 다른 은닉층보다 첫 번째 은닉층을 크게 하는 것이 도움이 된다. 

 

층의 개수와 마찬자기로 네트워크가 과대 적합되기 전까지 점진적으로 뉴런 수를 늘릴 수 있다.하지만 실전에서는 필요한 것보다 더 많은 층과 뉴런을 가진 모델을 선택하고 과대 적합되지 않도록 조기 종료나 규제 기법을 사용하는 것이 더 간단하고 효과적이다. 

 

일반적으로 뉴런 수보다 층의 수를 늘리는 쪽이 더 이득이 많다.

 

3.3 학습률, 배치 크기 그리고 다른 하이퍼파라미터

(1) 학습률

일반적으로 최적의 학습률은 최대 학습률의 절반 정도이다. 좋은 학습률을 찾는 한 가지 방법은 매우 낮은 학습률 (예를 들어 e-5) 에서 시작해서 점진적으로 매울 큰 학습률 (예를 들어 10)까지 수백 번 반복하여 모델을 훈련시키는 것이다. 각 반복마다 일정한 값을 학습률에 곱한다. 학습률에 대한 손실을 그래프로 그려, 손실이 줄어들다 다시 커지는 구간에서 멈춰, 손실이 다시 상승하기 전을 최적 학습률로 지정한다.

 

※ 최적 학습률은 다른 하이퍼파라미터에 의존적이다. 특히 배치 크기에 영향을 많이 받는다. 따라서 다른 하이퍼파라미터 수정하면 반드시 학습률도 다시 튜닝해야 한다!!

 

(2) 옵티마이저

고전적인 평범한 미니 배치 경사 하강법보다 더 좋은 옵티마이저를 선택하는 것도 중요하다. 

 

(3) 배치 크기

배치 크기는 모델 성능과 훈련 시간에 큰 영향을 미칠 수 있다. 

 

많은 연구자들은 GPU RAM에  맞는 가장 큰 배치 크기를 사용하라고 권장한다. 다만 실전에서 큰 배치를 사용하면 특히 훈련 초기에 종종 불안정하게 훈련된다. 결과 모델은 작은 배치 크기로 훈련된 모델만큼 일반화 성능을 내지 못할 수 있다. 

 

2018년 4월 얀 르쿤은 작은 배치가 적은 훈련 시간으로 더 좋은 모델을 만들기 때문에 작은 배치 (2~32) 를 사용하는 것이 바람직하다고 주장했다. 

 

그러나 2017년 일래드 호퍼 등의 논문을 살펴보면 학습률 예열(작은 학습률로 훈련을 시작해서 점점 커진다.) 같은 다양한 기법을 사용하면 매우 큰 배치 크기를 사용할 수 있다고 밝혔다. 

 

이에 따라 우리가 취할 수 있는 한 가지 전략은 학습률 예열을 사용해 큰 배치 크기를 도전해보고 만약 훈련이 불안정하거나 성능이 만족스럽지 못하면 작은 배치 크기를 사용해보는 것이다.

 

(4) 활성화 함수

일반적으로 ReLU 활성화 함수가 모든 은닉층에 좋은 기본값이다. 

 

(5) 반복 횟수

대부분의 경우 훈련 반복 횟수는 튜닝할 필요 없다. 대신 조기 종료를 사용한다.