def experiment(numColumns, sampleSize): locationSDRsByColumn = [dict((name, set(random.sample(xrange(1024), 40))) for name in LOCATIONS) for _ in xrange(numColumns)] featureSDRsByColumn = [dict((name, set(random.sample(xrange(1024), 40))) for name in FEATURES) for _ in xrange(numColumns)] exp = L4L2Experiment( "Hello", numCorticalColumns=numColumns, L2Overrides={ "sampleSizeDistal": sampleSize, }, seed=random.randint(2048, 4096) ) exp.learnObjects(dict((objectName, [dict((column, (locationSDRsByColumn[column][location], featureSDRsByColumn[column][features[location]])) for column in xrange(numColumns)) for location in LOCATIONS]) for objectName, features in OBJECTS.iteritems())) objectName = "Object 1" features = OBJECTS[objectName] inferredL2 = exp.objectL2Representations[objectName] touchCount = 0 for sensorPositions in greedySensorPositions(numColumns, len(LOCATIONS)): sensation = dict( (column, (locationSDRsByColumn[column][sensorPositions[column]], featureSDRsByColumn[column][features[sensorPositions[column]]])) for column in xrange(numColumns)) exp.infer([sensation]*TIMESTEPS_PER_SENSATION, reset=False, objectName=objectName) touchCount += 1 if exp.getL2Representations() == inferredL2: print "Inferred object after %d touches" % touchCount return touchCount if touchCount >= 60: print "Never inferred object" return None
def experiment(numColumns, sampleSize): locationSDRsByColumn = [ dict((name, set(random.sample(xrange(1024), 40))) for name in LOCATIONS) for _ in xrange(numColumns) ] featureSDRsByColumn = [ dict((name, set(random.sample(xrange(1024), 40))) for name in FEATURES) for _ in xrange(numColumns) ] exp = L4L2Experiment("Hello", numCorticalColumns=numColumns, L2Overrides={ "sampleSizeDistal": sampleSize, }, seed=random.randint(2048, 4096)) exp.learnObjects( dict((objectName, [ dict((column, (locationSDRsByColumn[column][location], featureSDRsByColumn[column][features[location]])) for column in xrange(numColumns)) for location in LOCATIONS ]) for objectName, features in OBJECTS.iteritems())) objectName = "Object 1" features = OBJECTS[objectName] inferredL2 = exp.objectL2Representations[objectName] touchCount = 0 for sensorPositions in greedySensorPositions(numColumns, len(LOCATIONS)): sensation = dict( (column, (locationSDRsByColumn[column][sensorPositions[column]], featureSDRsByColumn[column][features[sensorPositions[column]]])) for column in xrange(numColumns)) exp.infer([sensation] * TIMESTEPS_PER_SENSATION, reset=False, objectName=objectName) touchCount += 1 if exp.getL2Representations() == inferredL2: print "Inferred object after %d touches" % touchCount return touchCount if touchCount >= 60: print "Never inferred object" return None
def doExperiment(numColumns, l2Overrides, objectDescriptions, noiseMu, noiseSigma, numInitialTraversals, noiseEverywhere): """ Touch every point on an object 'numInitialTraversals' times, then evaluate whether it has inferred the object by touching every point once more and checking the number of correctly active and incorrectly active cells. @param numColumns (int) The number of sensors to use @param l2Overrides (dict) Parameters for the ColumnPooler @param objectDescriptions (dict) A mapping of object names to their feature-locations. See 'createRandomObjectDescriptions'. @param noiseMu (float) The average amount of noise in a feedforward input. The noise level for each column's input is determined once per touch. It is a gaussian distribution with mean 'noiseMu' and sigma 'noiseSigma'. @param noiseSigma (float) The sigma for the gaussian distribution of noise levels. If the noiseSigma is 0, then the noise level will always be 'noiseMu'. @param numInitialTraversals (int) The number of times to traverse the object before testing whether the object has been inferred. @param noiseEverywhere (bool) If true, add noise to every column's input, and record accuracy of every column. If false, add noise to one column's input, and only record accuracy of that column. """ # For each column, keep a mapping from feature-location names to their SDRs layer4sdr = lambda: np.array( sorted(random.sample(xrange(L4_CELL_COUNT), 40)), dtype="uint32") featureLocationSDRs = [defaultdict(layer4sdr) for _ in xrange(numColumns)] params = { "inputWidth": L4_CELL_COUNT, "lateralInputWidths": [4096] * (numColumns - 1), "seed": random.randint(0, 1024) } params.update(l2Overrides) l2Columns = [ColumnPooler(**params) for _ in xrange(numColumns)] # Learn the objects objectL2Representations = {} for objectName, featureLocations in objectDescriptions.iteritems(): for featureLocationName in featureLocations: # Touch it enough times for the distal synapses to reach the # connected permanence, and then once more. for _ in xrange(4): allLateralInputs = [l2.getActiveCells() for l2 in l2Columns] for columnNumber, l2 in enumerate(l2Columns): feedforwardInput = featureLocationSDRs[columnNumber][ featureLocationName] lateralInputs = [ lateralInput for i, lateralInput in enumerate(allLateralInputs) if i != columnNumber ] l2.compute(feedforwardInput, lateralInputs, learn=True) objectL2Representations[objectName] = [ set(l2.getActiveCells()) for l2 in l2Columns ] for l2 in l2Columns: l2.reset() results = [] # Try to infer the objects for objectName, featureLocations in objectDescriptions.iteritems(): for l2 in l2Columns: l2.reset() sensorPositionsIterator = greedySensorPositions( numColumns, len(featureLocations)) # Touch each location at least numInitialTouches times, and then touch it # once more, testing it. For each traversal, touch each point on the object # ~once. Not once per sensor -- just once. So we translate the "number of # traversals" into a "number of touches" according to the number of sensors. numTouchesPerTraversal = len(featureLocations) / float(numColumns) numInitialTouches = int( math.ceil(numInitialTraversals * numTouchesPerTraversal)) if noiseEverywhere: numTestTouches = int(math.ceil(1 * numTouchesPerTraversal)) else: numTestTouches = len(featureLocations) for touch in xrange(numInitialTouches + numTestTouches): sensorPositions = next(sensorPositionsIterator) # Give the system a few timesteps to settle, allowing lateral connections # to cause cells to be inhibited. for _ in xrange(3): allLateralInputs = [l2.getActiveCells() for l2 in l2Columns] for columnNumber, l2 in enumerate(l2Columns): position = sensorPositions[columnNumber] featureLocationName = featureLocations[position] feedforwardInput = featureLocationSDRs[columnNumber][ featureLocationName] if noiseEverywhere or columnNumber == 0: noiseLevel = random.gauss(noiseMu, noiseSigma) noiseLevel = max(0.0, min(1.0, noiseLevel)) feedforwardInput = noisy(feedforwardInput, noiseLevel, L4_CELL_COUNT) lateralInputs = [ lateralInput for i, lateralInput in enumerate(allLateralInputs) if i != columnNumber ] l2.compute(feedforwardInput, lateralInputs, learn=False) if touch >= numInitialTouches: if noiseEverywhere: for columnNumber, l2 in enumerate(l2Columns): activeCells = set(l2.getActiveCells()) correctCells = objectL2Representations[objectName][ columnNumber] results.append((len(activeCells & correctCells), len(activeCells - correctCells))) else: activeCells = set(l2Columns[0].getActiveCells()) correctCells = objectL2Representations[objectName][0] results.append((len(activeCells & correctCells), len(activeCells - correctCells))) return results
def doExperiment(numColumns, l2Overrides, objectDescriptions, noiseMu, noiseSigma, numInitialTraversals): """ Touch every point on an object 'numInitialTraversals' times, then evaluate whether it has inferred the object by touching every point once more and checking the number of correctly active and incorrectly active cells. @param numColumns (int) The number of sensors to use @param l2Overrides (dict) Parameters for the ColumnPooler @param objectDescriptions (dict) A mapping of object names to their feature-locations. See 'createRandomObjectDescriptions'. @param noiseMu (float) The average amount of noise in a feedforward input. The noise level for each column's input is determined once per touch. It is a gaussian distribution with mean 'noiseMu' and sigma 'noiseSigma'. @param noiseSigma (float) The sigma for the gaussian distribution of noise levels. If the noiseSigma is 0, then the noise level will always be 'noiseMu'. @param numInitialTraversals (int) The number of times to traverse the object before testing whether the object has been inferred. """ # For each column, keep a mapping from feature-location names to their SDRs layer4sdr = lambda : set(random.sample(xrange(L4_CELL_COUNT), 40)) featureLocationSDRs = [defaultdict(layer4sdr) for _ in xrange(numColumns)] params = {"inputWidth": L4_CELL_COUNT, "lateralInputWidths": [4096]*(numColumns-1), "seed": random.randint(0, 1024)} params.update(l2Overrides) l2Columns = [ColumnPooler(**params) for _ in xrange(numColumns)] # Learn the objects objectL2Representations = {} for objectName, featureLocations in objectDescriptions.iteritems(): for featureLocationName in featureLocations: # Touch it enough times for the distal synapses to reach the # connected permanence, and then once more. for _ in xrange(4): allLateralInputs = [l2.getActiveCells() for l2 in l2Columns] for columnNumber, l2 in enumerate(l2Columns): feedforwardInput = featureLocationSDRs[columnNumber][featureLocationName] lateralInputs = [lateralInput for i, lateralInput in enumerate(allLateralInputs) if i != columnNumber] l2.compute(feedforwardInput, lateralInputs, learn=True) objectL2Representations[objectName] = [set(l2.getActiveCells()) for l2 in l2Columns] for l2 in l2Columns: l2.reset() results = [] # Try to infer the objects for objectName, featureLocations in objectDescriptions.iteritems(): for l2 in l2Columns: l2.reset() sensorPositionsIterator = greedySensorPositions(numColumns, len(featureLocations)) # Touch each location at least numInitialTouches times, and then touch it # once more, testing it. For each traversal, touch each point on the object # ~once. Not once per sensor -- just once. So we translate the "number of # traversals" into a "number of touches" according to the number of sensors. numTouchesPerTraversal = len(featureLocations) / float(numColumns) numInitialTouches = int(math.ceil(numInitialTraversals * numTouchesPerTraversal)) numTestTouches = int(math.ceil(1 * numTouchesPerTraversal)) for touch in xrange(numInitialTouches + numTestTouches): sensorPositions = next(sensorPositionsIterator) # Give the system a few timesteps to settle, allowing lateral connections # to cause cells to be inhibited. for _ in xrange(3): allLateralInputs = [l2.getActiveCells() for l2 in l2Columns] for columnNumber, l2 in enumerate(l2Columns): noiseLevel = random.gauss(noiseMu, noiseSigma) noiseLevel = max(0.0, min(1.0, noiseLevel)) position = sensorPositions[columnNumber] featureLocationName = featureLocations[position] feedforwardInput = featureLocationSDRs[columnNumber][featureLocationName] feedforwardInput = noisy(feedforwardInput, noiseLevel, L4_CELL_COUNT) lateralInputs = [lateralInput for i, lateralInput in enumerate(allLateralInputs) if i != columnNumber] l2.compute(feedforwardInput, lateralInputs, learn=False) if touch >= numInitialTouches: for columnNumber, l2 in enumerate(l2Columns): activeCells = set(l2.getActiveCells()) correctCells = objectL2Representations[objectName][columnNumber] results.append((len(activeCells & correctCells), len(activeCells - correctCells))) return results
def doExperiment(numColumns, objects, l2Overrides, noiseLevels, numInitialTraversals, noisyFeature, noisyLocation): """ Touch every point on an object 'numInitialTraversals' times, then evaluate whether it has inferred the object by touching every point once more and checking the number of correctly active and incorrectly active cells. @param numColumns (int) The number of sensors to use @param l2Overrides (dict) Parameters for the ColumnPooler @param objects (dict) A mapping of object names to their features. See 'createRandomObjects'. @param noiseLevels (list of floats) The noise levels to experiment with. The experiment is run once per noise level. Noise is applied at a constant rate to exactly one cortical column. It's applied to the same cortical column every time, and this is the cortical column that is measured. @param noisyFeature (bool) Whether to use a noisy feature @param noisyLocation (bool) Whether to use a noisy location """ featureSDR = lambda : set(random.sample(xrange(NUM_L4_COLUMNS), 40)) locationSDR = lambda : set(random.sample(xrange(1024), 40)) featureSDRsByColumn = [defaultdict(featureSDR) for _ in xrange(numColumns)] locationSDRsByColumn = [defaultdict(locationSDR) for _ in xrange(numColumns)] exp = L4L2Experiment( "Experiment", numCorticalColumns=numColumns, inputSize=NUM_L4_COLUMNS, externalInputSize=1024, seed=random.randint(2048, 4096) ) exp.learnObjects( dict((objectName, [dict((column, (locationSDRsByColumn[column][location], featureSDRsByColumn[column][features[location]])) for column in xrange(numColumns)) for location in xrange(len(features))]) for objectName, features in objects.iteritems())) results = defaultdict(list) for noiseLevel in noiseLevels: # Try to infer the objects for objectName, features in objects.iteritems(): exp.sendReset() inferredL2 = exp.objectL2Representations[objectName] sensorPositionsIterator = greedySensorPositions(numColumns, len(features)) # Touch each location at least numInitialTouches times, and then touch it # once more, testing it. For each traversal, touch each point on the object # ~once. Not once per sensor -- just once. So we translate the "number of # traversals" into a "number of touches" according to the number of sensors. numTouchesPerTraversal = len(features) / float(numColumns) numInitialTouches = int(math.ceil(numInitialTraversals * numTouchesPerTraversal)) numTestTouches = len(features) for touch in xrange(numInitialTouches + numTestTouches): sensorPositions = next(sensorPositionsIterator) sensation = dict( (column, (locationSDRsByColumn[column][sensorPositions[column]], featureSDRsByColumn[column][features[sensorPositions[column]]])) for column in xrange(1, numColumns)) # Add noise to the first column. featureSDR = featureSDRsByColumn[0][features[sensorPositions[0]]] if noisyFeature: featureSDR = noisy(featureSDR, noiseLevel, NUM_L4_COLUMNS) locationSDR = locationSDRsByColumn[0][sensorPositions[0]] if noisyLocation: locationSDR = noisy(locationSDR, noiseLevel, 1024) sensation[0] = (locationSDR, featureSDR) exp.infer([sensation]*TIMESTEPS_PER_SENSATION, reset=False, objectName=objectName) if touch >= numInitialTouches: activeCells = exp.getL2Representations()[0] correctCells = inferredL2[0] results[noiseLevel].append((len(activeCells & correctCells), len(activeCells - correctCells))) return results
def inferObjects(self, bodyPlacement, maxTouches=2): """ Touch each object with multiple sensors twice. :returns: dict mapping the number of touches required to the number of objects that took that many touches to be uniquely inferred. The 'None' key is reserved for objects not recognized after `maxTouches` touches """ for monitor in self.monitors.itervalues(): monitor.afterBodyWorldLocationChanged(bodyPlacement) numTouchesRequired = collections.defaultdict(int) for objectName, objectFeatures in self.objects.iteritems(): self.reset() objectPlacement = self.objectPlacements[objectName] featureIndexByColumnIterator = ( greedySensorPositions(self.numCorticalColumns, len(objectFeatures))) for touch in xrange(maxTouches): # Choose where to place each sensor. featureIndexByColumn = featureIndexByColumnIterator.next() sensedFeatures = [objectFeatures[i] for i in featureIndexByColumn] featureSDRByColumn = [self.features[(iCol, feature["name"])] for iCol, feature in enumerate(sensedFeatures)] worldLocationByColumn = np.array([ [objectPlacement[0] + feature["top"] + feature["height"]/2, objectPlacement[1] + feature["left"] + feature["width"]/2] for feature in sensedFeatures]) for monitor in self.monitors.itervalues(): monitor.afterSensorWorldLocationChanged(worldLocationByColumn) egocentricLocationByColumn = worldLocationByColumn - bodyPlacement prevCellActivity = None for t in xrange(self.maxSettlingTime): for monitor in self.monitors.itervalues(): monitor.beforeCompute(egocentricLocationByColumn, featureSDRByColumn, isRepeat=(t > 0)) self.compute(egocentricLocationByColumn, featureSDRByColumn, learn=False) cellActivity = ( tuple(c.getAllCellActivity() for c in self.corticalColumns), tuple(set(module.activeCells) for module in self.bodyToSpecificObjectModules)) if cellActivity == prevCellActivity: # It settled. Cancel logging this timestep. for monitor in self.monitors.itervalues(): monitor.clearUnflushedData() break else: prevCellActivity = cellActivity for monitor in self.monitors.itervalues(): monitor.flush() # Check if the object is narrowed down if self.isObjectClassified(objectName): numTouchesRequired[touch + 1] += 1 break else: numTouchesRequired[None] += 1 return numTouchesRequired
def doExperiment(numColumns, objects, l2Overrides, noiseLevels, numInitialTraversals, noisyFeature, noisyLocation): """ Touch every point on an object 'numInitialTraversals' times, then evaluate whether it has inferred the object by touching every point once more and checking the number of correctly active and incorrectly active cells. @param numColumns (int) The number of sensors to use @param l2Overrides (dict) Parameters for the ColumnPooler @param objects (dict) A mapping of object names to their features. See 'createRandomObjects'. @param noiseLevels (list of floats) The noise levels to experiment with. The experiment is run once per noise level. Noise is applied at a constant rate to exactly one cortical column. It's applied to the same cortical column every time, and this is the cortical column that is measured. @param noisyFeature (bool) Whether to use a noisy feature @param noisyLocation (bool) Whether to use a noisy location """ featureSDR = lambda: set(random.sample(xrange(NUM_L4_COLUMNS), 40)) locationSDR = lambda: set(random.sample(xrange(1024), 40)) featureSDRsByColumn = [defaultdict(featureSDR) for _ in xrange(numColumns)] locationSDRsByColumn = [ defaultdict(locationSDR) for _ in xrange(numColumns) ] exp = L4L2Experiment("Experiment", numCorticalColumns=numColumns, inputSize=NUM_L4_COLUMNS, externalInputSize=1024, seed=random.randint(2048, 4096)) exp.learnObjects( dict((objectName, [ dict((column, (locationSDRsByColumn[column][location], featureSDRsByColumn[column][features[location]])) for column in xrange(numColumns)) for location in xrange(len(features)) ]) for objectName, features in objects.iteritems())) results = defaultdict(list) for noiseLevel in noiseLevels: # Try to infer the objects for objectName, features in objects.iteritems(): exp.sendReset() inferredL2 = exp.objectL2Representations[objectName] sensorPositionsIterator = greedySensorPositions( numColumns, len(features)) # Touch each location at least numInitialTouches times, and then touch it # once more, testing it. For each traversal, touch each point on the object # ~once. Not once per sensor -- just once. So we translate the "number of # traversals" into a "number of touches" according to the number of sensors. numTouchesPerTraversal = len(features) / float(numColumns) numInitialTouches = int( math.ceil(numInitialTraversals * numTouchesPerTraversal)) numTestTouches = len(features) for touch in xrange(numInitialTouches + numTestTouches): sensorPositions = next(sensorPositionsIterator) sensation = dict( (column, (locationSDRsByColumn[column][sensorPositions[column]], featureSDRsByColumn[column][features[ sensorPositions[column]]])) for column in xrange(1, numColumns)) # Add noise to the first column. featureSDR = featureSDRsByColumn[0][features[ sensorPositions[0]]] if noisyFeature: featureSDR = noisy(featureSDR, noiseLevel, NUM_L4_COLUMNS) locationSDR = locationSDRsByColumn[0][sensorPositions[0]] if noisyLocation: locationSDR = noisy(locationSDR, noiseLevel, 1024) sensation[0] = (locationSDR, featureSDR) exp.infer([sensation] * TIMESTEPS_PER_SENSATION, reset=False, objectName=objectName) if touch >= numInitialTouches: activeCells = exp.getL2Representations()[0] correctCells = inferredL2[0] results[noiseLevel].append( (len(activeCells & correctCells), len(activeCells - correctCells))) return results