2020. 1. 24. 14:26ㆍ분석 Python/구현 및 자료
하이퍼파라미터를 튜닝하는 방법에는 여러 가지가 있다.
일단 기본적으로 GridSearch 나 RandomSearch 같은 방법이 있다.
하지만 이 방법론은 각 파라미터를 돌릴 뿐이지, 최적의 파라미터를 찾아주지는 못한다.
이런 것을 활용하기 위해서 Bayesian Optimization 방법론을 사용하여야 한다.
아래 그림 중에서 밑에 실제 결과라는 부분은 learning rate에 따른 일반화 성능 함수를 나타낸다.
그러나 우리는 저기에서 어떤 learning rate가 최적의 값인지를 알지 못한다.
그렇지만 실제로 딥러닝을 할 때는 저것을 순차적으로 한다면, 원하는 성능을 얻을 수 있다는 확신도 없이 계속 돌려야 한다. 그래서 많은 연구자들이 이러한 문제점을 해결하기 위해 병렬로 돌리는 것을 연구하였고 그중에 몇 가지 알고리즘이 개발되었다.
그중에서 19년도 7월에 나온 optuna가 좀 더 편리한 것 같아서 써보기로 했다.
아래 그림에서 각 알고리즘 별로 기능별로 비교한 표가 있다.
저자가 주장하는 것은 optuna가 기존에 할 수 없었던 것을 다 할 수 있다고 한다.
보통 hyperopt와 비교를 하는 것 같지만 기능적 차이로 봤을 때 시각화하는 dashboard와 pruning 하는 것이 있다고 하는데, 추후에 pruning을 tensorflow 어떻게 쓸 수 있는지 알아봐야겠다.
Hyperparameter Optimization Framework : Optuna
optuna를 그냥 쓰면 여러 모델을 병렬적으로 쓰는 기능밖에 제시를 안 한다.
아래 코드에서는 x를 찾는 것을 하는데 TPESampler를 사용했다.
방법론에 대해서는 아래 문서를 참고하길 바란다.
많이 돌리면 결과는 비슷하게 나올 수 있겠지만 적은 시도로 최적의 값을 찾는 것이 중요하니 테스트를 해봤다.
TPESampler
https://optuna.readthedocs.io/en/stable/reference/samplers.html
import optuna
from optuna.samplers import TPESampler
optuna.logging.disable_default_handler()
def objective(trial):
x = trial.suggest_uniform('x', -10, 10)
return (x-1)**2
if __name__ == '__main__':
sampler = TPESampler(**TPESampler.hyperopt_parameters())
study = optuna.create_study(direction='minimize',sampler=sampler)
study.optimize(objective, n_trials=10)
print('Number of finished trials: ', len(study.trials))
print('Best trial:')
trial = study.best_trial
print(' Value: ', trial.value)
print(' Params: ')
for key, value in trial.params.items():
print(' {}: {}'.format(key, value))
위에 결과물은 10번 시도했을 때, 1을 찾는 것이다. 해당 시도에서는 x : 0.6이라는 값을 찾았다
SkoptSampler
아래 integration에서 여러 가지 프레임워크와 호환돼서 사용할 수 있는 Pruner와 Skopt Sampler를 제공하고 있다.
bayesian optimization 방법론 중에서 목적함수의 대략적은 형태에 대한 확률추정 모델로써 Gaussian Process 확률 모델을 사용한다.
skopt는 Gaussian Process 확률 모델을 활용한다고 알고 있다.
https://optuna.readthedocs.io/en/stable/reference/integration.html
from optuna.integration import SkoptSampler
optuna.logging.disable_default_handler()
sampler = SkoptSampler(
skopt_kwargs={'n_random_starts':5,
'acq_func':'EI',
'acq_func_kwargs': {'xi':0.02}})
if __name__ == '__main__':
study = optuna.create_study(direction='minimize',sampler=sampler)
study.optimize(objective, n_trials=10)
print('Number of finished trials: ', len(study.trials))
print('Best trial:')
trial = study.best_trial
print(' Value: ', trial.value)
print(' Params: ')
for key, value in trial.params.items():
print(' {}: {}'.format(key, value))
같은 trial에 대해서 x : 0.97이라는 가까운 값을 얻을 수 있게 되었다!!
위에서는 Gaussian Process에서 다음 파라미터를 추천하는 함수를 Acquisition Function이라고 하는데,
여기선 Expected Improvement(EI)를 사용했다. EI는 exploration 전략 및 exploitation 전략 모두를 내재적으로 일정 수준 포함하도록 설계된 것으로, Acquisition Function으로 가장 많이 사용된다.
물론 두 개의 sampler는 trial를 좀 높이면 비슷한 값을 얻는 것을 확인했다.
많은 연구자들이 좀 더 효율적으로 하이퍼파라미터를 찾기 위해 다양한 알고리즘을 만들고 있다.
요즘엔 NASNet 과 같이 Network Arhictecture까지 알아서 만드는 연구도 이미 많이 진행되고 있다.
AutoML이라는 영역이 점점 연구가 많이 되고 있는 것 같아서 개인적으로는 편하지만 불안하기도 하다.
추가적으로 tensorflow에서 해본 것인데,
기존에 skopt가 제공하던 같은 하이퍼파리미터에서 이미 있던 결과값을 gaussian process의 초기값에 넣어줄 수가 있을 것이 optuna에도 가능할 것 같아서 해보니 되는 것을 확인했다.
x0 = [[13, 3, 2, 4, 3, 4, 36, 32, 49, 40, 35, 'he_uniform', 3, 0.00015671897437797408], [10, 3, 4, 2, 2, 3, 34, 64, 45, 54, 40, 'he_normal', 3, 1.4147691642608397e-05], [12, 4, 3, 3, 4, 2, 46, 65, 62, 42, 57, 'xavier_uniform', 0, 0.0001151939657356718], [10, 3, 4, 2, 4, 4, 60, 34, 54, 63, 40, 'he_uniform', 3, 0.00023751936361984937], [11, 2, 4, 3, 4, 3, 38, 58, 39, 31, 63, 'caffe_uniform', 4, 1.185261441167407e-05], [12, 2, 2, 2, 2, 3, 43, 54, 42, 56, 30, 'caffe_uniform', 3, 2.8053303983617267e-05], [13, 3, 4, 3, 4, 2, 53, 31, 57, 31, 40, 'he_uniform', 1, 0.004342367249195597], [10, 3, 2, 2, 2, 2, 52, 56, 50, 40, 45, 'caffe_uniform', 2, 0.0002353657442834687], [12, 2, 3, 2, 2, 4, 37, 43, 38, 48, 56, 'xavier_normal', 2, 1.1695403014796976e-05], [10, 4, 3, 2, 4, 4, 62, 55, 56, 30, 44, 'xavier_uniform', 2, 0.00132122127636011], [12, 2, 4, 4, 3, 3, 64, 47, 60, 39, 64, 'xavier_normal', 3, 0.002818043271032938], [11, 2, 4, 3, 3, 4, 54, 34, 35, 49, 63, 'xavier_uniform', 1, 0.00011653454036311457], [12, 4, 2, 3, 4, 3, 51, 45, 36, 41, 40, 'caffe_uniform', 1, 0.0013094508034332806], [9, 3, 2, 4, 4, 3, 62, 51, 64, 36, 42, 'xavier_normal', 3, 0.006172462319995353], [8, 2, 3, 4, 2, 2, 65, 38, 38, 53, 65, 'xavier_uniform', 1, 0.004848434779819864], [8, 3, 2, 3, 2, 4, 65, 65, 60, 30, 30, 'caffe_uniform', 2, 0.09999999999999999], [10, 4, 4, 4, 3, 3, 65, 34, 65, 30, 46, 'xavier_normal', 3, 0.09999999999999999], [8, 2, 4, 3, 3, 4, 61, 53, 43, 52, 46, 'caffe_uniform', 3, 0.09999999999999999], [8, 4, 3, 4, 3, 2, 63, 57, 44, 55, 48, 'he_uniform', 1, 0.09999999999999999], [8, 2, 3, 4, 2, 3, 36, 30, 30, 63, 32, 'he_normal', 2, 0.09999999999999999], [8, 2, 3, 4, 2, 2, 60, 39, 41, 65, 33, 'xavier_uniform', 4, 0.0002012076028834959], [11, 3, 3, 4, 3, 4, 35, 63, 63, 62, 64, 'xavier_uniform', 1, 0.00866714545089891], [8, 2, 3, 3, 4, 4, 55, 56, 63, 60, 34, 'he_normal', 2, 0.00010933878687689759], [8, 2, 4, 3, 4, 4, 48, 40, 52, 60, 32, 'he_normal', 2, 0.09999999999999999], [8, 4, 4, 3, 3, 4, 60, 54, 65, 41, 32, 'he_normal', 3, 1.0054555508216113e-05], [8, 3, 3, 3, 3, 2, 31, 57, 60, 51, 30, 'he_normal', 1, 0.0026168135968490723], [8, 4, 4, 4, 3, 3, 37, 64, 62, 33, 52, 'he_normal', 0, 0.01685645874697779], [11, 4, 3, 3, 3, 4, 61, 47, 54, 55, 47, 'he_normal', 1, 0.0003765011074475807], [10, 2, 3, 3, 3, 3, 63, 52, 56, 58, 34, 'caffe_uniform', 3, 0.09999999999999999], [8, 2, 2, 4, 2, 2, 30, 30, 30, 65, 30, 'he_normal', 2, 0.09999999999999999], [8, 2, 2, 3, 2, 3, 30, 30, 30, 53, 32, 'he_normal', 0, 0.09999999999999999], [8, 4, 3, 3, 4, 3, 48, 63, 47, 34, 61, 'caffe_uniform', 0, 0.0006988342189973038], [8, 2, 2, 4, 2, 3, 48, 50, 38, 60, 44, 'he_normal', 3, 0.0010630558921353032], [8, 4, 3, 3, 3, 3, 55, 63, 37, 31, 51, 'xavier_uniform', 0, 0.040182145025863716], [8, 4, 3, 2, 4, 3, 52, 36, 65, 36, 54, 'caffe_uniform', 2, 1.799227078888316e-05], [8, 2, 2, 3, 3, 3, 30, 42, 46, 53, 53, 'he_normal', 3, 0.0017274481636200155], [8, 4, 2, 2, 4, 3, 39, 42, 58, 58, 34, 'caffe_uniform', 0, 0.02538727255814498], [8, 3, 2, 3, 2, 3, 34, 64, 54, 32, 44, 'caffe_uniform', 0, 0.05841467788043324], [8, 3, 2, 2, 4, 3, 30, 40, 36, 40, 35, 'caffe_uniform', 0, 2.6425141972924894e-05], [8, 4, 2, 3, 4, 3, 53, 50, 65, 54, 65, 'xavier_uniform', 2, 0.00035018555480494817], [8, 4, 2, 2, 4, 3, 60, 61, 64, 38, 56, 'xavier_uniform', 4, 0.00030709124496748716], [8, 2, 2, 3, 2, 3, 30, 53, 53, 56, 64, 'he_normal', 3, 0.056749864882203925], [8, 2, 2, 4, 2, 3, 30, 65, 59, 30, 65, 'xavier_uniform', 0, 0.09999999999999999], [9, 2, 2, 4, 3, 3, 57, 60, 56, 50, 63, 'xavier_uniform', 1, 2.1659583232534686e-05], [13, 2, 2, 4, 2, 3, 30, 65, 65, 30, 62, 'he_normal', 0, 0.007582478981301236], [8, 2, 2, 4, 2, 3, 30, 65, 65, 30, 65, 'he_normal', 0, 0.09999999999999999], [9, 3, 2, 4, 2, 3, 45, 65, 65, 30, 30, 'he_normal', 2, 0.09999999999999999], [8, 2, 2, 4, 2, 3, 41, 65, 30, 30, 65, 'he_normal', 2, 0.011195733193718348], [8, 2, 2, 4, 2, 3, 65, 65, 43, 30, 37, 'he_normal', 2, 0.015092488426198855], [8, 4, 2, 3, 2, 3, 63, 65, 47, 34, 43, 'he_normal', 2, 1e-05], [8, 4, 2, 2, 3, 3, 57, 55, 65, 42, 65, 'he_normal', 2, 1e-05], [8, 2, 3, 3, 4, 3, 34, 62, 47, 38, 64, 'he_normal', 0, 1.0017455593748346e-05], [10, 3, 2, 4, 2, 3, 54, 65, 39, 46, 50, 'he_normal', 0, 0.0010848883882730042], [13, 2, 3, 2, 2, 3, 57, 65, 36, 56, 55, 'he_normal', 0, 1e-05], [12, 3, 2, 2, 2, 3, 65, 53, 65, 35, 30, 'he_normal', 0, 1e-05], [13, 4, 3, 2, 4, 3, 47, 43, 53, 37, 61, 'he_normal', 4, 2.3448490928467227e-05], [8, 4, 3, 2, 2, 3, 43, 42, 31, 51, 48, 'caffe_uniform', 0, 8.923072180908639e-05], [13, 2, 2, 2, 3, 3, 36, 65, 30, 33, 64, 'he_normal', 0, 2.5008788649091418e-05], [13, 2, 3, 4, 2, 3, 55, 34, 41, 41, 33, 'he_normal', 0, 6.300417507628337e-05], [13, 3, 3, 4, 2, 3, 46, 49, 36, 36, 59, 'he_normal', 0, 1.4168106849205638e-05], [13, 3, 3, 4, 2, 3, 44, 57, 51, 57, 44, 'he_normal', 0, 0.047648161089890124], [10, 3, 3, 4, 2, 3, 53, 58, 48, 63, 52, 'he_normal', 0, 0.0006616156670531221], [11, 3, 3, 2, 2, 3, 49, 56, 61, 50, 35, 'he_normal', 0, 0.003874206631357768], [11, 4, 3, 2, 4, 3, 30, 35, 49, 30, 48, 'he_normal', 0, 0.09999999999999999], [13, 2, 3, 2, 4, 3, 45, 65, 30, 40, 39, 'caffe_uniform', 0, 1.3124990909659663e-05], [11, 4, 3, 2, 2, 3, 59, 60, 36, 51, 65, 'xavier_uniform', 0, 0.016798014117541147], [13, 4, 3, 2, 2, 3, 59, 51, 37, 48, 65, 'xavier_uniform', 0, 0.00010245200147978441], [13, 4, 4, 2, 2, 3, 56, 65, 30, 30, 65, 'he_normal', 0, 1e-05], [8, 4, 4, 2, 2, 3, 32, 58, 60, 39, 51, 'he_normal', 0, 1.138181205622081e-05], [8, 4, 2, 2, 2, 3, 41, 54, 30, 30, 65, 'he_normal', 0, 1e-05], [8, 4, 2, 2, 2, 3, 32, 55, 30, 30, 65, 'he_normal', 0, 1e-05], [13, 3, 3, 2, 2, 3, 38, 48, 56, 36, 65, 'caffe_uniform', 2, 7.267730586124988e-05], [13, 3, 3, 2, 2, 3, 55, 58, 42, 34, 65, 'he_normal', 2, 1.960429089732139e-05], [8, 4, 4, 3, 2, 3, 46, 61, 48, 36, 38, 'he_normal', 2, 0.03533183513155234], [8, 4, 4, 3, 2, 3, 45, 40, 64, 60, 41, 'he_normal', 1, 0.0017356418135645042], [8, 3, 4, 3, 2, 3, 58, 43, 47, 38, 40, 'he_normal', 0, 0.0009185683862714557], [8, 3, 4, 3, 2, 3, 62, 51, 57, 40, 42, 'he_normal', 0, 0.0003828493855941364]]
y0 = [0.5, 0.37312627079078414, 0.5, 0.5, 0.40127449514370905, 0.5, 0.5, 0.5, 0.3953523854056861, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.33482347489277114, 0.5194659099702321, 0.1966741884180666, 0.42179660969198135, 0.5488758740195663, 0.5, 0.5, 0.5, 0.4357786121775885, 0.32259930095007106, 0.5, 0.5, 0.5, 0.31408737435719747, 0.3165046787537358, 0.5782271547251162, 0.5, 0.5, 0.5000287786347415, 0.5, 0.5, 0.5, 0.5033644497408181, 0.5, 0.5, 0.5, 0.4474929984736806, 0.45493217463262253, 0.5, 0.5, 0.5785984352326466, 0.31545481099947675, 0.5, 0.5, 0.5561970460903911, 0.3749490185795035, 0.439759109548035, 0.5, 0.6167678019492814, 0.28535717674560535, 0.5, 0.5, 0.5, 0.5, 0.5611044938310887, 0.5258427040774896, 0.5, 0.5, 0.24205781919861497, 0.5, 0.5000913182518414, 0.5, 0.38260363612366477, 0.700793203550933, 0.507285148316521, 0.4964040570034959, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5]
sampler = SkoptSampler(
skopt_kwargs={'n_random_starts':10,
'acq_func':'EI',
'acq_func_kwargs': {'xi':0.02,
"x0" : x0,
"y0" : y0}})
if __name__ == '__main__':
logging.getLogger().info("Start optimization.")
study = optuna.create_study(direction='maximize',
sampler = sampler)
study.optimize(objective,
n_trials=100,
n_jobs = 30
)
print('Number of finished trials: ', len(study.trials))
print('Best trial:')
trial = study.best_trial
print(' Value: ', trial.value)
print(' Params: ')
for key, value in trial.params.items():
print(' {}: {}'.format(key, value))
study.trials_dataframe().sort_values(["value"],ascending = False)
x0 = []
y0 = []
for i in range(len(study.get_trials())) :
check = study.get_trials()[i].value
if check is None :
continue
x0.append(list(study.get_trials()[i].params.values()))
y0.append(study.get_trials()[i].value)
Reference
http://research.sualab.com/review/2018/09/28/nasnet-review.html
https://optuna.readthedocs.io/en/stable/
http://research.sualab.com/introduction/practice/2019/02/19/bayesian-optimization-overview-1.html
'분석 Python > 구현 및 자료' 카테고리의 다른 글
[ Python ] decorator로 Error 정리해서 출력하기 (0) | 2020.01.31 |
---|---|
[ Python ] Install all dependency packages (0) | 2020.01.25 |
[ Python ] numba 사용 예시 (0) | 2020.01.15 |
[ Python ] smtplib을 활용한 메일 보내기 (이미지 , 텍스트 , gif) (0) | 2020.01.05 |
[ Python ] 동적 변수 할당 및 불러들이기 (1) | 2019.12.15 |