前回、Deep Learning勉強している中で誤差逆伝搬法について勉強しましたが、
ちょっと分かりにくかったので自分で手を動かして勉強してみることにしました!!
elsammit-beginnerblg.hatenablog.com
勉強には、こちらの本を利用しました。
ゼロから作るDeep Learning ?Pythonで学ぶディープラーニングの理論と実装 新品価格 |
■計算グラフ
実際に行列や数式に対して誤差逆伝搬法で最小値を算出してみる前に、
算出するために用いる計算グラフについてまとめておきます。
数式グラフとは、計算の過程をグラフによって表したものです。
ここでのグラフとは、データ構造としてのグラフであり、複数のノード + エッジによって表現します。
例えば、こちらの数式ですと、
計算グラフは、
で表せます。
■誤差逆伝搬法で最小値を導き出す
行列だとパラメータが多すぎて理解しづらい部分があるため、まずは
といった2次関数での誤差逆伝搬法について確認していきたいと思います。
まず計算グラフはこんな感じになります。
前回のブログの通り、誤差逆伝搬時の返り値は微分値となりますので、
こちらのような数式が適用されます。
こちらの数式を元に誤差逆伝搬により最小値を導くコードはこちらになります。
import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D class MulLayer: def __init__(self): self.x = 0.0 self.y = 0.0 self.dx = 0.0 self.dy = 0.0 def forward(self, x, y): self.x = x self.y = y out = x * y return out def backward(self, dout): dx = dout * self.y dy = dout * self.x self.dx = dx self.dy = dy return dx, dy class AddLayer: def __init__(self): pass def forward(self, x, y): out = x + y return out def backward(self ,dout): dx = dout * 1 dy = dout * 1 return dx,dy class Square: def __init__(self): self.x = None self.dx = None def forward(self,x): self.x = x out = x **2 return out def backward(self, dout): self.dx = 2 * dout * self.x return self.dx pltx = 8 plty = 1 Square1 = Square() Square2 = Square() Mul1 = MulLayer() Add = AddLayer() listx = [] listy = [] listz = [] katamuki = 1 for i in range(100): x0 = Square1.forward(pltx) x1 = Mul1.forward(x0, 1/20) y1 = Square2.forward(plty) z = Add.forward(x1, y1) listx.append(pltx) listy.append(plty) listz.append(z) print(pltx, plty, z) bx0,by1 = Add.backward(katamuki) bx1,by_b = Mul1.backward(bx0) bx2 = Square1.backward(bx1) by2 = Square2.backward(by1) pltx = pltx - 0.9*bx2 plty = plty - 0.9*by2 ListX, ListY = np.meshgrid(listx, listy) fig = plt.figure() plt.plot(listx, listy) plt.show()
こちらを実行すると、結果としてこちらの通り、
(x, y) = (0, 0)
に収束しているのがわかるかと思います。
■収束方法にAdaGradを用いる
今回の方法よりも収束させるにあたりより効率のよい式があります。
それは、AdaGradと呼ばれる手法です。
AdaGradについてはこちらを参考に下さい。
https://www.slideshare.net/nishio/ss-66840545
コードはこちらになります。
import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D class MulLayer: def __init__(self): self.x = 0.0 self.y = 0.0 self.dx = 0.0 self.dy = 0.0 def forward(self, x, y): self.x = x self.y = y out = x * y return out def backward(self, dout): dx = dout * self.y dy = dout * self.x self.dx = dx self.dy = dy return dx, dy class AddLayer: def __init__(self): pass def forward(self, x, y): out = x + y return out def backward(self ,dout): dx = dout * 1 dy = dout * 1 return dx,dy class Square: def __init__(self): self.x = None self.dx = None def forward(self,x): self.x = x out = x **2 return out def backward(self, dout): self.dx = 2 * dout * self.x return self.dx class AdaGrad: def __init__(self, lr=0.1): self.lr = lr self.h = 0.0 def update(self, params, grads): self.h = self.h + grads * grads sabun = self.lr * grads/(np.sqrt(self.h)+ 1e-7) params = params - sabun return params pltx = 8 plty = 1 Square1 = Square() Square2 = Square() Mul1 = MulLayer() Add = AddLayer() AdaGrad = AdaGrad(1) listx = [] listy = [] listz = [] katamuki = 1 for i in range(100): x0 = Square1.forward(pltx) x1 = Mul1.forward(x0, 1/20) y1 = Square2.forward(plty) z = Add.forward(x1, y1) listx.append(pltx) listy.append(plty) listz.append(z) bx0,by1 = Add.backward(katamuki) bx1,by_b = Mul1.backward(bx0) bx2 = Square1.backward(bx1) by2 = Square2.backward(by1) pltx = AdaGrad.update(pltx,bx2) plty = AdaGrad.update(plty,by2) ListX, ListY = np.meshgrid(listx, listy) fig = plt.figure() plt.plot(listx, listy) plt.show()
追加したコードは、
class AdaGrad: def __init__(self, lr=0.1): self.lr = lr self.h = 0.0 def update(self, params, grads): self.h = self.h + grads * grads sabun = self.lr * grads/(np.sqrt(self.h)+ 1e-7) params = params - sabun return params
と、
pltx = AdaGrad.update(pltx,bx2) plty = AdaGrad.update(plty,by2)
になります。
適用する数式をAdaGradに変更するのみです。
結果はこちらになります。
効率的に収束していることが見て分かるかと思います!!
■最後に
今回は行列だと分かりにくいところもあったので2次関数を元に誤差逆伝搬について勉強しました。
また、AdaGradについても簡単に触れました。
自分で手を動かすことで理解が深まりました。
さらにDeep Learningについて理解深めていきたいと思います!!