AI/Hands-on ML

[핸즈온 머신러닝] 10장 - 케라스를 사용한 인공 신경망 3 (하이퍼파라미터 튜닝)

KIM DEON 2021. 3. 7. 20:40

[AI/Hands-on ML] - [핸즈온 머신러닝] 10장 - 케라스를 사용한 인공 신경망 2 (케라스로 딥러닝하기)

 

[핸즈온 머신러닝] 10장 - 케라스를 사용한 인공 신경망 2 (케라스로 딥러닝하기)

[AI/Hands-on ML] - [핸즈온 머신러닝] 10장 - 케라스를 사용한 인공 신경망 (인공 신경망 소개) [핸즈온 머신러닝] 10장 - 케라스를 사용한 인공 신경망 (인공 신경망 소개) 10. 인공 신경망 인공 신경망

kdeon.tistory.com


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

신경망의 유연성은 조정할 하이퍼파라미터가 많다는 단점을 가짐

 

주어진 문제에 최적인 하이퍼파라미터 조합을 찾는 방법

- 많은 하이퍼파라미터 조합을 시도해보고 어떤 것이 검증 세트에서 가장 좋은 점수를 내는지 확인

- GridSearchCV 나 RandomizedSearchCV를 사용해 하이퍼파라미터 공간 탐색

-> 이렇게 하려면 케라스 모델을 사키잇런 추정기처럼 보이도록 바꾸어야함

 

일련의 하이퍼파라미터로 케라스 모델을 만들고 컴파일하는 함수 만들기

def build_model(n_hidden=1, n_neurons=30, learning_rate=3e-3, input_shape=[8]):
    model = keras.models.Sequential()
    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

- 입력 크기와 은닉층 개수, 뉴런 개수로 단변량 회귀를 위한 간단한 Sequential 모델을 만듦

- 지정된 학습률을 사용하는 SGD 옵티마이저로 모델을 컴파일

 

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

- build_model() 함수로 만들어진 케라스 모델을 감싸는 래퍼

- 객체 생성시 하이퍼파라미터를 지정하지 않았으므로 기본 값 사용

-> 사이킷런 회귀 추정기처럼 이 객체를 사용할 수 있음

 

keras_reg.fit(X_train, y_train, epochs=100,
              validation_data=(X_valid, y_valid),
              callbacks=[keras.callbacks.EarlyStopping(patience=10)])
              
mse_test = keras_reg.score(X_test, y_test)
y_pred = keras_reg.predict(X_new)

- fit() 메서드에 지정한 모든 매개변수는 케라스 모델로 전달 됨

- 사이킷런은 손실이 아니라 점수를 계산하므로 출력 점수는 음수의 MSE

 

하이퍼파라미터 탐색

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)               .tolist(),
    "learning_rate": reciprocal(3e-4, 3e-2)      .rvs(1000).tolist(),
}

rnd_search_cv = RandomizedSearchCV(keras_reg, param_distribs, n_iter=10, cv=3, verbose=2)
rnd_search_cv.fit(X_train, y_train, epochs=100,
                  validation_data=(X_valid, y_valid),
                  callbacks=[keras.callbacks.EarlyStopping(patience=10)])

- 랜덤 탐색 이용

- 은닉층 개수, 뉴런 개수, 학습률 튜닝

 

랜덤 탐색이 찾은 최상의 하이퍼파라미터와 훈련된 케라스 모델

rnd_search_cv.best_params_

=> {'n_neurons': 74, 'n_hidden': 3, 'learning_rate': 0.005803602934201024}

rnd_search_cv.best_score_

=> -0.32039451599121094

rnd_search_cv.best_estimator_

 

- 이 후 모델을 저장하고 테스트 세트에서 평가하고, 만족스럽다면 상용 환경에 배포

 

랜덤 탐색은 간단한 문제에서 잘 동작하지만 훈련에 시간이 많이 걸리면 탐색할 수 있는 하이퍼파라미터 공간에 제약이 생김

 


하히어파라미터 공간 탐색 기법

탐색 지역이 좋다고 판명될 때 더 탐색을 수행하는 아이디어

 

  • Hyperopt
  • Hyperas, kopt, Talos
  • 케라스 튜너
  • Scikit-Optimizer(skopt)
  • Spearmint
  • Hyperband
  • Sklearn-Deap

AutoML

ai.googleblog.com/2018/03/using-evolutionary-automl-to-discover.html

 

심층 신경 진화 기법

eng.uber.com/deep-neuroevolution/


10. 3. 1 은닉층 개수

- 은닉층이 하나인 다층 퍼셉트론이더라도 뉴런 개수가 충분하면 복잡한 함수도 모델링할 수 있지만,

- 복잡한 문제에서는 심층 신경망이 얕은 신경망보다 파라미터 효율성이 좋음

- 심층 신경망은 복잡한 함수를 모델링하는 데 얕은 신경망보다 훨씬 적은 수의 뉴런을 사용하므로 동일한 양의 훈련 데이터에서 더 높은 성능을 냄

 

실제 데이터는 계층 구조를 가진 경우가 많으므로, 심층 신경망은 이런 경우에 유리

- 아래쪽 은닉층은 저수준의 구조를 모델링하고 (ex. 여러 방향이나 모양의 선)

- 중간 은닉층은 저수준의 구조를 연결해 중간 수준의 구조를 모델링 (ex. 사각형, 원)

- 가장 위쪽 은닉층과 출력층은 중간 수준의 구조를 연결해 고수준의 구조를 모델링 (ex. 얼굴)

 

계층 구조는 심층 신경망이 좋은 솔루션으로 수렴하게끔 도와줄 뿐만 아니라 새로운 데이터에 일반화되는 능력도 향상시켜줌

- 사진에서 얼굴을 인식하는 모델을 훈련한 후 헤어스타일을 인식하는 신경망을 새로 훈련하면 첫 번째 네트워크의 하위 층을 재사용하여 훈련을 시작할 수 있음

- 새로운 신경망에서 초기화하는 대신 첫 번째 신경망의 층에 있는 가중치와 편향값으로 초기화 가능

- 저수준 구조를 학습하지 않아도 됨, 헤어스타일 같은 고수준 구조만 학습하면 됨

=> 이를 전이 학습이라고 함

 

대규모 이미지 분류나 음성인식 같은 매우 복잡한 작업에서는 일반적으로 수십 개 층의 네트워크가 필요함

- 훈련 데이터도 아주 많이 필요함

- 이런 네트워크를 처음부터 훈련하는 경우는 드뭄

- 비슷한 작업에서 뛰어난 성능을 낸 미리 훈련된 네트워크 일부를 재사용 함

 


10. 3. 2 은닉층의 뉴런 개수

입력층과 출력층의 뉴런 개수는 해당 작업에 필요한 입력과 출력의 형태에 따라 결정됨

- MNIST는 28*28 개의 입력 뉴런과 10개의 출력 뉴런이 필요함

 

은닉층의 구성 방식

일반적으로 각 층의 뉴런을 점점 줄여서 깔때기처럼 구성

- 저수준의 많은 특성이 고수준의 적은 특성으로 합쳐질 수 있기 때문

- 예를들어 MNIST 신경망은 첫 번째 300개, 두 번째 200개, 세 번째는 100개의 뉴런으로 구성된 세 개의 은닉층을 가짐

=> 이 구성은 요즘 일반적이지 않음

- 대부분의 경우 모든 은닉층에 같은 크기를 사용해도 동일하거나 더 나은 성능을 냄

- 튜닝할 하이퍼파라미터가 층마다 한 개씩이 아니라 전체 통틀어 한 개가 됨

- 데이터셋에 따라 다르지만 다른 은닉층보다 첫 번째 은닉층을 크게 하는 것이 도움이 됨

 

뉴런 개수

층의 개수와 마찬가지로 네트워크가 과대적합되기 전까지 점진적으로 뉴런 수를 늘릴 수 있음

- 하지만 실제로는 필요한 것보다 더 많은 층과 뉴런을 가진 모델을 선택하고 그 후 과대적합 되지 않도록 조기 종료나 규제를 사용하는 것이 간단하고 효과적임

  • 모델에서 문제를 일으키는 병목층을 피할 수 있음

  • 하지만 한 층의 뉴런 수가 너무 적으면 입력에 있는 유용한 정보를 모두 유지하기 위한 표현 능력을 가지지 못함

    • EX. 뉴런 두 개를 가진 층은 2D 데이터만 출력할 수 있음 (3D 데이터 처리시 일부 정보를 잃음)

    • -> 네트워크의 나머지 층과 상관없이 이 정보는 복원되지 않음

 

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

 


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

은닉층과 뉴런 개수 외에, 가장 중요한 하이퍼파라미터 일부와 조정 방법

 

학습률

- 가장 중요한 하이퍼파라미터

- 일반적인 최적의 학습률은 최대 학습률 (훈련 알고리즘이 발산하는 학습률)의 절반 정도

- 좋은 학습률을 찾는 하나의 방법은 매우 낮은 학습률(ex. 10^-5)에서 시작해 점진적으로 매우 큰 학습률(ex. 10) 까지 수백 번 반복하며 모델을 훈련하는 것

  • 반복마다 일정한 값을 학습률에 곱함
  • 학습률에 대한 손실을 그래프로 그리면 처음에 손실이 줄어드는 것이 보임
  • 하지만 잠시 후 학습률이 커지면 손실이 다시 커짐
  • 최적의 학습률은 손실이 다시 상승하는 지점보다 조금 아래에 있을 것 (일반적으로 상승점보다 약 10배 낮은 지점)
  • 모델을 다시 초기화하고 앞에서 찾은 학습률을 사용해 다시 정상적으로 훈련

 

옵티마이저

- 평범한 미니배치 경사 하강법보다 더 좋은 옵티마이저를 선택하는 것(+ 이 옵티마이저의 하이퍼파라미터를 튜닝하는 것)도 중요함

 

 

배치 크기

- 모델 성능과 훈련 시간

- 큰 배치 크기를 사용하는 것의 장점은 GPU같은 하드웨어 가속기를 효율적으로 활용할 수 있다는 점 -> 훈련 알고리즘이 초당 더 많은 샘플을 처리할 수 있음

- 하지만 실전에서 큰 배치를 사용하면 훈련 초기에 종종 불안정하게 훈련됨 -> 작은 배치 크기로 훈련된 모델만큼 일반화 성능을 내지 못할 수 있음

- 작은 배치가 적은 훈련 시간으로 더 좋은 모델을 만드므로, 2~32 까지의 배치를 사용하는 것이 바람직하다는 논문이 있음

  •  반대로 학습률 예열 같은 기법으로 매우 큰 배치 크기를 사용할 수 있다는 논문도 있음

- 큰 배치 크기는 일반화 성능에 영향을 미치지 않고 훈련 시간을 매우 단축함

- 훈련이 불안정하거나 최종 성능이 만족스럽지 못하다면 작은 배치 크기를 사용

 

 

활성화 함수

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

- 출력층의 활성화 함수는 수행하는 작업에 따라 달라짐

 

 

반복 횟수

- 대부분의 경우 훈련 반복 횟수는 튜닝하지 않고, 조기 종료를 사용함

 

 

최적의 학습률은 다른 하이퍼 파라미터에 의존적임

- 특히 배치 크기에 영향을 많이 받음

- 다른 하이퍼파라미터를 수정하면 학습률도 반드시 튜닝해야 함

 

신경망 하이퍼파라미터 튜닝의 모범 사례

arxiv.org/abs/1803.09820