はじめに
ベイズ最適化の話について、興味が沸いたので簡単にまとめます。 (ただのメモです)
詳しくはこちらなどを見ると良いと思います。
ベイズ最適化
ベイズ最適化とは,未知の目的関数𝑓(𝑥)を最大化するを求める大域最適化の手法です。
ここで、は探索空間の変数集合であり、離散値でも連続値でも良い。
新しいデータの獲得する候補を評価する獲得関数を用いる。
現在までに得られているデータから獲得関数を最大化するについて調べる。
そこから観測値を取得し、新たなデータとしてに加える。
具体的には、次のように逐次的にデータに加えていく。
その後,獲得関数を最大にするを選びを観測することを繰り返しで最適値の探索を行う。
アルゴリズムは次のように表現される。
ガウス過程の導入
ベイズ最適化の枠組みでは,統計モデルとしてガウス過程(Gaussian process)が用いられる。
ベイス推定を用いて一つの関数を推定するのではなく、関数の分布を推定することができる。
<あとで追記>
得られた観測値の各点 はガウス分布に従っており、それが横に並んでいると考えられる。
は、今までに観測されている値である。
するとN点が観測された の事後分布(予測分布)が[ tex: x _{N+1} ] に対して定まる。
この事後分布は、次の平均と分散からなる正規分布となる。
この値を用いて獲得関数の更新を行うことになる。
用いられるカーネル
カーネルには様々なものが存在する。
よく用いられるカーネルは次のようなものである。
Squared Exponential Function
Gaussian Kernel
Ornstein-Uhlenbeck Process
探索と活用
最適値の探索では獲得関数が最大の点を探索することになる。
この獲得関数による観測点を決定する戦略は、複数提案されている。
基本的には過去のデータに基づいて平均的に最大となるもの(活用)とデータの少ない 未知の領域について調べるもの(探索)の二種類である。
Probability of Improvement(PI)
PIの獲得関数は次のようになる。
ここで、は今までに観測された値の最大値、は正規分布の累積密度関数、は探索と活用のどちらを重視するかのトレードオフパラメータ。
現在の最大値を超える確率が高い点を次に観測することを意味する。
局所解に落ちいる可能性がある。
Expected Improvement(EI)
EIの獲得関数は次のようになる。
評価値と現在の最大値の差の期待値が最も⾼くなる点を次に観測することを意味する。
Upper-Confidence Bound(UCB)
UCBの獲得関数は次にようになる。
ここで、は探索と活用のトレードオフを設定するパラメータである。
評価値の信頼区間の上限が最も高い点を次に観測することを意味する。
最適解を求めることができる理論的保証が存在する。
Rでベイズ最適化
rBayesianOptimization packageとmlrMBO packageを用いた方法のそれぞれを確認してみた。
rBayesianOptimization
リポジトリはこちら。
ここで用いるのは、オークランドの火山地帯にある火山の1つであるVolcano火山の地形情報であるvolcanoです。
このデータを用いて最も標高が高い点を探索してみます。
なお、獲得関数にはUCBを用いた。
library(rBayesianOptimization) x <- (1:nrow(volcano)) y <- (1:ncol(volcano)) image(x, y, volcano, col = terrain.colors(100), axes = FALSE) # 探索したい関数の定義 volcano_func <- function(x, y){ Pred <- volcano[x,y] tmp <- list(Score=Pred, Pred=Pred) return(tmp) } set.seed(123) LOOP <- 50 BO_Res <- BayesianOptimization(volcano_func, bounds = list(x=c(1L,87L), y=c(1L,61L)), init_points = LOOP, n_iter = 1, acq = "ucb", kappa = 1.5, eps = 0, verbose = TRUE)
推定された最適値の情報を確認する。
> BO_Res$Best_Par x y 21 35 > BO_Res$Best_Value [1] 190
最適ではないが、ある程度最適値に近い値を探索することができている。
(明るい色の方が標高が高い)
mlrMBO
ここで探索に利用するデータは、次のような関数により生成されたデータです。
mlrMBO packageを用いた方法が次のような物である。
# 探索対象の関数を定義 fun = function(x) { x <- as.numeric(x) x^2 + 8*sin(1.98 * pi * x) * cos(1.2 * pi * x) } # 探索するパラメータ空間を定義 ps = makeParamSet( makeNumericParam("x", lower = -5, upper = 5) ) # smoof関数でラップする fn = makeSingleObjectiveFunction( fn = fun, par.set = ps, has.simple.signature = FALSE ) # 初期探索点を取得 des = generateDesign(n = 3, par.set = ps) # 対応する関数の出力を取得 des$y = apply(des, 1, fn) # MBOの初期化 ctrl = makeMBOControl() ctrl = setMBOControlInfill(ctrl, crit = crit.ei) ctrl = setMBOControlTermination(ctrl, iters = 20) # learnerオブジェクトの作成 surr.km = makeLearner("regr.km", predict.type = "se", covtype = "matern3_2", control = list(trace = FALSE)) # configureMlr(show.info = FALSE, show.learner.output = FALSE) # 最適化処理 run = mbo(fun = fn, design = des, learner = surr.km, control = ctrl) # run = exampleRun(fn, learner = surr.km, control = ctrl, show.info = FALSE) # グラフ化 plotExampleRun(run, iters = c(1L:20L), pause = F)
推定の変化を確認します。
早いステップで最適解付近の探索が行えている。