def testCount(): rows = 5 cols = 5 coverage = 20 numbits = 10 numRounds = 500 trainingRounds = numRounds/4 originalInputVector = InputVector(numbits) inputVector = InputVector(0) predictions = dict() #repeat several times to increase activity: for i in range(3): inputVector.extendVector(originalInputVector) desiredLocalActivity = DESIRED_LOCAL_ACTIVITY newRegion = Region(rows,cols,inputVector,coverage,desiredLocalActivity) outputVector = newRegion.getOutputVector() correctBitPredictions = 0 for round in range(numRounds): # This test executes the CLA for a set number of rounds. #print("Round: " + str(round)) # if (round % 2 == 0): # val = 682 # else: # val = 341 val = Ultrasonic(brick, PORT_1).get_sample() setInput(originalInputVector,val) inputString = inputVector.toString() outputString = outputVector.toString() #print(originalInputVector.toString()) #for bit in originalInputVector.getVector(): # print(bit.bit) # print('') # print(inputString) if outputString in predictions: currentPredictionString = predictions[outputString] else: currentPredictionString = "[New input]" pred[outputString] = inputString print("Round: %d" % round) # Prints the number of the round printStats(inputString, currentPredictionString) if (round > trainingRounds): correctBitPredictions += stringOverlap(currentPredictionString, predictions[outputString]) newRegion.doRound() printColumnStats(newRegion) for key in predictions: print("key: " + key + " predictions: " + predictions[key]) print("Accuracy: " + str(float(correctBitPredictions)/float((30*(numRounds-trainingRounds)))))
def testCount(): rows = 5 cols = 5 coverage = 20 numbits = 10 numRounds = 500 trainingRounds = numRounds / 4 originalInputVector = InputVector(numbits) inputVector = InputVector(0) pred = dict() #repeat several times to increase activity: for i in range(3): inputVector.extendVector(originalInputVector) desiredLocalActivity = DESIRED_LOCAL_ACTIVITY r = Region(rows, cols, inputVector, coverage, desiredLocalActivity) outputVector = r.getOutputVector() correctBitPredctions = 0 for round in range(numRounds): #print("Round: " + str(round)) # if (round % 2 == 0): # val = 682 # else: # val = 341 val = round % 30 setInput(originalInputVector, val) inputString = inputVector.toString() outputString = outputVector.toString() # for bit in inputVector.getVector(): # printBit(bit) # print('') # print(inputString) if outputString in pred: curPredString = pred[outputString] else: curPredString = "[New input]" pred[outputString] = inputString printStats(inputString, curPredString) if (round > trainingRounds): correctBitPredctions += stringOverlap(curPredString, pred[outputString]) r.doRound() printColumnStats(r) for key in pred: print("key: " + key + " pred: " + pred[key]) print("Accuracy: " + str( float(correctBitPredctions) / float((30 * (numRounds - trainingRounds)))))
class Region: """An HTM cortical region""" # Array of columns in 2D for inhibition. Not my prefered geomertry, # but I'm working from a fork. I may make it a 1D geometry at some point. def __init__(self,rows,cols,inputVector,coverage,desiredLocalActivity): self.rows = rows self.cols = cols self.desiredLocalActivity=desiredLocalActivity self.columns = [Column() for i in range(self.rows*self.cols)] self.mapRegionToInputVector(inputVector,coverage) self.mapRegionToOutputVector() self.inhibitionRadius = min(INITIAL_INHIBITION_RADIUS,self.rows,self.cols) self.updateColumnNeighbors() def mapRegionToOutputVector(self): self.outputVector = InputVector(0) for c in self.columns: self.outputVector.extendVector(c.getOutputBits()) def mapRegionToInputVector(self,inputVector,coverage): # get the length of the input, and for each input bit assign # it to X columns randomly self.inputVector = inputVector for bitIndex in range(self.inputVector.getLength()): columnIndices = random.sample(range(len(self.columns)),coverage) for ci in columnIndices: self.columns[ci].mapColumnToInput(inputVector.getBit(bitIndex)) def getOutputVector(self): return self.outputVector def convert2Dindex(self,row,col,numCols): return row*(numCols) + col def computeNeighbors(self,cx,cy,radius): neighbors = [] for dy in range(-radius,radius+1): for dx in range(-radius,radius+1): # enforce circular shape. optional if (dy*dy+dx*dx > radius*radius): continue x = cx + dx y = cy + dy #wrap around: upper boundary check x = self.rows + x if (x < 0) else x y = self.cols + y if (y < 0) else y #wrap around: lower boundary check x = x - self.rows if (x >= self.rows) else x y = y - self.cols if (y >= self.cols) else y index = self.convert2Dindex(x,y,self.cols) #if (index < 0 or index >= len(self.columns)): #print('radius is' + str(radius)) #print("bad: " + str(cx) + ", " + str(cy) + ", " + str(x) + ", " + str(y) + ", " + str(dx) + ", " + str(dy)) n = self.columns[index] if (neighbors.count(n) == 0): neighbors.append(n) return neighbors def updateColumnNeighbors(self): for i in range(self.rows): for j in range(self.cols): index = self.convert2Dindex(i,j,self.cols) c = self.columns[index] c.setNeighbors(self.computeNeighbors(i,j,self.inhibitionRadius)) def updateInhibitionRadius(self): r = 0.0 for c in self.columns: r += c.getNumConnectedProximalSynapses() r /= len(self.columns) maxRadius = min(self.cols,self.rows) r = min(r,maxRadius) self.inhibitionRadius = int(r) self.updateColumnNeighbors() def getAllLearningCells(self,step): learningCellList = [] for c in self.columns: learningCells = c.getLearningCells(step) learningCellList.extend(learningCells) return learningCellList def spatialPoolerRun(self): [c.updateOverlap() for c in self.columns] [c.updateActiveState(self.desiredLocalActivity) for c in self.columns] [c.updateBoost() for c in self.columns] [c.updateActiveDutyCycle() for c in self.columns] self.updateInhibitionRadius() #DEBUG THIS count = 0 for c in self.columns: if c.active: count += 1 count = 0 for c in self.columns: for cell in c.cells: if cell.isActive(CURRENT_TIME_STEP): count += 1 def temporalPoolerRun(self): [c.advanceTimeStep() for c in self.columns] allLearningCells = self.getAllLearningCells(PREVIOUS_TIME_STEP) [c.updateCellActivity(allLearningCells) for c in self.columns] [c.updateCellPrediction(allLearningCells) for c in self.columns] [c.updateCellLearning() for c in self.columns] def doRound(self): self.spatialPoolerRun() self.temporalPoolerRun()
class Region: """An HTM cortical region""" #array of columns or 2D for inhibition def __init__(self, rows, cols, inputVector, coverage, desiredLocalActivity): self.rows = rows self.cols = cols self.desiredLocalActivity = desiredLocalActivity self.columns = [Column() for i in range(self.rows * self.cols)] self.mapRegionToInputVector(inputVector, coverage) self.mapRegionToOutputVector() self.inhibitionRadius = min(INITIAL_INHIBITION_RADIUS, self.rows, self.cols) self.updateColumnNeighbors() def mapRegionToOutputVector(self): self.outputVector = InputVector(0) for c in self.columns: self.outputVector.extendVector(c.getOutputBits()) def mapRegionToInputVector(self, inputVector, coverage): # get the length of the input, and for each input bit assign # it to X columns randomly self.inputVector = inputVector for bitIndex in range(self.inputVector.getLength()): columnIndices = random.sample(range(len(self.columns)), coverage) for ci in columnIndices: self.columns[ci].mapColumnToInput(inputVector.getBit(bitIndex)) def getOutputVector(self): return self.outputVector def convert2Dindex(self, row, col, numCols): return row * (numCols) + col def computeNeighbors(self, cx, cy, radius): neighbors = [] for dy in range(-radius, radius + 1): for dx in range(-radius, radius + 1): # enforce circular shape. optional if (dy * dy + dx * dx > radius * radius): continue x = cx + dx y = cy + dy #wrap around: upper boundary check x = self.rows + x if (x < 0) else x y = self.cols + y if (y < 0) else y #wrap around: lower boundary check x = x - self.rows if (x >= self.rows) else x y = y - self.cols if (y >= self.cols) else y index = self.convert2Dindex(x, y, self.cols) #if (index < 0 or index >= len(self.columns)): #print('radius is' + str(radius)) #print("bad: " + str(cx) + ", " + str(cy) + ", " + str(x) + ", " + str(y) + ", " + str(dx) + ", " + str(dy)) n = self.columns[index] if (neighbors.count(n) == 0): neighbors.append(n) return neighbors def updateColumnNeighbors(self): for i in range(self.rows): for j in range(self.cols): index = self.convert2Dindex(i, j, self.cols) c = self.columns[index] c.setNeighbors( self.computeNeighbors(i, j, self.inhibitionRadius)) def updateInhibitionRadius(self): r = 0.0 for c in self.columns: r += c.getNumConnectedProximalSynapses() r /= len(self.columns) maxRadius = min(self.cols, self.rows) r = min(r, maxRadius) self.inhibitionRadius = int(r) self.updateColumnNeighbors() def getAllLearningCells(self, step): learningCellList = [] for c in self.columns: learningCells = c.getLearningCells(step) learningCellList.extend(learningCells) return learningCellList def spatialPoolerRun(self): [c.updateOverlap() for c in self.columns] [c.updateActiveState(self.desiredLocalActivity) for c in self.columns] [c.updateBoost() for c in self.columns] [c.updateActiveDutyCycle() for c in self.columns] self.updateInhibitionRadius() #DEBUG THIS count = 0 for c in self.columns: if c.active: count += 1 count = 0 for c in self.columns: for cell in c.cells: if cell.isActive(CURRENT_TIME_STEP): count += 1 def temporalPoolerRun(self): [c.advanceTimeStep() for c in self.columns] allLearningCells = self.getAllLearningCells(PREVIOUS_TIME_STEP) [c.updateCellActivity(allLearningCells) for c in self.columns] [c.updateCellPrediction(allLearningCells) for c in self.columns] [c.updateCellLearning() for c in self.columns] def doRound(self): self.spatialPoolerRun() self.temporalPoolerRun()
def testCount(): rows = 5 cols = 5 coverage = 20 numbits = 10 # I may need more bits for my readngs. numRounds = 500 trainingRounds = numRounds/4 originalInputVector = InputVector(numbits) inputVector = InputVector(0) predictions = dict() # Repeat several times to increase activity: # Seems to just extend the number of elements in inputVector by numbits (10) 3 times. # Why not extend it by 3*numbits? # I think becuase rather than make it 3 times as long, it actually repeats the vector three times, # probably so as to, as said above, increase activity in those cells and aid learning. # Good old repartition. In which case, I'm not sure I want to use this in my tests... for i in range(3): inputVector.extendVector(originalInputVector) # Get a non-local variable and feed it to a local one for local manipulation. desiredLocalActivity = DESIRED_LOCAL_ACTIVITY # This sets up a new region, called newRegion, # a variable called ouputVector, which calls a method to find just that, # and a variable for the number of correct prodicitons, initialised as 0. newRegion = Region(rows,cols,inputVector,coverage,desiredLocalActivity) outputVector = newRegion.getOutputVector() correctBitPredictions = 0 # This is where the action starts. This loop forms the main body of the test. # For every time round, an input is given, the CLA updates spacial and temporal # poolers with this new input and an output is found. for round in range(numRounds): # The old version gave two inputs alternatly. The aim was to get the CLA to # predict one of two numbers. #print("Round: " + str(round)) # if (round % 2 == 0): # val = 682 # else: # val = 341 val = Ultrasonic(brick, PORT_1).get_sample() # Instead I'm now feeding in readings from the sonar. setInput(originalInputVector,val) # These next few lines convert the inputs and outputs from integers to bitstrings, inputString = inputVector.toString() # so that the CLA can handle them. outputString = outputVector.toString() #print(originalInputVector.toString()) #for bit in originalInputVector.getVector(): # print(bit.bit) # print('') # print(inputString) if outputString in predictions: # predictions was set up at the start, you might have missed it. currentPredictionString = predictions[outputString] else: currentPredictionString = "[New input]" predictions[outputString] = inputString # I'm sure this line should be here. It's not indented in the origonal. print("Round: %d" % round) # Prints the number of the round printStats(inputString, currentPredictionString) if (round > trainingRounds): correctBitPredictions += stringOverlap(currentPredictionString, predictions[outputString]) newRegion.doRound() # The CLA bit! printColumnStats(newRegion) # With the experiment now over, stat summaries are now printed. for key in predictions: print("key: " + key + " predictions: " + predictions[key]) print("Accuracy: " + str(float(correctBitPredictions)/float(30*(numRounds-trainingRounds))))
def experiment(): rows = 5 cols = 5 coverage = 20 numbits = 10 # I may need more bits for my readngs. numRounds = 10 numRuns = 1 minimum_distance = 7 #trainingRounds = numRounds/4 accuracies = [] sonarPositionResults = [] originalInputVector = InputVector(numbits) inputVector = InputVector(0) predictions = dict() state = "Going Forwards" # Repeat several times to increase activity: # Seems to just extend the number of elements in inputVector by numbits (10) 3 times. # Why not extend it by 3*numbits? # I think becuase rather than make it 3 times as long, it actually repeats the vector three times, # probably so as to, as said above, increase activity in those cells and aid learning. # Good old repartition. In which case, I'm not sure I want to use this in my tests... for i in range(3): inputVector.extendVector(originalInputVector) # Get a non-local variable and feed it to a local one for local manipulation. desiredLocalActivity = DESIRED_LOCAL_ACTIVITY # This sets up a new region, called newRegion, # a variable called ouputVector, which calls a method to find just that, # and a variable for the number of correct prodicitons, initialised as 0. newRegion = Region(rows,cols,inputVector,coverage,desiredLocalActivity) outputVector = newRegion.getOutputVector() correctBitPredictions = 0 robot = Robot() starting_position = robot.sonarReading() robot.move() # This is where the action starts. This loop forms the main body of the test. # For every time round, an input is given, the CLA updates spacial and temporal # poolers with this new input and an output is found. for round in range(numRounds): if state == "Kill Switch: Engage!": break end_this_round = False stuck_counter = 0 print state round_number = round+1 print ("Round: %d" % round_number) # Prints the number of the round #printStats(inputString, currentPredictionString) robot.move() while end_this_round is False: val = robot.sonarReading() print ("Sonar: %d cm" % val) sonarPositionResults.append(robot.currentSonarReading) setInput(originalInputVector,val) # These next few lines convert the inputs and outputs from integers to bitstrings, inputString = inputVector.toString() # so that the CLA can handle them. outputString = outputVector.toString() #print(originalInputVector.toString()) #for bit in originalInputVector.getVector(): #print(bit.bit) #print('') #print(inputString) if outputString in predictions: # If output string has been seen before, currentPredictionString = predictions[outputString] # summon the last input that caused that prediction and make it the "currentPredictionString"? That's confusing... else: currentPredictionString = "[New input]" # If not seen before, predictions[outputString] = inputString # Update the i/o record with the new relationship #if (round > trainingRounds): correctBitPredictions += stringOverlap(currentPredictionString, predictions[outputString]) # without training rounds, stringOverlap will be trying to compare binary stings with the string 'New input'. So correct BitPredictions is going to be 0 for a while, # until inputs start repeating. newRegion.runCLA() # The CLA bit! numRuns += 1 #printColumnStats(newRegion) accuracy = float(correctBitPredictions)/float(30*numRuns) # Times thirty becuase it's measuring the correct prediction of BITS not whole bit-strings, and there are 30 bits per input. # This makes sense as bits have semantic meaning where as bit-strings dont! accuracies.append(accuracy) if robot.killSwitch() == True: # This will terminate all loops and move to the end of the program end_this_round = True state = "Kill Switch: Engage!" print state if state == "Going Forwards": if robot.currentSonarReading <= minimum_distance: stuck_counter += 1 if stuck_counter == 2: # This routine confirms that a wall is hit, then sends the robot back to the start position robot.stop() print "Stuck Reflex" state = "Reversing" print state stuck_counter = 0 robot.move(-75) if state == "Reversing": if (starting_position-3) < robot.currentSonarReading < (starting_position+3): # Clean this up state = "Going Forwards" end_this_round = True # With the experiment now over, stat summaries are now printed. # for key in predictions: # print("key: " + key + " predictions: " + predictions[key]) robot.stop() #print("Accuracy: " + str(float(correctBitPredictions)/float(30*(numRounds-trainingRounds)))) #code below prints a graph of runs against accuracies runs = np.arange(1, numRuns, 1) plt.figure(1) plt.subplot(211) plt.grid(True) plt.plot(runs, accuracies) plt.plot(runs, accuracies, 'bo') plt.ylabel('Accuracy (correct preditions/predictions)') plt.title('Change in CLA accuracy of sonar position prediction') plt.subplot(212) plt.grid(True) plt.plot(runs, sonarPositionResults, 'r-') plt.plot(runs, sonarPositionResults, 'ro') plt.ylabel('Sonar Readings (cm)') plt.xlabel('Number of CLA runs') plt.show()