多層パーセプトロン-Stephen Machine Learning-
- 作者: Stephen Marsland
- 出版社/メーカー: Chapman and Hall/CRC
- 発売日: 2009/04/08
- メディア: ペーパーバック
- クリック: 35回
- この商品を含むブログ (5件) を見る
アルゴリズムは以下のようになる。
ちなみに、誤差逆伝搬法である(はず)。
1.初期化- Initialisation
2.訓練
繰り返し
Forward phase
隠れ層のそれぞれのニューロンjの活性を計算
出力層も同様
Backwards pahse
出力の誤差を計算
隠れ層の誤差を計算
出力層の荷重の更新
隠れ層の荷重の更新
3.呼び出し
上記の訓練時のForward phaseを用いる
上記のアルゴリズムのまま実装すると以下のようになる。
#-*- coding:utf-8 -*- import numpy as np class MLP: """"ニューラルネットワーク""" def __init__(self, input, target, nHidden, beta=1.0): #コンストラクタ #初期値の設定 self.nData = np.shape(input)[0] if np.ndim(input) > 1: self.nIn = np.shape(input)[1] else: self.nIn = 1 #targetの列の数を調べる if np.ndim(target) > 1: self.nOut = np.shape(target)[1] else: self.nOut = 1 #隠れ層の数 self.nHidden = nHidden #シグモイド関数に対して正のパラメータを設定 self.beta = beta #ネットワークの初期化 self.Hweight = np.random.rand(self.nIn+1,self.nHidden) - 0.5 self.Iweight = np.random.rand(self.nHidden+1,self.nOut) - 0.5 def train(self, input, target,eta,update): #バイアス項として-1を加える input = np.concatenate((-np.ones((self.nData,1)),input),axis=1) self.updateV = np.zeros((np.shape(self.Hweight))) self.updateW = np.zeros((np.shape(self.Iweight))) for N in xrange(update): self.output = self.fwd(input) self.bwd(input,target,eta) def fwd(self,input): #Forward phase #隠れ層のそれぞれのニューロンの活性を計算する-ロジスティック関数 self.hidden = np.dot(input,self.Hweight) self.hidden = 1.0/(1.0 + np.exp(-self.beta * self.hidden)) self.hidden = np.concatenate((-np.ones((np.shape(input)[0],1)),self.hidden),axis=1) #出力層の活性を計算する-ロジスティック関数 self.output = np.dot(self.hidden,self.Iweight) self.output = 1.0/(1.0 + np.exp(- self.beta * self.output)) return self.output def bwd(self,input,target,eta): #Backward phase #出力層の誤差を計算する delta_o = (target - self.output)*self.output*(1.0 - self.output) #隠れ層の誤差を計算する delta_h = self.hidden*(1.0 - self.hidden)*(np.dot(delta_o,(self.Iweight).T)) self.updateW = eta * np.dot(np.transpose(self.hidden),delta_o) self.updateV = eta * np.dot(np.transpose(input),delta_h[:,:-1]) #隠れ層の荷重を更新する self.Hweight += eta * self.updateV #出力層の荷重を更新する self.Iweight += self.updateW
しかし、これだけでは精度は結構悪い。
以下に精度を上げるテクニックについてまとめる。
アルゴリズムの実行速度を上げるには、入力と出力のデータを並び替えれば
いい。そうすることで、一回の更新の効果を上げることができる。
np.random.shuffle()を使う。
以下例。
In [1]: import numpy as np In [2]: arr = np.arange(10) In [3]: np.random.shuffle(arr) In [4]: arr Out[4]: array([0, 5, 2, 8, 6, 9, 4, 1, 7, 3]) In [5]: np.random.shuffle(arr) In [6]: arr Out[6]: array([3, 0, 4, 9, 1, 8, 6, 7, 5, 2])
実際には以下を、bwd後に行う。
change = range(self.nData) np.random.shuffle(change) input = input[change,:] output = target[change,:]
また、momentum(慣性項)を導入するとよい。
を
とする。
momentumはαである。
具体的には、
self.Hweight += eta * self.updateV self.Iweight += self.updateW
を
self.updateW = eta * np.dot(np.transpose(self.hidden),delta_o) + self.momentum*self.updateW self.updateV = eta * np.dot(np.transpose(input),delta_h[:,:-1]) + self.momentum*self.updateV
と書き換える。
通常、0 < α < 1で、0.9がよく使われるよう。理由はわかりません。
他にも、ロジスティック関数をソフトマックス関数に書き換えるなどがありますが、
割愛して以上の修正をまとめて書き直して、実行方法を書くと以下のようになります。
#-*- coding:utf-8 -*- import numpy as np class MLP: """"ニューラルネットワーク""" def __init__(self, input, target, nHidden, beta=1.0,momentum=0.9): #コンストラクタ #初期値の設定 self.nData = np.shape(input)[0] if np.ndim(input) > 1: self.nIn = np.shape(input)[1] else: self.nIn = 1 #targetの列の数を調べる if np.ndim(target) > 1: self.nOut = np.shape(target)[1] else: self.nOut = 1 #隠れ層の数 self.nHidden = nHidden #シグモイド関数に対して正のパラメータを設定 self.beta = beta #momentumの設定 self.momentum = momentum #ネットワークの初期化 #0.5はバイアス項 self.Hweight = np.random.rand(self.nIn+1,self.nHidden) - 0.5 self.Iweight = np.random.rand(self.nHidden+1,self.nOut) - 0.5 def train(self, input, target,eta,update): #バイアス項として-1を加える input = np.concatenate((-np.ones((self.nData,1)),input),axis=1) change = range(self.nData) np.random.shuffle(change) self.updateV = np.zeros((np.shape(self.Hweight))) self.updateW = np.zeros((np.shape(self.Iweight))) for N in xrange(update): self.output = self.fwd(input) self.bwd(input,target,eta) input = input[change,:] target = target[change,:] def fwd(self,input): #Forward phase #隠れ層のそれぞれのニューロンの活性を計算する-ロジスティック関数 self.hidden = np.dot(input,self.Hweight) self.hidden = 1.0/(1.0 + np.exp(-self.beta * self.hidden)) self.hidden = np.concatenate((-np.ones((np.shape(input)[0],1)),self.hidden),axis=1) #出力層の活性を計算する-ロジスティック関数 self.output = np.dot(self.hidden,self.Iweight) self.output = 1.0/(1.0 + np.exp(- self.beta * self.output)) return self.output def bwd(self,input,target,eta): #Backward phase #出力層の誤差を計算する delta_o = (target - self.output)*self.output*(1.0 - self.output) #隠れ層の誤差を計算する delta_h = self.hidden*(1.0 - self.hidden)*(np.dot(delta_o,(self.Iweight).T)) self.updateW = eta * np.dot(np.transpose(self.hidden),delta_o) + self.momentum*self.updateW self.updateV = eta * np.dot(np.transpose(input),delta_h[:,:-1]) + self.momentum*self.updateV #隠れ層の荷重を更新する self.Hweight += self.updateV #出力層の荷重を更新する self.Iweight += self.updateW def confmat(self,input,target): input = np.concatenate((-np.ones((np.shape(input)[0],1)),input),axis=1) output = self.fwd(input) nclasses = np.shape(target)[1] if nclasses ==1: nclasses = 2 output = np.where(output > 0.5,1,0) else: output = np.argmax(output,1) target = np.argmax(target,1) cm = np.zeros((nclasses,nclasses)) for i in xrange(nclasses): for j in xrange(nclasses): cm[i,j] = np.sum(np.where(output == i,1,0)*np.where(target == j,1,0)) print "Confusion matrix is:" print cm print "Percentage Correct: ",np.trace(cm)/np.sum(cm)*100
実行結果
In [4]: import numpy as np In [5]: import my_mlp In [6]: anddata = np.array([[0,0,0],[0,1,0],[1,0,0],[1,1,1]]) In [9]: p.train(anddata[:,0:2],anddata[:,2:3],0.25,5000) p.confmat(anddata[:,0:2],anddata[:,2:3]) In [10]: p.confmat(anddata[:,0:2],anddata[:,2:3]) Confusion matrix is: [[ 3. 0.] [ 0. 1.]] Percentage Correct: 100.0
以下が実行方法
In [1]: import numpy as np In [2]: import my_mlp In [3]: anddata = np.array([[0,0,0],[0,1,0],[1,0,0],[1,1,1]]) In [4]: p = my_mlp.MLP(anddata[:,0:2],anddata[:,2:3],2) In [5]: p.train(anddata[:,0:2],anddata[:,2:3],0.25,5000) In [6]: p.confmat(anddata[:,0:2],anddata[:,2:3]) Confusion matrix is: [[ 3. 0.] [ 0. 1.]] Percentage Correct: 100.0 In [7]: In [7]: xordata = np.array([[0,0,0],[0,1,1],[1,0,1],[1,1,0]]) In [8]: p = my_mlp.MLP(xordata[:,0:2],xordata[:,2:3],2) In [9]: p.train(xordata[:,0:2],xordata[:,2:3],0.25,1000) In [10]: p.confmat(xordata[:,0:2],xordata[:,2:3]) Confusion matrix is: [[ 2. 0.] [ 0. 2.]] Percentage Correct: 100.0
次回は放射基底関数Radical Basis Functionを用いてニューラルネットワークの実装もしてみる。