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
Exemplo n.º 5
0
    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