PRMLの第5章のニューラルネットワークの「勾配降下最適化」で「共役勾配法」という 方式がでてきたので、学習がてらsageを使って試してみます。
朱鷺の杜Wiki の説明とプログラムの変数を合わせると、以下のような2次形式の関数を考える $$ f(x) = \frac{1}{2} x^T A X - b^T x $$ この時、極値に達するには、勾配▽fからある程度接線方向tにずれた共役勾配d 方向に進まなくてはならない。(収束がほぼ直角に折れながら進んでいることに注意)
従って、 $$ d_n = - \nabla f(x_n) + \beta_n d_{n-1} $$ と書けます(一つ前の$d_{n-1}$が接線方向tであることに注意)。$\beta_n$は $$ \beta_n = \frac{(\nabla f(x_n))^T \nabla f(x_n)}{(\nabla f(x_{n-1}))^T \nabla f(x_{n-1})} $$ となり、dの初期値は$d_0 = - \nabla f(x_0)$から始めます。
$x$は刻み値$\alpha$、 $$ \alpha_n = - \frac{d_n^T \nabla f(x_n)}{d_n^T A d_n} $$ を使って次式で更新します。 $$ x_{n+1} = x_n + \alpha_n d_n $$
|
syou6162さんの最適化理論][R]共役勾配法を実装してみた の例題をSageを使って試してみます。
数式処理システムSageの特徴を活かすため、関数の引数をベクトルとし、var関数でベクトルの要素を宣言し、 ベクトルvにセットします。
つぎに関数fを以下のように定義します。 $$ f(x) = \frac{3}{2} x_1^2 + x_1 x_2 + x_2^2 - 6 x_1 - 7 x_2 $$
|
|
▽fの計算は、ちょっとトリックを使います。あらかじめ関数fの 各変数での偏微分をdfsに保持しておき、その結果に引数のベクトル vxの値を代入した結果を返しています。
|
ヘッセ行列もSageの数式機能を使えば、簡単にもとめることができます。
[3 1] [1 2] [3 1] [1 2] |
|
共役勾配法の反復処理は、至って単純です。条件を満たすまで与えられた式でxと共役勾配を 更新するだけです。
x= (1, 3) k= 2 x= (1, 3) k= 2 |
求まった解x= (1, 3)をSageの最適化機能で求めた結果と比較します。当然同じ結果になります。
Optimization terminated successfully. Current function value: -13.500000 Iterations: 2 Function evaluations: 5 Gradient evaluations: 5 (1.0, 3.0) Optimization terminated successfully. Current function value: -13.500000 Iterations: 2 Function evaluations: 5 Gradient evaluations: 5 (1.0, 3.0) |
Sageの強みは簡単に結果をグラフ化できることです。
|
|
共役勾配法での解の収束の様子をコンターズで示します。 朱鷺の杜Wiki の通り、2回の計算で収束しているのが分かります。
|
|