Last active
May 17, 2016 00:18
-
-
Save butsugiri/1b3091c1f8a45809b1eb5c98fad15322 to your computer and use it in GitHub Desktop.
多層パーセプトロンの実装例
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
""" | |
""" | |
import numpy as np | |
def sigmoid(x): | |
return 1./(1.+np.exp(-x)) | |
def sigmoid_deriv(x): | |
return x * (1.0 - x) | |
class SigmoidLayer: | |
""" | |
多層パーセプトロンの各層のレイヤーを表すクラス | |
""" | |
def __init__(self, input, n_in, n_out, W=None): | |
""" | |
Keyword arguments: | |
input -- layer input, given in numpy array. 各列が一つのデータを表す. | |
n_in -- dimension of each input data | |
n_out -- dimension of each output data | |
W -- weight | |
""" | |
self.input = input | |
self.n_in = n_in | |
self.n_out = n_out | |
# 重みの初期化 -1から1までのランダムな値 | |
# n_in + 1としているのは,各層にバイアス項が含まれるため | |
self.W = np.random.uniform(-1.0, 1.0, (self.n_out, self.n_in+1)) | |
def forward(self, input=None, last=False): | |
if input is not None: | |
self.input = input | |
u = np.dot(self.W, self.input) | |
self.output = sigmoid(u) | |
if last != True: | |
#出力層以外は,バイアス項を追加 | |
self.output = self.__add_bias(self.output) | |
return self.output | |
def backward(self, d, lr): | |
""" | |
ここでは,出力層を除くすべての層は,ユニットを二つ以上持つと仮定している. | |
なので隠れ層のユニットを一つに設定するとエラーとなるはず. | |
スライスでバイアス項を除いておく (backpropには使わない) | |
スライスによるバイアスの取り扱いについては, | |
参考: http://stmind.hatenablog.com/entry/2014/06/16/145524 | |
""" | |
if d.shape[0] > 1: | |
d = d[1::] | |
d_next = sigmoid_deriv(self.input) * np.dot(self.W.T, d) | |
self.W -= lr * np.dot(np.atleast_2d(d),np.atleast_2d(self.input).T) | |
return d_next | |
def __add_bias(self, x, axis=None): | |
ones = np.ones([1,x.shape[1]]) | |
return np.r_[ones,x] | |
def get_outputlayer_delta(self, y): | |
return (self.output - y) * sigmoid_deriv(self.output) | |
class MLP: | |
def __init__(self, input, label, n_in, hidden_layer_sizes,n_out): | |
""" | |
Keyword arguments: | |
input -- layer input, given in numpy array. 各列が一つのデータを表す. | |
label -- correct label given in numpy array. | |
n_in -- dimension of input layer | |
hidden_layer_sizes -- number of units in each hidden layer (e.g. [3,3]) | |
n_out -- dimension of output layer | |
""" | |
self.input = input | |
self.label = label | |
self.hidden_layers = [] | |
n_layers = len(hidden_layer_sizes) | |
self.n_layers = n_layers | |
for i in range(n_layers): | |
if i == 0: | |
input_size = n_in | |
layer_input = None | |
else: | |
input_size = hidden_layer_sizes[i-1] | |
layer_input = None | |
self.hidden_layers.append( | |
SigmoidLayer(layer_input, input_size, hidden_layer_sizes[i]) | |
) | |
self.output_layer = SigmoidLayer( | |
None, | |
hidden_layer_sizes[n_layers-1], | |
n_out | |
) | |
def train(self, lr=0.2, epochs=10000): | |
X = self.input | |
t = self.label | |
for i in xrange(epochs): | |
for n in range(0, X.shape[0]): | |
index = np.random.randint(X.shape[0]) | |
g = np.atleast_2d(X[index]).T | |
#入力にバイアス項を追加 | |
ones = np.ones([1,g.shape[1]]) | |
g = np.r_[ones,g] | |
for j in range(self.n_layers): | |
g = self.hidden_layers[j].forward(g) | |
g = self.output_layer.forward(input = g, last = True) | |
output_delta = self.output_layer.get_outputlayer_delta(t[index]) | |
delta = self.output_layer.backward(output_delta, lr) | |
for j in range(self.n_layers)[::-1]: | |
delta = self.hidden_layers[j].backward(delta, lr) | |
loss_sum = np.sum((self.predict() - t)**2) | |
print "epoch: {0:5d}, loss: {1:.5f}".format(i, loss_sum) | |
def predict(self, x=None): | |
if x is None: | |
x = self.input | |
x = np.hstack((np.ones([x.shape[0],1]),x)).T | |
for i in range(self.n_layers): | |
x = self.hidden_layers[i].forward(x) | |
return self.output_layer.forward(input = x, last = True) | |
if __name__ == "__main__": | |
x_train = np.array([[0,0], [0,1], [1,0], [1,1]]) | |
y_train = np.array([0,1,1,0]) | |
mlp = MLP(x_train,y_train, len(x_train[0]), [3], 1) | |
mlp.train() | |
for x,y in zip(x_train, y_train): | |
input = x | |
x = np.insert(x,0,1) | |
x = np.atleast_2d(x).T | |
print "input: {}\tlabel: {}\tprediction: {}".format(input, y, mlp.predict(x)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment