Python

Python BayesianOptimizationによるベイズ最適化入門

Python

どうも、月見(@Suzuka14144156)です。

今回は、BayesianOptimizationによるベイズ最適化について解説します。

BayesianOptimizationのインストール方法

以下をコマンドプロンプトに入力する。

pip install bayesian-optimization

ベイズ最適化とは?

ベイズ最適化 (Bayesian Optimization) とは、形状が不明な関数 (ブラックボックス関数) の最大値 (または最小値) を求めるための手法です。

月見
月見
  • 筆者は、研究者なのですが、具体的に使う場面としては、ある実験をしてみてた結果に基づいて、次実験すべき水準を逐次的に決める手段として用いることが多いです。

詳細は、以下の本を参考にしてみてください。

具体例をみていきましょう。

BayesianOptimizationよるベイズ最適化

真値の関数の定義

まずは、以下の関数を実装します。

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

def target(x):
    return np.exp(-(x - 2)**2) + np.exp(-(x - 6)**2/10) + 1/ (x**2 + 1)
x = np.linspace(-2, 10, 10000).reshape(-1, 1)
y = target(x)

plt.plot(x, y)
plt.show()

出力結果は、以下のようになるかと思います。

月見
月見
  • 実際は、このような関数がわからない状態で、最適解を探索するのですが、今回はあらかじめ最適解をわかった状態でベイズ最適化を用いて、本当に最大値を求められるのか?を確認していきます。

ベイズ最適化で最大値を求める

最大化するターゲット関数、その変数、および対応する範囲を入力します。アルゴリズムを開始するには、最低 2 つの初期推測が必要です。これらは、ランダムまたはユーザー定義のいずれかです。この例では、ユーティリティ関数として上限信頼限界 (UCB) を使用します。探索と搾取のバランスを制御するパラメーターがあります。この場合、アルゴリズムを非常に大胆にする設定を行います。

optimizer = BayesianOptimization(target, {'x': (-2, 10)}, random_state=27)
optimizer.maximize(init_points=2, n_iter=0, kappa=5)

最初に、プロットを簡単にするためにいくつかの関数を定義しましょう。

def posterior(optimizer, x_obs, y_obs, grid):
    optimizer._gp.fit(x_obs, y_obs)

    mu, sigma = optimizer._gp.predict(grid, return_std=True)
    return mu, sigma

def plot_gp(optimizer, x, y):
    fig = plt.figure(figsize=(16, 10))
    steps = len(optimizer.space)
    fig.suptitle(
        'Gaussian Process and Utility Function After {} Steps'.format(steps),
        fontdict={'size':30}
    )
    
    gs = gridspec.GridSpec(2, 1, height_ratios=[3, 1]) 
    axis = plt.subplot(gs[0])
    acq = plt.subplot(gs[1])
    
    x_obs = np.array([[res["params"]["x"]] for res in optimizer.res])
    y_obs = np.array([res["target"] for res in optimizer.res])
    
    mu, sigma = posterior(optimizer, x_obs, y_obs, x)
    axis.plot(x, y, linewidth=3, label='Target')
    axis.plot(x_obs.flatten(), y_obs, 'D', markersize=8, label=u'Observations', color='r')
    axis.plot(x, mu, '--', color='k', label='Prediction')

    axis.fill(np.concatenate([x, x[::-1]]), 
              np.concatenate([mu - 1.9600 * sigma, (mu + 1.9600 * sigma)[::-1]]),
        alpha=.6, fc='c', ec='None', label='95% confidence interval')
    
    axis.set_xlim((-2, 10))
    axis.set_ylim((None, None))
    axis.set_ylabel('f(x)', fontdict={'size':20})
    axis.set_xlabel('x', fontdict={'size':20})
    
    utility_function = UtilityFunction(kind="ucb", kappa=5, xi=0)
    utility = utility_function.utility(x, optimizer._gp, 0)
    acq.plot(x, utility, label='Utility Function', color='purple')
    acq.plot(x[np.argmax(utility)], np.max(utility), '*', markersize=15, 
             label=u'Next Best Guess', markerfacecolor='gold', markeredgecolor='k', markeredgewidth=1)
    acq.set_xlim((-2, 10))
    acq.set_ylim((0, np.max(utility) + 0.5))
    acq.set_ylabel('Utility', fontdict={'size':20})
    acq.set_xlabel('x', fontdict={'size':20})
    
    axis.legend(loc=2, bbox_to_anchor=(1.01, 1), borderaxespad=0.)
    acq.legend(loc=2, bbox_to_anchor=(1.01, 1), borderaxespad=0.)

plot_gp(optimizer, x, y)

すると以下が出力されます。

月見
月見
  • ブルーの領域は、95%信頼区間を示す
  • Utilityの黄色の星マークが次実験すべき水準を示す
95%信頼区間とは?
  • 「母集団から標本を取ってきて、その平均から95%信頼区間を求める、という作業を100回やったときに、95回はその区間の中に母平均が含まれる」という”頻度”もしくは”割合”を意味します

  • つまり、最大化の問題を解くときは、95%信頼区間が最大値の水準を次の実験水準に設定するというのが、ベイズ最適化の最大のポイント

あとは、以下のコードを任意回数を繰り返す。

optimizer.maximize(init_points=0, n_iter=1, kappa=5)
plot_gp(optimizer, x, y)

3回目

4回目

12回目

12回目でついに最大値を見つけることができます。

月見
月見
  • つまり実際の実験であれば、12回の実験で最適解を見つけることができるというわけです。

まとめ

今回は、BayesianOptimizationによるベイズ最適化について解説しました。

ベイズ最適化は、少ない実験回数で、最適解を求める場合に用いる手法です。

今回の記事は、以上です。

コメント

タイトルとURLをコピーしました