6. ガウス過程(Gaussian Process)#
ガウス過程(Gaussian Process, GP)は、関数の分布を扱うベイズ的なモデルである。主に回帰、ベイズ最適化などで利用される。
特に以下では、関数の回帰を行う関数の分布を推定・生成する方法としての観点から解説する。
理論的な詳細等については下記のガウス過程の名著(通称: GPML)を参照されたい。著者のページから無償でPDFが入手可能である:
"Gaussian Processes for Machine Learning" by Carl Edward Rasmussen and Christopher K. I. Williams
6.1. 概要#
今、図のようにデータが観測されているとする。このデータを説明する関数は無数に存在する。 そんな中、単一の関数を選ぶのではなく、「もっともらしい」関数の分布を考えることができれば、より柔軟にデータを説明できると考えられる。
ガウス過程は、このような関数の分布を直接扱うための枠組みの1つである。 背後にある考え方については、以下のとおりである。
任意の近傍二点に対して、その点での関数値は似ている(≒連続)であろう。
"似ている"度合いを非負の値を持つカーネル関数で定量化する。
既知のデータと未知の点での関数値の同時分布を考え、それが多変量ガウス分布に従うと仮定する。
とくに最後の点がガウス過程の名前の由来であると理解してもらってよい。
6.2. ガウス過程の定義#
観測データが \(\mathcal{D} = \{(x_i, y_i)\}_{i=1}^{n}\) で与えられるとする。ここで、\(x_i \in \mathbb{R}\) は説明変数、\(y_i \in \mathbb{R}\) は目的変数である。 説明変数・関数値とも、多次元でも構わないが、ここでは単純化のために1次元としよう。
自分の興味のある\(m\)個の点 \(\mathbf{x}^* \) に対して、関数値 \(\mathbf{y}^*\) を予測したいとする。 このときの\(\mathbf{x}^* = \{x_1^*, x_2^*, \ldots, x_m^*\}\) は、観測データ \(\mathcal{D}\) の説明変数 \(\mathbf{x}_i\) (データ点)とは異なる点であるとし、予測点とでも呼ぶことにする。
そのとき、\(\mathbf{x}, \mathbf{x}^*\) に対する関数値 \(\mathbf{y}, \mathbf{y}^*\) の同時分布が以下のように多変量ガウス分布に従うと仮定する。
平均ベクトルと共分散行列は、データ点と予測点を合わせて\(n+m\)次元のベクトル・行列としてまとめて書いた。 予測点を考えるときは、描画点を多数用意することが多いため、\(m\)は大きな値になることも多い。
ひとたび多次元正規分布の平均ベクトルと共分散行列が与えられれば、条件付き分布もまた多次元正規分布になるため、 以下のように、予測点での関数値の分布を得ることができる。
ここでは、多次元正規分布の条件付き確率分布の計算(3章)を用いた。 この意味するところは、予測点での関数値 \(\mathbf{y}^*\) は、観測データ \(\mathcal{D}\) に基づいて平均と分散が決定される正規分布に従う、ということである。 それぞれの予測点での関数値が分布に従うため、予測点での関数値の不確実性を考慮することができる。
6.3. カーネルとハイパーパラメータ#
カーネル関数 \(k(x, x')\) は、関数の滑らかさや周期性などの事前知識を反映する。代表的なカーネルは以下の通りである:
RBF(ガウス)カーネル:
\[ k(x, x') = \tau \exp\left(-\frac{(x-x')^2}{2l^2}\right) \]ハイパーパラメータ:\(\tau\)(出力のスケール)、\(l\)(長さ尺度, 相関長:correlation lengthとも言う)
Matérnカーネル:
\[ k(x, x') = \tau \frac{2^{1-\nu}}{\Gamma(\nu)} \left( \sqrt{2\nu} \frac{|x-x'|}{l} \right)^\nu K_\nu \left( \sqrt{2\nu} \frac{|x-x'|}{l} \right) \]ここで、\(K_\nu\) は第\(\nu\)種の変形ベッセル関数、\(\Gamma(\nu)\) はガンマ関数である。
ハイパーパラメータ:\(\tau\)(出力のスケール)、\(l\)(長さ尺度)、\(\nu\)(平滑度)
なかでも\(\nu=3/2\)や\(\nu=5/2\)がよく使われる。\(\nu=1/2\)のときは、指数カーネルとも呼ばれ、\(\nu \to \infty\)のときはRBFカーネルとなる。 RBFカーネルは無限回微分可能で非常に滑らかであるのに対し(それはデータが持つ連続性としては過剰な仮定と考えられ)、Matérnカーネルは\(\nu\)によって微分可能な回数が制御される。 実用上においても、RBFカーネルで距離の近いデータ点を取りすぎると、数値的に不安定になることがある。
ハイパーパラメータは、対数尤度最大化などで推定されることが多い。 上の、\(\tau, l\)をまとめて \(\theta = (\tau, l)\) と書くことにして、対数尤度の勾配は以下のように計算される。
また、カーネルが持つべき重要な性質としては、
対称性: \(k(x, x') = k(x', x)\)
正定値性: 任意の異なる点 \(\{x_1, x_2, \ldots, x_n\}\) に対して、対応するカーネル行列 \(K\) が正定値行列であること
非負性: \(k(x, x) \geq 0\) であること
が挙げられる。
問題
逆行列の微分と\(\log |\mathbf{A}|\)の微分の式(線形代数の章を参照)を用いて、上の対数尤度の微分に関する式を導出せよ。
6.4. ノイズの扱い#
ガウス過程では、観測データのノイズを自然に扱うことができる。
ここで、\(\epsilon_i\) は独立同分布に従うガウスノイズであるとする。 このとき、観測データの関数値 \(\mathbf{y}\) の共分散行列は、以下のようにノイズの分散を加えたもの
となる。ここで、\(I\) は単位行列である。このように、ノイズの分散を共分散行列に加えることで、ノイズを考慮した予測が可能となる。
一点注意すべきは、ノイズの分散 \(\sigma_n^2\) は、カーネルのハイパーパラメータとして推定されることが多いことである。
既存のGPyなどのライブラリでは、データを与えた際に、ノイズの分散を含むハイパーパラメータを対数尤度最大化で推定する機能が備わっている。
データは(多くの場合)標準化されていることが多いため、ノイズの分散は1よりもかなり小さい値になることが期待されるが、対数尤度最大化の結果、非常に大きな値になることがある。
この場合、データが本来持つ不定性を過大評価してしまうため、予測が過度に平滑化されてしまうことがある。
筆者の経験上、このあたりの問題を適切に理解した応用がなされていないものも多く散見するため、注意が必要である。
実装の背後にある理論や、データのドメイン知識が必要となる好例である。
6.5. 実装#
Pythonでは、GPyやscikit-learnなどのライブラリがガウス過程の実装を提供している。
以下では、自前でMatérnカーネル(\(\nu=5/2\))を用いたガウス過程を実装してみる。
とりあえず、ハイパーパラメータを固定して、予測点での関数値の分布を計算してみよう。
青線が、事後分布の平均、青色のバンドが、95%信頼区間を示している。破線で示したのは、事後確率から得られたサンプルである。
\(d\)個のデータ点と相関した\(m\)個の予測点を同時にサンプルすれば、各点で独立した値ではなく、連続的な関数のサンプルを得ることができる。
また\(K(\mathbf{x}, \mathbf{x})\)の逆行列を計算する際に、数値的に不安定になる。上の実装では、コレスキー分解を用いた。
ここで、\(L\)は下三角行列である。これを用いると、逆行列の計算は以下のように安定に行うことができる。
念の為、同じハイパーパラメータで、GPyのガウス過程の実装と比較してみよう。
両者がピッタリ重なっている事がわかる。ただし、GPyやscikit-learnなどのライブラリでは、データの分散や予測分散を別々にカスタマイズするのがやや面倒だったりもする。
6.6. \(\clubsuit\) 正規乱数の生成について#
余談になるが、正規分布に従う乱数の生成をどのように行えばよいだろうか?
もちろんnumpyやscipyなどのライブラリを使えば簡単に生成できるが、
どのように生成されているのか紹介しておこう。
簡単のため1次元の場合を考える。標準正規分布に従う乱数\(z\)を生成する方法の一つに、Box-Muller法がある。
Box-Muller法では、\(U_1, U_2\)を\([0,1)\)の一様分布に従う独立な乱数とするとき、以下の変換によって得られる\(Z_0, Z_1\)が標準正規分布に従うことを利用する。
この方法は、極座標変換を用いて、2次元の標準正規分布に従う乱数を生成し、それを1次元に分解している。 半径部分が指数分布に、角度部分が一様分布に従うことを利用している。
コードで確かめてみよう。一様乱数を2つ生成し、Box-Muller法で標準正規乱数を生成し、散布図とヒストグラムを描画してみた。
続いて、多次元正規分布に従う乱数を生成する方法についても紹介しよう。
こちらも、np.random.multivariate_normalなどの実装があるので、実用上はそれを使えばよいが、詳細な実現方法の一例を知っておくと便利である。
多次元正規分布の乱数生成は、共分散行列 \(\Sigma\) のコレスキー分解を用いればよい。
このとき、標準正規分布に従う乱数ベクトル \(\mathbf{z} \sim \mathcal{N}(0, I)\) に対して、変換
によって、\(\mathbf{y} \sim \mathcal{N}(\boldsymbol{\mu}, \Sigma)\) に従う乱数ベクトルを生成できる。
余談ついでに昔話をすると、Numpyの多次元正規分布は(少なくとも筆者が大学院生の頃は)何も考えずに使うとthread-unsafe、つまりマルチスレッド環境で使うと同様の乱数が生成されてしまう仕様であった。そのことに気がついたのは、粒子フィルタ(particle filter)と呼ばれる複数のworkerでサンプリングを行う、マルコフ連鎖モンテカルロ法の逐次バージョン的なアルゴリズムを実装していたときで、独立なはずのworkerが同じ乱択を繰り返していることに気が付いた。
Numpy 2.0になってからは、RNG(乱数生成器)周りでの改良が行われたようだが、やはり実際の乱数生成の結果を都度確認する癖はつけておいた方がよいだろう。
6.7. ベイズ最適化#
ガウス過程は、ベイズ最適化の核としても広く使われる。 関数の振る舞いをガウス過程でモデル化し、その不確実性を考慮しながら最適化を進めていく。
とくに、1回の観測(や数値実験など)にコストがかかり、勾配が利用できないような関数の最適化に有効である。 また、探索と活用のトレードオフを考慮しながら、効率的に最適解に近づくことができることも多く 機械学習のハイパーパラメータチューニングなどにも利用される。 探索というのは「井の中の蛙状態が怖いので、未知の領域を探索してみよう」というイメージで、 活用というのは「今までの経験から良さそうなところを掘り下げてみよう」というイメージである。
例えば今の関数の振る舞いを、パラメータ空間に対するコスト関数だと考え、その最小化や最大化を目指すとする。 すでに得られているデータ点をもとに、次に評価する点を獲得関数で決定する。 言い換えると、情報利得が高そうかつ、良さそうな点を次に評価するための、戦略を立てるための枠組みとも言える。
以下に、実装例を示す。 なお、獲得関数には、期待改善量(Expected Improvement, EI)を用いている。
ここで\(\Phi, \phi\)はそれぞれ標準正規分布の累積分布関数と確率密度関数である。この他にも
PI(Probability of Improvement): 現状の最適値よりもさらに良くなる確率を計算して次点を選ぶ方法
UCB(Upper Confidence Bound)/LCB(Lower Confidence Bound): ガウス過程の予測平均と分散を組み合わせて次点を選ぶ方法
今は単なる一次元の例を示したが、多次元にも拡張可能である。 最後に、ベイズ最適化を用いた各種のアプリケーションについて例示しておく。
ハイパーパラメータチューニング: 機械学習モデルのハイパーパラメータを最適化するために使用される。例えば、ニューラルネットワークの学習率や正則化パラメータの最適化など、人が手動で試行錯誤する作業を自動化できる。
材料科学: 新しい材料・化合物の特性(バンドギャップ、強度、磁化率など)の探索のためのスクリーニングに利用される。実験や数値シミュレーションなどのコストが高い場合に有用となる。
共通するのは、1回のデータの観測・評価・取得にコストがかかる場合であり、そのような場合に、効率的に最適解に近づくための手法としてベイズ最適化が有効であるということである。
獲得関数の設計やカーネルの選択など、応用に応じた工夫が必要となる場合も多いが、比較的容易に実装できるため、試してみる価値は大いにある。