勾配法あたりでやたらと見る数値微分法について調査し、まとめてみました。
今回、理論的なことは以下の書籍を参照し、図とプログラムは1から自作したものであり、特にプログラムは筆者がその場で簡易的に考え実装したものです。変数名などおかしい点がありますがご容赦ください。
数値微分法とは
勾配法においてはある重みにおいて、誤差関数をに関して偏微分したものの符号を入れ変えたものの方向に重みを更新します。この偏微分という動作をしなくても近似を使うことによって重みの更新をしちゃおう!というのが数値微分法の目的です。
まず、微分の定義を思い出します。
これが見慣れた形ですが今回は文字を変えて
とします。
余談ですが、式だけだとわかりづらいので僕が誰かに微分の定義を説明する時は上みたいな図を描いてこのεを0にもってくとその点での接線になるでしょ??って言います。
まず、数値微分法のうち、2点近似を紹介します。図は↑と同様で、式は
です。
数値微分法では極限などを使わず、手動で限りなく小さいεを設定することで勾配を近似します。例えばεを0.001と設定し、、とすると、
微分法:
数値微分法(2点近似):となり、誤差は約0.01ほどになります。
では、より誤差を減らす方法はないの?と思ったそこの奥様!あります。三点近似(中心差分)という手法です。図は先ほどと異なります。
そして式は
です。
試しに先ほどの2点近似と同様の条件で計算してみると
数値微分法(3点近似):となり、誤差が0.000001にまで減りました。
Pythonで観測
式自体は単純なものなので書く必要もないと思いますが、通常の微分したものとの差をグラフに描画するプログラムを書きます。
import matplotlib.pyplot as plt
%matplotlib inline
Ew = lambda w: w**3
Gw = lambda w: 3*w**2
e = 0.001
w = [-10000,-100,0,2,16,64,100,1000,10000]
_two = []
_three = []
def normal(w):
E_dashn = Gw(w)
return E_dashn
def three_point(w,e):
E_dashth = (Ew(w+e)-Ew(w-e)) / (2*e)
return E_dashth
def two_point(w,e):
E_dashtw = (Ew(w+e)-Ew(w)) / e
return E_dashtw
for i in range(len(w)):
_two.append(two_point(w[i],e)-normal(w[i]))
_three.append(three_point(w[i],e)-normal(w[i]))
plt.plot(w,_two,label='2point')
plt.plot(w,_three,label="3point")
plt.show()
プログラムは単純なものです。式Ewとそれを微分した式Gwを用意し、wを変化させた時の2点近似と3点近似と通常微分との値の差を取っています。
結果
グラフを観ると、2点近似は単調増加しており、3点近似は変化していません。これは今回のであることと、それぞれの式を観れば自明です。そして2点近似と3点近似の優劣は関数が変わっても変化しないでしょう。よって計算量が増加するというデメリットがありますが、3点近似を使う方がより誤差を減らすことができます。
参考文献
おわり。
もしよければ↓ぽちっと↓お願いします。