※記事内に商品プロモーションを含むことがあります。
はじめに
本記事では、BFGS公式の準ニュートン法について簡単に解説し、Pythonで実装した例を示す。実装は、数理工学社の「工学基礎 最適化とその応用」の4.8節「準ニュートン法」を参考にさせていただいた。
準ニュートン法は、再急降下法とニュートン法の両者の長所を持つような手法である。再急降下法は、収束速度が1次でしかない替わりに、初期点が解から離れていても収束する(大域的収束性)。一方、ニュートン法は、解近傍の収束速度は2次であるが、探索方向が評価関数の勾配方向と一致するとは限らないため、直線探索をそのまま利用できない。
両者の実装については、それぞれ以下の記事を参考。
直線探索を使った最急降下法をPythonで実装
ニュートン法による最適化とPythonによる実装
本記事で使用したPythonとライブラリのバージョンは以下の通り。
バージョン | |
---|---|
Python | 3.8.5 |
NumPy | 1.19.2 |
matplotlib | 3.3.2 |
実装では、以下のようにライブラリをインポートしていることを前提とする。
|
|
準ニュートン法
概要
最小化したい関数を$f(\bm{x})$とする。
ニュートン法の$k$回目の更新において、解の更新方向$\bm{d}_k$は次の方程式の解として与えられる。
$$ \nabla ^2 f(\bm{x}_k) \bm{d}_k = - \nabla f(\bm{x}_k) $$
しかし、一般にヘッセ行列$\nabla ^2 f(\bm{x}_k)$が正定値である保証はない。したがって、ヘッセ行列は逆行列を持たない可能性があり、上記の方程式を$\bm{d}_k$について解けるとは限らない。
そこで、準ニュートン法ではヘッセ行列を適当な正定値行列で近似する。準ニュートン法には、ヘッセ行列を近似する方法と、ヘッセ行列の逆行列を近似する方法の2つがある。この記事では前者について述べる。
ヘッセ行列を近似する正定値行列を$B_k$として、解の更新方向$\bm{d}_k$を次の方程式の解として求める。
$$ B_k \bm{d} = - \nabla f(\bm{x}_k) $$
$B_k$を求めるには、勾配$\nabla f(\bm{x})$のテイラー展開(次式)を利用する。
$$ \nabla f(\bm{x}_k) = \nabla f(\bm{x}_{k+1}) + \nabla^2 f(\bm{x}_{k+1}) (\bm{x}_k - \bm{x}_{k+1}) + … $$
すなわち、以下の近似式が成り立つ。
$$ \nabla^2 f(\bm{x}_{k+1}) (\bm{x}_{k+1} - \bm{x}_k) \approx \nabla f(\bm{x}_{k+1}) - \nabla f(\bm{x}_k) $$
さらに、
$$ \bm{s}_k = \bm{x}_{k+1} - \bm{x}_k, \\ \bm{y}_k = \nabla f(\bm{x}_{k+1}) - \nabla f(\bm{x}_k) $$
と置き、以下を満たすように近似行列$B_{k+1}$を求める。
$$ B_{k+1} \bm{s}_k = \bm{y}_k $$
この式をセカント条件と呼ぶ。
ヘッセ行列を近似する方法の1つとして、BFGS (Broyden–Fletcher–Goldfarb–Shanno) 法がある。この方法では、以下の公式を用いて近似行列を更新する。
$$ B_{k+1} = B_k - \frac{B_k \bm{s} (B_k \bm{s}_k)^\top}{\bm{s}_k^\top B_k \bm{s}_k} + \frac{\bm{y}_k \bm{y}_k^\top}{\bm{s}_k^\top \bm{y}_k } $$
初期行列$B_0$には通常は単位行列が用いられてる。
アルゴリズム
準ニュートン法のアルゴリズムは以下のようになる。
- 解の初期値$x_0$, 初期行列$B_0$を用意
- $B_k \bm{d}_k = - \nabla f(\bm{x}_k)$を解いて解の更新方向$\bm{d}_k$を求める
- 直線探索によりステップ幅$\alpha_k$を求める
- $\bm{x}_{k+1} = \bm{x}_k + \alpha_k \bm{d}_k$で解を更新
- BFGS公式で近似行列$B$を更新
解が収束するか、反復回数の上限に達するまで、上記のアルゴリズム2~5を繰り返す。
Pythonによる実装
BFGS公式を用いた準ニュートン法をPythonで実装した。
直線探索にはArmijo条件を用いた。
目的関数
以下の評価関数を考える。
$$ f(\bm{x}) = 2x_0^2 + x_0 x_1 + x_1^2 $$
この関数は$(x_1, x_2)=(0, 0)$で最小値0をとる。また、勾配ベクトルは次式となる。
$$ \nabla f(\bm{x}) = \begin{bmatrix} 4x_0 + x_1 \\ x_0 + 2x_1 \end{bmatrix} $$
評価関数と勾配ベクトルを返す関数を以下のように定義する。
|
|
評価関数のプロットを示す。
|
|
準ニュートン法
準ニュートン法のアルゴリズムを以下に示す。
解の初期値を$(3, 3)$, 反復回数を10回とした。
|
|
実行結果
解の推移を以下に示す。最適解$(0, 0)$に収束していることが分かる。
|
|
また、近似行列B
の反復1, 5, 10回目の値はそれぞれ以下の通り。
1回目
|
|
5回目
|
|
10回目
|
|
実際に評価関数のヘッセ行列を計算すると、以下のようになる。
$$ \nabla^2 f(\bm{x}) = \begin{bmatrix} 4 & 1 \\ 1 & 2 \end{bmatrix} $$
反復回数が増えるにつれて、実際のヘッセ行列の値に近づいている。
参考
準ニュートン法の詳細なアルゴリスムについては、以下の書籍を参考とした。