def __init__(self, trnCellShape=(32, 32), relayCellShape=(32, 32), inputShape=(32, 32), l6CellCount=1024, trnThreshold=10, relayThreshold=1, seed=42): """ :param trnCellShape: a 2D shape for the TRN :param relayCellShape: a 2D shape for the relay cells :param l6CellCount: number of L6 cells :param trnThreshold: dendritic threshold for TRN cells. This is the min number of active L6 cells on a dendrite for the TRN cell to recognize a pattern on that dendrite. :param relayThreshold: dendritic threshold for relay cells. This is the min number of active TRN cells on a dendrite for the relay cell to recognize a pattern on that dendrite. :param seed: Seed for the random number generator. """ self.trnCellShape = trnCellShape self.trnWidth = trnCellShape[0] self.trnHeight = trnCellShape[1] self.relayCellShape = relayCellShape self.relayWidth = relayCellShape[0] self.relayHeight = relayCellShape[1] self.l6CellCount = l6CellCount self.trnThreshold = trnThreshold self.relayThreshold = relayThreshold self.inputShape = inputShape self.seed = seed self.rng = Random(seed) self.trnActivationThreshold = 5 self.trnConnections = SparseMatrixConnections( trnCellShape[0]*trnCellShape[1], l6CellCount) self.relayConnections = SparseMatrixConnections( relayCellShape[0]*relayCellShape[1], trnCellShape[0]*trnCellShape[1]) # Initialize/reset variables that are updated with calls to compute self.reset() self._initializeTRNToRelayCellConnections()
def test_adjustActiveSynapses(self): for (name, cells, inputs, adjustedSegments, activeInputs, initialPermanence, delta, connectedPermanence, expected) in (("Basic test", [1, 2, 3], [42, 43, 44], [0, 2], [42, 44], 0.45, 0.1, 0.5, [2, 0, 2]), ("Negative increment", [1, 2, 3], [42, 43, 44], [0, 2], [42, 44], 0.55, -0.1, 0.5, [1, 3, 1]), ("No segments", [1, 2, 3], [42, 43, 44], [], [42, 44], 0.45, 0.1, 0.5, [0, 0, 0]), ("No active synapses", [1, 2, 3], [42, 43, 44], [0, 2], [], 0.45, 0.1, 0.5, [0, 0, 0]), ("Delta of zero", [1, 2, 3], [42, 43, 44], [0, 2], [42, 44], 0.55, 0.0, 0.5, [3, 3, 3])): connections = SparseMatrixConnections(2048, 2048) segments = connections.createSegments(cells) connections.growSynapses(segments, inputs, initialPermanence) connections.adjustActiveSynapses(segments[adjustedSegments], activeInputs, delta) overlaps = connections.computeActivity(inputs, connectedPermanence) np.testing.assert_equal(overlaps[segments], expected, name)
def test_computeActivity_thresholded(self): for (name, cells, inputs, activeInputs, initialPermanence, connectedPermanence, expected) in (("Accepted", [1, 2, 3], [42, 43, 44], [42, 44], 0.55, 0.5, [2, 2, 2]), ("Rejected", [1, 2, 3], [42, 43, 44], [42, 44], 0.55, 0.6, [0, 0, 0]), ("No segments", [], [42, 43, 44], [42, 44], 0.55, 0.5, []), ("No active inputs", [1, 2, 3], [42, 43, 44], [], 0.55, 0.5, [0, 0, 0]) ): connections = SparseMatrixConnections(2048, 2048) segments = connections.createSegments(cells) connections.growSynapses(segments, inputs, initialPermanence) overlaps = connections.computeActivity(activeInputs, connectedPermanence) np.testing.assert_equal(overlaps[segments], expected, name)
def test_computeActivity(self): for (name, cells, inputs, activeInputs, initialPermanence, expected) in (("Basic test", [1, 2, 3], [42, 43, 44], [42, 44], 0.45, [2, 2, 2]), ("Small permanence", [1, 2, 3], [42, 43, 44], [42, 44], 0.01, [2, 2, 2]), ("No segments", [], [42, 43, 44], [42, 44], 0.45, []), ("No active inputs", [1, 2, 3], [42, 43, 44], [], 0.45, [0, 0, 0]) ): connections = SparseMatrixConnections(2048, 2048) segments = connections.createSegments(cells) connections.growSynapses(segments, inputs, initialPermanence) overlaps = connections.computeActivity(activeInputs) np.testing.assert_equal(overlaps[segments], expected, name)
def test_growSynapses(self): for (name, cells, growingSegments, presynapticInputs, activeInputs, initialPermanence, connectedPermanence, expected) in (("Basic test", [1, 2, 3], [0, 2], [42, 43, 44], [42, 43], 0.55, 0.5, [2, 0, 2]), ("No segments selected", [1, 2, 3], [], [42, 43, 44], [42, 43], 0.55, 0.5, [0, 0, 0]), ("No inputs selected", [1, 2, 3], [0, 2], [], [42, 43], 0.55, 0.5, [0, 0, 0]) ): connections = SparseMatrixConnections(2048, 2048) segments = connections.createSegments(cells) connections.growSynapses(segments[growingSegments], presynapticInputs, initialPermanence) overlaps = connections.computeActivity(activeInputs, connectedPermanence) np.testing.assert_equal(overlaps[segments], expected, name)
def __init__(self, cellCount, cellCountBySource): """ @param cellCountBySource (dict) The number of cells in each source. Example: {"customInputName1": 16, "customInputName2": 42} """ self.connectionsBySource = dict( (source, SparseMatrixConnections(cellCount, presynapticCellCount)) for source, presynapticCellCount in cellCountBySource.iteritems())
def __init__(self, cellCount, deltaLocationInputSize, featureLocationInputSize, activationThreshold=13, initialPermanence=0.21, connectedPermanence=0.50, learningThreshold=10, sampleSize=20, permanenceIncrement=0.1, permanenceDecrement=0.1, maxSynapsesPerSegment=-1, seed=42): # For transition learning, every segment is split into two parts. # For the segment to be active, both parts must be active. self.internalConnections = SparseMatrixConnections( cellCount, cellCount) self.deltaConnections = SparseMatrixConnections( cellCount, deltaLocationInputSize) # Distal segments that receive input from the layer that represents # feature-locations. self.featureLocationConnections = SparseMatrixConnections( cellCount, featureLocationInputSize) self.activeCells = np.empty(0, dtype="uint32") self.activeDeltaSegments = np.empty(0, dtype="uint32") self.activeFeatureLocationSegments = np.empty(0, dtype="uint32") self.initialPermanence = initialPermanence self.connectedPermanence = connectedPermanence self.learningThreshold = learningThreshold self.sampleSize = sampleSize self.permanenceIncrement = permanenceIncrement self.permanenceDecrement = permanenceDecrement self.activationThreshold = activationThreshold self.maxSynapsesPerSegment = maxSynapsesPerSegment self.rng = Random(seed)
def test_mapSegmentsToSynapseCounts(self): connections = SparseMatrixConnections(2048, 2048) segments = connections.createSegments([1, 2, 3]) connections.growSynapses(segments, [42, 43, 44], 0.5) np.testing.assert_equal( connections.mapSegmentsToSynapseCounts(segments), [3, 3, 3]) segments2 = connections.createSegments([4, 5]) np.testing.assert_equal( connections.mapSegmentsToSynapseCounts(segments2), [0, 0]) np.testing.assert_equal(connections.mapSegmentsToSynapseCounts([]), [])
def __init__(self, cellDimensions, anchorInputSize, activationThreshold=10, initialPermanence=0.21, connectedPermanence=0.50, learningThreshold=10, sampleSize=20, permanenceIncrement=0.1, permanenceDecrement=0.0, maxSynapsesPerSegment=-1, seed=42): """ @param cellDimensions (sequence of ints) @param anchorInputSize (int) @param activationThreshold (int) """ self.activationThreshold = activationThreshold self.initialPermanence = initialPermanence self.connectedPermanence = connectedPermanence self.learningThreshold = learningThreshold self.sampleSize = sampleSize self.permanenceIncrement = permanenceIncrement self.permanenceDecrement = permanenceDecrement self.activationThreshold = activationThreshold self.maxSynapsesPerSegment = maxSynapsesPerSegment self.rng = Random(seed) self.cellCount = np.prod(cellDimensions) cellCountBySource = { "bodyToSpecificObject": self.cellCount, "sensorToBody": self.cellCount, } self.metricConnections = Multiconnections(self.cellCount, cellCountBySource) self.anchorConnections = SparseMatrixConnections( self.cellCount, anchorInputSize)
def test_clipPermanences(self): connections = SparseMatrixConnections(2048, 2048) # Destroy synapses with permanences <= 0.0 segments = connections.createSegments([1, 2, 3]) connections.growSynapses(segments, [42, 43, 44], 0.05) connections.growSynapses(segments, [45, 46], 0.1) connections.adjustInactiveSynapses(segments, [], -0.1) connections.clipPermanences(segments) np.testing.assert_equal( connections.mapSegmentsToSynapseCounts(segments), [0, 0, 0]) # Clip permanences to 1.0 connections.growSynapses(segments, [42, 43, 44], 0.95) connections.adjustInactiveSynapses(segments, [], 0.50) connections.clipPermanences(segments) np.testing.assert_equal( connections.mapSegmentsToSynapseCounts(segments), [3, 3, 3]) connections.adjustInactiveSynapses(segments, [], -0.5) overlaps1 = connections.computeActivity([42, 43, 44], 0.49) overlaps2 = connections.computeActivity([42, 43, 44], 0.51) np.testing.assert_equal(overlaps1, [3, 3, 3]) np.testing.assert_equal(overlaps2, [0, 0, 0])
def test_whenPermanenceFallsBelowZero(self): connections = SparseMatrixConnections(2048, 2048) segments = connections.createSegments([1, 2, 3]) connections.growSynapses(segments, [42, 43], 0.05) connections.adjustSynapses(segments, [42, 43], -0.06, 0.0) np.testing.assert_equal( connections.mapSegmentsToSynapseCounts(segments), [0, 0, 0]) connections.growSynapses(segments, [42, 43], 0.05) connections.adjustSynapses(segments, [], 0.0, -0.06) np.testing.assert_equal( connections.mapSegmentsToSynapseCounts(segments), [0, 0, 0]) connections.growSynapses(segments, [42, 43], 0.05) connections.adjustActiveSynapses(segments, [42, 43], -0.06) np.testing.assert_equal( connections.mapSegmentsToSynapseCounts(segments), [0, 0, 0]) connections.growSynapses(segments, [42, 43], 0.05) connections.adjustInactiveSynapses(segments, [], -0.06) np.testing.assert_equal( connections.mapSegmentsToSynapseCounts(segments), [0, 0, 0])
def __init__(self, columnCount=2048, basalInputSize=0, apicalInputSize=0, cellsPerColumn=32, activationThreshold=13, reducedBasalThreshold=10, initialPermanence=0.21, connectedPermanence=0.50, minThreshold=10, sampleSize=20, permanenceIncrement=0.1, permanenceDecrement=0.1, basalPredictedSegmentDecrement=0.0, apicalPredictedSegmentDecrement=0.0, maxSynapsesPerSegment=-1, seed=42): """ @param columnCount (int) The number of minicolumns @param basalInputSize (sequence) The number of bits in the basal input @param apicalInputSize (int) The number of bits in the apical input @param cellsPerColumn (int) Number of cells per column @param activationThreshold (int) If the number of active connected synapses on a segment is at least this threshold, the segment is said to be active. @param reducedBasalThreshold (int) The activation threshold of basal (lateral) segments for cells that have active apical segments. If equal to activationThreshold (default), this parameter has no effect. @param initialPermanence (float) Initial permanence of a new synapse @param connectedPermanence (float) If the permanence value for a synapse is greater than this value, it is said to be connected. @param minThreshold (int) If the number of potential synapses active on a segment is at least this threshold, it is said to be "matching" and is eligible for learning. @param sampleSize (int) How much of the active SDR to sample with synapses. @param permanenceIncrement (float) Amount by which permanences of synapses are incremented during learning. @param permanenceDecrement (float) Amount by which permanences of synapses are decremented during learning. @param basalPredictedSegmentDecrement (float) Amount by which segments are punished for incorrect predictions. @param apicalPredictedSegmentDecrement (float) Amount by which segments are punished for incorrect predictions. @param maxSynapsesPerSegment The maximum number of synapses per segment. @param seed (int) Seed for the random number generator. """ self.columnCount = columnCount self.cellsPerColumn = cellsPerColumn self.initialPermanence = initialPermanence self.connectedPermanence = connectedPermanence self.minThreshold = minThreshold self.sampleSize = sampleSize self.permanenceIncrement = permanenceIncrement self.permanenceDecrement = permanenceDecrement self.basalPredictedSegmentDecrement = basalPredictedSegmentDecrement self.apicalPredictedSegmentDecrement = apicalPredictedSegmentDecrement self.activationThreshold = activationThreshold self.reducedBasalThreshold = reducedBasalThreshold self.maxSynapsesPerSegment = maxSynapsesPerSegment self.basalConnections = SparseMatrixConnections(columnCount*cellsPerColumn, basalInputSize) self.disableApicalDependence = False self.apicalConnections = SparseMatrixConnections(columnCount*cellsPerColumn, apicalInputSize) self.rng = Random(seed) self.activeCells = np.empty(0, dtype="uint32") self.winnerCells = np.empty(0, dtype="uint32") self.predictedCells = np.empty(0, dtype="uint32") self.predictedActiveCells = np.empty(0, dtype="uint32") self.activeBasalSegments = np.empty(0, dtype="uint32") self.activeApicalSegments = np.empty(0, dtype="uint32") self.matchingBasalSegments = np.empty(0, dtype="uint32") self.matchingApicalSegments = np.empty(0, dtype="uint32") self.basalPotentialOverlaps = np.empty(0, dtype="int32") self.apicalPotentialOverlaps = np.empty(0, dtype="int32")
def __init__(self, cellCount, inputSize, threshold): self.proximalConnections = SparseMatrixConnections(cellCount, inputSize) self.threshold = threshold self.activeCells = np.empty(0, dtype='uint32') self.activeSegments = np.empty(0, dtype='uint32')
def __init__(self, columnCount=2048, basalInputSize=0, apicalInputSize=0, cellsPerColumn=32, initialPermanence=0.21, connectedPermanence=0.50, sampleSize=20, permanenceIncrement=0.1, permanenceDecrement=0.1, activationThresholdBasal=13, minThresholdBasal=10, activationThresholdApical=2, minThresholdApical=1, basalPredictedSegmentDecrement=0.0, apicalPredictedSegmentDecrement=0.0, maxSynapsesPerSegment=-1, seed=42): """ @param columnCount (int) The number of minicolumns @param basalInputSize (sequence) The number of bits in the basal input @param apicalInputSize (int) The number of bits in the apical input @param cellsPerColumn (int) Number of cells per column @param initialPermanence (float) Initial permanence of a new synapse @param connectedPermanence (float) If the permanence value for a synapse is greater than this value, it is said to be connected. @param activationThresholdBasal (int) If the number of active connected basal synapses on a segment is at least this threshold, the segment is said to be active. @param activationThresholdApical (int) If the number of active connected apical synapses on a segment is at least this threshold, the segment is said to be active. @param minThresholdBasal (int) If the number of potential basal synapses active on a segment is at least this threshold, it is said to be "matching" and is eligible for learning. @param minThresholdApical (int) If the number of potential apical synapses active on a segment is at least this threshold, it is said to be "matching" and is eligible for learning. @param sampleSize (int) How much of the active SDR to sample with synapses. @param permanenceIncrement (float) Amount by which permanences of synapses are incremented during learning. @param permanenceDecrement (float) Amount by which permanences of synapses are decremented during learning. @param basalPredictedSegmentDecrement (float) Amount by which segments are punished for incorrect predictions. @param apicalPredictedSegmentDecrement (float) Amount by which segments are punished for incorrect predictions. @param maxSynapsesPerSegment The maximum number of synapses per segment. @param seed (int) Seed for the random number generator. """ self.columnCount = columnCount self.cellsPerColumn = cellsPerColumn self.initialPermanence = initialPermanence self.connectedPermanence = connectedPermanence self.sampleSize = sampleSize self.permanenceIncrement = permanenceIncrement self.permanenceDecrement = permanenceDecrement self.maxSynapsesPerSegment = maxSynapsesPerSegment # weighted basal/apical params self.basalPredictedSegmentDecrement = basalPredictedSegmentDecrement self.apicalPredictedSegmentDecrement = apicalPredictedSegmentDecrement self.minThresholdBasal = minThresholdBasal self.minThresholdApical = minThresholdApical self.activationThresholdBasal = activationThresholdBasal self.activationThresholdApical = activationThresholdApical self.basalConnections = SparseMatrixConnections( columnCount * cellsPerColumn, basalInputSize) self.apicalConnections = SparseMatrixConnections( columnCount * cellsPerColumn, apicalInputSize) self.rng = Random(seed) self.activeCells = () self.winnerCells = () self.predictedCells = () self.activeBasalSegments = () self.activeApicalSegments = ()
def __init__(self, cellDimensions, moduleMapDimensions, orientation, anchorInputSize, pointOffsets=(0.5, ), activationThreshold=10, initialPermanence=0.21, connectedPermanence=0.50, learningThreshold=10, sampleSize=20, permanenceIncrement=0.1, permanenceDecrement=0.0, maxSynapsesPerSegment=-1, seed=42): """ @param cellDimensions (tuple(int, int)) Determines the number of cells. Determines how space is divided between the cells. @param moduleMapDimensions (tuple(float, float)) Determines the amount of world space covered by all of the cells combined. In grid cell terminology, this is equivalent to the "scale" of a module. A module with a scale of "5cm" would have moduleMapDimensions=(5.0, 5.0). @param orientation (float) The rotation of this map, measured in radians. @param anchorInputSize (int) The number of input bits in the anchor input. @param pointOffsets (list of floats) These must each be between 0.0 and 1.0. Every time a cell is activated by anchor input, this class adds a "point" which is shifted in subsequent motions. By default, this point is placed at the center of the cell. This parameter allows you to control where the point is placed and whether multiple are placed. For example, With value [0.2, 0.8], it will place 4 points: [0.2, 0.2], [0.2, 0.8], [0.8, 0.2], [0.8, 0.8] """ self.cellDimensions = np.asarray(cellDimensions, dtype="int") self.moduleMapDimensions = np.asarray(moduleMapDimensions, dtype="float") self.cellFieldsPerUnitDistance = self.cellDimensions / self.moduleMapDimensions self.orientation = orientation self.rotationMatrix = np.array( [[math.cos(orientation), -math.sin(orientation)], [math.sin(orientation), math.cos(orientation)]]) self.pointOffsets = pointOffsets # These coordinates are in units of "cell fields". self.activePoints = np.empty((0, 2), dtype="float") self.cellsForActivePoints = np.empty(0, dtype="int") self.activeCells = np.empty(0, dtype="int") self.activeSegments = np.empty(0, dtype="uint32") self.connections = SparseMatrixConnections(np.prod(cellDimensions), anchorInputSize) self.initialPermanence = initialPermanence self.connectedPermanence = connectedPermanence self.learningThreshold = learningThreshold self.sampleSize = sampleSize self.permanenceIncrement = permanenceIncrement self.permanenceDecrement = permanenceDecrement self.activationThreshold = activationThreshold self.maxSynapsesPerSegment = maxSynapsesPerSegment self.rng = Random(seed)
def __init__(self, cellDimensions, moduleMapDimensions, orientation, anchorInputSize, cellCoordinateOffsets=(0.5, ), activationThreshold=10, initialPermanence=0.21, connectedPermanence=0.50, learningThreshold=10, sampleSize=20, permanenceIncrement=0.1, permanenceDecrement=0.0, maxSynapsesPerSegment=-1, anchoringMethod="narrowing", rotationMatrix=None, seed=42): """ @param cellDimensions (tuple(int, int)) Determines the number of cells. Determines how space is divided between the cells. @param moduleMapDimensions (tuple(float, float)) Determines the amount of world space covered by all of the cells combined. In grid cell terminology, this is equivalent to the "scale" of a module. A module with a scale of "5cm" would have moduleMapDimensions=(5.0, 5.0). @param orientation (float) The rotation of this map, measured in radians. @param anchorInputSize (int) The number of input bits in the anchor input. @param cellCoordinateOffsets (list of floats) These must each be between 0.0 and 1.0. Every time a cell is activated by anchor input, this class adds a "phase" which is shifted in subsequent motions. By default, this phase is placed at the center of the cell. This parameter allows you to control where the point is placed and whether multiple are placed. For example, with value [0.2, 0.8], when cell [2, 3] is activated it will place 4 phases, corresponding to the following points in cell coordinates: [2.2, 3.2], [2.2, 3.8], [2.8, 3.2], [2.8, 3.8] """ self.cellDimensions = np.asarray(cellDimensions, dtype="int") self.moduleMapDimensions = np.asarray(moduleMapDimensions, dtype="float") self.phasesPerUnitDistance = 1.0 / self.moduleMapDimensions if rotationMatrix is None: self.orientation = orientation self.rotationMatrix = np.array( [[math.cos(orientation), -math.sin(orientation)], [math.sin(orientation), math.cos(orientation)]]) if anchoringMethod == "discrete": # Need to convert matrix to have integer values nonzeros = self.rotationMatrix[np.where( np.abs(self.rotationMatrix) > 0)] smallestValue = np.amin(nonzeros) self.rotationMatrix /= smallestValue self.rotationMatrix = np.ceil(self.rotationMatrix) else: self.rotationMatrix = rotationMatrix self.cellCoordinateOffsets = cellCoordinateOffsets # Phase is measured as a number in the range [0.0, 1.0) self.activePhases = np.empty((0, 2), dtype="float") self.cellsForActivePhases = np.empty(0, dtype="int") self.phaseDisplacement = np.empty((0, 2), dtype="float") self.activeCells = np.empty(0, dtype="int") self.activeSegments = np.empty(0, dtype="uint32") self.connections = SparseMatrixConnections(np.prod(cellDimensions), anchorInputSize) self.initialPermanence = initialPermanence self.connectedPermanence = connectedPermanence self.learningThreshold = learningThreshold self.sampleSize = sampleSize self.permanenceIncrement = permanenceIncrement self.permanenceDecrement = permanenceDecrement self.activationThreshold = activationThreshold self.maxSynapsesPerSegment = maxSynapsesPerSegment self.anchoringMethod = anchoringMethod self.rng = Random(seed)
def test_growSynapsesToSample_multi(self): rng = Random() for (name, cells, growingSegments, initialConnectedInputs, presynapticInputs, activeInputs, initialPermanence, connectedPermanence, sampleSizes, expected) in (("Basic test", [1, 2, 3], [0, 2], [], [42, 43, 44, 45], [42, 43, 44, 45], 0.55, 0.5, [2, 3], [2, 0, 3]), ("One already connected", [1, 2, 3], [0, 2], [42], [42, 43, 44, 45], [42, 43, 44, 45], 0.55, 0.5, [1, 2], [2, 0, 3]), ("Higher sample size than axon count", [1, 2, 3], [0, 2], [], [42, 43, 44, 45], [42, 43, 44, 45], 0.55, 0.5, [5, 10], [4, 0, 4]), ("Higher sample size than available axon count", [1, 2, 3], [0, 2], [42, 43], [42, 43, 44, 45], [42, 43, 44, 45], 0.55, 0.5, [3, 3], [4, 0, 4])): connections = SparseMatrixConnections(2048, 2048) segments = connections.createSegments(cells) connections.growSynapses(segments[growingSegments], initialConnectedInputs, initialPermanence) connections.growSynapsesToSample(segments[growingSegments], presynapticInputs, sampleSizes, initialPermanence, rng) overlaps = connections.computeActivity(activeInputs, connectedPermanence) np.testing.assert_equal(overlaps[segments], expected, name) for (name, cells, growingSegments, initialConnectedInputs, presynapticInputs, activeInputs, initialPermanence, connectedPermanence, sampleSizes) in (("Basic randomness test", [1, 2, 3], [0, 2], [], [42, 43, 44, 45], [42, 43], 0.55, 0.5, [2, 3]), ): # Activate a subset of the inputs. The resulting overlaps should # differ on various trials. firstResult = None differingResults = False for _ in range(20): connections = SparseMatrixConnections(2048, 2048) segments = connections.createSegments(cells) connections.growSynapses(segments[growingSegments], initialConnectedInputs, initialPermanence) connections.growSynapsesToSample(segments[growingSegments], presynapticInputs, sampleSizes, initialPermanence, rng) overlaps = connections.computeActivity(activeInputs, connectedPermanence) if firstResult is None: firstResult = overlaps[segments] else: differingResults = not np.array_equal( overlaps[segments], firstResult) if differingResults: break self.assertTrue(differingResults, name)