この記事は,Pythonそのものの使い方かDeepLearningの仕組みまで,1から細かく学習した際のメモ書きとスライドのまとめです.
多層パーセプトロン(AND真偽値表の学習)
今回は,多層パーセプトロン(Perceptron)を用いて,AND真偽値表の出力を学習させることを目指す.AND真偽値表とは,入力の2つが共に1である時のみ1を出力するものである.
このAND真偽値表は,前回の1から学ぶDeepLearning (1) で扱ったように,単純パーセプトロンで学習ができたものであった.
今回は,多層パーセプトロンを学習することを第一の目的として,内容の同じ学習を行い,単純パーセプトロンとの違いを見てみることにする.
x1 | x2 | y |
---|---|---|
0 | 0 | 0 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
import numpy as np
# 活性化関数の定義(Sigmoid関数)
def sigmoid(x):
return 1/(1+np.exp(-x))
def sigmoid_grad(x):
return (1.0 - sigmoid(x))*sigmoid(x)
class MLP:
def __init__(self, input_size, hidden_size, output_size, weight_init_std=0.1):
self.w1 = weight_init_std * np.random.randn(input_size, hidden_size)
self.w2 = weight_init_std * np.random.randn(hidden_size, output_size)
self.b1 = 0.0
self.b2 = 0.0
self.grads = {}
def forward(self, x): # x : 入力
self.a1 = np.dot(x, self.w1) + self.b1
self.z1 = sigmoid(self.a1)
self.a2 = np.dot(self.z1, self.w2) + self.b2
self.y = sigmoid(self.a2)
return self.y
def backward(self, x, t): # x : 入力,y : 教師
# 誤差の算出
l = -1 * (t - self.y)
d_a2 = sigmoid_grad(self.a2) * l
self.grads['w2'] = np.dot(self.z1.T, d_a2)
self.grads['b2'] = d_a2
d_z1 = np.dot(d_a2, self.w2.T)
d_a1 = d_z1 * sigmoid_grad(self.a1)
self.grads['w1'] = np.dot(x.T, d_a1)
self.grads['b1'] = d_a1
def update_parameters(self, lr = 0.1): # lr : 学習率
self.w1 -= lr * self.grads['w1']
self.w2 -= lr * self.grads['w2']
self.b1 -= lr * self.grads['b1']
self.b2 -= lr * self.grads['b2']
def display_model_parameters(model):
print("w1 : ", model.w1)
print("w2 : ", model.w2)
print("b1 : ", model.b1)
print("b2 : ", model.b2)
if __name__ == '__main__':
# AND回路の学習を行うための入力データと教師ラベルの定義
input_data = np.array([[0,0],[0,1],[1,0],[1,1]])
label_data = np.array([0,0,0,1])
# モデルの作成
input_size = 2
hidden_size = 3
output_size = 1
model = MLP(input_size, hidden_size, output_size)
display_model_parameters(model)
# ハイパーパラメータの指定
num_train_data = 4
epoch_num = 5000
lerning_rate = 0.1
for i in range(1,epoch_num+1,1):
sum_loss = 0.0
for j in range(0,num_train_data,1):
x = input_data[j:j+1]
t = label_data[j:j+1]
y_pred = model.forward(x)
model.backward(x, t)
model.update_parameters(lerning_rate)
sum_loss = np.power(t - y_pred, 2)
print("epoch : {}, loss : {}".format(i, sum_loss/4))
display_model_parameters(model)
#正解率の算出
cnt_correct = 0
cnt_all = 0
tolerance = 0.05 #許容範囲の設定
for i in range(0,len(input_data)):
y = model.forward(input_data[i])
print("input_data : {}, y : {}".format(input_data[i], y))
label = label_data[i]
if label-tolerance < y and y < label+tolerance:
cnt_correct += 1
cnt_all += 1
accuracy = cnt_correct/cnt_all
print("accuracy : ", accuracy)
実行結果
epoch : 5000, loss : [[0.00178896]]
w1 : [[-2.6255562 -2.0996942 -1.82297711]
[-2.6269102 -1.89913472 -2.03126441]]
w2 : [[-5.08765545]
[-3.5903548 ]
[-3.41550001]]
b1 : [[3.23467422 2.07894497 1.93356411]]
b2 : [[3.87595026]]
input_data : [0 0], y : [[0.0007504]]
input_data : [0 1], y : [[0.04749434]]
input_data : [1 0], y : [[0.04750903]]
input_data : [1 1], y : [[0.91554948]]
accuracy : 0.75
単純パーセプトロン(前回プログラム)の実行結果
epoch : 5000, loss : 0.0019097360320011203
w : [5.82859069 5.82738022] b : -9.028217956770213
input_data : [0 0], y : 0.00011996171284962275
input_data : [0 1], y : 0.03913420962830516
input_data : [1 0], y : 0.039179751963228676
input_data : [1 1], y : 0.9326264954936772
accuracy : 1.0
同じ学習率,エポック数で行った結果だが,学習損失を示したものの最後をみると,中間層を増やした多層パーセプトロンの方が,良くない結果になっていることが確認できる.
実験前までは,単純に層を増やした方が,柔軟に対応できるようになり良い結果が得られると考えていたが,この予想に反する結果になった.
そこで,学習で調整するパラメータが多いのが主な要因であると考えた.エポック数を倍の10000にして再度実行して挙動をみてみることにする.
エポック数を10000に変更して再度実行
epoch : 10000, loss : [[0.00058127]]
w1 : [[-2.93745684 -1.50381849 -2.61486656]
[-3.05729588 -1.25551698 -2.56420406]]
w2 : [[-5.95868659]
[-1.94927261]
[-4.95068125]]
b1 : [[3.85144893 0.67567557 3.15570244]]
b2 : [[4.40249983]]
input_data : [0 0], y : [[0.00056819]]
input_data : [0 1], y : [[0.02691188]]
input_data : [1 0], y : [[0.02732029]]
input_data : [1 1], y : [[0.95180993]]
accuracy : 1.0
単純パーセプトロン(前回プログラム)も同様にエポック数を10000にて再度実行
epoch : 10000, loss : 0.000508028532782091
w : [7.20750455 7.20687697] b : -11.097796727457217
input_data : [0 0], y : 1.5145427708191534e-05
input_data : [0 1], y : 0.020017658200903544
input_data : [1 0], y : 0.020029973106389383
input_data : [1 1], y : 0.9649934048107632
accuracy : 1.0
同じエポック数では,また多層パーセプトロンの学習結果の方が劣った結果になった.
やはり,単純パーセプトロンで解ける問題は,単純パーセプトロンで解いた方が効率も精度も良いということなのか...