共役勾配法
目次
共役勾配法の概要
経緯と概要
共役勾配法(conjugate gradeint method)はHestenesとStiefel1によって提案された連立一次方程式の数値解法で,CG法とも呼ばれる.発表当初から大々的に報道されたようで,“数値計算法の一解法が, これほど大々的に報道されたことは, 前にも後にも例がない"との記述も2.1980年代にはKrylov部分空間法として再定式化されたことでも有名.ちなみにKrylov部分空間法は20世紀のトップ10アルゴリズムの1つである.この記事では,共役勾配法はどこから来たのか,何がすごいのか,そして,Krylov部分空間法とは何者か簡単に説明する.実験に使ったJuliaプログラムはこちら.
共役勾配法を利用するメリット
共役勾配法はなぜこれほどまで注目されたのだろうか.この解法の特に優れた点を以下に挙げてみよう.
- 原理的には ,有限回の反復で厳密解に収束する
- 行列の全成分を知らなくても, 行列-ベクトル積が分かれば アルゴリズム自体は動く
- fill inを回避できる(=行列の疎性が壊れない)
1点目に関して補足すると,理論上は$n\times n$の係数行列に対して$n$回の反復で収束するが,実際の計算では丸め誤差の影響で,収束により多くの反復を要する ことがある.2点目に関しては,極論,係数行列の中身が分からなくても良い.とにかくベクトル行列式を計算する関数さえ定義できれば良いのだ.3点目に関して,fill inとは,係数行列の零成分が反復の途中で非零になる現象を指す.非零になった分メモリを確保する必要があり,余計にコストがかかるため,fill inは嬉しくない現象である.まあとにかく,共役勾配法を使わない手はない!(Juliaのデフォルトのソルバーは優秀なので自分でコードを組むことは少ないかもしれない.なお,共役勾配法を含むKrylob部分空間法を基にした数値解法を実装したパッケージは充実している模様.)
共役勾配法のアルゴリズム
詳細に入る前に,共役勾配法のアルゴリズムを示しておこう.
共役勾配法とは,$n$次正方行列$A$,$n$次元ベクトル$b$に対して,連立一次方程式$Ax=b$の近似解列$\left\{ x_n \right\}_{n=0}^{\infty}$を次のように生成する方法を指す.
Initialize $x_0$, and set $r_0=b-Ax_0$ and $p_0=r_0$.
for $k=0, 1, \dots$ do
Update $\alpha_k = \frac{r_{k}^\top p_k}{p_k^{\top} Ap_k}$.
Update $x_{k+1} = x_k + \alpha_k p_k$.
Update $r_{k+1} = b - Ax_{k+1}$.
Update $\beta_k = -\frac{r_{k+1}^\top Ap_k}{p_k^{\top} Ap_k}$.
Update $p_{k+1} = r_{k+1} + \beta_k p_k$.
end
2つのストーリー
この記事では,数値解析の書籍3456を参考に,共役勾配法を2通りに説明する.一つ目は最適化問題から出発してアルゴリズムを構成していくストーリー,二つ目はKrylov部分空間法の観点から共役勾配法を俯瞰するストーリーである.両者は仮定がやや異なり,後者の方がより一般の場合に適用できる.
共役勾配法を構成する
解の特徴づけ
本節では,係数行列$A$が正定値対称行列であるとする.このとき,連立一次方程式$Ax=b$には解が一意に存在することに注意して,次のような関数を考えよう: \begin{equation} \Phi (\xi) = \frac{1}{2}(\xi-x)^{\top}A(\xi-x). \end{equation} この関数は解$x$で唯一の最小値をとることに着目し,ここでは関数の最小化アルゴリズムから共役勾配法を構成 してみよう.
最小化アルゴリズムといえば,最急降下法だろう.現在の解の候補$x_k$における目的関数の勾配を計算すると, \begin{equation} \nabla \Phi (x_k) = Ax_k - b = -r_k \end{equation} である.ただし,$r_k=b-Ax_k$は残差と呼ばれる.以上から,次の更新式が候補となる: \begin{equation} x_{k+1} = x_k + \alpha_k r_k. \end{equation} 実は,共役勾配法はこれを修正したものである.ということで,修正の方針について述べよう.共役勾配法における更新方向ベクトル$\{p_0, p_1, \dots \}$は,最急降下法における更新方向ベクトル$\{r_0, r_1, \dots\}$を,内積$(x,y)\mapsto x^\top Ay$に関して直交化したものである.
直交化
残差ベクトルを直交化して更新方向のベクトルを構成しよう.本節の詳しい証明は専門書を参照されたい6.
Gram-Schmidtの正規直交化により,$p_0=r_0$および \begin{equation} p_{k+1} = r_{k+1} - \sum_{j=0}^{k}\frac{r_{k+1}^\top Ap_j}{p_j^{\top} Ap_j}p_j, \quad (k=0, 1, \dots) \end{equation} と定義する.このとき,右辺第2項の和の大部分が消え \begin{equation} p_{k+1} = r_{k+1} + \beta_k p_j, \quad \beta_k = -\frac{r_{k+1}^\top Ap_k}{p_k^{\top} Ap_k} \end{equation} となることを示すことができる.こうして得られる更新方向ベクトルを用いて,解を \begin{equation} x_{k+1} = x_k + \alpha_k p_k \end{equation} と更新すれば,共役勾配法における解の更新式が得られる.最後に,ステップサイズ$\alpha_k$を定める必要がある.これは \begin{equation} \alpha_k = \underset{\alpha > 0}{\mathrm{argmin}}\ \Phi (x_k + \alpha p_k) \end{equation} とするのが自然だろう.これを解くと \begin{equation} \alpha_k = \frac{r_{k}^\top p_k}{p_k^{\top} Ap_k} \end{equation} が得られる.以上で,共役勾配法のアルゴリズムが導出できた.
さて,こうして得られたアルゴリズムには次のようなメリットがある.残差ベクトル同士は標準内積に関して直交する.したがって,最初の$n$反復で得られたベクトル同士は直交系となり,それ以降の残差ベクトルはゼロベクトルとなる.すなわち,$n$反復で厳密解に到達する .しかし,実際には丸め誤差などの影響でより多くの反復を要することが多い.
共役勾配法を俯瞰する
本節では,係数行列$A$が対称行列であるとする.
Krylov部分空間法
非零ベクトル$v\in\mathbb{R}^n$,行列$A\in\mathbb{R}^{n\times n}$,自然数$m(\leq n)$に対して,$v, Av, A^2v, \dots, A^{m-1}v$が一次独立であるとき,集合 \begin{equation} K_m(A, v) = \mathrm{span} \left\{v, Av, A^2v, \dots, A^{m-1}v \right\} \end{equation} を行列$A$とベクトル$v$に関する$m$次のKrylov部分空間という.
Krylov部分空間を次のように用いた解法を一般にKrylov部分空間法という.
連立一次方程式$Ax=b$の初期近似解$x_0$と初期残差$r_0=b-Ax_0$に対して, \begin{equation} x_k = x_0 + z_k , \quad z_k\in K_k(A, r_0) \end{equation} のように近似解列を構成する方法を,Krylov部分空間法という.
Krylov部分空間は次数が上がるごとに大きくなる.すなわち,$K_k(A, r_0) \subset K_{k+1}(A, r_0)$が成り立つため,反復するごとに近似解の範囲が広がる.
共役勾配法の位置づけ
共役勾配法は,Krylov部分空間に対して \begin{equation} r_k \perp K_k(A, r_0), \quad r_k = b - Ax_k \end{equation} が成り立つような特別な場合である.この条件を満たす残差$r_k$は,Lanczos過程5により作り出すことができる.細かい証明は数値解析の教科書45を参照されたい.
数値実験
本節では,共役勾配法の数値実験例を2つほど紹介する.
例1:密行列の場合
係数行列$A\in\mathbb{R}^{n\times n}$を,正規乱数を成分とする正方行列$M$を用いて$A=M^\top M$と定義する.ただし,$n=2000$とする.下図に,共役勾配法の反復中における$\frac{\|r_k\|}{\|b\|}$の変化を示した.

実行時間は$2.74$,真の解との相対誤差は$2.50\times 10^{-3}$であった.比較として実装したLU分解では,実行時間は$18.86$,真の解との相対誤差は$1.75\times 10^{-10}$であった.
例2:疎行列の場合
係数行列$A\in\mathbb{n\times n}$を次のような疎行列とする: \begin{equation} A = \begin{bmatrix} -1 & 2 & 1 & 0 & \cdots & 0 \\ 2 & -1 & 2 & 1 & \cdots & 0 \\ 1 & 2 & -1 & 2 & \cdots & 0 \\ 0 & 1 & 2 & -1 & \cdots & 0\\ \vdots & \vdots & \vdots & \vdots & \vdots & \vdots\\ 0 & 0 & 0 & 1 & 2 & -1 \end{bmatrix}. \end{equation} ただし,$n=2000$とする.下図に,共役勾配法の反復中における$\frac{\|r_k\|}{\|b\|}$の変化を示した.

実行時間は$0.16$,真の解との相対誤差は$1.00 \times 10^{-8}$であった.比較として実装したLU分解では,実行時間は$19.07$,真の解との相対誤差は$4.31\times 10^{-15}$であった.共役勾配法が疎行列向きであることが分かるだろう.