def _calculateBasalLearning(self, activeColumns, burstingColumns, correctPredictedCells, activeBasalSegments, matchingBasalSegments, basalPotentialOverlaps): """ Basic Temporal Memory learning. Correctly predicted cells always have active basal segments, and we learn on these segments. In bursting columns, we either learn on an existing basal segment, or we grow a new one. The only influence apical dendrites have on basal learning is: the apical dendrites influence which cells are considered "predicted". So an active apical dendrite can keep some basal segments in active columns from learning. @param correctPredictedCells (numpy array) @param burstingColumns (numpy array) @param activeBasalSegments (numpy array) @param matchingBasalSegments (numpy array) @param basalPotentialOverlaps (numpy array) @return (tuple) - learningActiveBasalSegments (numpy array) Active basal segments on correct predicted cells - learningMatchingBasalSegments (numpy array) Matching basal segments selected for learning in bursting columns - basalSegmentsToPunish (numpy array) Basal segments that should be punished for predicting an inactive column - newBasalSegmentCells (numpy array) Cells in bursting columns that were selected to grow new basal segments - learningCells (numpy array) Cells that have learning basal segments or are selected to grow a basal segment """ # Correctly predicted columns learningActiveBasalSegments = self.basalConnections.filterSegmentsByCell( activeBasalSegments, correctPredictedCells) cellsForMatchingBasal = self.basalConnections.mapSegmentsToCells( matchingBasalSegments) matchingCells = np.unique(cellsForMatchingBasal) (matchingCellsInBurstingColumns, burstingColumnsWithNoMatch) = np2.setCompare( matchingCells, burstingColumns, matchingCells / self.cellsPerColumn, rightMinusLeft=True) learningMatchingBasalSegments = self._chooseBestSegmentPerColumn( self.basalConnections, matchingCellsInBurstingColumns, matchingBasalSegments, basalPotentialOverlaps, self.cellsPerColumn) newBasalSegmentCells = self._getCellsWithFewestSegments( self.basalConnections, self.rng, burstingColumnsWithNoMatch, self.cellsPerColumn) learningCells = np.concatenate( (correctPredictedCells, self.basalConnections.mapSegmentsToCells(learningMatchingBasalSegments), newBasalSegmentCells)) # Incorrectly predicted columns correctMatchingBasalMask = np.in1d( cellsForMatchingBasal / self.cellsPerColumn, activeColumns) basalSegmentsToPunish = matchingBasalSegments[~correctMatchingBasalMask] return (learningActiveBasalSegments, learningMatchingBasalSegments, basalSegmentsToPunish, newBasalSegmentCells, learningCells)
def compute(self, activeColumns, basalInput, basalGrowthCandidates, apicalInput=EMPTY_UINT_ARRAY, apicalGrowthCandidates=EMPTY_UINT_ARRAY, learn=True): """ @param activeColumns (numpy array) @param basalInput (numpy array) @param basalGrowthCandidates (numpy array) @param apicalInput (numpy array) @param apicalGrowthCandidates (numpy array) @param learn (bool) """ # Calculate predictions for this timestep (activeBasalSegments, matchingBasalSegments, basalPotentialOverlaps) = self._calculateSegmentActivity( self.basalConnections, basalInput, self.connectedPermanence, self.activationThreshold, self.minThreshold) (activeApicalSegments, matchingApicalSegments, apicalPotentialOverlaps) = self._calculateSegmentActivity( self.apicalConnections, apicalInput, self.connectedPermanence, self.activationThreshold, self.minThreshold) predictedCells = self._calculatePredictedCells(activeBasalSegments, activeApicalSegments) # Calculate active cells (correctPredictedCells, burstingColumns) = np2.setCompare(predictedCells, activeColumns, predictedCells / self.cellsPerColumn, rightMinusLeft=True) newActiveCells = np.concatenate((correctPredictedCells, np2.getAllCellsInColumns( burstingColumns, self.cellsPerColumn))) # Calculate learning (learningActiveBasalSegments, learningMatchingBasalSegments, basalSegmentsToPunish, newBasalSegmentCells, learningCells) = self._calculateBasalLearning( activeColumns, burstingColumns, correctPredictedCells, activeBasalSegments, matchingBasalSegments, basalPotentialOverlaps) (learningActiveApicalSegments, learningMatchingApicalSegments, apicalSegmentsToPunish, newApicalSegmentCells) = self._calculateApicalLearning( learningCells, activeColumns, activeApicalSegments, matchingApicalSegments, apicalPotentialOverlaps) # Learn if learn: # Learn on existing segments for learningSegments in (learningActiveBasalSegments, learningMatchingBasalSegments): self._learn(self.basalConnections, self.rng, learningSegments, basalInput, basalGrowthCandidates, basalPotentialOverlaps, self.initialPermanence, self.sampleSize, self.permanenceIncrement, self.permanenceDecrement, self.maxSynapsesPerSegment) for learningSegments in (learningActiveApicalSegments, learningMatchingApicalSegments): self._learn(self.apicalConnections, self.rng, learningSegments, apicalInput, apicalGrowthCandidates, apicalPotentialOverlaps, self.initialPermanence, self.sampleSize, self.permanenceIncrement, self.permanenceDecrement, self.maxSynapsesPerSegment) # Punish incorrect predictions if self.predictedSegmentDecrement != 0.0: self.basalConnections.adjustActiveSynapses( basalSegmentsToPunish, basalInput, -self.predictedSegmentDecrement) self.apicalConnections.adjustActiveSynapses( apicalSegmentsToPunish, apicalInput, -self.predictedSegmentDecrement) # Grow new segments if len(basalGrowthCandidates) > 0: self._learnOnNewSegments(self.basalConnections, self.rng, newBasalSegmentCells, basalGrowthCandidates, self.initialPermanence, self.sampleSize, self.maxSynapsesPerSegment) if len(apicalGrowthCandidates) > 0: self._learnOnNewSegments(self.apicalConnections, self.rng, newApicalSegmentCells, apicalGrowthCandidates, self.initialPermanence, self.sampleSize, self.maxSynapsesPerSegment) # Save the results self.activeCells = newActiveCells self.winnerCells = learningCells self.prevPredictedCells = predictedCells
def _calculateLearning(self, activeColumns, burstingColumns, correctPredictedCells, activeBasalSegments, activeApicalSegments, matchingBasalSegments, matchingApicalSegments, basalPotentialOverlaps, apicalPotentialOverlaps): """ Learning occurs on pairs of segments. Correctly predicted cells always have active basal and apical segments, and we learn on these segments. In bursting columns, we either learn on an existing segment pair, or we grow a new pair of segments. @param activeColumns (numpy array) @param burstingColumns (numpy array) @param correctPredictedCells (numpy array) @param activeBasalSegments (numpy array) @param activeApicalSegments (numpy array) @param matchingBasalSegments (numpy array) @param matchingApicalSegments (numpy array) @param basalPotentialOverlaps (numpy array) @param apicalPotentialOverlaps (numpy array) @return (tuple) - learningActiveBasalSegments (numpy array) Active basal segments on correct predicted cells - learningActiveApicalSegments (numpy array) Active apical segments on correct predicted cells - learningMatchingBasalSegments (numpy array) Matching basal segments selected for learning in bursting columns - learningMatchingApicalSegments (numpy array) Matching apical segments selected for learning in bursting columns - basalSegmentsToPunish (numpy array) Basal segments that should be punished for predicting an inactive column - apicalSegmentsToPunish (numpy array) Apical segments that should be punished for predicting an inactive column - newSegmentCells (numpy array) Cells in bursting columns that were selected to grow new segments - learningCells (numpy array) Every cell that has a learning segment or was selected to grow a segment """ # Correctly predicted columns learningActiveBasalSegments = self.basalConnections.filterSegmentsByCell( activeBasalSegments, correctPredictedCells) learningActiveApicalSegments = self.apicalConnections.filterSegmentsByCell( activeApicalSegments, correctPredictedCells) # Bursting columns cellsForMatchingBasal = self.basalConnections.mapSegmentsToCells( matchingBasalSegments) cellsForMatchingApical = self.apicalConnections.mapSegmentsToCells( matchingApicalSegments) matchingCells = np.intersect1d( cellsForMatchingBasal, cellsForMatchingApical) (matchingCellsInBurstingColumns, burstingColumnsWithNoMatch) = np2.setCompare( matchingCells, burstingColumns, matchingCells / self.cellsPerColumn, rightMinusLeft=True) (learningMatchingBasalSegments, learningMatchingApicalSegments) = self._chooseBestSegmentPairPerColumn( matchingCellsInBurstingColumns, matchingBasalSegments, matchingApicalSegments, basalPotentialOverlaps, apicalPotentialOverlaps) newSegmentCells = self._getCellsWithFewestSegments( burstingColumnsWithNoMatch) # Incorrectly predicted columns if self.basalPredictedSegmentDecrement > 0.0: correctMatchingBasalMask = np.in1d( cellsForMatchingBasal / self.cellsPerColumn, activeColumns) basalSegmentsToPunish = matchingBasalSegments[~correctMatchingBasalMask] else: basalSegmentsToPunish = () if self.apicalPredictedSegmentDecrement > 0.0: correctMatchingApicalMask = np.in1d( cellsForMatchingApical / self.cellsPerColumn, activeColumns) apicalSegmentsToPunish = matchingApicalSegments[~correctMatchingApicalMask] else: apicalSegmentsToPunish = () # Make a list of every cell that is learning learningCells = np.concatenate( (correctPredictedCells, self.basalConnections.mapSegmentsToCells(learningMatchingBasalSegments), newSegmentCells)) return (learningActiveBasalSegments, learningActiveApicalSegments, learningMatchingBasalSegments, learningMatchingApicalSegments, basalSegmentsToPunish, apicalSegmentsToPunish, newSegmentCells, learningCells)
def activateCells(self, activeColumns, basalReinforceCandidates, apicalReinforceCandidates, basalGrowthCandidates, apicalGrowthCandidates, learn=True): """ Activate cells in the specified columns, using the result of the previous 'depolarizeCells' as predictions. Then learn. @param activeColumns (numpy array) List of active columns @param basalReinforceCandidates (numpy array) List of bits that the active cells may reinforce basal synapses to. @param apicalReinforceCandidates (numpy array) List of bits that the active cells may reinforce apical synapses to. @param basalGrowthCandidates (numpy array or None) List of bits that the active cells may grow new basal synapses to. @param apicalGrowthCandidates (numpy array or None) List of bits that the active cells may grow new apical synapses to @param learn (bool) Whether to grow / reinforce / punish synapses """ # Calculate active cells (correctPredictedCells, burstingColumns) = np2.setCompare(self.predictedCells, activeColumns, self.predictedCells / self.cellsPerColumn, rightMinusLeft=True) newActiveCells = np.concatenate((correctPredictedCells, np2.getAllCellsInColumns( burstingColumns, self.cellsPerColumn))) # Calculate learning (learningActiveBasalSegments, learningActiveApicalSegments, learningMatchingBasalSegments, learningMatchingApicalSegments, basalSegmentsToPunish, apicalSegmentsToPunish, newSegmentCells, learningCells) = self._calculateLearning(activeColumns, burstingColumns, correctPredictedCells, self.activeBasalSegments, self.activeApicalSegments, self.matchingBasalSegments, self.matchingApicalSegments, self.basalPotentialOverlaps, self.apicalPotentialOverlaps) if learn: # Learn on existing segments for learningSegments in (learningActiveBasalSegments, learningMatchingBasalSegments): self._learn(self.basalConnections, self.rng, learningSegments, basalReinforceCandidates, basalGrowthCandidates, self.basalPotentialOverlaps, self.initialPermanence, self.sampleSize, self.permanenceIncrement, self.permanenceDecrement, self.maxSynapsesPerSegment) for learningSegments in (learningActiveApicalSegments, learningMatchingApicalSegments): self._learn(self.apicalConnections, self.rng, learningSegments, apicalReinforceCandidates, apicalGrowthCandidates, self.apicalPotentialOverlaps, self.initialPermanence, self.sampleSize, self.permanenceIncrement, self.permanenceDecrement, self.maxSynapsesPerSegment) # Punish incorrect predictions if self.basalPredictedSegmentDecrement != 0.0: self.basalConnections.adjustActiveSynapses( basalSegmentsToPunish, basalReinforceCandidates, -self.basalPredictedSegmentDecrement) if self.apicalPredictedSegmentDecrement != 0.0: self.apicalConnections.adjustActiveSynapses( apicalSegmentsToPunish, apicalReinforceCandidates, -self.apicalPredictedSegmentDecrement) # Only grow segments if there is basal *and* apical input. if len(basalGrowthCandidates) > 0 and len(apicalGrowthCandidates) > 0: self._learnOnNewSegments(self.basalConnections, self.rng, newSegmentCells, basalGrowthCandidates, self.initialPermanence, self.sampleSize, self.maxSynapsesPerSegment) self._learnOnNewSegments(self.apicalConnections, self.rng, newSegmentCells, apicalGrowthCandidates, self.initialPermanence, self.sampleSize, self.maxSynapsesPerSegment) # Save the results newActiveCells.sort() learningCells.sort() self.activeCells = newActiveCells self.winnerCells = learningCells self.predictedActiveCells = correctPredictedCells
def _calculateBasalLearning(self, activeColumns, burstingColumns, correctPredictedCells, activeBasalSegments, matchingBasalSegments, basalPotentialOverlaps): """ Basic Temporal Memory learning. Correctly predicted cells always have active basal segments, and we learn on these segments. In bursting columns, we either learn on an existing basal segment, or we grow a new one. The only influence apical dendrites have on basal learning is: the apical dendrites influence which cells are considered "predicted". So an active apical dendrite can prevent some basal segments in active columns from learning. @param correctPredictedCells (numpy array) @param burstingColumns (numpy array) @param activeBasalSegments (numpy array) @param matchingBasalSegments (numpy array) @param basalPotentialOverlaps (numpy array) @return (tuple) - learningActiveBasalSegments (numpy array) Active basal segments on correct predicted cells - learningMatchingBasalSegments (numpy array) Matching basal segments selected for learning in bursting columns - basalSegmentsToPunish (numpy array) Basal segments that should be punished for predicting an inactive column - newBasalSegmentCells (numpy array) Cells in bursting columns that were selected to grow new basal segments - learningCells (numpy array) Cells that have learning basal segments or are selected to grow a basal segment """ # Correctly predicted columns learningActiveBasalSegments = self.basalConnections.filterSegmentsByCell( activeBasalSegments, correctPredictedCells) cellsForMatchingBasal = self.basalConnections.mapSegmentsToCells( matchingBasalSegments) matchingCells = np.unique(cellsForMatchingBasal) (matchingCellsInBurstingColumns, burstingColumnsWithNoMatch) = np2.setCompare(matchingCells, burstingColumns, matchingCells / self.cellsPerColumn, rightMinusLeft=True) learningMatchingBasalSegments = self._chooseBestSegmentPerColumn( self.basalConnections, matchingCellsInBurstingColumns, matchingBasalSegments, basalPotentialOverlaps, self.cellsPerColumn) newBasalSegmentCells = self._getCellsWithFewestSegments( self.basalConnections, self.rng, burstingColumnsWithNoMatch, self.cellsPerColumn) learningCells = np.concatenate( (correctPredictedCells, self.basalConnections.mapSegmentsToCells( learningMatchingBasalSegments), newBasalSegmentCells)) # Incorrectly predicted columns correctMatchingBasalMask = np.in1d( cellsForMatchingBasal / self.cellsPerColumn, activeColumns) basalSegmentsToPunish = matchingBasalSegments[ ~correctMatchingBasalMask] return (learningActiveBasalSegments, learningMatchingBasalSegments, basalSegmentsToPunish, newBasalSegmentCells, learningCells)
def compute(self, activeColumns, basalInput, apicalInput, basalGrowthCandidates=None, apicalGrowthCandidates=None, learn=True): """ Perform one timestep. Use the basal and apical input to form a set of predictions, then activate the specified columns. @param activeColumns (numpy array) List of active columns @param basalInput (numpy array) List of active input bits for the basal dendrite segments @param apicalInput (numpy array) List of active input bits for the apical dendrite segments @param basalGrowthCandidates (numpy array or None) List of bits that the active cells may grow new basal synapses to. If None, the basalInput is assumed to be growth candidates. @param apicalGrowthCandidates (numpy array or None) List of bits that the active cells may grow new apical synapses to If None, the apicalInput is assumed to be growth candidates. @param learn (bool) Whether to grow / reinforce / punish synapses """ if basalGrowthCandidates is None: basalGrowthCandidates = basalInput if apicalGrowthCandidates is None: apicalGrowthCandidates = apicalInput # Calculate predictions for this timestep (activeBasalSegments, matchingBasalSegments, basalPotentialOverlaps) = self._calculateSegmentActivity( self.basalConnections, basalInput, self.connectedPermanence, self.activationThresholdBasal, self.minThresholdBasal) (activeApicalSegments, matchingApicalSegments, apicalPotentialOverlaps) = self._calculateSegmentActivity( self.apicalConnections, apicalInput, self.connectedPermanence, self.activationThresholdApical, self.minThresholdApical) # Take union of predictions predictedCells = np.union1d( self.basalConnections.mapSegmentsToCells(activeBasalSegments), self.apicalConnections.mapSegmentsToCells(activeApicalSegments)) # Calculate active cells (correctPredictedCells, burstingColumns) = np2.setCompare( predictedCells, activeColumns, predictedCells / self.cellsPerColumn, rightMinusLeft=True) newActiveCells = np.concatenate( (correctPredictedCells, np2.getAllCellsInColumns(burstingColumns, self.cellsPerColumn))) # Calculate learning (learningActiveBasalSegments, learningActiveApicalSegments, learningMatchingBasalSegments, learningMatchingApicalSegments, basalSegmentsToPunish, apicalSegmentsToPunish, newSegmentCells, learningCells) = self._calculateLearning( activeColumns, burstingColumns, correctPredictedCells, activeBasalSegments, activeApicalSegments, matchingBasalSegments, matchingApicalSegments, basalPotentialOverlaps, apicalPotentialOverlaps) if learn: # Learn on existing segments for learningSegments in (learningActiveBasalSegments, learningMatchingBasalSegments): self._learn(self.basalConnections, self.rng, learningSegments, basalInput, basalGrowthCandidates, basalPotentialOverlaps, self.initialPermanence, self.sampleSize, self.permanenceIncrement, self.permanenceDecrement, self.maxSynapsesPerSegment) for learningSegments in (learningActiveApicalSegments, learningMatchingApicalSegments): self._learn(self.apicalConnections, self.rng, learningSegments, apicalInput, apicalGrowthCandidates, apicalPotentialOverlaps, self.initialPermanence, self.sampleSize, self.permanenceIncrement, self.permanenceDecrement, self.maxSynapsesPerSegment) # Punish incorrect predictions if self.basalPredictedSegmentDecrement != 0.0: self.basalConnections.adjustActiveSynapses( basalSegmentsToPunish, basalInput, -self.basalPredictedSegmentDecrement) if self.apicalPredictedSegmentDecrement != 0.0: self.apicalConnections.adjustActiveSynapses( apicalSegmentsToPunish, apicalInput, -self.apicalPredictedSegmentDecrement) # Only grow segments if there is basal *and* apical input. if len(basalGrowthCandidates) > 0 and len( apicalGrowthCandidates) > 0: self._learnOnNewSegments(self.basalConnections, self.rng, newSegmentCells, basalGrowthCandidates, self.initialPermanence, self.sampleSize, self.maxSynapsesPerSegment) self._learnOnNewSegments(self.apicalConnections, self.rng, newSegmentCells, apicalGrowthCandidates, self.initialPermanence, self.sampleSize, self.maxSynapsesPerSegment) # Save the results newActiveCells.sort() learningCells.sort() self.activeCells = newActiveCells self.winnerCells = learningCells self.predictedCells = predictedCells self.activeBasalSegments = activeBasalSegments self.activeApicalSegments = activeApicalSegments