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 __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 read(cls, proto): """Deserialize from proto instance. :param proto: (TemporalMemoryShimProto) the proto instance to read from """ tm = super(TemporalMemoryShim, cls).read(proto.baseTM) tm.predictiveCells = set(proto.predictedState) tm.connections = Connections.read(proto.conncetions)
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 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 connectionsFactory(*args, **kwargs): """ Create a :class:`~nupic.algorithms.connections.Connections` instance. :class:`TemporalMemory` subclasses may override this method to choose a different :class:`~nupic.algorithms.connections.Connections` implementation, or to augment the instance otherwise returned by the default :class:`~nupic.algorithms.connections.Connections` implementation. See :class:`~nupic.algorithms.connections.Connections` for constructor signature and usage. :returns: :class:`~nupic.algorithms.connections.Connections` instance """ return Connections(*args, **kwargs)
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 __init__(self, l4N, l4W, numModules, moduleDimensions, maxActivePerModule, l6ActivationThreshold): self.numModules = numModules self.moduleDimensions = moduleDimensions self._cellsPerModule = np.prod(moduleDimensions) self.maxActivePerModule = maxActivePerModule self.l4N = l4N self.l4W = l4W self.l6ActivationThreshold = l6ActivationThreshold self.l4TM = TemporalMemory( columnCount=l4N, basalInputSize=numModules * self._cellsPerModule, cellsPerColumn=4, #activationThreshold=int(numModules / 2) + 1, #reducedBasalThreshold=int(numModules / 2) + 1, activationThreshold=1, reducedBasalThreshold=1, initialPermanence=1.0, connectedPermanence=0.5, minThreshold=1, sampleSize=numModules, permanenceIncrement=1.0, permanenceDecrement=0.0, ) self.l6Connections = [ Connections(numCells=self._cellsPerModule) for _ in xrange(numModules) ] self.pooler = ColumnPooler(inputWidth=self.numModules * self._cellsPerModule, ) self.classifier = KNNClassifier(k=1, distanceMethod="rawOverlap") #self.classifier = KNNClassifier(k=1, distanceMethod="norm") # Active state self.activeL6Cells = [[] for _ in xrange(numModules)] self.activeL5Cells = [[] for _ in xrange(numModules)] self.predictedL6Cells = [set([]) for _ in xrange(numModules)] # Debug state self.activeL6BeforeMotor = [[] for _ in xrange(numModules)] self.l6ToL4Map = collections.defaultdict(list)
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 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 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.assertEqual(2, connections.numSegments(11)) self.assertEqual(2, connections.numSegments())
def read(cls, proto): """ Reads deserialized data from proto object. :param proto: (DynamicStructBuilder) Proto object :returns: (:class:TemporalMemory) TemporalMemory instance """ tm = object.__new__(cls) # capnp fails to save a tuple, so proto.columnDimensions was forced to # serialize as a list. We prefer a tuple, however, because columnDimensions # should be regarded as immutable. tm.columnDimensions = tuple(proto.columnDimensions) tm.cellsPerColumn = int(proto.cellsPerColumn) tm.activationThreshold = int(proto.activationThreshold) tm.initialPermanence = proto.initialPermanence tm.connectedPermanence = proto.connectedPermanence tm.minThreshold = int(proto.minThreshold) tm.maxNewSynapseCount = int(proto.maxNewSynapseCount) tm.permanenceIncrement = proto.permanenceIncrement tm.permanenceDecrement = proto.permanenceDecrement tm.predictedSegmentDecrement = proto.predictedSegmentDecrement tm.maxSegmentsPerCell = int(proto.maxSegmentsPerCell) tm.maxSynapsesPerSegment = int(proto.maxSynapsesPerSegment) tm.connections = Connections.read(proto.connections) #pylint: disable=W0212 tm._random = Random() tm._random.read(proto.random) #pylint: enable=W0212 tm.activeCells = [int(x) for x in proto.activeCells] tm.winnerCells = [int(x) for x in proto.winnerCells] flatListLength = tm.connections.segmentFlatListLength() tm.numActiveConnectedSynapsesForSegment = [0] * flatListLength tm.numActivePotentialSynapsesForSegment = [0] * flatListLength tm.lastUsedIterationForSegment = [0] * flatListLength tm.activeSegments = [] tm.matchingSegments = [] for protoSegment in proto.activeSegments: tm.activeSegments.append( tm.connections.getSegment(protoSegment.cell, protoSegment.idxOnCell)) for protoSegment in proto.matchingSegments: tm.matchingSegments.append( tm.connections.getSegment(protoSegment.cell, protoSegment.idxOnCell)) for protoSegment in proto.numActivePotentialSynapsesForSegment: segment = tm.connections.getSegment(protoSegment.cell, protoSegment.idxOnCell) tm.numActivePotentialSynapsesForSegment[segment.flatIdx] = (int( protoSegment.number)) tm.iteration = long(proto.iteration) for protoSegment in proto.lastUsedIterationForSegment: segment = tm.connections.getSegment(protoSegment.cell, protoSegment.idxOnCell) tm.lastUsedIterationForSegment[segment.flatIdx] = (long( protoSegment.number)) return tm
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 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 1 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) inputVec = [50, 52, 53, 80, 81, 82, 150, 151] (numActiveConnected, numActivePotential) = connections.computeActivity(inputVec, .5) self.assertEqual(1, numActiveConnected[segment1a.flatIdx]) self.assertEqual(2, numActivePotential[segment1a.flatIdx]) self.assertEqual(2, numActiveConnected[segment2a.flatIdx]) self.assertEqual(3, numActivePotential[segment2a.flatIdx])
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 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 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 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 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 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(set([synapse2, synapse3, synapse4]), connections.synapsesForSegment(segment3)) connections.destroySegment(segment5) self.assertEqual(set([synapse2, synapse3, synapse4]), connections.synapsesForSegment(segment3)) self.assertEqual(203, synapse3.presynapticCell)
def testWriteRead(self): c1 = Connections(1024) # Add data before serializing s1 = c1.createSegment(0) c1.createSynapse(s1, 254, 0.1173) s2 = c1.createSegment(100) c1.createSynapse(s2, 20, 0.3) c1.createSynapse(s1, 40, 0.3) s3 = c1.createSegment(0) c1.createSynapse(s3, 0, 0.5) c1.createSynapse(s3, 1, 0.5) s4 = c1.createSegment(10) c1.createSynapse(s4, 0, 0.5) c1.createSynapse(s4, 1, 0.5) c1.destroySegment(s4) proto1 = ConnectionsProto_capnp.ConnectionsProto.new_message() c1.write(proto1) # Write the proto to a temp file and read it back into a new proto with tempfile.TemporaryFile() as f: proto1.write(f) f.seek(0) proto2 = ConnectionsProto_capnp.ConnectionsProto.read(f) # Load the deserialized proto c2 = Connections.read(proto2) # Check that the two connections objects are functionally equal self.assertEqual(c1, c2)
def testDestroySegment(self): """ Creates a segment, destroys it, and makes sure it got destroyed along with all of its synapses. """ connections = Connections(1024) connections.createSegment(10) segment2 = connections.createSegment(20) connections.createSegment(30) connections.createSegment(40) connections.createSynapse(segment2, 80, 0.85) connections.createSynapse(segment2, 81, 0.85) connections.createSynapse(segment2, 82, 0.15) self.assertEqual(4, connections.numSegments()) self.assertEqual(3, connections.numSynapses()) connections.destroySegment(segment2) self.assertEqual(3, connections.numSegments()) self.assertEqual(0, connections.numSynapses()) (numActiveConnected, numActivePotential) = connections.computeActivity([80, 81, 82], 0.5) self.assertEqual(0, numActiveConnected[segment2.flatIdx]) self.assertEqual(0, numActivePotential[segment2.flatIdx])
def read(cls, proto): """ Reads deserialized data from proto object. :param proto: (DynamicStructBuilder) Proto object :returns: (:class:TemporalMemory) TemporalMemory instance """ tm = object.__new__(cls) # capnp fails to save a tuple, so proto.columnDimensions was forced to # serialize as a list. We prefer a tuple, however, because columnDimensions # should be regarded as immutable. tm.columnDimensions = tuple(proto.columnDimensions) tm.cellsPerColumn = int(proto.cellsPerColumn) tm.activationThreshold = int(proto.activationThreshold) tm.initialPermanence = round(proto.initialPermanence, EPSILON_ROUND) tm.connectedPermanence = round(proto.connectedPermanence, EPSILON_ROUND) tm.minThreshold = int(proto.minThreshold) tm.maxNewSynapseCount = int(proto.maxNewSynapseCount) tm.permanenceIncrement = round(proto.permanenceIncrement, EPSILON_ROUND) tm.permanenceDecrement = round(proto.permanenceDecrement, EPSILON_ROUND) tm.predictedSegmentDecrement = round(proto.predictedSegmentDecrement, EPSILON_ROUND) tm.maxSegmentsPerCell = int(proto.maxSegmentsPerCell) tm.maxSynapsesPerSegment = int(proto.maxSynapsesPerSegment) tm.connections = Connections.read(proto.connections) #pylint: disable=W0212 tm._random = Random() tm._random.read(proto.random) #pylint: enable=W0212 tm.activeCells = [int(x) for x in proto.activeCells] tm.winnerCells = [int(x) for x in proto.winnerCells] flatListLength = tm.connections.segmentFlatListLength() tm.numActiveConnectedSynapsesForSegment = [0] * flatListLength tm.numActivePotentialSynapsesForSegment = [0] * flatListLength tm.lastUsedIterationForSegment = [0] * flatListLength tm.activeSegments = [] tm.matchingSegments = [] for protoSegment in proto.activeSegments: tm.activeSegments.append( tm.connections.getSegment(protoSegment.cell, protoSegment.idxOnCell)) for protoSegment in proto.matchingSegments: tm.matchingSegments.append( tm.connections.getSegment(protoSegment.cell, protoSegment.idxOnCell)) for protoSegment in proto.numActivePotentialSynapsesForSegment: segment = tm.connections.getSegment(protoSegment.cell, protoSegment.idxOnCell) tm.numActivePotentialSynapsesForSegment[segment.flatIdx] = ( int(protoSegment.number)) tm.iteration = long(proto.iteration) for protoSegment in proto.lastUsedIterationForSegment: segment = tm.connections.getSegment(protoSegment.cell, protoSegment.idxOnCell) tm.lastUsedIterationForSegment[segment.flatIdx] = ( long(protoSegment.number)) return tm
def read(cls, proto): """ Reads deserialized data from proto object. @param proto (DynamicStructBuilder) Proto object @return (TemporalMemory) TemporalMemory instance """ tm = object.__new__(cls) # capnp fails to save a tuple, so proto.columnDimensions was forced to # serialize as a list. We prefer a tuple, however, because columnDimensions # should be regarded as immutable. tm.columnDimensions = tuple(proto.columnDimensions) tm.cellsPerColumn = int(proto.cellsPerColumn) tm.activationThreshold = int(proto.activationThreshold) tm.initialPermanence = proto.initialPermanence tm.connectedPermanence = proto.connectedPermanence tm.minThreshold = int(proto.minThreshold) tm.maxNewSynapseCount = int(proto.maxNewSynapseCount) tm.permanenceIncrement = proto.permanenceIncrement tm.permanenceDecrement = proto.permanenceDecrement tm.predictedSegmentDecrement = proto.predictedSegmentDecrement tm.connections = Connections.read(proto.connections) #pylint: disable=W0212 tm._random = Random() tm._random.read(proto.random) #pylint: enable=W0212 tm.activeCells = [int(x) for x in proto.activeCells] tm.winnerCells = [int(x) for x in proto.winnerCells] flatListLength = tm.connections.segmentFlatListLength() tm.numActiveConnectedSynapsesForSegment = [0] * flatListLength tm.numActivePotentialSynapsesForSegment = [0] * flatListLength tm.activeSegments = [] tm.matchingSegments = [] for i in xrange(len(proto.activeSegmentOverlaps)): protoSegmentOverlap = proto.activeSegmentOverlaps[i] segment = tm.connections.getSegment(protoSegmentOverlap.cell, protoSegmentOverlap.segment) tm.activeSegments.append(segment) overlap = protoSegmentOverlap.overlap tm.numActiveConnectedSynapsesForSegment[segment.flatIdx] = overlap for i in xrange(len(proto.matchingSegmentOverlaps)): protoSegmentOverlap = proto.matchingSegmentOverlaps[i] segment = tm.connections.getSegment(protoSegmentOverlap.cell, protoSegmentOverlap.segment) tm.matchingSegments.append(segment) overlap = protoSegmentOverlap.overlap tm.numActivePotentialSynapsesForSegment[segment.flatIdx] = overlap return tm