面白いデータを探して

適当に書く。間違えていたら教えてください。

数値微分について

数値微分について調べてみたのでメモ代わり。

はじめに

機械学習をしているとパラメータの更新に微分が現れる。

たとえば、SGD(Stochastic Gradient Descent : 確率的勾配降下法)では


 \displaystyle \theta \leftarrow \theta - \alpha \frac{\partial L}{\partial \theta}

となる。ただし、 Lは損失関数、 \thetaは更新したいパラメータ、 \alphaは学習率。

したがって、あるパラメータ \thetaの現在の値に対する偏微分を計算しなければならないが、コンピュータ上でこれをどのように実装したら良いかについて。

微分の定義について

ある関数 f(x)があって、 f(x)区間 (-\infty, \infty)微分可能であるとする。このとき、関数 f(x) x=aにおける導関数 f'(a)は以下で定義される。


 \displaystyle f'(a) = \lim_{h \rightarrow 0} \frac{f(a + h)-f(a)}{h}\ \ \cdots\cdots(1)

数値微分の気持ち

ここで、(1)の右辺に注目すると、この右辺では hを0に近づけている。なので、 hを0に近い値として右辺を計算すれば近似値が求まる。

たとえば、


 \displaystyle f'(a) \sim \frac{f(a + 0.00001) - f(a)}{0.00001}

一般には


 \displaystyle f'(a) \sim \frac{f(a + h) - f(a)}{h}

やってみる

 f(x)=\sin(x)

 f(x)=\sin (x)について試してみる。 x \in X = \{ -3.14, -3.13, \cdots\cdots, 3.13, 3.14 \} として計算。 hを0.1、0.01、0.001としたもの、そして正しい f'(x)の4つをグラフ上にプロットしてみる。そして、それぞれについて誤差がどのくらいになるか調べる。誤差は絶対誤差の平均を以下で計算した。


 \displaystyle \frac{1}{|X|}\sum_{x\in X}\left|f'(x) - \frac{f(x+h)-f(x)}{h}\right|

f:id:netres:20190724162601p:plain
重なってしまって見にくいが、 hを0.01、0.001としたものはほぼ正しい f'(x)と重なっており、おおよそ正しい値が計算できていることがわかる。

 h 誤差
0.1 0.0317892503788
0.01 0.00317963692601
0.001 0.000317964178614


 hの値を0.1倍するごとに、誤差も0.1倍されるような感じ。

 f(x)=\log (x)

 f(x)=\log (x)についても試してみる。 x \in X = \{ 0.01, 0.02, \cdots\cdots, 2.00 \} について同様にやってみる。

f:id:netres:20190724171535p:plain
 xが0に近いところで誤差が結構大きい。 \log(x)微分 \displaystyle \frac{1}{x}であるが、 xが0に近づくと発散するので、敏感になるのだろうと考えられる。

 h 誤差
0.1 1.03668486616
0.01 0.288800794761
0.001 0.0393169186566


上と同様の理由で、誤差も大きくなる。

両側近似の気持ち


 \displaystyle f'(a) = \lim_{h \rightarrow 0} \frac{f(a + h)-f(a)}{h}

であったが、 hは正の方から0に近づけるのと、負の方から0に近づける場合が考えられる。上の例である

 \displaystyle f'(a) \sim \frac{f(a + 0.00001) - f(a)}{0.00001}

では正の方から近づけることを考えているが、微分可能であるということは負の方から0に近づけても近似値は取れるはずであるから、

 \displaystyle f'(a) \sim \frac{f(a - 0.00001) - f(a)}{-0.00001}

としても良いはずである。

なので、両方計算して、その平均を f'(a)としてみる。


 \begin{eqnarray*} f'(a) &\sim& \frac{1}{2} \left\{\frac{f(a + 0.00001) - f(a)}{0.00001} + \frac{f(a - 0.00001) - f(a)}{-0.00001}\right\} \\ &=& \frac{1}{2}\left\{\frac{f(a+0.00001)-f(a-0.00001)}{0.00001}\right\} \end{eqnarray*}

一般には


 \displaystyle f'(a)\sim \frac{f(a+h) - f(a-h)}{2h}

試してみる

 f(x) = \sin (x)についてどのくらい誤差が変化するか試してみる。設定は上と同じ。

 h 正の側から 負の側から 両側
0.1 0.0361962278046 0.0361962278046 0.000907100835736
0.01 0.00355426634458 0.00355426634458 9.07549967163e-06
0.001 0.000354746370367 0.000354746370367 9.07554592842e-08


両側から誤差を取るとだいぶ小さくなっていることがわかる。

まとめ

数値微分についていろいろ比較してみました。

Appendix : 両側微分すると誤差が小さくなることの証明

 f(x)が十分な回数だけ微分可能であるとすると、テイラー展開を用いると示せる。


 \displaystyle f(x+h) = f(x) + hf'(x) + \frac{h^2}{2}f''(x) + \frac{h^3}{3!}f'(x) + \cdots\cdots
 \displaystyle f(x-h) = f(x) - hf'(x) + \frac{h^2}{2}f''(x) - \frac{h^3}{3!}f'(x) + \cdots\cdots

正の側からの近似は
 \begin{eqnarray*} f'(a) &~& \frac{f(a + h) - f(a)}{h} \\ &=& f'(a) + \frac{h}{2}f''(a) + \frac{h^2}{3!}f'(a) + \cdots\cdots \\ &=& f'(a) + \mathcal{O}(h) \end{eqnarray*}

負の側からの近似は
 \begin{eqnarray*} f'(a) &~& \frac{f(a - h) - f(a)}{-h} \\ &=& f'(a) - \frac{h}{2}f''(a) + \frac{h^2}{3!}f'(a) - \cdots\cdots \\ &=& f'(a) + \mathcal{O}(h) \end{eqnarray*}

両側近似では
 \begin{eqnarray*} f'(a) &~& \frac{f(a + h) - f(a-h)}{2h} \\ &=& f'(a) + \frac{h}{3!}f'''(a) + \cdots\cdots \\ &=& f'(a) + \mathcal{O}(h^2) \end{eqnarray*}

以上より、両側近似が最も誤差のオーダーが低くなる。