Keras Tuner
keras에서 하이퍼파라미터를 튜닝할 때는 keras tuner를 사용하는 것이 좋다.
Keras tuner를 사용할 때는 먼저 다음과 같이 keras 모델을 구축, 컴파일하여 변환하는 함수를 작성한다.
import keras_tuner as kt
def build_model(hp):
n_hidden = hp.Int("n_hidden", min_value=0, max_value=8, default=2)
n_neurons = hp.Int("n_neurons", min_value=16, max_value=256)
learning_rate = hp.Float("learning_rate", min_value=1e-4, max_value=1e-2,
sampling="log")
optimizer = hp.Choice("optimizer", values=["sgd", "adam"])
if optimizer == "sgd":
optimizer = tf.keras.optimizers.SGD(learning_rate=learning_rate)
else:
optimizer = tf.keras.optimizers.Adam(learning_rate=learning_rate)
model = tf.keras.Sequential()
model.add(tf.keras.layers.Flatten())
for _ in range(n_hidden):
model.add(tf.keras.layers.Dense(n_neurons, activation="relu"))
model.add(tf.keras.layers.Dense(10, activation="softmax"))
model.compile(loss="sparse_categorical_crossentropy", optimizer=optimizer,
metrics=["accuracy"])
return model
위 함수는 은닉 층 수(n_hidden
), 은닉 층의 뉴런 수(n_neurons
), 학습률(learning_rate
), optimizer(optimizer
) 등을 하이퍼파라미터로 정의한다. hp.Int("n_hidden", min_value=0, max_value=8, default=2)
는 다음과 같은 의미를 가진다.
n_hidden
이라는 하이퍼파라미터가 hp객체 안에 있는지 확인. 있으면 그 값 반환.- 없으면 가능 범위가 0~8인
n_hidden
이라는 새로운 정수 하이퍼파라미터를 등록하고 기본 값(default
) 2 반환(기본 값이 없다면min_value
반환).
랜덤 서치
기본적인 랜덤서치를 수행하려면 kt.RandomSearch
튜너를 만들고 search()
메서드를 호출한다.
random_search_tuner = kt.RandomSearch(
build_model, objective='val_accuracy', max_trials=5, overwrite=True,
directory='my_fashion_mnist', project_name='my_rnd_search', seed=42
)
random_search_tuner.search(X_train, y_train, epochs=10, validation_data=(X_valid, y_valid))
위 코드는 다음과 같은 순서로 작동한다.
- 모든 하이퍼파라미터 사양을 수집하기 위해 빈
Hyperparameters
객체로build_model()
한 번 호출. - 아래 과정 5번 시도(
max_trials=5
).- 범위 내에서 랜덤하게 샘플링된 하이퍼파라미터를 이용해 모델을 생성.
- 해당 모델을 10 epoch 동안 훈련.
- ‘my_fashion_mnist/my_rnd_search’의 서브 디렉터리에 저장. (
overwrite=True
이므로 훈련 시작 전에 ‘my_rnd_search’ 디렉터리가 삭제됨.)
만약 위 코드를 max_trials=10, overwrite=True
로 바꾸어서 실행하면, 5번 실행된 기존 디렉터리가 삭제되지 않기 때문에 뒤 이어 5번만 추가로 더 실행될 것이다.
최상의 모델, 하이퍼파라미터는 다음과 같이 얻는다.
# best model
top3_models = random_search_tuner.get_best_models(num_models=3)
best_model = top3_models[0]
# best hyperparemeters
top3_params = random_search_tuner.get_best_hyperparameters(num_trials=3)
top3_params[0].values
각 튜너는 oracle의 안내를 받는다. 튜너는 시도 전에 oracle에 다음 시도가 무엇인지 알려달라고 요청한다. Oracle은 모든 시도를 기록하고 있으며, 최상의 시도가 무엇인지 정보를 요청할 수 있다. 다음은 oracle을 이용해 최상의 시도를 요약한 것이다.
best_trial = random_search_tuner.oracle.get_best_trials(num_trials=1)[0]
best_trial.summary()
model.fit()
미세 튜닝
간혹 model.fit()
매개 변수를 미세 튜닝해야할 수도 있다. 데이터 전처리 하이퍼파라미터나 배치 크기를 조정하는 경우가 이에 해당한다. 이를 위해서는 kt.HyperModel
의 서브 클래스를 만들고 직접 build()
메서드와 fit()
메서드를 정의해주어야 한다.
다음 코드는 데이터를 학습하기 전에 훈련 데이터를 normalize할지 여부를 결정하는 기능을 추가한 것이다.
class MyClassificationHyperModel(kt.HyperModel):
def build(self, hp):
return build_model(hp)
def fit(self, hp, model, X, y, **kwargs):
if hp.Boolean("normalize"):
norm_layer = tf.keras.layers.Normalization()
X = norm_layer(X)
return model.fit(X, y, **kwargs)
Hyperband
kt.Hyperband
튜너는 몇 번의 epoch 동안 여러 모델을 훈련하고, 최악의 모델을 제거한 뒤 상위 1 / factor
개(e.g. factor=3
이라면 상위 33%)의 모델만 남긴다. 이 과정을 단일 모델이 남을 때까지 반복한다.
hyperband_tuner = kt.Hyperband(
MyClassificationHyperModel(), objective='val_accuracy', seed=42,
max_epochs=10, factor=3, hyperband_iterations=2, overwrite=True,
directory='my_fashion_mnist', project_name='hyperband'
)
max_epochs
는 최상의 모델을 훈련할 최대 epoch 수이며, 전체 과정은 두 번 반복(hyperband_iterations=2
)된다. 각 hyperhand 반복에서 전체 모델의 총 훈련 수는 ‘max_epochs
* (log(max_epochs
) / log(factor
))**2’이다.
Hyperband 튜너는 다음과 같이 실행한다. 다음 코드는 tensorboard callback과 early stopping callback도 같이 사용하고 있다.
root_logdir = Path(hyperband_tuner.project_dir) / "tensorboard"
tensorboard_cb = tf.keras.callbacks.TensorBoard(root_logdir)
early_stopping_cb = tf.keras.callbacks.EarlyStopping(patience=2)
hyperband_tuner.search(X_train, y_train, epochs=10, validation_data=(X_valid, y_valid),
callbacks=[early_stopping_cb, tensorboard_cb])
Hyperband는 리소스를 할당하는 방식에서 순수 랜덤 서치보다는 똑똑하지만, 여전히 랜덤으로 탐색하기 때문에 빠르지만 듬성듬성하다.
BayesianOptimization
kt.BayesianOptimization
는 가우스 과정 확률 모델을 적용하여, 하이퍼파라미터 공간의 어느 영역이 가장 유망한지 점진적으로 학습한다.
bayesian_opt_tuner = kt.BayesianOptimization(
MyClassificationHyperModel(), objective='val_accuracy', seed=42,
max_trials=10, alpha=1e-4, beta=2.6,
overwrite=True, directory='my_fashion_mnist', project_name='baysian_opt'
)
bayesian_opt_tuner.search(X_train, y_train, epochs=10,
validation_data=(X_valid, y_valid),
callbacks=[early_stopping_cb])
유망한 공간을 집중 탐색한다는 것이 장점이지만, alpha
와 beta
라는 추가 하이퍼파라미터가 등장한다는 점은 단점이다.
alpha
: 여러 번의 시도에 걸친 성능 측정에서 예상되는 잡음 수준beta
: 하이퍼파라미터 공간에서 알려진 좋은 영역을 단순히 활용하는 대신, 알고리즘이 얼마나 공간을 탐색할지 지정.
하이퍼파라미터 가이드라인
-
은닉 층 개수
하나 혹은 두 개의 은닉 층으로도 충분한 경우가 많지만, 보통의 경우 심층 신경망이 얕은 신경망보다 성능이 더 좋다. 필요하다면 다른 신경망의 저수준 구조를 가져온 뒤, 고수준 구조만 학습할 수도 있다(전이 학습). -
은닉 층의 뉴런 개수
과거에 신경망은 보통 깔떄기 형태처럼 뉴런의 수를 점차 줄여 나가는 구조(300 > 200 > 100)로 구성되는 경우가 많았다. 하지만 요즘에는 은닉 층에 같은 수의 뉴런을 사용해도 성능 차이가 나지 않거나 오히려 성능이 더 나은 경우가 많다. 첫 번째 은닉 층을 다른 은닉 층보다는 크게 하는 것이 도움이 될 때도 있다. 신경망이 과대적합되기 전까지 점진적으로 뉴런의 개수를 늘릴 수도 있고, 필요한 것보다 많은 뉴런과 층을 가진 모델을 선택한 다음 과대적합되지 않도록 조기 종료하거나 규제 기법을 사용해도 된다. -
학습률
매우 낮은 학습률에서 시작해서 높은 학습률까지 모델을 수백 번 훈련하는 것도 좋은 방법이다. 또는 반복마다 일정한 값을 학습률에 곱하는 것도 가능하다. -
Optimizer
고전적인 경사 하강법보다 더 좋은 optimizer가 많으니 잘 선택하자. -
batch 크기
큰 batch를 사용하면 GPU 같은 하드웨어 가속기를 효율적으로 활용할 수 있지만, 훈련 초기에 종종 불안정하게 훈련될 수 있다. 일반화 성능이 떨어지는 것이다. 적절한 batch 크기는 연구자들 사이에서도 의견이 다르다. 한 가지 방법은 학습률 예열(작은 학습률로 시작해서 학습률을 증가시킴)을 사용하여 큰 batch 크기를 시도하고, 좋지 않다면 크기를 줄이는 것이다. -
활성화 함수
ReLU가 일반적으로는 가장 좋은 기본 값이다. 수행하는 작업에 따라 달라진다. -
반복 횟수
따로 튜닝할 필요 없이 조기 종료를 사용하자.
별도의 출처 표시가 있는 이미지를 제외한 모든 이미지는 강의자료에서 발췌하였음을 밝힙니다.
댓글남기기