|
Last updated: 2020.4.17(first uploaded 2018.6.13)
勾配降下法と誤差逆伝播法(backward propagation)のPython 実装 |
- import numpy as np
- import matplotlib.pylab as plt
- def numerical_gradient(f, x):
- h = 1e-4 # 0.0001
- grad = np.zeros_like(x)
- for idx in range(x.size):
- tmp_val = x[idx]
- x[idx] = tmp_val + h
- fx1 = f(x)
- x[idx] = tmp_val - h
- fx2 = f(x)
- grad[idx] = (fx1 - fx2) / (2*h)
- return grad
- def gradient_descent(f, init_x, eta=0.01, ite_num=100):
- x = init_x
- x_history = []
- for i in range(ite_num):
- x_history.append( x.copy() )
- grad = numerical_gradient(f, x)
- x -= eta * grad
- return x, np.array(x_history)
- def function_2(x):
- return (x[0] - 1)**2 + (x[1] - 2)**2
- init_x = np.array([0.0, 0.0])
- eta = 0.1
- ite_num = 20
- x, x_history = gradient_descent(function_2, init_x, eta, ite_num)
- plt.plot( [-5, 5], [2,2], '--b')
- plt.plot( [1,1], [-5, 5], '--b')
- plt.plot(x_history[:,0], x_history[:,1], 'o')
- plt.xlim(-3.5, 3.5)
- plt.ylim(-4.5, 4.5)
- plt.xlabel("X0")
- plt.ylabel("X1")
- plt.show()
- import numpy as np
- class Sigmoid:
- def __init__(self):
- self.out = None
- def forward(self, x):
- out = 1/(1 + np.exp(-x))
- self.out = out
- return out
- def backward(self, dout):
- dx = dout * (1.0 - self.out) * self.out
- return dx
- class Dense_layer:
- def __init__(self, W, b):
- self.W =W
- self.b = b
- self.x = None
- self.dW = None
- self.db = None
- def forward(self, x):
- self.x = x
- out = np.dot(self.x, self.W) + self.b
- return out
- def backward(self, dout):
- dx = np.dot(dout, self.W.T)
- self.dW = np.dot(self.x.T, dout)
- self.db = np.sum(dout, axis=0)
- return dx
確率的勾配降下法(SGD)のPython 実装 |
ミニバッチ方式で勾配降下法を使用するアルゴリズムを確率的勾配降下法(SGD)と言います。Deep Learningで用いられる最適化手法には、SGDの他に、AdaDelta、Adam、Momentum、Nesterov、RMSPropと呼ばれるアルゴリズムがあります。いずれにしても、損失関数の勾配(偏微分値)を使用します。
ここでは、確率的勾配降下法(SGD)のPython実装の例を紹介します。偏微分計算をするモジュールを grad として、paramsをネットワークの重みとするとき、以下のような形式になります。
- import numpy as np
- class SGD:
- """確率的勾配降下法(Stochastic Gradient Descent)"""
- def __init__(self, lr=0.01):
- self.lr = lr
- def update(self, params, grads):
- for key in params.keys():
- params[key] -= self.lr * grads[key]
- optimizer = SGD()
- ---
- for i in range(300):
- grads['x'], grads['y'] = grad(params['x'], params['y'])
- optimizer.update(params, grads)
- ---
機械学習で使用されているPython API には、こうした最適化関数のモジュールと微分計算のモジュールが準備されています。ちなみに、以下の例はPyTorchにおける最適関数の利用方法となります。loss.backward()は逆伝播法による微分計算の実行を表現します。nn.MSELoss()は平均二乗誤差法による損失関数を呼び出します。
- def main(opt_type):
- loss_list = []
- # データの作成
- x = torch.randn(1, 10)
- w = torch.randn(1, 1)
- y = torch.mul(w, x) +2
- # ネットワークの定義
- net = Net()
- # 損失関数
- criterion = nn.MSELoss()
- # 最適化関数の指定
- if opt_type == "SGD":
- optimizer = optim.SGD(net.parameters(), lr=0.1)
- elif opt_type == "Momentum":
- optimizer = optim.SGD(net.parameters(), lr=0.1, momentum=0.9)
- elif opt_type == "Adadelta":
- optimizer = optim.Adadelta(net.parameters(), rho=0.95, eps=1e-04)
- elif opt_type == "Adagrad":
- optimizer = optim.Adagrad(net.parameters())
- elif opt_type == "Adam":
- optimizer = optim.Adam(net.parameters(), lr=1e-1, betas=(0.9, 0.99), eps=1e-09)
- elif opt_type == "RMSprop":
- optimizer = optim.RMSprop(net.parameters())
- # 学習ループ
- for epoch in range(20):
- optimizer.zero_grad()
- y_pred = net(x)
- loss = criterion(y_pred, y)
- loss.backward()
- optimizer.step()
- loss_list.append(loss.data.item())
- return loss_list
- loss_hist = main('SGD')
この例からわかるように、opt_type を具体的に指定することによって、主要な最適化関数が利用できます。詳しくは、PyTorchの公式ページを参照ください。同じように、TensorFlowの tf.keras.optimizer モジュールにも、以下の通り、主要な最適化関数の9種類が用意されています。
詳しくは、TensorFlowのTutorialsを参照ください。