#はじめに
この記事はゼロから作るディープラーニング 5章ニューラルネットワークの学習を自分なりに理解して分かりやすくアウトプットしたものです。
文系の自分でも理解することが出来たので、気持ちを楽にして読んでいただけたら幸いです。
また、本書を学習する際に参考にしていただけたらもっと嬉しいです。
#学習機能を実装したニューラルネットワーク
今回は分類問題を解く専用の学習機能付きニューラルネットワークのクラスを実装して行きたいと思います。
今回の実装の流れを簡単に説明します。
1, インスタンス変数でパラメータとハイパーパラメータを実装
2, 予測データを出力するニューラルネットワークの処理を行うクラスメソッドpredictの実装
3, ニューラルネットワークから損失関数までの処理を行うクラスメソッドlossの実装
4, 予測データの正答率を出すメソッドaccuracyの実装
5, 学習を行うための勾配式を実装
#1, インスタンス変数でパラメータとハイパーパラメータを実装
class MNST_net:# 中間層は今回一層
def __init__(self, input_size, hiden_size, output_size, weight_init_std = 0.01):
self.params = {}#パラメータの初期化
self.params['W1'] = weight_init_std * np.random.randn(input_size, hiden_size)
self.params['b1'] = np.zeros(hiden_size)
self.params['W2'] = weight_init_std * np.random.randn(hiden_size, output_size)
self.params['b2'] = np.zeros(output_size)
最初のクラスメソッドでハイパーパラメータとパラメータを実装します。
**init(self):**のカッコの中には、input_size(入力層のニューロン数),hiden_size(中間層のニューロン数),output_size(出力層のニューロン数)、weight_init_std(重みを小さなな値にして過学習を抑える)などの人間が設定しないといけないハイパーパラメータを記述します。
重みやバイアスなどのパラメータの実装(初期化)はparamsと言う辞書をインスタンス変数として作成し、その中に各層ごと各パラメータの種類ごとに分けて実装していきます。
重みは、np.random.randnを使って(入力信号✖︎ニューロン数)のランダムな整数が入った配列を作成し、weight_init_stdをかけることで実装(初期化)できます。
バイアスは初期値をゼロにしないといけないので、np.zerosでニューロン数のゼロが入った一次元配列を作成することで実装(初期化)できます。
#2, 予測データを出力するニューラルネットワークの処理を行うクラスメソッドpredictの実装
class MNST_net:# 中間層は今回一層
def __init__(self, input_size, hiden_size, output_size, weight_init_std = 0.01):
self.params = {}#パラメータの初期化
self.params['W1'] = weight_init_std * np.random.randn(input_size, hiden_size)
self.params['b1'] = np.zeros(hiden_size)
self.params['W2'] = weight_init_std * np.random.randn(hiden_size, output_size)
self.params['b2'] = np.zeros(output_size)
def predict(self, x):# ニューラルネットワークの処理
W1, W2 = self.params['W1'], self.params['W2']
b1, b2 = self.params['b1'], self.params['b2']
a1 = np.dot(x, W1) + b1# 入力層から隠れ層1段の処理
z1 = sigmoid_function(a1)
a2 = np.dot(z1, W2) + b2
y = softmax_function_pro(a2)
return y
初期化されたパラメータをそれぞれ変数に入れて、各層のニューラルネットワークのニューロンの処理を実装していきます。
#3, ニューラルネットワークから損失関数までの処理を行うクラスメソッドlossの実装
class MNST_net:# 中間層は今回一層
def __init__(self, input_size, hiden_size, output_size, weight_init_std = 0.01):
self.params = {}#パラメータの初期化
self.params['W1'] = weight_init_std * np.random.randn(input_size, hiden_size)
self.params['b1'] = np.zeros(hiden_size)
self.params['W2'] = weight_init_std * np.random.randn(hiden_size, output_size)
self.params['b2'] = np.zeros(output_size)
def predict(self, x):# ニューラルネットワークの処理
W1, W2 = self.params['W1'], self.params['W2']
b1, b2 = self.params['b1'], self.params['b2']
a1 = np.dot(x, W1) + b1# 入力層から隠れ層1段の処理
z1 = sigmoid_function(a1)
a2 = np.dot(z1, W2) + b2
y = softmax_function_pro(a2)
return y
def loss(self, x, t):# NNから損失関数までの処理
y = self.predict(x)
return cross_entropy_errors_label(t, y)
predictメソッドで予測データを取得して変数yに入れ、それを交差エントロピー誤差の引数に入れてreturnで返します。
#4, 予測データの正答率を出すメソッドaccuracyの実装
class MNST_net:# 中間層は今回一層
def __init__(self, input_size, hiden_size, output_size, weight_init_std = 0.01):
self.params = {}#パラメータの初期化
self.params['W1'] = weight_init_std * np.random.randn(input_size, hiden_size)
self.params['b1'] = np.zeros(hiden_size)
self.params['W2'] = weight_init_std * np.random.randn(hiden_size, output_size)
self.params['b2'] = np.zeros(output_size)
def predict(self, x):# ニューラルネットワークの処理
W1, W2 = self.params['W1'], self.params['W2']
b1, b2 = self.params['b1'], self.params['b2']
a1 = np.dot(x, W1) + b1# 入力層から隠れ層1段の処理
z1 = sigmoid_function(a1)
a2 = np.dot(z1, W2) + b2
y = softmax_function_pro(a2)
return y
def loss(self, x, t):# NNから損失関数までの処理
y = self.predict(x)
return cross_entropy_errors_label(t, y)
def accuracy(self, x, t):# 正答率
y = self.predict(x)
y = np.argmax(y, axis = 1)# 一番確率の高いラベルのインデックスを出す
# t = np.argmax(t, axis = 1)# 正解ラベルのインデックスを出す one-hot法
accuracy = (y == t).sum() / float(x.shape[0])
return accuracy
predictで予測データを出して、一番値が大きいindexをnp.argmaxで出し、それと正解データを比べて正解したものの合計 / 全体数 で正答率を出します。
#5, 学習を行うための勾配式を実装
class MNST_net:# 中間層は今回一層
def __init__(self, input_size, hiden_size, output_size, weight_init_std = 0.01):
self.params = {}#パラメータの初期化
self.params['W1'] = weight_init_std * np.random.randn(input_size, hiden_size)
self.params['b1'] = np.zeros(hiden_size)
self.params['W2'] = weight_init_std * np.random.randn(hiden_size, output_size)
self.params['b2'] = np.zeros(output_size)
def predict(self, x):# ニューラルネットワークの処理
W1, W2 = self.params['W1'], self.params['W2']
b1, b2 = self.params['b1'], self.params['b2']
a1 = np.dot(x, W1) + b1# 入力層から隠れ層1段の処理
z1 = sigmoid_function(a1)
a2 = np.dot(z1, W2) + b2
y = softmax_function_pro(a2)
return y
def loss(self, x, t):# NNから損失関数までの処理
y = self.predict(x)
return cross_entropy_errors_label(t, y)
def accuracy(self, x, t):# 正答率
y = self.predict(x)
y = np.argmax(y, axis = 1)# 一番確率の高いラベルのインデックスを出す
# t = np.argmax(t, axis = 1)# 正解ラベルのインデックスを出す one-hot法
accuracy = (y == t).sum() / float(x.shape[0])
return accuracy
def slopeing_grad_net(self, x, t):# 初期パラメータ勾配式
loss_c = lambda W: self.loss(x, t) # 関数化させないといけなかった 引数Wはダミー
grads = {}
grads['W1'] = slopeing_grad(loss_c,self.params['W1'])
grads['b1'] = slopeing_grad(loss_c,self.params['b1'])
grads['W2'] = slopeing_grad(loss_c,self.params['W2'])
grads['b2'] = slopeing_grad(loss_c,self.params['b2'])
return grads
ニューラルネットワークから損失関数までの処理を変数loss_cに入れて、それと初期化されたパラメータを各層・各種類ごとに前回作成したslopeing_gradで勾配を求めて、それをgradsと言う辞書にまとめてreturnで返します。