def testPathsNotInvalidatedByOtherDestroys(self): """ Creates segments and synapses, then destroys segments and synapses on either side of them and verifies that existing Segment and Synapse instances still point to the same segment / synapse as before. """ connections = Connections(1024) segment1 = connections.createSegment(11) connections.createSegment(12) segment3 = connections.createSegment(13) connections.createSegment(14) segment5 = connections.createSegment(15) synapse1 = connections.createSynapse(segment3, 201, .85) synapse2 = connections.createSynapse(segment3, 202, .85) synapse3 = connections.createSynapse(segment3, 203, .85) synapse4 = connections.createSynapse(segment3, 204, .85) synapse5 = connections.createSynapse(segment3, 205, .85) self.assertEqual(203, synapse3.presynapticCell) connections.destroySynapse(synapse1) self.assertEqual(203, synapse3.presynapticCell) connections.destroySynapse(synapse5) self.assertEqual(203, synapse3.presynapticCell) connections.destroySegment(segment1) self.assertEqual([synapse2, synapse3, synapse4], list(connections.synapsesForSegment(segment3))) connections.destroySegment(segment5) self.assertEqual([synapse2, synapse3, synapse4], list(connections.synapsesForSegment(segment3))) self.assertEqual(203, synapse3.presynapticCell)
def __init__(self, columnDimensions=(2048, ), cellsPerColumn=32, activationThreshold=13, initialPermanence=0.21, connectedPermanence=0.50, minThreshold=10, maxNewSynapseCount=20, permanenceIncrement=0.10, permanenceDecrement=0.10, seed=42): """ Translate parameters and initialize member variables specific to TemporalMemory """ numberOfCols = 1 for n in columnDimensions: numberOfCols *= n super(TemporalMemoryShim, self).__init__(numberOfCols=numberOfCols, cellsPerColumn=cellsPerColumn, initialPerm=initialPermanence, connectedPerm=connectedPermanence, minThreshold=minThreshold, newSynapseCount=maxNewSynapseCount, permanenceInc=permanenceIncrement, permanenceDec=permanenceDecrement, permanenceMax=1.0, globalDecay=0, activationThreshold=activationThreshold, seed=seed) self.connections = Connections(numberOfCols * cellsPerColumn) self.predictiveCells = set()
def __init__(self, columnDimensions=(2048, ), cellsPerColumn=32, activationThreshold=13, initialPermanence=0.21, connectedPermanence=0.50, minThreshold=10, maxNewSynapseCount=20, permanenceIncrement=0.10, permanenceDecrement=0.10, predictedSegmentDecrement=0.0, seed=42): """ @param columnDimensions (list) Dimensions of the column space @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 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 synapses active on a segment is at least this threshold, it is selected as the best matching cell in a bursting column. @param maxNewSynapseCount (int) The maximum number of synapses added to a segment during learning. @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 predictedSegmentDecrement (float) Amount by which active permanences of synapses of previously predicted but inactive segments are decremented. @param seed (int) Seed for the random number generator. """ # Error checking if not len(columnDimensions): raise ValueError( "Number of column dimensions must be greater than 0") if not cellsPerColumn > 0: raise ValueError( "Number of cells per column must be greater than 0") # TODO: Validate all parameters (and add validation tests) # Save member variables self.columnDimensions = columnDimensions self.cellsPerColumn = cellsPerColumn self.activationThreshold = activationThreshold self.initialPermanence = initialPermanence self.connectedPermanence = connectedPermanence self.minThreshold = minThreshold self.maxNewSynapseCount = maxNewSynapseCount self.permanenceIncrement = permanenceIncrement self.permanenceDecrement = permanenceDecrement self.predictedSegmentDecrement = predictedSegmentDecrement # Initialize member variables self.connections = Connections(self.numberOfCells()) self._random = Random(seed) self.activeCells = set() self.predictiveCells = set() self.activeSegments = set() self.winnerCells = set() self.matchingSegments = set() self.matchingCells = set()
def connectionsFactory(*args, **kwargs): """ Create a Connections instance. TemporalMemory subclasses may override this method to choose a different Connections implementation, or to augment the instance otherwise returned by the default Connections implementation. See Connections for constructor signature and usage @return: Connections instance """ return Connections(*args, **kwargs)
def testComputeActivity(self): """ Creates a sample set of connections, and makes sure that computing the activity for a collection of cells with no activity returns the right activity data. """ connections = Connections(1024) # Cell with 1 segment. # Segment with: # - 1 connected synapse: active # - 2 matching synapses segment1a = connections.createSegment(10) connections.createSynapse(segment1a, 150, .85) connections.createSynapse(segment1a, 151, .15) # Cell with 2 segment. # Segment with: # - 2 connected synapse: 2 active # - 3 matching synapses: 3 active segment2a = connections.createSegment(20) connections.createSynapse(segment2a, 80, .85) connections.createSynapse(segment2a, 81, .85) synapse = connections.createSynapse(segment2a, 82, .85) connections.updateSynapsePermanence(synapse, .15) # Segment with: # - 2 connected synapses: 1 active, 1 inactive # - 3 matching synapses: 2 active, 1 inactive # - 1 non-matching synapse: 1 active segment2b = connections.createSegment(20) connections.createSynapse(segment2b, 50, .85) connections.createSynapse(segment2b, 51, .85) connections.createSynapse(segment2b, 52, .15) connections.createSynapse(segment2b, 53, .05) # Cell with one segment. # Segment with: # - 1 non-matching synapse: 1 active segment3a = connections.createSegment(30) connections.createSynapse(segment3a, 53, .05) inputVec = [50, 52, 53, 80, 81, 82, 150, 151] active, matching = connections.computeActivity(inputVec, .5, 2, .1, 1) self.assertEqual(1, len(active)) self.assertEqual(segment2a, active[0].segment) self.assertEqual(2, active[0].overlap) self.assertEqual(3, len(matching)) self.assertEqual(segment1a, matching[0].segment) self.assertEqual(2, matching[0].overlap) self.assertEqual(segment2a, matching[1].segment) self.assertEqual(3, matching[1].overlap) self.assertEqual(segment2b, matching[2].segment) self.assertEqual(2, matching[2].overlap)
def testCreateSegment(self): connections = Connections(1024) segment1 = connections.createSegment(10) self.assertEqual(segment1.cell, 10) segment2 = connections.createSegment(10) self.assertEqual(segment2.cell, 10) self.assertEqual([segment1, segment2], list(connections.segmentsForCell(10)))
def testUpdateSynapsePermanence(self): """ Creates a synapse and updates its permanence, and makes sure that its data was correctly updated. """ connections = Connections(1024) segment = connections.createSegment(10) synapse = connections.createSynapse(segment, 50, .34) connections.updateSynapsePermanence(synapse, .21) synapseData = connections.dataForSynapse(synapse) self.assertAlmostEqual(synapseData.permanence, .21)
def testReachSegmentLimitMultipleTimes(self): """ Hit the maxSynapsesPerSegment threshold multiple times. Make sure it works more than once. """ connections = Connections(1024, 2, 2) segment = connections.createSegment(10) connections.createSynapse(segment, 201, .85) self.assertEqual(1, connections.numSynapses()) connections.createSynapse(segment, 202, .9) self.assertEqual(2, connections.numSynapses()) connections.createSynapse(segment, 203, .8) self.assertEqual(2, connections.numSynapses()) synapse = connections.createSynapse(segment, 204, .8) self.assertEqual(2, connections.numSynapses())
def testCreateSegmentReuse(self): connections = Connections(1024, 2) segment1 = connections.createSegment(42) connections.createSynapse(segment1, 1, .5) connections.createSynapse(segment1, 2, .5) # Let some time pass. connections.startNewIteration() connections.startNewIteration() connections.startNewIteration() # Create a segment with 3 synapse. segment2 = connections.createSegment(42) connections.createSynapse(segment2, 1, .5) connections.createSynapse(segment2, 2, .5) connections.createSynapse(segment2, 3, .5) connections.startNewIteration() # Give the first segment some activity. connections.recordSegmentActivity(segment1) # Create a new segment with 1 synapse. segment3 = connections.createSegment(42) connections.createSynapse(segment3, 1, .5) segments = connections.segmentsForCell(42) self.assertEqual(2, len(segments)) # Verify first segment is still there with the same synapses. self.assertEqual( set([1, 2]), set(synapse.presynapticCell for synapse in connections.synapsesForSegment(segments[0]))) # Verify second segment has been replaced. self.assertEqual( set([1]), set(synapse.presynapticCell for synapse in connections.synapsesForSegment(segments[1]))) # Verify the flatIdxs were properly reused. self.assertLess(segment1.flatIdx, 2) self.assertLess(segment3.flatIdx, 2) self.assertTrue( segment1 is connections.segmentForFlatIdx(segment1.flatIdx)) self.assertTrue( segment3 is connections.segmentForFlatIdx(segment3.flatIdx))
def testCreateSegmentReuse(self): connections = Connections(1024, 2) segment1 = connections.createSegment(42) connections.createSynapse(segment1, 1, .5) connections.createSynapse(segment1, 2, .5) connections.computeActivity([], .5, 2, .1, 1) connections.computeActivity([], .5, 2, .1, 1) connections.computeActivity([], .5, 2, .1, 1) segment2 = connections.createSegment(42) activeSegs, _ = connections.computeActivity([1, 2], .5, 2, .1, 1) self.assertEqual(1, len(activeSegs)) self.assertEqual(segment1, activeSegs[0].segment) segment3 = connections.createSegment(42) self.assertEqual(segment2.idx, segment3.idx)
def __init__(self, learnOnOneCell=True, **kwargs): """ @param learnOnOneCell (boolean) If True, the winner cell for each column will be fixed between resets. """ super(ExtendedTemporalMemory, self).__init__(**kwargs) self.activeExternalCells = set() self.learnOnOneCell = learnOnOneCell self.chosenCellForColumn = dict() self.unpredictedActiveColumns = set() self.predictedActiveCells = set() self.activeApicalCells = set() self.apicalConnections = Connections(self.numberOfCells()) self.activeApicalSegments = set() self.matchingApicalSegments = set()
def testCreateSegmentReuse(self): connections = Connections(1024, 2) segment1 = connections.createSegment(42) connections.createSynapse(segment1, 1, .5) connections.createSynapse(segment1, 2, .5) # Let some time pass. connections.startNewIteration() connections.startNewIteration() connections.startNewIteration() segment2 = connections.createSegment(42) connections.startNewIteration() connections.recordSegmentActivity(segment1) segment3 = connections.createSegment(42) self.assertEqual(segment2.idx, segment3.idx)
def testDestroySegmentsThenReachLimit(self): """ Destroy some segments then verify that the maxSegmentsPerCell is still correctly applied. """ connections = Connections(1024, 2, 2) segment1 = connections.createSegment(11) segment2 = connections.createSegment(11) self.assertEqual(2, connections.numSegments()) connections.destroySegment(segment1) connections.destroySegment(segment2) self.assertEqual(0, connections.numSegments()) connections.createSegment(11) self.assertEqual(1, connections.numSegments()) connections.createSegment(11) self.assertEqual(2, connections.numSegments()) segment3 = connections.createSegment(11) self.assertLess(segment3.idx, 2) self.assertEqual(2, connections.numSegments())
def testSynapseReuse(self): """ Creates a synapse over the synapses per segment limit, and verifies that the lowest permanence synapse is removed to make room for the new synapse. """ connections = Connections(1024, 1024, 2) segment = connections.createSegment(10) synapse1 = connections.createSynapse(segment, 50, .34) synapse2 = connections.createSynapse(segment, 51, .34) synapses = connections.synapsesForSegment(segment) self.assertEqual(synapses, [synapse1, synapse2]) #Add an additional synapse to force it over the limit of num synapses #per segment. synapse3 = connections.createSynapse(segment, 52, .52) self.assertEqual(0, synapse3.idx) #ensure lower permanence synapse was removed synapses = connections.synapsesForSegment(segment) self.assertEqual(synapses, [synapse3, synapse2])
def testReuseSegmentWithDestroyedSynapses(self): """ Destroy a segment that has a destroyed synapse and a non-destroyed synapse. Create a new segment in the same place. Make sure its synapse count is correct. """ connections = Connections(1024) segment = connections.createSegment(11) synapse1 = connections.createSynapse(segment, 201, .85) connections.createSynapse(segment, 202, .85) connections.destroySynapse(synapse1) self.assertEqual(1, connections.numSynapses(segment)) connections.destroySegment(segment) reincarnated = connections.createSegment(11) self.assertEqual(0, connections.numSynapses(reincarnated)) self.assertEqual(0, len(connections.synapsesForSegment(reincarnated)))
def testDestroySynapsesThenReachLimit(self): """ Destroy some synapses then verify that the maxSynapsesPerSegment is still correctly applied. """ connections = Connections(1024, 2, 2) segment = connections.createSegment(10) synapse1 = connections.createSynapse(segment, 201, .85) synapse2 = connections.createSynapse(segment, 202, .85) self.assertEqual(2, connections.numSynapses()) connections.destroySynapse(synapse1) connections.destroySynapse(synapse2) self.assertEqual(0, connections.numSynapses()) connections.createSynapse(segment, 201, .85) self.assertEqual(1, connections.numSynapses()) connections.createSynapse(segment, 202, .90) self.assertEqual(2, connections.numSynapses()) synapse3 = connections.createSynapse(segment, 203, .8) self.assertEqual(2, connections.numSynapses())
def testDestroySynapse(self): """ Creates a segment, creates a number of synapses on it, destroys a synapse, and makes sure it got destroyed. """ connections = Connections(1024) segment = connections.createSegment(20) synapse1 = connections.createSynapse(segment, 80, .85) synapse2 = connections.createSynapse(segment, 81, .85) synapse3 = connections.createSynapse(segment, 82, .15) self.assertEqual(3, connections.numSynapses()) connections.destroySynapse(synapse2) self.assertEqual(2, connections.numSynapses()) self.assertEqual(connections.synapsesForSegment(segment), [synapse1, synapse3]) active, matching = connections.computeActivity([80, 81, 82], .5, 2, 0.0, 1) self.assertEqual(0, len(active)) self.assertEqual(1, len(matching)) self.assertEqual(2, matching[0].overlap)
def testSynapseReuse(self): """ Creates a synapse over the synapses per segment limit, and verifies that the lowest permanence synapse is removed to make room for the new synapse. """ connections = Connections(1024, 1024, 2) segment = connections.createSegment(10) synapse1 = connections.createSynapse(segment, 50, .34) synapse2 = connections.createSynapse(segment, 51, .48) synapses = connections.synapsesForSegment(segment) self.assertEqual(set([synapse1, synapse2]), synapses) # Add an additional synapse to force it over the limit of num synapses # per segment. connections.createSynapse(segment, 52, .52) # Ensure lower permanence synapse was removed. self.assertEqual( set([51, 52]), set(synapse.presynapticCell for synapse in connections.synapsesForSegment(segment)))
def testDestroySynapse(self): """ Creates a segment, creates a number of synapses on it, destroys a synapse, and makes sure it got destroyed. """ connections = Connections(1024) segment = connections.createSegment(20) synapse1 = connections.createSynapse(segment, 80, .85) synapse2 = connections.createSynapse(segment, 81, .85) synapse3 = connections.createSynapse(segment, 82, .15) self.assertEqual(3, connections.numSynapses()) connections.destroySynapse(synapse2) self.assertEqual(2, connections.numSynapses()) self.assertEqual(set([synapse1, synapse3]), connections.synapsesForSegment(segment)) (numActiveConnected, numActivePotential) = connections.computeActivity([80, 81, 82], .5) self.assertEqual(1, numActiveConnected[segment.flatIdx]) self.assertEqual(2, numActivePotential[segment.flatIdx])
def testDestroySegmentWithDestroyedSynapses(self): """ Destroy a segment that has a destroyed synapse and a non-destroyed synapse. Make sure nothing gets double-destroyed. """ connections = Connections(1024) segment1 = connections.createSegment(11) segment2 = connections.createSegment(12) connections.createSynapse(segment1, 101, .85) synapse2a = connections.createSynapse(segment2, 201, .85) connections.createSynapse(segment2, 202, .85) self.assertEqual(3, connections.numSynapses()) connections.destroySynapse(synapse2a) self.assertEqual(2, connections.numSegments()) self.assertEqual(2, connections.numSynapses()) connections.destroySegment(segment2) self.assertEqual(1, connections.numSegments()) self.assertEqual(1, connections.numSynapses())
def __init__(self, columnDimensions=(2048, ), cellsPerColumn=32, activationThreshold=13, initialPermanence=0.21, connectedPermanence=0.50, minThreshold=10, maxNewSynapseCount=20, permanenceIncrement=0.10, permanenceDecrement=0.10, predictedSegmentDecrement=0.0, maxSegmentsPerCell=255, maxSynapsesPerSegment=255, seed=42, **kwargs): """ @param columnDimensions (list) Dimensions of the column space @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 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 synapses active on a segment is at least this threshold, it is selected as the best matching cell in a bursting column @param maxNewSynapseCount (int) The maximum number of synapses added to a segment during learning @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 predictedSegmentDecrement (float) Amount by which active permanences of synapses of previously predicted but inactive segments are decremented. @param seed (int) Seed for the random number generator Notes: predictedSegmentDecrement: A good value is just a bit larger than (the column-level sparsity * permanenceIncrement). So, if column-level sparsity is 2% and permanenceIncrement is 0.01, this parameter should be something like 4% * 0.01 = 0.0004). """ # Error checking if not len(columnDimensions): raise ValueError( "Number of column dimensions must be greater than 0") if cellsPerColumn <= 0: raise ValueError( "Number of cells per column must be greater than 0") if minThreshold > activationThreshold: raise ValueError( "The min threshold can't be greater than the activation threshold" ) # TODO: Validate all parameters (and add validation tests) # Save member variables self.columnDimensions = columnDimensions self.cellsPerColumn = cellsPerColumn self.activationThreshold = activationThreshold self.initialPermanence = initialPermanence self.connectedPermanence = connectedPermanence self.minThreshold = minThreshold self.maxNewSynapseCount = maxNewSynapseCount self.permanenceIncrement = permanenceIncrement self.permanenceDecrement = permanenceDecrement self.predictedSegmentDecrement = predictedSegmentDecrement # Initialize member variables self.connections = Connections( self.numberOfCells(), maxSegmentsPerCell=maxSegmentsPerCell, maxSynapsesPerSegment=maxSynapsesPerSegment) self._random = Random(seed) self.activeCells = [] self.winnerCells = [] self.activeSegments = [] self.matchingSegments = []
def setUp(self): self.connections = Connections(2048 * 32)