自動微分

自動微分（じどうびぶん、アルゴリズム的微分とも）とは、プログラムで定義された関数を解析し、偏導関数の値を計算するプログラムを導出する技術である。自動微分は複雑なプログラムであっても加減乗除などの基本的な算術演算や基本的な関数（指数関数・対数関数・三角関数など）のような基本的な演算の組み合わせで構成されていることを利用し、これらの演算に対して連鎖律を繰り返し適用することによって実現される。自動微分を用いることで偏導関数値を少ない計算量で自動的に求めることができる。 自動微分は 数式微分 (Symbolic differentiation, 原関数を表す数式から数式処理により導関数を導出する) 数値微分 (Numerical differentiation, 原関数の値から近似的に微分係数を算出する) のどちらとも異なる。 数式微分は効率が悪くなりやすく、プログラムで定義された関数から微分表現を導くのは困難であるという問題がある。一方、数値微分では離散化の際の丸め誤差や桁落ちによる精度の低下が問題である。さらに、どちらの手法も計算量や誤差の関係で高次の微分係数を求めることが難しい。また、勾配を用いた最適化で必要となる、多くの入力変数を持つ関数に対する偏微分値の計算を行うには速度が遅い。自動微分はこれらの古典的手法の問題を解決する。 英語では Automatic differentiation (あるいは単に AD) と呼ばれる。 自動微分の基本原理は連鎖律を用いた微分の分解である。たとえば、簡単な合成関数である y = g(h(x)) = g(w) に対して連鎖律を適用すると d y d x = d y d w d w d x {\displaystyle {\frac {dy}{dx}}={\frac {dy}{dw}}{\frac {dw}{dx}}} を得る。 自動微分は大きく2種類に分けられ、それぞれボトムアップ型自動微分（フォーワードモード、狭義の自動微分）とトップダウン型自動微分（リバースモード、高速自動微分）と呼ばれる。 ボトムアップ型自動微分では連鎖律を内側から外側に計算し（dw/dxを計算した後で dy/dw を計算する）、トップダウン型自動微分では外側から内側に計算する。 ボトムアップ型自動微分では最初に微分を行う入力変数を固定し、それぞれの部分式を再帰的に計算する。手計算においては連鎖律において内側の関数を繰り返し置き換えていくことに相当する。 ∂ y ∂ x = ∂ y ∂ w 1 ∂ w 1 ∂ x = ∂ y ∂ w 1 ( ∂ w 1 ∂ w 2 ∂ w 2 ∂ x ) = ∂ y ∂ w 1 ( ∂ w 1 ∂ w 2 ( ∂ w 2 ∂ w 3 ∂ w 3 ∂ x ) ) = ⋯ {\displaystyle {\frac {\partial y}{\partial x}}={\frac {\partial y}{\partial w_{1}}}{\frac {\partial w_{1}}{\partial x}}={\frac {\partial y}{\partial w_{1}}}\left({\frac {\partial w_{1}}{\partial w_{2}}}{\frac {\partial w_{2}}{\partial x}}\right)={\frac {\partial y}{\partial w_{1}}}\left({\frac {\partial w_{1}}{\partial w_{2}}}\left({\frac {\partial w_{2}}{\partial w_{3}}}{\frac {\partial w_{3}}{\partial x}}\right)\right)=\cdots } 多変数の場合はヤコビ行列の積として一般化できる。 トップダウン型自動微分と比較すると、ボトムアップ型自動微分は自然であり、微分に関する情報の流れが計算の順序と一致するため簡単に実行できる。それぞれの変数にその偏導関数値ẇ w ˙ = ∂ w ∂ x {\displaystyle {\dot {w}}={\frac {\partial w}{\partial x}}} の計算値を保存する領域を付け加えるだけで、変数値の計算と同時に偏導関数値を計算することができる。 例として次の関数を考える。 z = f ( x 1 , x 2 ) = x 1 x 2 + sin ⁡ x 1 = w 1 w 2 + sin ⁡ w 1 = w 3 + w 4 = w 5 {\displaystyle {\begin{aligned}z&=f(x_{1},x_{2})\\&=x_{1}x_{2}+\sin x_{1}\\&=w_{1}w_{2}+\sin w_{1}\\&=w_{3}+w_{4}\\&=w_{5}\end{aligned}}} 簡単のためそれぞれの部分式を wi としてラベル付けした。 どの入力変数で微分するかによってẇ1 や ẇ2の初期値が異なる。x1 に関する微分をそのつど計算する場合の初期値は、 w ˙ 1 = ∂ x 1 ∂ x 1 = 1 w ˙ 2 = ∂ x 2 ∂ x 1 = 0 {\displaystyle {\begin{aligned}{\dot {w}}_{1}={\frac {\partial x_{1}}{\partial x_{1}}}=1\\{\dot {w}}_{2}={\frac {\partial x_{2}}{\partial x_{1}}}=0\end{aligned}}} となる。初期値が決まったら下の表に示す連鎖律に従って各偏導関数値を順に計算していく。図2はこの処理を計算グラフとして表している。 Operations to compute value Operations to compute derivative w 1 = x 1 w ˙ 1 = 1  (seed) w 2 = x 2 w ˙ 2 = 0  (seed) w 3 = w 1 ⋅ w 2 w ˙ 3 = w 2 ⋅ w ˙ 1 + w 1 ⋅ w ˙ 2 w 4 = sin ⁡ w 1 w ˙ 4 = cos ⁡ w 1 ⋅ w ˙ 1 w 5 = w 3 + w 4 w ˙ 5 = w ˙ 3 + w ˙ 4 {\displaystyle {\begin{array}{l|l}{\text{Operations to compute value}}&{\text{Operations to compute derivative}}\\\hline w_{1}=x_{1}&{\dot {w}}_{1}=1{\text{ (seed)}}\\w_{2}=x_{2}&{\dot {w}}_{2}=0{\text{ (seed)}}\\w_{3}=w_{1}\cdot w_{2}&{\dot {w}}_{3}=w_{2}\cdot {\dot {w}}_{1}+w_{1}\cdot {\dot {w}}_{2}\\w_{4}=\sin w_{1}&{\dot {w}}_{4}=\cos w_{1}\cdot {\dot {w}}_{1}\\w_{5}=w_{3}+w_{4}&{\dot {w}}_{5}={\dot {w}}_{3}+{\dot {w}}_{4}\end{array}}} この関数に対する勾配を求めるためにはx1だけではなくx2に関する偏導関数値も求める必要がある。そのため、初期値を w ˙ 1 = 0 ; w ˙ 2 = 1 {\displaystyle {\dot {w}}_{1}=0;{\dot {w}}_{2}=1} とした同様の計算を追加で行わなければならない。 ボトムアップ型自動微分を1回行うのに必要な計算量は、元のプログラムの計算量に比例する。 勾配を求める場合に必要なボトムアップ型自動微分の実行回数は入力変数の個数と等しく、トップダウン型自動微分では出力変数の個数に等しい。そのため、微分する関数f : ℝn → ℝm が m ≫ n を満たす場合、ボトムアップ型自動微分はトップダウン型自動微分よりも効率的である。 トップダウン型自動微分では、はじめに微分される出力変数を固定して、それぞれの部分式に関する偏導関数値を再帰的に計算する。手計算においては部分式を連鎖律における外側の関数の微分で繰り返し置き換えていくことに相当する。 ∂ y ∂ x = ∂ y ∂ w 1 ∂ w 1 ∂ x = ( ∂ y ∂ w 2 ∂ w 2 ∂ w 1 ) ∂ w 1 ∂ x = ( ( ∂ y ∂ w 3 ∂ w 3 ∂ w 2 ) ∂ w 2 ∂ w 1 ) ∂ w 1 ∂ x = ⋯ {\displaystyle {\frac {\partial y}{\partial x}}={\frac {\partial y}{\partial w_{1}}}{\frac {\partial w_{1}}{\partial x}}=\left({\frac {\partial y}{\partial w_{2}}}{\frac {\partial w_{2}}{\partial w_{1}}}\right){\frac {\partial w_{1}}{\partial x}}=\left(\left({\frac {\partial y}{\partial w_{3}}}{\frac {\partial w_{3}}{\partial w_{2}}}\right){\frac {\partial w_{2}}{\partial w_{1}}}\right){\frac {\partial w_{1}}{\partial x}}=\cdots } トップダウン型自動微分において、求める値は随伴であり[訳語疑問点]、上線(w̄)で表す。これは選択された出力変数のwに関する微分 w ¯ = ∂ y ∂ w {\displaystyle {\bar {w}}={\frac {\partial y}{\partial w}}} である。 トップダウン型自動微分は連鎖律を外側から内側（図3の計算グラフでは上から下）にたどっていく。例示した関数は1変数関数なので、勾配を計算するには計算グラフを一度たどるだけでよい。これは2回計算グラフをたどる必要があったボトムアップ型自動微分の計算量の半分である。しかし、トップダウン型自動微分は中間変数wi を保存するための領域と、1964年に R.E. Wengert が発表した Wengert リスト（テープとも呼ばれる） というデータ構造に中間変数を保存するための命令が必要となるためメモリ使用量の点で不利であり、計算グラフが巨大になるとメモリ使用量が問題となる可能性がある。この問題は保存する中間変数を限定し、必要な中間変数を再計算することによって軽減される。 トップダウン型自動微分を用いて偏導関数値を計算するための演算は以下の通りである（関数値を求める時と順番が逆であることに注意） Operations to compute derivative w ¯ 5 = 1  (seed) w ¯ 4 = w ¯ 5 w ¯ 3 = w ¯ 5 w ¯ 2 = w ¯ 3 ⋅ w 1 w ¯ 1 = w ¯ 3 ⋅ w 2 + w ¯ 4 ⋅ cos ⁡ w 1 {\displaystyle {\begin{array}{l}{\text{Operations to compute derivative}}\\\hline {\bar {w}}_{5}=1{\text{ (seed)}}\\{\bar {w}}_{4}={\bar {w}}_{5}\\{\bar {w}}_{3}={\bar {w}}_{5}\\{\bar {w}}_{2}={\bar {w}}_{3}\cdot w_{1}\\{\bar {w}}_{1}={\bar {w}}_{3}\cdot w_{2}+{\bar {w}}_{4}\cdot \cos w_{1}\end{array}}} 微分する関数f : ℝn → ℝm が m ≪ nを満たすとき、トップダウン型自動微分はボトムアップ型自動微分よりも効率的である。 機械学習で用いられる多層パーセプトロンのバックプロパゲーション はトップダウン型自動微分の特殊なケースである。 フォワードモード自動微分は実数の代数に（元を）添加して新しい算術を導入することによって可能である。全ての数（通常の実数）に対して、その数における関数の微分を表現する追加の成分が足され、全ての算術演算がこの添加代数に拡張される。すなわち二重数の代数である。このアプローチはプログラミング空間上の演算子法（英語版）の理論（つまり双対空間のテンソル代数）によって一般化される（解析的プログラミング空間（英語版）を見よ)。 各数 x {\displaystyle x} を数 x + x ′ ε {\displaystyle x+x'\varepsilon } に置き換える。ここで x ′ {\displaystyle x'} は実数だが、 ε {\displaystyle \varepsilon } は ε 2 = 0 {\displaystyle \varepsilon ^{2}=0} を満たす抽象的数（英語版）である（無限小；滑らかな無限小解析も参照）。ちょうどこれだけを用いて通常の演算が得られる： ( x + x ′ ε ) + ( y + y ′ ε ) = x + y + ( x ′ + y ′ ) ε ( x + x ′ ε ) ⋅ ( y + y ′ ε ) = x y + x y ′ ε + y x ′ ε + x ′ y ′ ε 2 = x y + ( x y ′ + y x ′ ) ε {\displaystyle {\begin{aligned}(x+x'\varepsilon )+(y+y'\varepsilon )&=x+y+(x'+y')\varepsilon \\(x+x'\varepsilon )\cdot (y+y'\varepsilon )&=xy+xy'\varepsilon +yx'\varepsilon +x'y'\varepsilon ^{2}=xy+(xy'+yx')\varepsilon \end{aligned}}} 引き算と割り算についても同様である。 いまやこの拡張算術のもとで多項式を計算できる。もし P ( x ) = p 0 + p 1 x + p 2 x 2 + ⋯ + p n x n {\displaystyle P(x)=p_{0}+p_{1}x+p_{2}x^{2}+\cdots +p_{n}x^{n}} ならば、 P ( x + x ′ ε ) = p 0 + p 1 ( x + x ′ ε ) + ⋯ + p n ( x + x ′ ε ) n = p 0 + p 1 x + ⋯ + p n x n + p 1 x ′ ε + 2 p 2 x x ′ ε + ⋯ + n p n x n − 1 x ′ ε = P ( x ) + P ( 1 ) ( x ) x ′ ε {\displaystyle {\begin{aligned}P(x+x'\varepsilon )&=p_{0}+p_{1}(x+x'\varepsilon )+\cdots +p_{n}(x+x'\varepsilon )^{n}\\&=p_{0}+p_{1}x+\cdots +p_{n}x^{n}+p_{1}x'\varepsilon +2p_{2}xx'\varepsilon +\cdots +np_{n}x^{n-1}x'\varepsilon \\&=P(x)+P^{(1)}(x)x'\varepsilon \end{aligned}}} ここで P ( 1 ) {\displaystyle P^{(1)}} は P {\displaystyle P} の最初の引数に対する微分であり、 x ′ {\displaystyle x'} （種と呼ばれる）は任意に取れる。 上に述べたように、この新しい算術は、順序対（ ⟨ x , x ′ ⟩ {\displaystyle \langle x,x'\rangle } と書かれる元）と、最初の成分に対しては通常の算術を、第二の成分に対しては一階微分の算術を、それぞれ与えたものからなる。多項式に関する上の結果を解析関数に広げれば、新しい算術に対する、基本的な算術と幾つかの標準的な関数のリストが得られる： ⟨ u , u ′ ⟩ + ⟨ v , v ′ ⟩ = ⟨ u + v , u ′ + v ′ ⟩ ⟨ u , u ′ ⟩ − ⟨ v , v ′ ⟩ = ⟨ u − v , u ′ − v ′ ⟩ ⟨ u , u ′ ⟩ ∗ ⟨ v , v ′ ⟩ = ⟨ u v , u ′ v + u v ′ ⟩ ⟨ u , u ′ ⟩ / ⟨ v , v ′ ⟩ = ⟨ u v , u ′ v − u v ′ v 2 ⟩ ( v ≠ 0 ) sin ⁡ ⟨ u , u ′ ⟩ = ⟨ sin ⁡ ( u ) , u ′ cos ⁡ ( u ) ⟩ cos ⁡ ⟨ u , u ′ ⟩ = ⟨ cos ⁡ ( u ) , − u ′ sin ⁡ ( u ) ⟩ exp ⁡ ⟨ u , u ′ ⟩ = ⟨ exp ⁡ u , u ′ exp ⁡ u ⟩ log ⁡ ⟨ u , u ′ ⟩ = ⟨ log ⁡ ( u ) , u ′ / u ⟩ ( u > 0 ) ⟨ u , u ′ ⟩ k = ⟨ u k , k u k − 1 u ′ ⟩ ( u ≠ 0 ) | ⟨ u , u ′ ⟩ | = ⟨ | u | , u ′ sign u ⟩ ( u ≠ 0 ) {\displaystyle {\begin{aligned}\left\langle u,u'\right\rangle +\left\langle v,v'\right\rangle &=\left\langle u+v,u'+v'\right\rangle \\\left\langle u,u'\right\rangle -\left\langle v,v'\right\rangle &=\left\langle u-v,u'-v'\right\rangle \\\left\langle u,u'\right\rangle *\left\langle v,v'\right\rangle &=\left\langle uv,u'v+uv'\right\rangle \\\left\langle u,u'\right\rangle /\left\langle v,v'\right\rangle &=\left\langle {\frac {u}{v}},{\frac {u'v-uv'}{v^{2}}}\right\rangle \quad (v\neq 0)\\\sin \left\langle u,u'\right\rangle &=\left\langle \sin(u),u'\cos(u)\right\rangle \\\cos \left\langle u,u'\right\rangle &=\left\langle \cos(u),-u'\sin(u)\right\rangle \\\exp \left\langle u,u'\right\rangle &=\left\langle \exp u,u'\exp u\right\rangle \\\log \left\langle u,u'\right\rangle &=\left\langle \log(u),u'/u\right\rangle \quad (u>0)\\\left\langle u,u'\right\rangle ^{k}&=\left\langle u^{k},ku^{k-1}u'\right\rangle \quad (u\neq 0)\\\left|\left\langle u,u'\right\rangle \right|&=\left\langle \left|u\right|,u'{\mbox{sign}}u\right\rangle \quad (u\neq 0)\end{aligned}}} 一般に、プリミティヴの関数 g {\displaystyle g} に対して、 g ( ⟨ u , u ′ ⟩ , ⟨ v , v ′ ⟩ ) = ⟨ g ( u , v ) , g u ( u , v ) u ′ + g v ( u , v ) v ′ ⟩ {\displaystyle g(\langle u,u'\rangle ,\langle v,v'\rangle )=\langle g(u,v),g_{u}(u,v)u'+g_{v}(u,v)v'\rangle } ここで g u {\displaystyle g_{u}} と g v {\displaystyle g_{v}} はそれぞれ g {\displaystyle g} の最初と2番目の引数に対する微分である。 基本的な二項算術演算を（実数と二重数の）混在した引数に対して、つまり順序対 ⟨ u , u ′ ⟩ {\displaystyle \langle u,u'\rangle } と実数 c {\displaystyle c} に対して適用するとき、まずこの実数を ⟨ c , 0 ⟩ {\displaystyle \langle c,0\rangle } に引き上げる（lifting）。関数 f : R → R {\displaystyle f:\mathbb {R} \rightarrow \mathbb {R} } の x 0 {\displaystyle x_{0}} に於ける微分はいまや f ( ⟨ x 0 , 1 ⟩ ) {\displaystyle f(\langle x_{0},1\rangle )} に上の算術を使って計算することによって得られる。これは ⟨ f ( x 0 ) , f ′ ( x 0 ) ⟩ {\displaystyle \langle f(x_{0}),f'(x_{0})\rangle } を結果として与える。 多変数関数は、方向微分作用素を用いることで、一変数関数の場合と同様の効率と仕組みで取り扱える。つまり、 f : R n → R m {\displaystyle f:\mathbb {R} ^{n}\rightarrow \mathbb {R} ^{m}} の x ∈ R n {\displaystyle x\in \mathbb {R} ^{n}} における x ′ ∈ R n {\displaystyle x'\in \mathbb {R} ^{n}} 方向微分 y ′ = ∇ f ( x ) ⋅ x ′ {\displaystyle y'=\nabla f(x)\cdot x'} を計算したい場合、それは ( ⟨ y 1 , y 1 ′ ⟩ , … , ⟨ y m , y m ′ ⟩ ) = f ( ⟨ x 1 , x 1 ′ ⟩ , … , ⟨ x n , x n ′ ⟩ ) {\displaystyle (\langle y_{1},y'_{1}\rangle ,\ldots ,\langle y_{m},y'_{m}\rangle )=f(\langle x_{1},x'_{1}\rangle ,\ldots ,\langle x_{n},x'_{n}\rangle )} を上と同様の算術を使って計算すればよい。もし ∇ f {\displaystyle \nabla f} の全ての要素が望みならば、 n {\displaystyle n} 個の関数評価が要求される。ここで、多くの最適化アプリケーションでは、実際には方向微分があれば十分である。 上の算術は多変数関数の二階やもっと高階の微分の計算の為に一般化出来る。しかし、その算術規則は直ちに極めて複雑なものとなる：複雑性は最高次の微分の次数に対して二次関数的となる。その代わりに、途中で打ち切った（truncated）テイラー多項式の代数を使用できる。結果得られる算術（一般化された二重数の上で定義された）は、関数を新しいデータ型であるかのように使って、効率的に計算することを可能にする。ひとたび関数のテイラー多項式が分かれば、その導関数たちは容易に抽出できる。 厳密で一般的な定式化はテンソル級数展開（英語版）を通してプログラミング空間上の演算子法（英語版）を用いることにより達成される。 自動微分の実装方法には大きく分けて、ソースコードの変換とオペレータオーバーローディングによる方法の2つがある。 関数値を求める関数を記述した元のソースコードから、偏導関数値を計算する処理を含んだプログラムを自動的に生成する手法である。 ソースコード変換はあらゆるプログラミング言語で実装でき、コンパイル時の最適化を行いやすいが、自動微分ツールの作成は難しい。 この手法は演算子のオーバーロードがサポートされているプログラミング言語で記述されたソースコードに対してのみ適用可能である。元のソースコードの流れを大きく変更することなく実現できるが、基本データ型の変更などの小さな変更は必要である。 ボトムアップ型自動微分をオペレータオーバーロードで実現するのは容易である。トップダウン型自動微分についても可能であるが、現状のコンパイラではボトムアップ型自動微分と比べると最適化の面で不利である。 自動微分を実装したライブラリなどのソフトウェアが存在する。詳細は英語版を参照のこと。 ^ R.E. Wengert (1964年). “A simple automatic derivative evaluation program”. Comm. ACM 7: 463–464. doi:10.1145/355586.364791.  ^ Bartholomew-Biggs, Michael; Brown, Steven; Christianson, Bruce; Dixon, Laurence (2000年). “Automatic differentiation of algorithms”. Journal of Computational and Applied Mathematics 124 (1-2): 171-190. doi:10.1016/S0377-0427(00)00422-2. http://ac.els-cdn.com/S0377042700004222/1-s2.0-S0377042700004222-main.pdf?_tid=61070b3c-31f1-11e5-a550-00000aacb35f&acdnat=1437735029_c639352923bb07e65307eb75c420d42f.  久保田, 光一; 伊理, 正夫 (1998). アルゴリズムの自動微分と応用. 現代非線形科学シリーズ. 3. コロナ社. ISBN 978-4339026023.  (1993), 伊理 正夫, "高速自動微分法", 応用数理 3(1), 58-66, 19930315, http://ci.nii.ac.jp/naid/110007390406/, 日本応用数理学会. (1991), 伊理 正夫, 久保田,光一, "高速自動微分法(I)", 応用数理 1(1), 17-35, 19910315, 日本応用数理学会. Rall, Louis B. (1981). Automatic Differentiation: Techniques and Applications. Lecture Notes in Computer Science. 120. Springer. ISBN 3-540-10861-0.  Griewank, Andreas; Walther, Andrea (2008). Evaluating Derivatives: Principles and Techniques of Algorithmic Differentiation. Other Titles in Applied Mathematics. 105 (2nd ed.). SIAM. ISBN 978-0-89871-659-7. http://www.ec-securehost.com/SIAM/OT105.html.  Neidinger, Richard (2010年). “Introduction to Automatic Differentiation and MATLAB Object-Oriented Programming”. SIAM Review 52 (3): 545–563. doi:10.1137/080743627. http://academics.davidson.edu/math/neidinger/SIAMRev74362.pdf 2013年3月15日閲覧。.  www.autodiff.org - Community Portal for Automatic Differentiation 《高速微分法》 - ORWiki www.autodiff.org, An "entry site to everything you want to know about automatic differentiation" Automatic Differentiation of Parallel OpenMP Programs Automatic Differentiation, C++ Templates and Photogrammetry Automatic Differentiation, Operator Overloading Approach Compute analytic derivatives of any Fortran77, Fortran95, or C program through a web-based interface Automatic Differentiation of Fortran programs Description and example code for forward Automatic Differentiation in Scala Adjoint Algorithmic Differentiation: Calibration and Implicit Function Theorem [1], Exact First- and Second-Order Greeks by Algorithmic Differentiation [2], Adjoint Algorithmic Differentiation of a GPU Accelerated Application [3], Adjoint Methods in Computational Finance Software Tool Support for Algorithmic Differentiation