数値最適化の反復法であるBFGSメソッドは、その研究者にちなんで名付けられました: Bロイデン、 Fレッチャー、 Gオールドファーブ、 Sハノ。 いわゆる準ニュートン法のクラスに属します。 ニュートン法とは対照的に、準ニュートン法はヘッセ関数を直接計算しません。 二次偏導関数を見つける必要はありません。 代わりに、ヘッセ行列はこれまでに実行された手順に基づいて近似的に計算されます。
メソッドにはいくつかの変更があります。
L-BFGS (メモリ使用量の制限)-多数の未知の場合に使用されます。
L-BFGS-Bは、多次元キューブでのメモリ使用量が制限された変更です。
この方法は効果的で安定しているため、最適化機能でよく使用されます。 たとえば、Python言語の一般的なライブラリであるSciPyでは、最適化機能はデフォルトでBFGS、L-BFGS-Bを使用します。
アルゴリズム
何らかの機能を与えましょう f(x、y) そして最適化問題を解きます: minf(x、y) 。
一般的な場合の場所 f(x、y) は、連続的な二次導関数を持つ非凸関数です。
ステップ1
開始点を初期化する x0 ;
検索の精度を設定します ε > 0;
初期近似を決定します H0=B−10 どこで B−10 -逆ヘッセ関数;
初期近似の選択方法 H0 ?
残念ながら、すべての場合にうまく機能する一般的な公式はありません。 初期近似として、初期点で計算された関数のヘッセ行列を取ることができます x0 。 それ以外の場合、適切に調整された非縮退行列を使用できますが、実際には、多くの場合、単一の行列が使用されます。
ステップ番号2
検索する方向のポイントを見つけると、次のように決定されます。
pk=−Hk∗ nablafk
ステップ番号3
計算する xk+1 再帰関係を通じて:
xk+1=xk+αk∗pk
係数 αk 線形検索(行検索)を使用して見つける αk ウルフの条件を満たす :
f(xk+αk∗pk) leqf(xk)+c1∗αk∗ nablafTk∗pk
nablaf(xk+αk∗pk)T∗pk geqc2∗ nablafTk∗pk
定数 s1 そして s2 次のように選択します。 0 leqc1 leqc2 leq1 。 ほとんどの実装では: c1=0.0001 そして s2=0.9 。
実際、これを見つけます αk 関数の値 f(xk+αk∗pk) 最低限。
ステップ4
ベクトルを定義します。
sk=xk+1−xk
yk= nablafk+1− nablafk
sk -反復のアルゴリズムのステップ、 yk -反復で勾配を変更します。
ステップ番号5
次の式に従ってヘッセ関数を更新します。
Hk+1=(I−ρk∗sk∗yTk)Hk(I−ρk∗yk∗sTk)+ρ∗sk∗sTk
どこで ρk
ρk= frac1yTksk
I 単位行列です。
発言
式を見る yk∗sTk 2つのベクトルの外積です 。
2つのベクトルを定義します U そして V その外積は行列積と同等です UVT 。 たとえば、平面内のベクトルの場合:
UVT= beginpmatrixU1U2 endpmatrix beginpmatrixV1&V2 endpmatrix= beginpmatrixU1V1&U1V2U2V1&U2V2 endpmatrix
ステップ6
このアルゴリズムは、不等式が真になるまで実行され続けます。 | nablafk|>ε 。
アルゴリズムの概略
例
次の関数の極値を見つけます。 f(x、y)=x2−xy+y2+9x−6y+20
出発点として、 x0=(1、1) ;
必要な精度 ε=0.001 ;
関数の勾配を見つける f(x、y) :
nablaf= beginpmatrix2x−y+9−x+2y−6 endpmatrix
反復番号0 :
x0=(1、1)
ポイントで勾配を見つける x0 :
nablaf(x0)= beginpmatrix10−5 endpmatrix
検索の終了を確認します。
| nablaf(x0)|= sqrt102+(−5)2=11.18
| nablaf(x0)|=11.18>0.001
不等式は成り立たないため、反復プロセスを継続します。
検索する方向にポイントを見つけます。
p0=−H0∗ nablaf(x0)=− beginpmatrix1&00&1 endpmatrix beginpmatrix10−5 endpmatrix= beginpmatrix−105 endpmatrix
どこで H0=I 単位行列です。
これを探しています α0 geq 0から f(x0+α0∗p0)=min(f(x0+α0∗p0))
分析的に、問題は1つの変数の関数の極値を見つけることで軽減できます。
$$表示$$ x_0 +α_0* p_0 =(1、1)+α_0(-10、5)=(1-10α_0、1 +5α_0)$$表示$$
それから
$インライン$ f(α_0)=(1-10α_0)^ 2-(1-10α_0)(1 +5α_0)+(1 +5α_0)^ 2 + 9(1-10α_0)-6(1 +5α_0)+ 20 $インライン$
式を単純化すると、導関数が見つかります。
frac partialf partialx=350α0−125=0\右矢印α0=0.357
次のポイントを見つける x1 :
x1=x0+α0∗p0=(−2.571、2.786)
s0=x1−x0=(−2.571、2.786)−(1、1)=(−3.571、1.786)
tの勾配の値を計算します。 x1 :
nablaf(x1)= beginpmatrix1.0712.143 endpmatrix
y0= nablaf(x1)− nablaf(x0)=(1.071、2.143)−(10、−5)=(−8.929、7.143)
ヘッセ近似を求めます。
H1= beginpmatrix0.694および0.3670.367および0.709 endpmatrix
反復1:
x1=(−2.571、2.786)
nablaf(x1)= beginpmatrix1.0712.143 endpmatrix
検索の終了を確認します。
| nablaf(x1)|=2.396>0.001
不等式は成り立たないため、反復プロセスを続けます。
H1= beginpmatrix0.694および0.3670.367および0.709 endpmatrix
p1=−H1 nablaf(x1)=− beginpmatrix0.694&0.3670.367&0.709 endpmatrix beginpmatrix1.0712.143 endpmatrix=− beginpmatrix1.5311.913 endpmatrix
見つける α1 > 0:
$インライン$ f(α_1)=-2.296α_1+(-1.913α_1+ 2.786)^ 2-(-1.913α_1+ 2.786)(-1.531α_1-2.571)+(-1.531α_1-2.571)^ 2-19.86 $ inline $
frac partialf partialα1=6.15α1−5.74=0 Rightarrowα1=0.933
次に:
x2=(−3.571、0.786)
s1=x2−x1=(−4、1)−(−2.571、2.786)=(−1.429、−1.786)
ポイントで勾配の値を計算する x2 :
nablaf(x2)= beginpmatrix00 endpmatrix
g1= nablaf(x2)− nablaf(x1)=(0、0)−(1.071、2.143)=(−1.071、−2.143)
H2= beginpmatrix0.667および0.3330.333および0.667 endpmatrix
反復2 :
x2=(−4、1)
検索の終了を確認します。
| nablaf(x2)|=0<0.001
不等式が満たされるため、検索は終了します。 関数の極値を分析的に見つけます;それは x2 。
メソッドの詳細
各反復はコストをかけて行うことができます。 O(n2) (さらに、関数の計算と勾配の推定のコスト)。 ここではない O(n3) 線形システムの解法や複雑な数学演算などの操作。 このアルゴリズムは安定しており、超線形収束を備えており、ほとんどの実用的な問題には十分です。 ニュートンの手法がはるかに高速に(2次的に)収束しても、線形システムを解く必要があるため、各反復のコストは高くなります。 アルゴリズムの否定できない利点は、もちろん、二次導関数を計算する必要がないことです。
この方法が実際にうまく機能することは一般に受け入れられていますが、非凸平滑関数の場合のアルゴリズムの収束については、理論的にはほとんど知られていません。
BFGS式には自己修正プロパティがあります。 行列 H 関数の曲率を誤って推定し、この不適切な推定によりアルゴリズムの速度が低下した場合、ヘッセ行列の近似により、数ステップで状況を修正しようとします。 アルゴリズムの自己修正プロパティは、対応する線形検索が実装されている場合にのみ機能します(Wolfe条件が満たされている)。
Pythonの実装例
アルゴリズムは、numpyおよびscipyライブラリを使用して実装されます。 線形検索は、scipy.optimizeモジュールのline_search()関数を使用して実装されました。 この例では、反復回数に制限が課されています。
''' Pure Python/Numpy implementation of the BFGS algorithm. Reference: https://en.wikipedia.org/wiki/Broyden%E2%80%93Fletcher%E2%80%93Goldfarb%E2%80%93Shanno_algorithm ''' #!/usr/bin/python # -*- coding: utf-8 -*- import numpy as np import numpy.linalg as ln import scipy as sp import scipy.optimize # Objective function def f(x): return x[0]**2 - x[0]*x[1] + x[1]**2 + 9*x[0] - 6*x[1] + 20 # Derivative def f1(x): return np.array([2 * x[0] - x[1] + 9, -x[0] + 2*x[1] - 6]) def bfgs_method(f, fprime, x0, maxiter=None, epsi=10e-3): """ Minimize a function func using the BFGS algorithm. Parameters ---------- func : f(x) Function to minimise. x0 : ndarray Initial guess. fprime : fprime(x) The gradient of `func`. """ if maxiter is None: maxiter = len(x0) * 200 # initial values k = 0 gfk = fprime(x0) N = len(x0) # Set the Identity matrix I. I = np.eye(N, dtype=int) Hk = I xk = x0 while ln.norm(gfk) > epsi and k < maxiter: # pk - direction of search pk = -np.dot(Hk, gfk) # Line search constants for the Wolfe conditions. # Repeating the line search # line_search returns not only alpha # but only this value is interesting for us line_search = sp.optimize.line_search(f, f1, xk, pk) alpha_k = line_search[0] xkp1 = xk + alpha_k * pk sk = xkp1 - xk xk = xkp1 gfkp1 = fprime(xkp1) yk = gfkp1 - gfk gfk = gfkp1 k += 1 ro = 1.0 / (np.dot(yk, sk)) A1 = I - ro * sk[:, np.newaxis] * yk[np.newaxis, :] A2 = I - ro * yk[:, np.newaxis] * sk[np.newaxis, :] Hk = np.dot(A1, np.dot(Hk, A2)) + (ro * sk[:, np.newaxis] * sk[np.newaxis, :]) return (xk, k) result, k = bfgs_method(f, f1, np.array([1, 1])) print('Result of BFGS method:') print('Final Result (best point): %s' % (result)) print('Iteration Count: %s' % (k))
私の記事に関心をお寄せいただきありがとうございます。 彼女があなたにとって有益であり、あなたが多くを学んだことを願っています。
FUNNYDMANはあなたと一緒でした。 みなさんさようなら!