머신러닝에서 배웠던 cross validation, gridsearch를 통한 hyperparameter의 내용을 떠올리자!
- 신경망에 cross validation 적용
- scikit-learn과 keras tuner를 사용하여 신경망의 hyperparmeter 탐색
- 실험 계획 라이브러리인 WandB의 사용법을 익히고, keras를 엮어서 사용
- WandB를 사용하여 hyperparameter 탐색 적용
지금까지 다뤘던 머신러닝 알고리즘은 많아야 20개 정도의 hyperparameter만 탐색하면 됬었다.
하지만, 신경망은 층을 깊게 쌓을수록 조정해주어야 할 hyperparmeter가 훨씬 더 많아지게 된다.
머신러닝 때 사용했던 것과 거의 비슷함. (복습하는 차원에서 한 번 더 공부하자!)
🌀 신경망에 Cross-validation 적용해보기
cross validation(교차검증) : 모델 학습 시 데이터를 train용, test용으로 교차하여 선택하는 방법
- 장점 : 과적합 방지, 일반화 성능, 데이터 규모 작을 시 과소적합 방지
- 단점 : 반복 학습 횟수 증가로 인해 소요시간 증가
가장 기본적인 CV의 형태인 K-Fold Cross-Validation를 사용해보자!
k=5로 하게 되면, train set:test set=4:1, 총 5가지의 다른 test set으로 모델 성능 평가를 하여 한번만 train test split을 한 경우보다 overfitting을 방지할 수 있겠지!!
from sklearn.model_selection import KFold, StratifiedKFold
kf = KFold(n_splits=5)
skf = StratifiedKFold(n_splits=5, shuffle=True) # shuffle=True : 나누기 전에 데이터 섞어줌
어떤 경우에 사용하는 게 효율적일까?
- 데이터가 독립적이고 동일한 분포를 가지며, 데이터셋 크기가 큰 경우
KFold
- 불균형 클래스, 다중 클래스 분류에서 각 클래스가 균등하게 분포되어있지 않을 경우
StratifiedKFold
- 시계열 데이터의 경우
TimeSeriesSplit
: 시계열 데이터는 연속적인 데이터를 유지해야하므로, 앞에서 훈련시킨 것들을 다음에도 연속적 사용, 훈련 데이터를 키워나가는 식으로 진행
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
model = Sequential()
model.add(Dense(64, activation='relu'))
model.add(Dense(64, activation='relu'))
model.add(Dense(1))
for train_index, val_index in kf.split(np.zeros(x_train.shape[0]),y_train):
training_data = x_train.iloc[train_index, :]
training_data_label = y_train.iloc[train_index]
validation_data = x_train.iloc[val_index, :]
validation_data_label = y_train.iloc[val_index]
model.compile(loss='mean_squared_error', optimizer='adam')
model.fit(training_data, training_data_label,
epochs=10, batch_size=32,
validation_data=(validation_data, validation_data_label))
results=model.evaluate(x_test, y_test, batch_size=32)
print('test loss, test mse', results)
5-fold cv로 했으니 5번 돌겠지. 한번당 10번의 epoch을 돌며.
🌀 신경망에서의 hyperparameter tuning
- GridSearch
- RandomSearch
- Bayesian Methods :
bayes_opt
hyperopt
튜닝 가능한 대표적인 hyperparmeter
- batch_size
- epochs
- optimizers
- learning rate
- activation
- Regularization (weight decay, dropout)
- hidden layer의 노드수
인공 신경망 모델을 Scikit-learn에서 사용하기 위해 wrapping을 해줘야한다. wrapping하는 방법으로 scikeras
를 사용해보겠다.
scikit-learn은 머신러닝을 위한 파이썬 라이브러리 중 하나로, 인공 신경망 모델도 제공하지만, 이 모델은 딥러닝 모델에 비해 제한된 기능을 가진다.
따라서, scikit-learn에서 제공하는 인공 신경망 모델을 사용하기 위해서는 다른 딥러닝 라이브러리를 사용하여 모델을 정의하고 학습해야한다.
scikeras는 Scikit-learn과 keras를 연결하여 Scikit-learn의 인터페이스를 따르면서 Keras의 딥러닝 기능을 사용할 수 있도록 wrapping하는 도구이다.
이를 통해 scikit-learn에서 제공하는 인공 신경망 모델을 쉽게 구성하고, keras의 딥러닝 기능을 사용하여 학습할 수 있다.(wrapping: 한 라이브러리에서 다른 라이브러리의 기능을 사용할 수 있도록 하는 기술)
KerasClassifier
로 wrapping하기위해 신경망 모델을 함수 형태로 정의한다.
def create_model(nodes=8):
model=Sequential()
model.add(Dense(nodes, Input_dim=8, actiation='relu'))
model.add(Dense(nodes, activation='relu')
model.add(Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
return model
# wrapping
model = KerasClassifier(model=create_model, batch_size=8)
GridSearchCV
nodes = [16,32,64]
batch_size = [16,32,64]
param_grid = dict(model__nodes=nodes, batch_size=batch_size)
grid = GridSearchCV(estimator=model, param_grid=param_grid, n_jobs=1, cv=3)
grid_result = grid.fit(x,y)
grid_result.best_score_, grid_result.best_params_
>> 0.5989583333333334, {'batch_size': 32, 'model__nodes': 64}
🌀 Keras Tuner를 사용하여 hyperparameter 탐색하기
Keras Tuner : 케라스 프레임워크에서 hyperparam 튜닝하는데 도움이 되는 라이브러리
hp.Int
: 아래 dense layer 내 units에 들어올 integer의 형태로, hyperparam의 범위 설정
hp.Choice
: 아래 optimizer내 learning rate 인자에 list values들 중 하나를 선택하는 hyperparam의 범위 설정
from tensorflow imort keras
import keras_tuner as kt
def model_builder(hp):
"""
Tuner를 지정하기 전에 했던 Grid search와 마찬가지로 함수의 형태로 신경망 모델 구축 후 선언
함수 내 변수 hp를 통해 다양한 hyperparam의 범위 설정
"""
model = keras.Sequential()
model.add(Flatten(input_shape=(28,28)))
# 은닉층 노드 수 결정
hp_units = hp.Int('units', min_value=32, max_value=512, step=32)
model.add(Dense(units=hp_units, activation='relu'))
model.add(Dense(10, activation='softmax'))
# 학습률 값 결정
hp_learning_rate = hp.Choice('learning_rate', values=[1e-2, 1e-3, 1e-4])
model.compile(optimizer=keras.optimizers.Adam(learning_rate=hp_learning_rate),
loss=keras.losses.SparseCategoricalCrossEntropy(),
metrics=['accuracy'])
return model
하이퍼파라미터 튜닝을 수행할 튜너 지정!!!!
Keras Tuner에서는 Random Search, Bayseian Optimization, Hyperband 등의 최적화 방법 수행할 수 있다.
아래에서는 Hyperband
를 통해 튜닝을 수행해보겠다.
Hyperband는 리소스를 알아서 조절하고 조기 종료(Early-Stopping)기능을 사용해 높은 성능을 보이는 조합을 신속하게 통합한다는 장점을 가지고 있다.
kt.Hyperband
(model_builder, objective, max_epochs, factor)
model_builder
: hyperparam 조정할 모델의 구조를 정의한 함수objective
: 최적화의 목적 지표 설정max_epochs
: 최대 epoch 수factor
: 매 step마다 줄어드는 설정 개수- hyperband는 처음에는 작은 epoch 수로 모델을 학습시키고, 그 중에서 validation 성능이 좋은 일부 모델만 선택해 더 많은 epoch으로 학습을 진행한다. 이 때, ‘factor’는 얼마나 많은 epoch를 추가로 학습할지 결정한다.
- factor값이 크면 iteration당 epoch수가 작아져 더 많은 iteration이 필요로 해지고, 더 많은 모델들이 평가된다.
- factor값이 작으면 iteration당 epoch수가 커져 더 적은 iteration안에 튜닝을 마칠 수 있지만, 더 적은 모델들이 평가된다.
- hyperband는 각 step마다 반복을 수행하며, iteration마다 factor만큼 설정 줄인다.
tuner = kt.Hyperband(model_builder,
objective='val_accuracy',
max_epochs=10,
factor=3,
directory='my_dir' # 튜닝 결과를 저장할 directory 설정
project_name='bomi_first_tuning') # 저장하는 튜닝 결과 이름
Hyperband는 Succesive Halving Algorithm을 보완한 알고리즘이다.
코딩 끝나고 More Study 부분에 작동 흐름에 대해 설명해보겠다.
Callback 함수 지정
하이퍼파라미터 탐색을 진행하기 전, 학습이 끝날 때마다 이전 출력이 지워지도록 콜백 함수 정의함. (모두 출력되면 내용이 매우 깊어지기 때문)
class ClearTrainingOutput(tf.keras.callbacks.Callback):
# 훈련이 끝날 때마다 셀의 출력 결과를 지우는 콜백 함수
def on_train_end(*args, **kwargs):
IPython.display.clear_output(wait=True)
tuner.search(x_train, y_train, epochs=10,
validation_data=(x_test, y_test),
callbacks=[ClearTrainingOutput]
# 반환할 최고의 조합 선언
best_hps = tuner.get_best_hyperparameters(num_trials=1)[0]
print(f"""
하이퍼 파라미터 검색이 완료되었습니다.
최적화된 첫 번째 Dense 노드 수는 {best_hps.get('units')} 입니다.
최적의 학습 속도는 {best_hps.get('learning_rate')} 입니다.
""")
>> 하이퍼 파라미터 검색이 완료되었습니다.
최적화된 첫 번째 Dense 노드 수는 128 입니다.
최적의 학습 속도는 0.001 입니다.
# 이후, 최고 성능을 보이는 hyperparameter 조합으로 다시 학습 진행
🌀 Wandb
Comet.ml, Weights and Biases (wandb) 등 실험 기록 도구가 등장하였다.
이 중, 나는 wandb를 사용해보겠다. 참고
wandb는 딥러닝 모델의 학습과정을 시각화하고, 관리하기 위한 온라인 플랫폼이다.
이런 실험 기록 도구는 실험 결과를 실시간으로 기록하고 코드, 결과값을 보관해주며, 실험 결과를 원하는 기준대로 언제든지 시각화하여 모델의 성능을 비교할 수 있도록 도와준다. 매 epoch이 끝날 때마다 데이터가 해당 툴에 보내지기 때문에 모델이 수렴하고 있는지도 확인 가능하다. 모델을 저장하며, 모델을 배포하여 다른 환경에서 실행이 가능하다.
사용법을 알아보기 위해, Wandb 라이브러리를 사용해 CIFAR-10 데이터셋을 이용한 CNN 모델을 학습해 보겠다.
import wandb
from wandb.keras import WandbCallback
# 반복되는 프로젝트 이름, 그룹 이름 변수화해줌.
wandb_project='practice'
wandb_group=''
# 각자의 로그인 키 넣기
!wandb login ---
# wandb 초기화, 내가 만든 프로젝트 이름 넣어주기
wandb.init(project=wandb_project)
# 예시로, cifar10 데이터 사용해보자.
(train_images, train_labels), (test_images, test_labels) = datasets.cifar10.load_data()
train_images, test_images = train_images/255.0, test_images/255.0
# wandb.config를 통해 하이퍼파라미터인 epoch, batch_size 지정해주기
wandb.config.epochs=10
wandb.config.batch_size=64
model = Sequential()
model.add(Conv2D(32,(3,3), activation='relu', input_shape=(32,32,3)))
model.add(MaxPooling2D((2,2)))
model.add(Conv2d(64,(3,3), activation='relu'))
model.add(MaxPooling2D((2,2)))
model.add(Conv2D(64,(3,3), activation='relu'))
model.add(Flatten())
model.add(Dense(64, activation='relu'))
model.add(Dense(10, activation='softmax'))
WandbCallback()을 fit함수의 callbacks인자에 추가해, 모델 학습 중 wandb에 로그를 기록할 수 있다.
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
model.fit(train_images, train_labels,
validation_data=(test_images, test_labels),
epochs=wandb.config.epochs,
batch_size=wandb.config.batch_size,
callbacks=[WandbCallback()])
wandb 홈페이지의 대시보드에서 내가 만든 프로젝트로 이동
- 학습시킨 모델의 성능 지표 그래프, 하이퍼파라미터, 학습 로그 등 시각화하여 볼 수 있다.
- 그래프 클릭 시 해당 지표에 대한 자세한 정보 볼 수 있다.
- 학습 중인 모델 비교, 개선할 수 있는 지표 파악 가능
익숙하지 않지만, 다음 번에 프로젝트 할 때 써봐야겠다!!
More Study
Succesive Halving Algorithm (SHA)
hyperparam 튜닝을 위한 알고리즘 중 하나
매우 작은 epoch수로 모델 학습시키고, hyperparam 조합의 모델을 무작위로 절반씩 선택하며 epoch수를 증가시킨다. 이런 방식으로 iteration을 반복하며 hyperparm 조합의 모델 개수는 16→8→4→2→1 형태로 줄어들며, 하나의 hyperpam 조합 모델을 출력한다.
Input
- budget B
- budget : 학습에 사용되는 자원 (iterations, epochs, dataset개수 등)
- n : hyperparm 개수
(무작위로 뽑은 hyperparm 조합을 계속해서 줄여나가는 과정!)
숫자 대입해보면 더 이해하기 쉽다!!
SHA의 문제점
- input인 B,n에 따라 탐색 비율 고정됨
- 위와 같은 예시의 경우, 예산이 4고, 모델 수가 14니까 탐색 비율은 64/16=4로, 이는 4개의 모델을 탐색하면서 1개의 모델만 선택하도록 하는 것을 의미한다.
- 탐색 비율이 고정되면, 모델 성능이 안 좋은 hyperparm조합에 빠져 더 이상 좋은 조합을 찾지 못하는 경우 발생할 수 있다.
- 무작위로 hyperparam 조합을 뽑아서, 성능이 좋지 않은 모델들도 무작위로 선택될 수 있다.
SHA의 문제점을 개선한 알고리즘 : Hyperband
- B, n 을 설정하지 않고, R하나만 설정하는 것으로도 다양한 탐색 비율 번영한 검색 진행 가능
- 무작위로 hyperparam 조합을 선택하는 것이 아니라, 적절한 확률분포를 이용해 hyperparam 조합을 선택해 더욱 효율적인 탐색 가능해진다.
input
- R : 한 hyperparam 설정에 할당되는 최대 budget
- ehta : 매 step마다 줄어드는 설정 개수 (늘어나는 budget의 비율) 설정
- Hyperband의
factor
(default=3) - SHA에서는 절반씩이라, 2로 작용했다.
- Hyperband의
1,2줄의 공식을 통해 n,r 구해준 후, SHA에 들어갈 B,n을 구해준다.
for문의 s 만큼, SHA를 연속해 사용하는 방식이다.
Ex. 아래 코드 실행 시, 학습될 파라미터의 개수는?
model = Sequential([
Dense(8, activation='relu', input_dim=4),
Dense(3, activation='softmax')
])
model.compile(
optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['acc'])
model.fit(
X_train, y_train,
batch_size=32,
epochs=100)
파라미터는 가중치, 편향으로 구성되어있다.
입력층과 은닉층 사이의 파라미터 = 가중치 + 편향 = 입력층노드수x은닉층노드수 + 은닉층노드수 = 4x8+8=40
은닉층과 출력층 사이의 파라미터 = 가중치 + 편향 = 은닉층노드수x출력층노드수 + 출력층노드수 = 8x3+3=27
총 40+27 = 67개의 파라미터가 학습된다.
이번 Session에서 배운 것 요약
- Perceptron
- MLP
- input, hidden, output layer
- 신경망 학습 : 순전파-손실 계산-역전파 과정
- Gradient Descent
- Optimizer
- Learning Rate - decay, scheduling
- Weight Initialization - Xavier, He
- Overfitting
- weight decay (regularizer)
- Dropout
- Early Stopping
- Cross Validation
- GridSearch, RandomSearch
'Machine Learning' 카테고리의 다른 글
[CV 2] Image Augmentation (0) | 2023.05.07 |
---|---|
[CV] CNN, Tranfer Learning (0) | 2023.05.07 |
[Neural Networks 3] 더 나은 신경망 학습을 위한 방법 (0) | 2023.04.24 |
[Neural Networks 2] Training Neural Networks (0) | 2023.04.24 |
[Neural Networks 1] Artificial Neural Network (0) | 2023.04.23 |