| 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
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
|
# imported modules
from pyrobot.brain import Brain
from pyrobot.brain.conx import *
from pyrobot.gui.plot.scatter import *
from pyrobot.gui.plot.hinton import *
import pyrobot.brain.ravq
import os
import time
import sys
# log file directories
rootDirectory = "/home/stober/ravq/experiments/"
currentExperiment = "Nolfi_RAVQ_Long/"
currentBrain = "/home/stober/ravq/Nolfi_Ravq.py"
class RAVQBrain(Brain):
"""A brain that uses a RAVQ to classify hidden layer activations in a prediction network."""
def setup(self):
# robot parameters
self.robot.range.units = 'ROBOTS'
self.maxvalue = self.robot.range.getMaxvalue()
# status variables
self.verbosity = 1
self.direction = 1
self.blockedFront = 0
self.wasStalled = 0
self.counter = 0
self.previous = [0.0, 0.0]
# tweakable params
self.timer = 50000 # turns on hiddenRavq
self.stop = 100000
self.sleepTime = 0.1
self.backupTimer = 10000
# create network
self.net = SRN()
self.net.setSequenceType("ordered-continuous")
self.inSize = self.robot.range.count + 2
self.net.addLayers(self.inSize, self.inSize/2, 2)
# defaults - but here explicit
self.net.setBatch(0)
self.net.setInteractive(0)
self.net.setVerbosity(0)
self.net.setInitContext(0)
# initialize network
self.net.initialize()
# learning parameters
self.net.setEpsilon(0.2)
self.net.setMomentum(0.1)
self.net.setTolerance(0.05)
# set learning
self.net.setLearning(1)
# hidden ravq (tweakable parameters)
self.hiddenRavq = pyro.brain.ravq.ARAVQ(10, .2, .5, .03)
self.hiddenRavq.setHistory(0)
self.hiddenRavq.setAddModels(0)
self.hiddenRavq.setLearning(0)
# input ravq (tweakable parameters)
self.inputRavq = pyro.brain.ravq.ARAVQ(10, .2, .6, .03)
self.inputRavq.setHistory(0)
self.inputRavq.setAddModels(1)
self.inputRavq.setLearning(1)
# file IO
self.path = rootDirectory + currentExperiment
if(os.path.isfile(self.path + "exp.lock")):
raise "Lock error!"
else:
try:
os.mkdir(self.path)
except:
pass
lock = open(self.path + "exp.lock", "w")
lock.write("This file locks the experiment directory to prevent overwriting experimental data.")
lock.close()
# archive brain
os.system("cp " + currentBrain + " " + self.path + "archive.py")
self.netInfo = open(self.path + 'nn.dat', 'w')
self.hiddenRavq.openLog(self.path + 'hidden_history.log')
self.hiddenRavqInfo = open(self.path + 'hidden_ravq.dat', 'w')
self.inputRavq.openLog(self.path + 'input_history.log')
self.inputRavqInfo = open(self.path + 'input_ravq.dat', 'w')
self.repositionLog = open(self.path + 'reposition.dat', 'w')
# gui displays
self.plot1 = Scatter()
self.plot1.setTitle('Target: Translate x Rotate')
self.plot2 = Scatter()
self.plot2.setTitle('Activation: Translate x Rotate')
self.hidd = Hinton(self.inSize/2, title = 'Hidden Layer')
self.inputs = Hinton(self.inSize, title = 'Input Layer')
def destroy(self):
self.plot1.destroy()
self.plot2.destroy()
self.hidd.destroy()
self.inputs.destroy()
self.netInfo.close()
self.hiddenRavq.closeLog()
self.hiddenRavqInfo.close()
self.inputRavq.closeLog()
self.inputRavqInfo.close()
self.repositionLog.close()
del self.net
del self.hiddenRavq
del self.inputRavq
def scaleSensors(self, val):
"""From Robots (or anything) to [0, 1]"""
return (val / self.maxvalue)
def scaleMotors(self, val):
"""[-1, 1] to [0, 1]"""
return (val + 1) / 2.0
def kick(self):
"""How to get unstuck."""
self.wasStalled += 1
self.repositionLog.write("STALLED " + str(self.counter) + "\n")
self.move(0.1, 0.0)
time.sleep(.2)
if self.robot.stall:
self.move(-0.1, 0.0)
time.sleep(.2)
if self.robot.stall and self.wasStalled > 10:
self.repositionLog.write("Cannot fix stall at " + str(self.counter) + " " + \
str(self.robot.simulation[0].getPose("Pioneer")')) +
" so repositioning to (796, 2211, 92).\n")
# we'll call this the hand of god
self.set('robot/truth/pose', (796, 2211, 92))
else:
self.wasStalled = 0
def controller(self):
# tweakable parameters
minRange = 0.85
maxRange = 1.25
#rand = random.random() * 0.5
rand = 0.25
# important sensors
minFront = min([s.value for s in self.robot.range["front"]])
minLeft = min([s.value for s in self.robot.range["front-left"]])
minRight = min([s.value for s in self.robot.range["front-right"]])
left = min([s.value for s in self.robot.range["left"]])
right = min([s.value for s in self.robot.range["right"]])
# the decision algorithm
if minFront < minRange:
if not self.blockedFront:
if right < left:
self.direction = 1
else:
self.direction = -1
self.blockedFront = 1
return [0, self.direction * rand]
elif minLeft < minRange:
if self.blockedFront:
return [0, self.direction * rand]
else:
return [rand, -rand]
elif minLeft > maxRange:
if self.blockedFront:
return [0, self.direction * rand]
else:
return [rand, rand]
elif minRight < minRange:
if self.blockedFront:
return [0, self.direction * rand]
else:
return [rand, rand]
else:
self.blockedFront = 0
return [0.5, 0.0]
def backup(self, tag):
self.net.saveWeightsToFile(self.path + "predict" + str(tag) + ".wts")
self.inputRavq.saveRAVQToFile(self.path + "input_ravq" + str(tag) + ".pck")
self.hiddenRavq.saveRAVQToFile(self.path + "hidden_ravq" + str(tag) + ".pck")
def step(self):
"""
1. Determine new motor values.
2. Determine inputs (old sensors + old motors).
3. Step through with new motor values as targets.
4. Move robot.
5. New motor values become old motor values.
"""
# display count
if self.verbosity > 0: print self.counter
# switch between training network and training ravq
if self.counter == self.timer:
self.net.setLearning(0)
self.hiddenRavq.setAddModels(1)
self.hiddenRavq.setLearning(1)
self.net.saveNetworkToFile(self.path + "predict")
self.net.saveWeightsToFile(self.path + "predict.wts")
elif self.counter == self.stop:
self.hiddenRavq.logHistory(0, str(self.robot.simulation[0],getPose('Pioneer')))
self.hiddenRavqInfo.write(str(self.hiddenRavq))
self.hiddenRavq.saveRAVQToFile(self.path + "hidden_ravq.pck")
self.inputRavq.logHistory(0, str(self.robot.simulation[0].getPose('Pioneer')))
self.inputRavqInfo.write(str(self.inputRavq))
self.inputRavq.saveRAVQToFile(self.path + "input_ravq.pck")
self.pleaseStop()
self.destroy()
else:
# train network or ravq
motors = self.controller()
inputs = [self.scaleSensors(s.value) for s in self.robot.range["all"] + map(self.scaleMotors, self.previous)
(error, correct, total) = self.net.step( input = inputs, \
output = map(self.scaleMotors, motors))
self.inputRavq.input(inputs)
# hidden ravq
if self.counter > self.timer:
self.hiddenRavq.input(self.net['hidden'].activation)
self.hiddenRavq.logHistory(0, \
str(self.robot.simulation[0].getPose('Pioneer')))
# backup sometimes
if self.counter % self.backupTimer == 0:
self.backup(self.counter)
# other IO
self.inputRavq.logHistory(0, \
str(self.robot.simulation[0].getPose('Pioneer')))
self.netInfo.write(str(self.counter) + " " + str(error) + "\n")
self.plot1.addPoint(self.scaleMotors(motors[0]), self.scaleMotors(motors[1]))
self.plot2.addPoint(self.net['output'].activation[0], \
self.net['output'].activation[1])
self.hidd.update(self.net['hidden'].activation)
self.inputs.update(self.net['input'].activation)
if self.verbosity > 0: print (error, correct, total)
# move robot
self.move(motors[0], motors[1])
self.previous = motors
# kick if things get bad
if self.robot.stall:
self.kick()
# sleep and increment counter
time.sleep(self.sleepTime)
self.counter += 1
def INIT(engine):
return RAVQBrain('RAVQBrain', engine) |