Beispiel #1
0
        /// <summary>
        /// Add a new SegmentUpdateInfo object to this Cell containing proposed changes to the
        /// specified segment.
        /// </summary>
        /// <remarks>
        /// If the segment is NULL, then a new segment is to be added, otherwise
        /// the specified segment is updated.  If the segment exists, find all active
        /// synapses for the segment (either at t or t-1 based on the 'previous' parameter)
        /// and mark them as needing to be updated.  If newSynapses is true, then
        /// Region.newSynapseCount - len(activeSynapses) new synapses are added to the
        /// segment to be updated.  The (new) synapses are randomly chosen from the set
        /// of current learning cells (within Region.predictionRadius if set).
        ///
        /// These segment updates are only applied when the applySegmentUpdates
        /// method is later called on this Cell.
        /// </remarks>
        public SegmentUpdateInfo UpdateSegmentActiveSynapses(bool previous, Segment segment, bool newSynapses, UpdateType updateType)
        {
            List <DistalSynapse> activeDistalSyns = null;

            if (segment != null)
            {
                List <Synapse> activeSyns = previous
                                               ? segment.PrevActiveSynapses
                                               : segment.ActiveSynapses;
                activeDistalSyns = activeSyns.Cast <DistalSynapse>().ToList();
            }

            var segmentUpdate = new SegmentUpdateInfo();

            segmentUpdate.Initialize(this, segment, activeDistalSyns, newSynapses, this.Column.Region.StepCounter, updateType);
            this._segmentUpdates.Add(segmentUpdate);
            return(segmentUpdate);
        }
Beispiel #2
0
        /// <summary>
        /// This function reinforces each segment in this Cell's SegmentUpdateInfo.
        /// </summary>
        /// <remarks>
        /// Using the segmentUpdateInfo, the following changes are
        /// performed. If positiveReinforcement is true then synapses on the active
        /// list get their permanence counts incremented by permanenceInc. All other
        /// synapses get their permanence counts decremented by permanenceDec. If
        /// positiveReinforcement is false, then synapses on the active list get
        /// their permanence counts decremented by permanenceDec. After this step,
        /// any synapses in segmentUpdate that do yet exist get added with a permanence
        /// count of initialPerm. These new synapses are randomly chosen from the
        /// set of all cells that have learnState output = 1 at time step t.
        /// </remarks>
        public void ApplySegmentUpdates(int curTime, ApplyUpdateTrigger trigger)
        {
            Segment segment          = null;
            var     modifiedSegments = new List <Segment>();

            // Iterate through all segment updates, skipping those not to be applied now, and removing those that are applied.
            int segInfoIndex = 0;

            while (segInfoIndex < this._segmentUpdates.Count)
            {
                SegmentUpdateInfo segInfo = this._segmentUpdates[segInfoIndex];

                // Do not apply the current segment update if it was created at the current time step, and was created as a result of the cell being predictive.
                // If this is the case, then this segment update can only be evaluated at a later time step, and so should remain in the queue for now.
                bool applyUpdate = !((segInfo.CreationTimeStep == curTime) && (segInfo.UpdateType == UpdateType.DueToPredictive));

                // Do not apply the current segment update if its numPredictionSteps > 1, and if we are applying updates due to the cell still being predictive,
                // but with a greater numPredictionSteps. Unless the segment being updated predicted activation in 1 prediction step, it cannot be proven
                // incorrect, and so shouldn't be processed yet. This is because a "prediction step" can take more than one time step.
                if ((trigger == ApplyUpdateTrigger.LongerPrediction) && (segInfo.NumPredictionSteps > 1))
                {
                    applyUpdate = false;
                }

                if (applyUpdate)
                {
                    segment = segInfo.Segment;

                    if (segment != null)
                    {
                        if (trigger == ApplyUpdateTrigger.Active)
                        {
                            // The cell has become actve; positively reinforce the segment.
                            segment.UpdatePermanences(ref segInfo.ActiveDistalSynapses);
                        }
                        else
                        {
                            // The cell has become inactive of is predictive but with a longer prediction. Negatively reinforce the segment.
                            segment.DecreasePermanences(ref segInfo.ActiveDistalSynapses);
                        }

                        // Record that this segment has been modified, so it can later be checked for synapses that should be removed.
                        if (modifiedSegments.Contains(segment) == false)
                        {
                            modifiedSegments.Add(segment);
                        }
                    }

                    // Add new synapses (and new segment if necessary)
                    if (segInfo.AddNewSynapses && (trigger == ApplyUpdateTrigger.Active))
                    {
                        if (segment == null)
                        {
                            if (segInfo.CellsThatWillLearn.Count > 0) //only add if learning cells available
                            {
                                segment = segInfo.CreateCellSegment(this.Column.Region.StepCounter);
                            }
                        }
                        else if (segInfo.CellsThatWillLearn.Count > 0)
                        {
                            //add new synapses to existing segment
                            segInfo.CreateSynapsesToLearningCells(this.Column.Region.DistalSynapseParams);
                        }
                    }

                    // Remove and release the current SegmentUpdateInfo.
                    this._segmentUpdates.RemoveAt(segInfoIndex);
                }
                else
                {
                    segInfoIndex++;
                }
            }

            // Only process modified segments if all segment updates have been processed, to avoid deleting segments or synapses that
            // are referred to by still-existing segment updates.
            if (this._segmentUpdates.Count == 0)
            {
                // All segment updates have been processed, so there are none left that may have references to this cell's
                // synapses or segments. Therefore we can iterate through all segments modified above, to prune unneeded synpses and segments.
                while (modifiedSegments.Count > 0)
                {
                    // Get pointer to the current modified segment, and remove it from the modifiedSegments list.
                    segment = modifiedSegments[0];
                    modifiedSegments.RemoveAt(0);

                    // Remove from the current modified segment any synapses that have reached permanence of 0.
                    int synIndex = 0;
                    while (synIndex < segment.Synapses.Count)
                    {
                        Synapse syn = segment.Synapses[synIndex];
                        if (syn.Permanence == 0.0f)
                        {
                            // Remove and release the current synapse, whose permanence has reached 0.
                            segment.Synapses.RemoveAt(synIndex);
                        }
                        else
                        {
                            synIndex++;
                        }
                    }

                    // If this modified segment now has no synapses, remove the segment from this cell.
                    if (segment.Synapses.Count == 0)
                    {
                        this.Segments.Remove(segment);
                    }
                }
            }
            else
            {
                // Not all of the segment updates have been processed, so synapses and segments cannot be pruned.
                // (because they may be referred to by segment updates that still exist). So just clear the list of modified segments.
                modifiedSegments.Clear();
            }
        }
Beispiel #3
0
        /// <summary>
        /// Performs temporal pooling based on the current spatial pooler output.
        /// </summary>
        /// <remarks>
        /// From the Numenta white paper:
        /// The input to this code is activeColumns(t), as computed by the spatial pooler.
        /// The code computes the active and predictive state for each cell at the current
        /// timestep, t. The boolean OR of the active and predictive states for each cell
        /// forms the output of the temporal pooler for the next level.
        /// Phase 1:
        ///     Compute the active state, activeState(t), for each cell.
        ///     The first phase calculates the activeState for each cell that is in a winning
        ///     column. For those columns, the code further selects one cell per column as the
        ///     learning cell (learnState). The logic is as follows: if the bottom-up input was
        ///     predicted by any cell (i.e. its predictiveState output was 1 due to a sequence
        ///     segmentUpdateList), then those cells become active (lines 23-27).
        ///     If that segmentUpdateList became active from cells chosen with learnState on,
        ///     this cell is selected as the learning cell (lines 28-30). If the bottom-up input
        ///     was not predicted, then all cells in the column become active (lines 32-34).
        ///     In addition, the best matching cell is chosen as the learning cell (lines 36-41)
        ///     and a new segmentUpdateList is added to that cell.
        /// Phase 2:
        ///     Compute the predicted state, predictiveState(t), for each cell.
        ///     The second phase calculates the predictive state for each cell. A cell will turn
        ///     on its predictive state output if one of its segments becomes active, i.e. if
        ///     enough of its lateral inputs are currently active due to feed-forward input.
        ///     In this case, the cell queues up the following changes: a) reinforcement of the
        ///     currently active segmentUpdateList (lines 47-48), and b) reinforcement of a
        ///     segmentUpdateList that could have predicted this activation, i.e. a
        ///     segmentUpdateList that has a (potentially weak) match to activity during the
        ///     previous time step (lines 50-53).
        /// Phase 3:
        ///     Update synapses. The third and last phase actually carries out learning. In this
        ///     phase segmentUpdateList updates that have been queued up are actually implemented
        ///     once we get feed-forward input and the cell is chosen as a learning cell
        ///     (lines 56-57). Otherwise, if the cell ever stops predicting for any reason, we
        ///     negatively reinforce the segments (lines 58-60).
        /// </remarks>
        public void PerformTemporalPooling()
        {
            int    colIndex;
            Column column;
            Cell   cell;

            // Determine whether temporal learning is currently allowed.
            bool allowTemporalLearning = Global.AllowTemporalLearning && ((this.TemporalLearningStartTime == -1) || (this.TemporalLearningStartTime <= this.StepCounter)) && ((this.TemporalLearningEndTime == -1) || (this.TemporalLearningEndTime >= this.StepCounter));

            // Phase 1: Compute cell active states and segment learning updates
            for (colIndex = 0; colIndex < this.SizeX * this.SizeY; colIndex++)
            {
                column = this.Columns[colIndex];

                if (column.IsActive)
                {
                    bool predicted       = false;
                    bool learnCellChosen = false;

                    for (int cellIndex = 0; cellIndex < this.CellsPerCol; cellIndex++)
                    {
                        cell = column.Cells[cellIndex];

                        if (cell.WasPredicted)
                        {
                            Segment segment = cell.GetPreviousActiveSegment();
                            if ((segment != null) && segment.IsSequence)
                            {
                                predicted     = true;
                                cell.IsActive = true;
                                if (allowTemporalLearning && segment.GetWasActiveFromLearning())
                                {
                                    learnCellChosen = true;
                                    cell.IsLearning = true;
                                }
                            }
                        }
                    }

                    if (!predicted)
                    {
                        for (int cellIndex = 0; cellIndex < this.CellsPerCol; cellIndex++)
                        {
                            cell          = column.Cells[cellIndex];
                            cell.IsActive = true;
                        }
                    }

                    if (allowTemporalLearning && !learnCellChosen)
                    {
                        // isSequence=true, previous=true
                        Cell    bestCell    = null;
                        Segment bestSegment = null;
                        column.GetBestMatchingCell(1, true, out bestCell, out bestSegment);
                        if (Global.Debug)
                        {
                            Debug.Assert(bestCell != null);
                        }

                        bestCell.IsLearning = true;

                        // segmentToUpdate is added internally to the bestCell's update list.
                        // Then set number of prediction steps to 1 (meaning it's a sequence segment)
                        SegmentUpdateInfo segmentUpdateInfo = bestCell.UpdateSegmentActiveSynapses(true, bestSegment, true, UpdateType.DueToActive);
                        segmentUpdateInfo.NumPredictionSteps = 1;
                    }
                }
            }

            // Phase 2: Compute the predicted state for each cell
            for (colIndex = 0; colIndex < this.SizeX * this.SizeY; colIndex++)
            {
                column = this.Columns[colIndex];

                for (int cellIndex = 0; cellIndex < this.CellsPerCol; cellIndex++)
                {
                    cell = column.Cells[cellIndex];

                    // Process all segments on the cell to cache the activity for later.
                    foreach (Segment seg in cell.Segments)
                    {
                        seg.ProcessSegment();
                    }

                    foreach (Segment seg in cell.Segments)
                    {
                        // Now check for an active segment, we only need one for the cell to predict, but all Segments need to be checked
                        // so that a segment update will be created for each active segment, and so that the lowest numPredictionSteps
                        // among active segments is adopted by the cell.
                        if (seg.IsActive)
                        {
                            cell.SetIsPredicting(true, seg.NumPredictionSteps);

                            if (seg.IsSequence)
                            {
                                cell.IsSegmentPredicting = true;
                            }

                            // a) reinforcement of the currently active segments
                            if (allowTemporalLearning)
                            {
                                // Add segment update to this cell
                                cell.UpdateSegmentActiveSynapses(false, seg, false, UpdateType.DueToPredictive);
                            }
                        }
                    }

                    // b) reinforcement of a segment that could have predicted
                    //    this activation, i.e. a segment that has a (potentially weak)
                    //    match to activity during the previous time step (lines 50-53).
                    // NOTE: The check against MaxTimeSteps is a correctly functioning way of enforcing a maximum number of time steps,
                    // as opposed to the previous way of storing Max(numPredictionSteps, MaxTimeSteps) as a segment's numPredictionSteps,
                    // which caused inaccurate numPredictionSteps values to be stored, resulting in duplicate segments being created.
                    // Note also that if the system of recording and using an exact number of time steps is abandonded (and replaced with the
                    // original sequence/non-sequence system), then all references to MaxTimeSteps can be removed.
                    if (allowTemporalLearning && cell.IsPredicting && (cell.NumPredictionSteps != Segment.MaxTimeSteps))
                    {
                        Segment predictiveSegment = cell.GetBestMatchingPreviousSegment();

                        // Either update existing or add new segment for this cell considering
                        // only segments matching the number of prediction steps of the
                        // best currently active segment for this cell.
                        SegmentUpdateInfo predictiveSegUpdate = cell.UpdateSegmentActiveSynapses(true, predictiveSegment, true, UpdateType.DueToPredictive);
                        if (predictiveSegment == null)
                        {
                            predictiveSegUpdate.NumPredictionSteps = cell.NumPredictionSteps + 1;
                        }
                    }
                }
            }

            // Phase 3: Update synapses
            if (allowTemporalLearning)
            {
                for (colIndex = 0; colIndex < this.SizeX * this.SizeY; colIndex++)
                {
                    column = this.Columns[colIndex];

                    for (int cellIndex = 0; cellIndex < this.CellsPerCol; cellIndex++)
                    {
                        cell = column.Cells[cellIndex];

                        if (cell.IsLearning)
                        {
                            cell.ApplySegmentUpdates(this.StepCounter, ApplyUpdateTrigger.Active);
                        }
                        else if ((cell.IsPredicting == false) && cell.WasPredicted)
                        {
                            cell.ApplySegmentUpdates(this.StepCounter, ApplyUpdateTrigger.Inactive);
                        }
                        else if (cell.IsPredicting && cell.WasPredicted && (cell.NumPredictionSteps > 1) && (cell.PrevNumPredictionSteps == 1))
                        {
                            cell.ApplySegmentUpdates(this.StepCounter, ApplyUpdateTrigger.LongerPrediction);
                        }
                    }
                }
            }
        }