ニューラルネットワークのべんきょー

やろうやろうと思ってなかなか手を付けられなかったニューラルネットワークにようやく手を出しました。

こちらの本のソースをPythonに書き換えて試してみました。ちゃんと組めているかは些か怪しいですけど。

ゲーム開発者のためのAI入門



入力層、中間層、出力層の3層からなるネットワークです。
nn_fig.png

ひとつハマったのが、この本のソースの一部、たぶん、足りない部分があります。

LinearOutputで出力層のニューロンの活性化関数を線形関数にした場合は、学習の際のニューロンの値の計算の部分も線形関数にしてあげないと、実際の出力値と学習の際に計算している出力値に食い違いが起こってしまうので、出力値がマイナスになった場合などに、収束せずに拡散してしまいます。

ためしにサイン関数を0~2πの範囲で学習させてみました。

nn_result.png
凡例の数字は、入力層、中間層、出力層のニューロンの数を表しています。
教師データは、ランダムに10000組ほど学習させています。

入力、出力は1つでいいのかなーっと思っていたんですが、どうも出力が1つだと凸1つの傾向しか示さないので、試しに2つにしたら、0以下の出力が出来ませんでした。んー多分これミスです。
コーディングでミスってるのか、アルゴリズム自体に問題があるのか、なんでしょうねぇもう。

ちなみに、0~πまでだとこんな。割かし似ている。
nn_result2.png

僕はてっきりニューラルネットワークはこんな結果を返してくれると思ってたんですけど。うーん、これ合ってんの?ニューロンの数足らんのかな。


ソース(NeuralNetwork_1_py.txt
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
import random
import math
 
learning_rate = 0.25
momentum_factor = 0.5
 
class Node:
def __init__(self,no):
self.no = no
self.value = 0
self.targetValue= 0
self.bias = 1.0
self.biasWeight = 0
self.error = 0
 
def setLayer(self,layer):
self.layer = layer
self.weights = []
self.weightChanges = []
if layer.childLayer:
for n in layer.childLayer.nodes:
self.weights.append(0)
self.weightChanges.append(0)
 
class Layer:
useMomentum = True
useLinear = True
parentLayer = None
childLayer = None
nodes = []
 
def __init__(self,nodes_num):
self.parentLayer = None
self.childLayer = None
self.nodes = []
 
for i in range(nodes_num):
node = Node(i)
self.nodes.append(node)
 
def setup(self):
for node in self.nodes:
node.setLayer(self)
 
def randWeights(self):
for node in self.nodes:
node.biasWeight = random.random()*2-1
for cnode in node.layer.childLayer.nodes:
node.weights[cnode.no] = random.random()*2-1
 
def calcuValues(self):
if self.parentLayer:
for node in self.nodes:
value = 0
for pnode in self.parentLayer.nodes:
value += pnode.value * pnode.weights[node.no]
value += node.bias * node.biasWeight
 
if self.childLayer==None and self.useLinear:
node.value = value
else:
node.value = 1.0 / (1+math.exp(-value))
 
 
def calcuErrors(self):
errs = 0
for node in self.nodes:
if not self.childLayer: #output layer
if self.useLinear:
node.error = node.targetValue - node.value
else:
node.error = ((node.targetValue - node.value)*
node.value*(1.0-node.value))
elif not self.parentLayer: #input layer
node.error = 0
else: #hidden layer
su = 0
for cnode in self.childLayer.nodes:
su += cnode.error * node.weights[cnode.no]
node.error = su*node.value*(1.0-node.value)
 
def adjustWeights(self):
if self.childLayer:
for node in self.nodes:
for cnode in self.childLayer.nodes:
dw = learning_rate*cnode.error*node.value
if self.useMomentum:
wc = node.weightChanges[cnode.no]
node.weights[cnode.no] += dw+momentum_factor*wc
node.weightChanges[cnode.no] = dw
else:
node.weights[cnode.no] += dw
 
 
for cnode in self.childLayer.nodes:
cnode.baisWeight = (learning_rate *
cnode.error *
cnode.bias)
 
class Network:
 
def __init__(self,input_node_num,
hidden_node_num,
output_node_num):
self.inputLayer = Layer(input_node_num)
self.hiddenLayer= Layer(hidden_node_num)
self.outputLayer = Layer(output_node_num)
 
self.inputLayer.parentLayer = None
self.inputLayer.childLayer = self.hiddenLayer
self.inputLayer.setup()
self.inputLayer.randWeights()
 
self.hiddenLayer.parentLayer = self.inputLayer
self.hiddenLayer.childLayer = self.outputLayer
self.hiddenLayer.setup()
self.hiddenLayer.randWeights()
 
self.outputLayer.parentLayer = self.hiddenLayer
self.outputLayer.childLayer = None
self.outputLayer.setup()
 
def setInput(self,no,value):
node = self.inputLayer.nodes[no]
node.value= value
 
def getOutput(self,no):
node = self.outputLayer.nodes[no]
return node.value
 
def setTargetOutput(self,no,value):
node = self.outputLayer.nodes[no]
node.targetValue = value
 
def feedForward(self):
self.inputLayer.calcuValues()
self.hiddenLayer.calcuValues()
self.outputLayer.calcuValues()
 
def backPropagate(self):
self.outputLayer.calcuErrors()
self.hiddenLayer.calcuErrors()
 
self.hiddenLayer.adjustWeights()
self.outputLayer.adjustWeights()
 
def getMaxOutputNo(self):
max_value = self.outputLayer.nodes[0].value
max_no = 0
for node in self.outputLayer.nodes:
if node.value > max_value:
max_value = node.value
max_no = node.no
return max_no
 
def calcuError(self):
err = 0
for node in self.outputLayer.nodes:
try:
err += (node.value - node.targetValue)**2
except OverflowError:
print("OverflowError")
exit()
 
err = err / len(self.outputLayer.nodes)
return err
 
def test():
nw = Network(1,6,1)
 
#learning
total_n = 0
x,max_x = 0,math.pi
for n in range(10000):
x = random.randint(0,int(max_x*100))
x = x/100
nw.setInput(0,x)
nw.setTargetOutput(0,math.sin(x))
while True:
nw.feedForward()
nw.backPropagate()
e = nw.calcuError()
total_n += 1
if e < 0.001: break
r = nw.getOutput(nw.getMaxOutputNo())
pr = (n,x,r,math.sin(x),e)
#print "%3d: %3.2f => %.5f(%.5f) err:%.5f" % pr
print "total %s cycle:" % total_n
 
#make table
f = open("test.csv",'w')
f.write("x,sinx,result\n")
x,sp = 0,0.05
for i in range(int(max_x/sp)+1):
nw.setInput(0,x)
nw.feedForward()
r = nw.getOutput(nw.getMaxOutputNo())
f.write("%s,%s,%s\n" % (x,math.sin(x),r))
x += sp
f.close()
 
def main():
test()
 
main()
 

関連記事

コメント

コメントの投稿

非公開コメント

このブログについて
□ ブログ内容
決まった趣旨はありません。
興味を持ったこと・日常で行ったことを何でも書きます。

3DCG・プログラミングなどが多めです。

□ 現在の活動
・ウェブサイト制作
 (http://tiblab.net)
・3Dゲーム制作
 (コックパニック)
検索フォーム
ユーザータグ

Blender キャプチャ blendファイル BGE Python GameEngine ムービー Android CG  Red5 Terragen C# C++ 

カテゴリー
プロフィール

TiBra

Author:TiBra
趣味でCG制作、プログラミング等を行っています。メイカーズに憧れています。

ネットを通じた交流を広げたく思っていますので、コメント・メールはお気軽にどぞー

戯言程度のことは、こちらのブログに投稿しています。基本戯言なので、実質移転しているようなものです。

Mail:tibraあっとlive.jp
HP:TibLabmemocode
動画:VimeoFC2動画ニコニコ
ファイル:SkyDrive
企画:3Dゲーム作業実況

Blogリンク
不都合がございましたらご連絡ください。
当ブログのリンクバナー
FC2 ID
FC2カウンター
RSSフィード+解析コード