본문 바로가기

Computer Science/Machine Learning

Bayesian Hyperparameter Optimization 겉핥기

Bayesian hyperparameter optimization(베이지안 하이퍼 파라메터 최적화)은 나름 유명한 주제인데, 이를 겉핥기 수준으로 한 번 맛보자.

Optimization Problem

베이지안 최적화를 알려면 먼저 최적화가 뭔지를 알아야 한다. 최적화 문제는 함수 $f$와 $f$의 (bounded) domain $X$가 주어졌을 때, $$x^* = \arg\max_{x \in X} f(x)$$ (혹은 $x^* = \arg\min_{x \in X} f(x)$) 를 구하는 문제라고 할 수 있다.

 

우리가 관심을 두는 대상은 최적화 문제 중에서도 기계학습에서 발생하는 최적화 문제이다. 기계학습에서의 최적화 문제는 대개 다음과 같은 양상을 띈다고 할 수 있다:

  • 함수 $f$는 closed-form을 모르는 black-box 함수이고,
  • $f$의 값을 한 번 계산하는데 많은 비용(cost)이 든다.

즉, 우리가 베이지안 최적화를 통해 찾고자 하는 $x^*$는 모델의 성능을 최대화하는 하이퍼파라메터라고 할 수 있다.

Hyperparameter Optimization

기존에 널리 쓰이는 하이퍼 파라메터 최적화 방법은 다음과 같다:

 

1. Manual Search

  • 우리가 흔히 사용하는 방법으로 우리의 직관을 믿고 하이퍼 파라메터의 값을 바꿔가며 대입해보는 방식
  • 하이퍼 파라메터 여러 개가 상호작용 하는 경우 좋은 결과를 내기 어렵다.
  • Manual Search를 통해 찾은 하이퍼 파라메터가 전역 최적해임은 보장되지 않는다.

2. Grid Search

  • 탐색의 대상이 되는 모든 후보 하이퍼 파라메터들을 적당한 간격을 두고 선정하여 "전수조사"를 시행한다.
  • 이후 가장 성능이 좋았던 것을 하이퍼 파라메터로 택한다.
  • 구간의 간격을 줄이면 전체 탐색 시간이 늘어나고, 구간의 간격을 늘이면 전역 최적해를 찾지 못할 수도 있다.
  • 요약: 1에 비하면 낫지만, 여전히 한계점이 있다.

3. Random Search

  • 2와 비슷한데, 균등하게 나눈 구간에서 랜덤으로 샘플링하여 탐색한다.
  • 2의 단점을 어느 정도 보완하나, 여전히 부족하다.
    (1에서는 우리 뇌(살아있는 베이지안 머신)의 통계적 추론 결과가 "직관"에 반영되나, 2와 3에서는 이전 탐색으로 부터 얻은 정보가 새로운 탐색에 반영되지 않는다.)
  • 고차원의 하이퍼 파라메터를 최적화 할 때는 2에 비해 좋은 성능을 냄이 알려져 있다. (J.Bergstra & Y. Bengio, 2012)

Bayesian Hyperparameter Optimization

베이지안 하이퍼 파라메터 최적화는 이전 탐색에서 얻은 사전 지식을 활용하며 보다 체계적으로 탐색을 수행하는 방법이다. 다만, 이는 기존의 3가지 탐색 방법과는 큰 차이점이 있다.

베이지안 최적화의 목적은 최적 하이퍼 파라메터의 후보값($x$)을 어떻게 입력할지 결정하기 위함이 아니고, 목적 함수($f$)의 형태를 잘 추정하기 위함이다.

 

Theorem. (Bayes' Theorem) 다음이 성립한다:

$$P(\theta|\textbf{D}) = P(\theta ) \frac{P(\textbf{D} |\theta)}{P(\textbf{D})},$$

즉, posterior는 prior과 likelihood의 곱에 비례한다.

 

위의 베이즈 정리에 대응시켜 간단히 설명하자면, 베이지안 하이퍼 파라메터 최적화는

  • prior (=기존에 추정한 $f$의 모양)과
  • likelihood (=관측)을 통해
  • posterior (=새로 추정한 $f$의 모양)를 얻는 과정이라고 할 수 있다.

베이지안 하이퍼 파라메터 최적화는

  • 현재까지의 관측으로 $f$를 추정하는 모델 $S$(Surrogate Model)와
  • 현재까지 추정한 $f$에 대한 정보를 바탕으로 최적해를 찾는데 있어 유용할만한 다음 입력값을 추천해주는 함수 $A$(Acquisition Function)가 있을 때

다음과 같은 의사코드로 작동한다.

 

Algorithm. Bayesian Hyperparameter Optimization

for $t = 1, 2, 3, \dots$ do:

    $S$를 통해 기존에 얻어진 데이터 $\{(x_i, f(x_i)) : i \le t \}$를 토대로 $f$를 추정

    $A$를 통해 새로운 입력값 $x_{t+1}$을 선정

    $f(x_{t+1})$을 얻음

 

이를 실제로 활용하기 위해서는 적절한 Surrogate model과 Acquisition function을 선정하는게 중요한데, 주로 사용되는 것은 각각 Gaussian Process와 Expected Improvement이다.

 

Gaussian Process는 continuous한 domain에 대해 정의되는 random process인데, 각 점이 normal distribution을 따르는 random variable로 mapping 된다. 아래의 그림을 보면 직관적인 이해에 도움이 될 것이다. 관측을 수행할수록 "$f$의 후보군" (파란색 영역)이 줄어드는 것을 관찰할 수 있다.

(E. Brochu, et. al, 2010)

즉, 위 그래프에서 실선으로 표시된 mean function $\mu(x)$와 kernel function $k(x, x')$를 정의하고 나면, 임의의 $x \in X$(domain)에 대한 확률분포(파란색 영역)를 얻어낼 수 있게 된다. (어떤 점에서의 kernel function의 함숫값이 그 점에서의 $\sigma$ 값이라 생각하면 된다.) $\sigma(x)$의 경우, $x$가 이미 관측된 점에 가까울수록 작고, 멀수록 큰 경향성을 띄는데, 이는 두 점 사이의 거리가 가까울수록 ($f$ 값의) 연관성이 크고, 멀면 별 연관성이 없다는 의미를 담고 있다. Kernel function으로는 주로 squared-exponential이 많이 사용된다.

 

Expected Improvement은 다음의 (서로 trade-off 관계에 있는) 두 전략을 포괄적으로 포함하는 개념이라고 볼 수 있는데,

  • exploitation: $x^*$가 현재까지 관측된 점들 중 함숫값이 최대인 점 근처에 있을 가능성에 초점을 두는 전략
  • exploration: $x^*$가 현재까지 관측된 점들과는 먼 미지의 영역에 있을 가능성에 초점을 두는 전략

현재까지 추정한 $f$의 형태를 바탕으로, 각 $x$에 대해

  • $f(x) > \max_{1 \le i \le t} f(x_i)$일 확률과
  • $f(x) - \max_{1 \le i \le t} f(x_i)$(커진다면 얼마나 더 커지는가?)를

고려하여 $x$의 "유용성"을 수치로 반환해준다고 생각하면 된다. EI가 closed form으로 어떻게 나타나는지에 대해서는 이 글에서 다루지 않는다. 직관적인 이해에는 아래 그림이 도움이 될 것이다.

아래는 간단한 Python 데모 코드이다.

from bayes_opt import BayesianOptimization
import numpy as np
import matplotlib.pyplot as plt
from bayes_opt import UtilityFunction
from matplotlib import gridspec

# 목적 함수 정의
def target(x):
  return np.cos(x) + np.sin(x/2) + x/20 + 3
  
# Domain 정의
l, r = 0, 10

# 목적 함수 visualize 
def visualize(f, l, r):
  X = np.linspace(l, r, 100).reshape(-1, 1)
  y = f(X)
  plt.plot(X, y)
  plt.show()

visualize(target, l, r)

# x^\star 찾기
bayes_optimizer = BayesianOptimization(target, {'x': (l, r)})
bayes_optimizer.maximize(init_points=3, n_iter=7, acq='ei', xi=0.01)
print(bayes_optimizer.max)

위의 코드에서의 목적 함수는 다음과 같은 개형을 띄고,

Bayesian Optimization의 결과로는 아래와 같은 값이 나옴을 확인할 수 있다.

|   iter    |  target   |     x     |
-------------------------------------
|  1        |  3.749    |  4.439    |
|  2        |  3.318    |  2.393    |
|  3        |  1.698    |  8.77     |
|  4        |  4.0      |  0.0      |
|  5        |  4.136    |  0.7476   |
|  6        |  4.41     |  5.729    |
|  7        |  4.305    |  6.302    |
|  8        |  4.411    |  5.929    |
|  9        |  4.329    |  5.391    |
|  10       |  4.415    |  5.83     |
=====================================
{'target': 4.415215559168083, 'params': {'x': 5.8298993776504915}}

더 자세한 데모 코드의 경우 https://github.com/krasserm/bayesian-machine-learning 에 jupyter notebook을 통해 친절하게 나와있다. 여기를 참고하도록 하자.

 

krasserm/bayesian-machine-learning

Notebooks related to Bayesian methods for machine learning - krasserm/bayesian-machine-learning

github.com

 

'Computer Science > Machine Learning' 카테고리의 다른 글

Bayesian Hyperparameter Optimization 겉핥기  (0) 2020.03.04