エルマンネットワーク
というのを実装して見た。リカレントニューラルネットワーク(RNN)の一形態?
単純再帰型ネットワーク
http://www.cis.twcu.ac.jp/~asakawa/waseda2002/elman.pdf
import numpy as np def sigmoid(x): return np.tanh(x) def dsigmoid(x): return 1.0-x*x class ElmanNet: def __init__(self , numIn , numHidden , numOut): self.input = np.ones( numIn ) self.output = np.ones( numOut ) self.hidden = np.ones( numHidden ) self.context = np.zeros( numHidden ) self.weight_in_hid = np.random.uniform(low=-0.5,high=0.5,size=(numIn , numHidden) ) self.weight_hid_out = np.random.uniform(low=-0.5,high=0.5,size=(numHidden,numOut) ) self.weight_cont_hid = np.random.uniform(low=-0.5,high=0.5,size=(numHidden,numHidden) ) def propagate_forward(self , data): self.input = np.copy(data) self.context = np.copy(self.hidden) self.hidden = np.vectorize(sigmoid)(np.dot(self.input , self.weight_in_hid) + np.dot(self.context , self.weight_cont_hid)) self.output = np.vectorize(sigmoid)(np.dot(self.hidden , self.weight_hid_out)) return self.output def propagate_backward(self , target , learnRate=0.1): error_out = (target - self.output) * np.vectorize(dsigmoid)(self.output) error_hidden = np.dot(error_out , self.weight_hid_out.T) * np.vectorize(dsigmoid)(self.hidden) self.weight_hid_out += np.array( learnRate * np.matrix(self.hidden).T * np.matrix(error_out) ) self.weight_in_hid += np.array( learnRate * np.matrix(self.input).T * np.matrix(error_hidden) ) self.weight_cont_hid += np.array( learnRate * np.matrix(self.context).T * np.matrix(error_hidden) ) def train(self , samples , r=1500): L = len(samples) for _ in xrange(r): for (inp,outp) in samples: self.propagate_forward(inp) self.propagate_backward(outp) def predict(self , data): return self.propagate_forward(data) if __name__=="__main__": def tobit(n,nbits=6): return [int(n==i) for i in xrange(nbits)] net = ElmanNet(6,15,6) samples = [(tobit(0),tobit(1)),(tobit(1),tobit(2)),(tobit(2),tobit(3)),(tobit(3),tobit(4)), (tobit(4),tobit(5)),(tobit(5),tobit(4)),(tobit(4),tobit(3)),(tobit(3),tobit(2)), (tobit(2),tobit(1)),(tobit(1),tobit(0)),(tobit(0),tobit(1)),(tobit(1),tobit(2)), (tobit(2),tobit(3)),(tobit(3),tobit(4)),(tobit(4),tobit(5)),(tobit(5),tobit(4))] net.train(samples) out = net.predict(tobit(4)) print(out) out = net.predict(out) print(out) print net.predict(tobit(2))
例として、0,1,2,3,4,5,4,3,2,1,0,1,2,3,4,5,...という時系列を学習させている。一応、値が上昇中か下降中か覚えておく必要があるけど、勝手に覚えておいてくれるという寸法。0,1,2,3,4,5は、[1,0,0,0,0,0],[0,1,0,0,0,0],[0,0,1,0,0,0],...にエンコードしてる。3bitで[0,0,0],[0,0,1],[0,1,],[0,1,1],...とかやった方がメモリには優しいけど、予測精度がでない
一応、上の計算結果は(乱数で初期化している部分があるので、結果は毎回異なるけど)例えば
[ 0.05445429 -0.0483922 -0.14895301 0.98319809 0.09161327 -0.09690022] [ 0.05653943 0.13345083 0.98843438 -0.28019387 -0.08493135 0.05609208] [-0.09952735 0.98482479 0.22479163 -0.13254797 -0.08240431 0.20785037]
とかなって、[0,0,0,1,0,0],[0,0,1,0,0,0],[0,1,0,0,0,0]に近い値が返ってくる
有限オートマトンとか、ある種の文法構造を学習することができるっぽいけど、他の文法推論アルゴリズムと比べて、大規模な文法の推論には向かないらしい