Exemple #1
0
        /// <summary>
        /// This method ensures that each column has enough connections to input bits
        /// to allow it to become active. Since a column must have at least
        /// 'stimulusThreshold' overlaps in order to be considered during the
        /// inhibition phase, columns without such minimal number of connections, even
        /// if all the input bits they are connected to turn on, have no chance of
        /// obtaining the minimum threshold. For such columns, the permanence values
        /// are increased until the minimum number of connections are formed.
        /// </summary>
        /// <param name="htmConfig"></param>
        /// <param name="permanences">An array of permanence values for a column. The array is "dense", i.e. it contains an entry for each input bit, even if the permanence value is 0.</param>
        /// <param name="potentialIndexes">The indexes of inputs in the specified <see cref="Column"/>'s pool.</param>
        public static void BoostProximalSegment(HtmConfig htmConfig, double[] permanences, int[] potentialIndexes)
        {
            // TODO. Consider moving this condition to the initialization of the SP.
            if (potentialIndexes.Length < htmConfig.StimulusThreshold)
            {
                throw new ArgumentException("StimulusThreshold as number of required connected synapses cannot be greather than number of neurons in receptive field.");
            }

            ArrayUtils.EnsureBetweenMinAndMax(permanences, htmConfig.SynPermMin, htmConfig.SynPermMax);

            while (true)
            {
                // Gets number of synapses with permanence value grather than 'SynPermConnected' = Connected Synapses.
                int numConnected = ArrayUtils.GreaterThanAtIndex(htmConfig.SynPermConnected, permanences, potentialIndexes);

                // If enough synapses are connected, all ok.
                if (numConnected >= htmConfig.StimulusThreshold)
                {
                    return;
                }

                // If number of connected synapses is below threshold,
                // then permanences of all synapses will be incremented (raised) until column is connected.
                ArrayUtils.RaiseValuesBy(htmConfig.SynPermBelowStimulusInc, permanences, potentialIndexes);
            }
        }
        /// <summary>
        /// Draws all inputs and related SDRs. It also outputs the similarity matrix.
        /// </summary>
        /// <param name="cfg"></param>
        /// <param name="inputValues"></param>
        /// <param name="activeColIndicies"></param>
        /// <param name="activeCols"></param>
        private static void GenerateResult(HtmConfig cfg, List <int[]> inputValues,
                                           Dictionary <string, int[]> activeColIndicies, Dictionary <string, int[]> activeCols)
        {
            int inpLen = (int)(Math.Sqrt(inputValues[0].Length) + 0.5);

            Dictionary <string, int[]> inpVectorsMap = new Dictionary <string, int[]>();

            for (int k = 0; k < inputValues.Count; k++)
            {
                inpVectorsMap.Add(GetInputGekFromIndex(k), ArrayUtils.IndexWhere(inputValues[k], c => c == 1));
            }

            var outRes = MathHelpers.CalculateSimilarityMatrix(activeColIndicies);

            var inRes = MathHelpers.CalculateSimilarityMatrix(inpVectorsMap);

            string[,] matrix = new string[inpVectorsMap.Keys.Count, inpVectorsMap.Keys.Count];
            int i = 0;

            foreach (var inputKey in inpVectorsMap.Keys)
            {
                for (int j = 0; j < inpVectorsMap.Keys.Count; j++)
                {
                    matrix[i, j] = $"{inRes[i, j].ToString("0.##")}/{outRes[i, j].ToString("0.##")}";
                }

                DrawBitmaps(cfg, inputKey, inputValues[i], inpLen, activeCols[inputKey]);

                i++;
            }

            PrintMatrix(inpVectorsMap.Keys.Count, inpVectorsMap.Keys.ToArray(), matrix);
        }
Exemple #3
0
        public void SerializeConnectionsTest()
        {
            int[]     inputDims  = { 3, 4, 5 };
            int[]     columnDims = { 35, 43, 52 };
            HtmConfig cfg        = new HtmConfig(inputDims, columnDims);

            Connections connections = new Connections(cfg);

            Cell cells = new Cell(12, 14, 16, 18, new CellActivity());

            var distSeg1 = new DistalDendrite(cells, 1, 2, 2, 1.0, 100);

            var distSeg2 = new DistalDendrite(cells, 44, 24, 34, 1.0, 100);

            connections.ActiveSegments.Add(distSeg1);

            using (StreamWriter sw = new StreamWriter($"ser_{nameof(SerializeConnectionsTest)}.txt"))
            {
                connections.Serialize(sw);
            }
            using (StreamReader sr = new StreamReader($"ser_{nameof(SerializeConnectionsTest)}.txt"))
            {
                Connections connections1 = Connections.Deserialize(sr);
                Assert.IsTrue(connections.Equals(connections1));
            }
        }
Exemple #4
0
        public void LearningInLayerTest(int width, int height, string imageName)
        {
            // Prepare test output folder
            var outFolder = EnsureFolderExist(nameof(ImageEncoderTest));

            // Prepare input file for test
            string inputImage = Path.Combine("TestFiles", imageName);

            // Initialize Image Encoder
            ImageEncoder encoder = new ImageEncoder(new BinarizerParams {
                ImageWidth = width, ImageHeight = height
            });

            // Initialize HTMModules
            int       inputBits  = width * height;
            int       numColumns = 1024;
            HtmConfig cfg        = new HtmConfig(new int[] { inputBits }, new int[] { numColumns });
            var       mem        = new Connections(cfg);

            SpatialPoolerMT sp = new SpatialPoolerMT();

            sp.Init(mem);

            CortexLayer <object, object> layer1 = new CortexLayer <object, object>("L1");

            layer1.HtmModules.Add("encoder", encoder);
            layer1.HtmModules.Add("sp", sp);

            //Test Compute method
            var computeResult  = layer1.Compute(inputImage, true) as int[];
            var activeCellList = GetActiveCells(computeResult);

            Debug.WriteLine($"Active Cells computed from Image {inputImage}: {activeCellList}");
        }
        /// <summary>
        /// It traverses all connected synapses of the column and calculates the span, which synapses
        /// spans between all input bits. Then it calculates average of spans accross all dimensions.
        /// </summary>
        /// <param name="column"></param>
        /// <param name="htmConfig">Topology</param>
        /// <returns></returns>
        public static double CalcAvgSpanOfConnectedSynapses(Column column, HtmConfig htmConfig)
        {
            // Gets synapses connected to input bits.(from pool of the column)
            int[] connected = column.ProximalDendrite.GetConnectedSynapsesSparse();

            if (connected == null || connected.Length == 0)
            {
                return(0);
            }

            int[] maxCoord = new int[htmConfig.InputModuleTopology.Dimensions.Length];
            int[] minCoord = new int[maxCoord.Length];
            ArrayUtils.FillArray(maxCoord, -1);
            ArrayUtils.FillArray(minCoord, ArrayUtils.Max(htmConfig.InputModuleTopology.Dimensions));

            //
            // It takes all connected synapses
            for (int i = 0; i < connected.Length; i++)
            {
                maxCoord = ArrayUtils.MaxBetween(maxCoord, AbstractFlatMatrix.ComputeCoordinates(htmConfig.InputModuleTopology.Dimensions.Length,
                                                                                                 htmConfig.InputModuleTopology.DimensionMultiplies, htmConfig.InputModuleTopology.IsMajorOrdering, connected[i]));

                minCoord = ArrayUtils.MinBetween(minCoord, AbstractFlatMatrix.ComputeCoordinates(htmConfig.InputModuleTopology.Dimensions.Length,
                                                                                                 htmConfig.InputModuleTopology.DimensionMultiplies, htmConfig.InputModuleTopology.IsMajorOrdering, connected[i]));
            }

            return(ArrayUtils.Average(ArrayUtils.Add(ArrayUtils.Subtract(maxCoord, minCoord), 1)));
        }
Exemple #6
0
        /// <summary>
        /// Performs remote initialization and configuration of all coulms in all partitions.
        /// </summary>
        /// <param name="htmConfig"></param>
        /// <returns>List of average spans of all columns on this node in this partition.
        /// This list is agreggated by caller to estimate average span for all system.</returns>
        public List <double> ConnectAndConfigureInputsDist(HtmConfig htmConfig2)
        {
            // List of results.
            ConcurrentDictionary <int, double> aggLst = new ConcurrentDictionary <int, double>();

            ParallelOptions opts = new ParallelOptions();

            opts.MaxDegreeOfParallelism = Environment.ProcessorCount;

            runBatched((batchOfElements) =>
            {
                Parallel.ForEach(batchOfElements, opts, (placement) =>
                {
                    while (true)
                    {
                        try
                        {
                            //Debug.WriteLine($"C: {placement.ActorRef.Path}");
                            var avgSpanOfPart = ((ActorReference)placement.ActorRef).Ask <double>(new ConnectAndConfigureColumnsMsg(), this.Config.ConnectionTimeout, placement.NodePath).Result;
                            aggLst.TryAdd(placement.PartitionIndx, avgSpanOfPart);
                            break;
                        }
                        catch (Exception ex)
                        {
                            Thread.Sleep(1000);
                        }
                    }
                });
            }, this.ActorMap, this.Config.BatchSize / 2);

            return(aggLst.Values.ToList());
        }
        public void Run()
        {
            Console.WriteLine($"Hello NeocortexApi! Experiment {nameof(SequenceLearning)}");

            int inputBits  = 100;
            int numColumns = 1024;

            HtmConfig cfg = new HtmConfig(new int[] { inputBits }, new int[] { numColumns })
            {
                Random = new ThreadSafeRandom(42),

                CellsPerColumn             = 25,
                GlobalInhibition           = true,
                LocalAreaDensity           = -1,
                NumActiveColumnsPerInhArea = 0.02 * numColumns,
                PotentialRadius            = (int)(0.15 * inputBits),
                StimulusThreshold          = 5.0,

                MaxBoost                = 10.0,
                DutyCyclePeriod         = 25,
                MinPctOverlapDutyCycles = 0.75,
                MaxSynapsesPerSegment   = (int)(0.02 * numColumns),

                ActivationThreshold = 15,
                ConnectedPermanence = 0.5,

                // Learning is slower than forgetting in this case.
                PermanenceDecrement = 0.25,
                PermanenceIncrement = 0.15,

                // Used by punishing of segments.
                PredictedSegmentDecrement = 0.1,
            };

            double max = 20;

            Dictionary <string, object> settings = new Dictionary <string, object>()
            {
                { "W", 15 },
                { "N", inputBits },
                { "Radius", -1.0 },
                { "MinVal", 0.0 },
                { "Periodic", false },
                { "Name", "scalar" },
                { "ClipInput", false },
                { "MaxVal", max }
            };

            EncoderBase encoder = new ScalarEncoder(settings);

            // not stable with 2048 cols 25 cells per column and 0.02 * numColumns synapses on segment.
            // Stable with permanence decrement 0.25/ increment 0.15 and ActivationThreshold 25.
            // With increment=0.2 and decrement 0.3 has taken 15 min and didn't entered the stable state.
            List <double> inputValues = new List <double>(new double[] { 0.0, 1.0, 0.0, 2.0, 3.0, 4.0, 5.0, 6.0, 5.0, 4.0, 3.0, 7.0, 1.0, 9.0, 12.0, 11.0, 12.0, 13.0, 14.0, 11.0, 12.0, 14.0, 5.0, 7.0, 6.0, 9.0, 3.0, 4.0, 3.0, 4.0, 3.0, 4.0 });

            //List<double> inputValues = new List<double>(new double[] { 6.0, 7.0, 8.0, 9.0, 10.0 });

            RunExperiment(inputBits, cfg, encoder, inputValues);
        }
        public void SpatialSimilarityExperimentTest()
        {
            Console.WriteLine($"Hello {nameof(SpatialSimilarityExperiment)} experiment.");

            // Used as a boosting parameters
            // that ensure homeostatic plasticity effect.
            double minOctOverlapCycles = 1.0;
            double maxBoost            = 5.0;

            // We will use 200 bits to represe nt an input vector (pattern).
            int inputBits = 200;

            // We will build a slice of the cortex with the given number of mini-columns
            int numColumns = 2048;

            //
            // This is a set of configuration parameters used in the experiment.
            HtmConfig cfg = new HtmConfig(new int[] { inputBits }, new int[] { numColumns })
            {
                CellsPerColumn             = 10,
                MaxBoost                   = maxBoost,
                DutyCyclePeriod            = 100,
                MinPctOverlapDutyCycles    = minOctOverlapCycles,
                StimulusThreshold          = 5,
                GlobalInhibition           = true,
                NumActiveColumnsPerInhArea = 0.02 * numColumns,
                PotentialRadius            = (int)(0.15 * inputBits),
                LocalAreaDensity           = -1,//0.5,
                ActivationThreshold        = 10,
                MaxSynapsesPerSegment      = (int)(0.01 * numColumns),
                Random = new ThreadSafeRandom(42)
            };

            double max   = 100;
            int    width = 15;
            //
            // This dictionary defines a set of typical encoder parameters.
            Dictionary <string, object> settings = new Dictionary <string, object>()
            {
                { "W", width },
                { "N", inputBits },
                { "Radius", -1.0 },
                { "MinVal", 0.0 },
                { "Periodic", false },
                { "Name", "scalar" },
                { "ClipInput", false },
                { "MaxVal", max }
            };

            EncoderBase encoder = new ScalarEncoder(settings);

            //
            // We create here 100 random input values.
            List <int[]> inputValues = GetTrainingvectors(0, inputBits, width);

            RunExperiment(cfg, encoder, inputValues);
        }
        public void TemporalMemoryInit()
        {
            HtmConfig htmConfig = new HtmConfig(new int[] { 32 }, new int[] { 32 });

            Connections connections = new Connections(htmConfig);

            TemporalMemory temporalMemory = new TemporalMemory();

            temporalMemory.Init(connections);
        }
Exemple #10
0
 public static DistributedMemory GetMemory(HtmConfig htmConfig = null)
 {
     if (htmConfig == null)
     {
         return(GetInMemoryDictionary());
     }
     else
     {
         return(GetDistributedDictionary(htmConfig));
     }
 }
        private static void DrawImages(HtmConfig cfg, string inputKey, int[] input, int[] activeColumns)
        {
            List <int[, ]> twoDimArrays = new List <int[, ]>();

            int[,] twoDimInpArray           = ArrayUtils.Make2DArray <int>(input, (int)(Math.Sqrt(input.Length) + 0.5), (int)(Math.Sqrt(input.Length) + 0.5));
            twoDimArrays.Add(twoDimInpArray = ArrayUtils.Transpose(twoDimInpArray));
            int[,] twoDimOutArray           = ArrayUtils.Make2DArray <int>(activeColumns, (int)(Math.Sqrt(cfg.NumColumns) + 0.5), (int)(Math.Sqrt(cfg.NumColumns) + 0.5));
            twoDimArrays.Add(twoDimInpArray = ArrayUtils.Transpose(twoDimOutArray));

            NeoCortexUtils.DrawBitmaps(twoDimArrays, $"{inputKey}.png", Color.Yellow, Color.Gray, 1024, 1024);
        }
Exemple #12
0
        public static DistributedMemory GetDistributedDictionary(HtmConfig htmConfig)
        {
            var cfg = Helpers.DefaultSbConfig;

            return(new DistributedMemory()
            {
                ColumnDictionary = new ActorSbDistributedDictionaryBase <Column>(cfg, UnitTestHelpers.GetLogger()),

                //ColumnDictionary = new HtmSparseIntDictionary<Column>(cfg),
                //PoolDictionary = new HtmSparseIntDictionary<Pool>(cfg),
            });
        }
        /// <summary>
        /// Runs the learning of sequences.
        /// </summary>
        /// <param name="sequences">Dictionary of sequences. KEY is the sewuence name, the VALUE is th elist of element of the sequence.</param>
        public HtmPredictionEngine Run(Dictionary <string, List <double> > sequences)
        {
            Console.WriteLine($"Hello NeocortexApi! Experiment {nameof(MultiSequenceLearning)}");

            int inputBits  = 100;
            int numColumns = 1024;

            HtmConfig cfg = new HtmConfig(new int[] { inputBits }, new int[] { numColumns })
            {
                Random = new ThreadSafeRandom(42),

                CellsPerColumn             = 25,
                GlobalInhibition           = true,
                LocalAreaDensity           = -1,
                NumActiveColumnsPerInhArea = 0.02 * numColumns,
                PotentialRadius            = (int)(0.15 * inputBits),
                //InhibitionRadius = 15,

                MaxBoost                = 10.0,
                DutyCyclePeriod         = 25,
                MinPctOverlapDutyCycles = 0.75,
                MaxSynapsesPerSegment   = (int)(0.02 * numColumns),

                ActivationThreshold = 15,
                ConnectedPermanence = 0.5,

                // Learning is slower than forgetting in this case.
                PermanenceDecrement = 0.25,
                PermanenceIncrement = 0.15,

                // Used by punishing of segments.
                PredictedSegmentDecrement = 0.1
            };

            double max = 20;

            Dictionary <string, object> settings = new Dictionary <string, object>()
            {
                { "W", 15 },
                { "N", inputBits },
                { "Radius", -1.0 },
                { "MinVal", 0.0 },
                { "Periodic", false },
                { "Name", "scalar" },
                { "ClipInput", false },
                { "MaxVal", max }
            };

            EncoderBase encoder = new ScalarEncoder(settings);

            return(RunExperiment(inputBits, cfg, encoder, sequences));
        }
Exemple #14
0
 public static void RaisePermanenceToThresholdSparse(HtmConfig htmConfig, double[] perm)
 {
     ArrayUtils.Clip(perm, htmConfig.SynPermMin, htmConfig.SynPermMax);
     while (true)
     {
         int numConnected = ArrayUtils.ValueGreaterCount(htmConfig.SynPermConnected, perm);
         if (numConnected >= htmConfig.StimulusThreshold)
         {
             return;
         }
         ArrayUtils.RaiseValuesBy(htmConfig.SynPermBelowStimulusInc, perm);
     }
 }
Exemple #15
0
        public void SerializeHtmConfigTest(int[] inputDims, int[] columnDims)
        {
            HtmConfig matrix = new HtmConfig(inputDims, columnDims);

            using (StreamWriter sw = new StreamWriter($"ser_{nameof(SerializeHtmConfigTest)}.txt"))
            {
                matrix.Serialize(sw);
            }
            using (StreamReader sr = new StreamReader($"ser_{nameof(SerializeHtmConfigTest)}.txt"))
            {
                HtmConfig matrix1 = HtmConfig.Deserialize(sr);
                Assert.IsTrue(matrix.Equals(matrix1));
            }
        }
        public void TestBurstUnpredictedColumns1()
        {
            HtmConfig   htmConfig = GetDefaultTMParameters();
            Connections cn        = new Connections(htmConfig);

            TemporalMemory tm = new TemporalMemory();

            tm.Init(cn);

            int[]        activeColumns = { 0 };
            IList <Cell> burstingCells = cn.GetCellSet(new int[] { 0, 1, 2, 3 });

            ComputeCycle cc = tm.Compute(activeColumns, true) as ComputeCycle;

            Assert.IsTrue(cc.ActiveCells.SequenceEqual(burstingCells));
        }
Exemple #17
0
        /// <summary>
        /// This method updates the permanences with a column's new permanence values. The column is identified by its index, which reflects the row in
        /// the matrix, and the permanence is given in 'sparse' form, i.e. an array whose members are associated with specific indexes. It is in charge of
        /// implementing 'clipping' - ensuring that the permanence values are always between 0 and 1 - and 'trimming' - enforcing sparseness by zeroing out
        /// all permanence values below 'synPermTrimThreshold'. It also maintains the consistency between 'permanences' (the matrix storing the permanence values),
        /// 'connectedSynapses', (the matrix storing the bits each column is connected to), and 'connectedCounts' (an array storing the number of input bits each
        /// column is connected to). Every method wishing to modify the permanence matrix should do so through this method.
        /// </summary>
        /// <param name="htmConfig">the configuration used in <see cref="Connections"/>.</param>
        /// <param name="perm">An array of permanence values for a column. The array is "dense", i.e. it contains an entry for each input bit, even if the permanence value is 0.</param>
        /// <param name="column">The column to be updated.</param>
        /// <param name="potentialIndexes">The indexes of inputs in the specified <see cref="Column"/>'s pool.</param>
        /// <param name="raisePerm">a boolean value indicating whether the permanence values</param>
        public static void UpdatePermanencesForColumn(HtmConfig htmConfig, double[] perm, Column column, int[] potentialIndexes, bool raisePerm)
        {
            if (raisePerm)
            {
                // During every learning cycle, this method ensures that every column
                // has enough connections (perm > SynPermConnected) to the iput space.
                BoostProximalSegment(htmConfig, perm, potentialIndexes);
            }

            // Here we set all permanences to 0 if the permanence value is less than SynPermTrimThreshold.
            ArrayUtils.LessOrEqualXThanSetToY(perm, htmConfig.SynPermTrimThreshold, 0);

            ArrayUtils.EnsureBetweenMinAndMax(perm, htmConfig.SynPermMin, htmConfig.SynPermMax);

            column.SetPermanences(htmConfig, perm);
        }
Exemple #18
0
        /// <summary>
        /// This method updates the permanence matrix with a column's new permanence values. The column is identified by its index, which reflects the row in
        /// the matrix, and the permanence is given in 'sparse' form, i.e. an array whose members are associated with specific indexes. It is in charge of
        /// implementing 'clipping' - ensuring that the permanence values are always between 0 and 1 - and 'trimming' - enforcing sparseness by zeroing out
        /// all permanence values below 'synPermTrimThreshold'. It also maintains the consistency between 'permanences' (the matrix storing the permanence values),
        /// 'connectedSynapses', (the matrix storing the bits each column is connected to), and 'connectedCounts' (an array storing the number of input bits each
        /// column is connected to). Every method wishing to modify the permanence matrix should do so through this method.
        /// </summary>
        /// <param name="htmConfig">the configuration used in <see cref="Connections"/>.</param>
        /// <param name="perm">An array of permanence values for a column. The array is "dense", i.e. it contains an entry for each input bit, even if the permanence value is 0.</param>
        /// <param name="column">The column in the permanence, potential and connectivity matrices.</param>
        /// <param name="maskPotential">The indexes of inputs in the specified <see cref="Column"/>'s pool.</param>
        /// <param name="raisePerm">a boolean value indicating whether the permanence values</param>
        public static void UpdatePermanencesForColumn(HtmConfig htmConfig, double[] perm, Column column, int[] maskPotential, bool raisePerm)
        {
            if (raisePerm)
            {
                // During every learning cycle, this method ensures that every column
                // has enough connections ('SynPermConnected') to iput space.
                RaisePermanenceToThreshold(htmConfig, perm, maskPotential);
            }

            // Here we set all permanences to 0
            ArrayUtils.LessOrEqualXThanSetToY(perm, htmConfig.SynPermTrimThreshold, 0);

            ArrayUtils.Clip(perm, htmConfig.SynPermMin, htmConfig.SynPermMax);

            column.SetPermanences(htmConfig, perm);
        }
Exemple #19
0
        /// <summary>
        /// Maps a column to its input bits. This method encapsulates the topology of the region. It takes the index of the column as an argument and determines
        /// what are the indices of the input vector that are located within the column's potential pool. The return value is a list containing the indices of
        /// the input bits. The current implementation of the base class only supports a 1 dimensional topology of columns with a 1 dimensional topology of inputs.
        /// To extend this class to support 2-D topology you will need to override this method. Examples of the expected output of this method:
        /// <list type="bullet">
        ///     <item>
        ///     If the potentialRadius is greater than or equal to the entire input space, (global visibility), then this method returns an array filled with
        ///     all the indices
        ///     </item>
        ///     <item>
        ///     If the topology is one dimensional, and the potentialRadius is 5, this method will return an array containing 5 consecutive values centered on
        ///     the index of the column (wrapping around if necessary).
        ///     </item>
        ///     <item>If the topology is two dimensional (not implemented), and the potentialRadius is 5, the method should return an array containing 25 '1's, where
        ///     the exact indices are to be determined by the mapping from 1-D index to 2-D position.
        ///     </item>
        /// </list>
        /// </summary>
        /// <param name="htmConfig">The configuration used in <see cref="Connections"/>.</param>
        /// <param name="columnIndex">The index identifying a column in the permanence, potential and connectivity matrices.</param>
        /// <param name="rnd"></param>
        /// <returns></returns>
        public static int[] MapPotential(HtmConfig htmConfig, int columnIndex, Random rnd)
        {
            int centerInput = MapColumn(columnIndex, htmConfig.ColumnModuleTopology, htmConfig.InputModuleTopology);

            // Here we have Receptive Field (RF)
            int[] columnInputs = HtmCompute.GetInputNeighborhood(htmConfig.WrapAround, htmConfig.InputModuleTopology, centerInput, htmConfig.PotentialRadius);

            // Select a subset of the receptive field to serve as the the potential pool.
            int numPotential = (int)(columnInputs.Length * htmConfig.PotentialPct + 0.5);

            int[] retVal = new int[numPotential];

            var data = ArrayUtils.Sample(columnInputs, retVal, rnd);

            return(data);
        }
        private HtmConfig GetDefaultTMParameters()
        {
            HtmConfig htmConfig = new HtmConfig(new int[] { 32 }, new int[] { 32 })
            {
                CellsPerColumn            = 4,
                ActivationThreshold       = 3,
                InitialPermanence         = 0.21,
                ConnectedPermanence       = 0.5,
                MinThreshold              = 2,
                MaxNewSynapseCount        = 3,
                PermanenceIncrement       = 0.1,
                PermanenceDecrement       = 0.1,
                PredictedSegmentDecrement = 0,
                Random        = new ThreadSafeRandom(42),
                RandomGenSeed = 42
            };

            return(htmConfig);
        }
Exemple #21
0
        public void VectorSimilarityExperimentTest()
        {
            Console.WriteLine($"Hello {nameof(SpatialPoolerVectorSimilarityExperiment)} experiment.");

            // Used as a boosting parameters
            // that ensure homeostatic plasticity effect.
            double minOctOverlapCycles = 1.0;
            double maxBoost            = 5.0;

            // We will use 200 bits to represe nt an input vector (pattern).
            int inputBits = 200;

            // We will build a slice of the cortex with the given number of mini-columns
            int numColumns = 2048;

            //
            // This is a set of configuration parameters used in the experiment.
            HtmConfig cfg = new HtmConfig(new int[] { inputBits }, new int[] { numColumns })
            {
                CellsPerColumn             = 10,
                MaxBoost                   = maxBoost,
                DutyCyclePeriod            = 100,
                MinPctOverlapDutyCycles    = minOctOverlapCycles,
                StimulusThreshold          = 5,
                GlobalInhibition           = false,
                NumActiveColumnsPerInhArea = 0.02 * numColumns,
                PotentialRadius            = (int)(0.15 * inputBits),
                LocalAreaDensity           = 0.5,
                ActivationThreshold        = 10,
                MaxSynapsesPerSegment      = (int)(0.01 * numColumns),
                Random = new ThreadSafeRandom(42)
            };

            int width = 15;

            //
            // We create here 100 random input values.
            List <int[]> inputValues = GetTrainingvectors(0, inputBits, width);

            RunExperiment(cfg, inputValues);
        }
Exemple #22
0
        /// <summary>
        /// Initializes the permanences of a column. The method returns a 1-D array the size of the input, where each entry in the array represents the initial
        /// permanence value between the input bit at the particular index in the array, and the column represented by the 'index' parameter.
        /// </summary>
        /// <param name="htmConfig">An array specifying the potential pool of the column. Permanence values will only be generated for input bits corresponding to
        ///                         indices for which the mask value is 1. <b>WARNING</b>: potentialPool is sparse, not an array of "1's"
        ///                         </param>
        /// <param name="potentialPool"></param>
        /// <param name="random"></param>
        /// <returns></returns>
        public static double[] InitSynapsePermanences(HtmConfig htmConfig, int[] potentialPool, Random random)
        {
            //Random random = new Random();
            double[] perm = new double[htmConfig.NumInputs];

            //foreach (int idx in column.ProximalDendrite.ConnectedInputs)
            foreach (int idx in potentialPool)
            {
                if (random.NextDouble() <= htmConfig.InitialSynapseConnsPct)
                {
                    perm[idx] = InitPermConnected(htmConfig.SynPermMax, htmConfig.SynPermMax, random);
                }
                else
                {
                    perm[idx] = InitPermNonConnected(htmConfig.SynPermConnected, random);
                }

                perm[idx] = perm[idx] < htmConfig.SynPermTrimThreshold ? 0 : perm[idx];
            }

            return(perm);
        }
Exemple #23
0
        /// <summary>
        /// This method ensures that each column has enough connections to input bits
        /// to allow it to become active. Since a column must have at least
        /// 'stimulusThreshold' overlaps in order to be considered during the
        /// inhibition phase, columns without such minimal number of connections, even
        /// if all the input bits they are connected to turn on, have no chance of
        /// obtaining the minimum threshold. For such columns, the permanence values
        /// are increased until the minimum number of connections are formed.        ///
        /// </summary>
        /// <param name="htmConfig"></param>
        /// <param name="perm"></param>
        /// <param name="maskPotential"></param>
        public static void RaisePermanenceToThreshold(HtmConfig htmConfig, double[] perm, int[] maskPotential)
        {
            if (maskPotential.Length < htmConfig.StimulusThreshold)
            {
                throw new ArgumentException("StimulusThreshold as number of required connected synapses cannot be greather than number of neurons in receptive field.");
            }

            ArrayUtils.Clip(perm, htmConfig.SynPermMin, htmConfig.SynPermMax);
            while (true)
            {
                // Gets number of synapses with permanence value grather than 'PermConnected'.
                int numConnected = ArrayUtils.ValueGreaterThanCountAtIndex(htmConfig.SynPermConnected, perm, maskPotential);

                // If enough synapces are connected, all ok.
                if (numConnected >= htmConfig.StimulusThreshold)
                {
                    return;
                }

                // If number of connected synapses is below threshold,
                // then permanences of all synapses will be incremented (raised) until column is connected.
                ArrayUtils.RaiseValuesBy(htmConfig.SynPermBelowStimulusInc, perm, maskPotential);
            }
        }
Exemple #24
0
        public HtmActor(ActorId id) : base(id)
        {
            Receive <PingNodeMsg>((msg) =>
            {
                this.Logger?.LogInformation($"Received message: '{msg.GetType().Name}'");

                return($"Ping back - {msg.Msg}");
            });

            Receive <CreateDictNodeMsg>((msg) =>
            {
                this.HtmConfig = msg.HtmAkkaConfig;

                this.Logger?.LogInformation($"Received message: '{msg.GetType().Name}'");

                return(-1);
            });

            Receive <InitColumnsMsg>((msg) =>
            {
                this.Logger?.LogDebug($"Received message: '{msg.GetType().Name}', Id: {this.Id}");

                var res = InitializeColumns(msg);

                this.Logger?.LogInformation($"Completed message: '{msg.GetType().Name}'. min:{msg.MinKey}, max:{msg.MaxKey} ,Column range: {res}, Hashcode: {this.GetHashCode()}, Elements: {this.Dict.Count}, Id: {this.Id}");

                return(res);
            });

            Receive <ConnectAndConfigureColumnsMsg>((msg) =>
            {
                this.Logger?.LogDebug($"{Id} - Received message: '{msg.GetType().Name}',  dict: {Dict.Count}, Id: {this.Id}");

                var res = CreateAndConnectColumns(msg);

                if (Dict.Count == 0)
                {
                }

                this.Logger?.LogInformation($"{Id} - Completed message: '{msg.GetType().Name}'. Avg. col. span: {res}, Hashcode: {this.GetHashCode()}, dict: {Dict.Count}, Id: {this.Id}");

                return(res);
            });

            Receive <CalculateOverlapMsg>((msg) =>
            {
                this.Logger?.LogDebug($"Received message: '{msg.GetType().Name}'");

                var res = CalculateOverlap(msg);

                if (res.Count == 0)
                {
                }

                this.Logger?.LogInformation($"Completed message: '{msg.GetType().Name}', Hashcode: {this.GetHashCode()}, Result: {res.Count}, Id={this.Id} ");

                return(res);
            });

            Receive <AdaptSynapsesMsg>((msg) =>
            {
                this.Logger?.LogDebug($"Started message: '{msg.GetType().Name}'");

                var res = AdaptSynapses(msg);

                this.Logger?.LogInformation($"Completed message: '{msg.GetType().Name}'. Result: {res}");

                return(res);
            });


            Receive <BumUpWeakColumnsMsg>((msg) =>
            {
                this.Logger?.LogDebug($"Started message: '{msg.GetType().Name}'");

                var res = BumpUpWeakColumns(msg);

                Console.WriteLine($"Completed message: '{msg.GetType().Name}'");

                return(res);
            });
        }
Exemple #25
0
        public void TestCortexLayer()
        {
            int inputBits = 100;

            double max        = 20;
            int    numColumns = 2048;

            List <double> inputValues = new List <double>(new double[] { 0.0, 1.0, 0.0, 2.0, 3.0, 4.0, 5.0, 6.0, 5.0, 4.0, 3.0, 7.0, 1.0, 9.0, 12.0, 11.0, 12.0, 13.0, 14.0, 11.0, 12.0, 14.0, 5.0, 7.0, 6.0, 9.0, 3.0, 4.0, 3.0, 4.0, 3.0, 4.0 });
            int           numInputs   = inputValues.Distinct().ToList().Count;

            var inputs = inputValues.ToArray();

            Dictionary <string, object> settings = new Dictionary <string, object>()
            {
                { "W", 15 },
                { "N", inputBits },
                { "Radius", -1.0 },
                { "MinVal", 0.0 },
                { "Periodic", false },
                { "Name", "scalar" },
                { "ClipInput", false },
                { "MaxVal", max }
            };

            EncoderBase encoder = new ScalarEncoder(settings);

            HtmConfig htmConfig = new HtmConfig(new int[] { inputBits }, new int[] { numColumns })
            {
                Random                     = new ThreadSafeRandom(42),
                CellsPerColumn             = 25,
                GlobalInhibition           = true,
                LocalAreaDensity           = -1,
                NumActiveColumnsPerInhArea = 0.02 * numColumns,
                PotentialRadius            = 50,
                InhibitionRadius           = 15,
                MaxBoost                   = 10.0,
                DutyCyclePeriod            = 25,
                MinPctOverlapDutyCycles    = 0.75,
                MaxNewSynapseCount         = (int)(0.02 * numColumns),
                ActivationThreshold        = 15,
                ConnectedPermanence        = 0.5,
                PermanenceDecrement        = 0.25,
                PermanenceIncrement        = 0.15,
                PredictedSegmentDecrement  = 0.1
            };

            Connections memory = new Connections(htmConfig);

            HomeostaticPlasticityController hpa = new HomeostaticPlasticityController(memory, numInputs * 55, (isStable, numPatterns, actColAvg, seenInputs) =>
            {
                if (isStable)
                {
                    // Event should be fired when entering the stable state.
                    Debug.WriteLine($"STABLE: Patterns: {numPatterns}, Inputs: {seenInputs}, iteration: {seenInputs / numPatterns}");
                }
                else
                {
                    // Ideal SP should never enter unstable state after stable state.
                    Debug.WriteLine($"INSTABLE: Patterns: {numPatterns}, Inputs: {seenInputs}, iteration: {seenInputs / numPatterns}");
                }
            }, numOfCyclesToWaitOnChange: 25);

            SpatialPoolerMT spatialPooler = new SpatialPoolerMT(hpa);

            spatialPooler.Init(memory, UnitTestHelpers.GetMemory());

            TemporalMemory temporalMemory = new TemporalMemory();

            temporalMemory.Init(memory);

            List <CortexRegion> regions = new List <CortexRegion>();
            CortexRegion        region0 = new CortexRegion("1st Region");

            regions.Add(region0);

            CortexLayer <object, object> layer1 = new CortexLayer <object, object>("L1");

            region0.AddLayer(layer1);
            layer1.HtmModules.Add("encoder", encoder);
            layer1.HtmModules.Add("sp", spatialPooler);
            layer1.HtmModules.Add("tm", temporalMemory);

            bool learn = true;

            int maxCycles = 3500;

            for (int i = 0; i < maxCycles; i++)
            {
                foreach (var input in inputs)
                {
                    var lyrOut = layer1.Compute(input, learn) as ComputeCycle;
                }
            }
        }
        public void FeedForwardNetTest()
        {
            int    cellsPerColumnL4    = 20;
            int    numColumnsL4        = 500;
            int    cellsPerColumnL2    = 20;
            int    numColumnsL2        = 500;
            int    inputBits           = 100;
            double minOctOverlapCycles = 1.0;
            double maxBoost            = 10.0;
            double max = 20;

            HtmConfig htmConfig_L4 = new HtmConfig(new int[] { inputBits }, new int[] { numColumnsL4 })
            {
                Random                     = new ThreadSafeRandom(42),
                CellsPerColumn             = cellsPerColumnL4,
                GlobalInhibition           = true,
                LocalAreaDensity           = -1,
                NumActiveColumnsPerInhArea = 0.02 * numColumnsL4,
                PotentialRadius            = inputBits,// Ever column is connected to 50 of 100 input cells.
                //InhibitionRadius = 15,
                MaxBoost                  = maxBoost,
                DutyCyclePeriod           = 25,
                MinPctOverlapDutyCycles   = minOctOverlapCycles,
                MaxSynapsesPerSegment     = (int)(0.02 * numColumnsL4),
                ActivationThreshold       = 15,
                ConnectedPermanence       = 0.10,
                PermanenceDecrement       = 0.25,
                PermanenceIncrement       = 0.15,
                PredictedSegmentDecrement = 0.1
            };

            // The HTM of the L2 is connected to cells of the HTM of L4.
            int inputsL2 = numColumnsL4 * cellsPerColumnL4;

            HtmConfig htmConfig_L2 = new HtmConfig(new int[] { inputsL2 }, new int[] { numColumnsL2 })
            {
                Random = new ThreadSafeRandom(42),

                CellsPerColumn             = cellsPerColumnL2,
                GlobalInhibition           = true,
                LocalAreaDensity           = -1,
                NumActiveColumnsPerInhArea = 0.1 * numColumnsL2,
                PotentialRadius            = inputsL2, // Every columns
                //InhibitionRadius = 15,
                MaxBoost                  = maxBoost,
                DutyCyclePeriod           = 25,
                MinPctOverlapDutyCycles   = minOctOverlapCycles,
                MaxSynapsesPerSegment     = (int)(0.05 * numColumnsL2),
                ActivationThreshold       = 15,
                ConnectedPermanence       = 0.5,
                PermanenceDecrement       = 0.25,
                PermanenceIncrement       = 0.15,
                PredictedSegmentDecrement = 0.1
            };

            Dictionary <string, object> settings = new Dictionary <string, object>()
            {
                { "W", 15 },
                { "N", inputBits },
                { "Radius", -1.0 },
                { "MinVal", 0.0 },
                { "Periodic", false },
                { "Name", "scalar" },
                { "ClipInput", false },
                { "MaxVal", max }
            };

            EncoderBase encoder = new ScalarEncoder(settings);
            //List<double> inputValues = new List<double>(new double[] { 12, 12, 17, 17, 12 });
            // List<double> inputValues = new List<double>(new double[] { 7, 8, 9, 10, 11, 8, 9, 12 });
            //List<double> inputValues = new List<double>(new double[] { 7, 8, 9 });
            //List<double> inputValues = new List<double>(new double[] { 12345,12345,6783,6783,12345 });
            List <double> inputValues = new List <double>(new double[] { 2, 6, 6, 7, 6, 6, 8, 1 });

            RunExperiment(inputBits, htmConfig_L4, encoder, inputValues, htmConfig_L2);
        }
Exemple #27
0
        /// <summary>
        ///
        /// </summary>
        private void RunExperiment(int inputBits, HtmConfig cfg, EncoderBase encoder, List <double> inputValues)
        {
            Stopwatch sw = new Stopwatch();

            sw.Start();

            int  maxMatchCnt = 0;
            bool learn       = true;

            var mem = new Connections(cfg);

            bool isInStableState = false;

            HtmClassifier <string, ComputeCycle> cls = new HtmClassifier <string, ComputeCycle>();

            var numInputs = inputValues.Distinct <double>().ToList().Count;

            CortexLayer <object, object> layer1 = new CortexLayer <object, object>("L1");

            TemporalMemory tm = new TemporalMemory();

            HomeostaticPlasticityController hpa = new HomeostaticPlasticityController(mem, numInputs * 150, (isStable, numPatterns, actColAvg, seenInputs) =>
            {
                if (isStable)
                {
                    // Event should be fired when entering the stable state.
                    Debug.WriteLine($"STABLE: Patterns: {numPatterns}, Inputs: {seenInputs}, iteration: {seenInputs / numPatterns}");
                }
                else
                {
                    // Ideal SP should never enter unstable state after stable state.
                    Debug.WriteLine($"INSTABLE: Patterns: {numPatterns}, Inputs: {seenInputs}, iteration: {seenInputs / numPatterns}");
                }

                // We are not learning in instable state.
                learn = isInStableState = isStable;

                //if (isStable && layer1.HtmModules.ContainsKey("tm") == false)
                //    layer1.HtmModules.Add("tm", tm);

                // Clear all learned patterns in the classifier.
                cls.ClearState();

                // Clear active and predictive cells.
                //tm.Reset(mem);
            }, numOfCyclesToWaitOnChange: 50);


            SpatialPoolerMT sp = new SpatialPoolerMT(hpa);

            sp.Init(mem);
            tm.Init(mem);

            layer1.HtmModules.Add("encoder", encoder);
            layer1.HtmModules.Add("sp", sp);

            double[] inputs         = inputValues.ToArray();
            int[]    prevActiveCols = new int[0];

            int cycle   = 0;
            int matches = 0;

            string lastPredictedValue = "0";

            //Dictionary<double, List<List<int>>> activeColumnsLst = new Dictionary<double, List<List<int>>>();

            //foreach (var input in inputs)
            //{
            //    if (activeColumnsLst.ContainsKey(input) == false)
            //        activeColumnsLst.Add(input, new List<List<int>>());
            //}

            int           maxCycles      = 3500;
            int           maxPrevInputs  = inputValues.Count - 1;
            List <string> previousInputs = new List <string>();

            previousInputs.Add("-1.0");

            //
            // Training SP to get stable. New-born stage.
            //

            for (int i = 0; i < maxCycles; i++)
            {
                matches = 0;

                cycle++;

                Debug.WriteLine($"-------------- Newborn Cycle {cycle} ---------------");

                foreach (var input in inputs)
                {
                    Debug.WriteLine($" -- {input} --");

                    var lyrOut = layer1.Compute(input, learn);

                    if (isInStableState)
                    {
                        break;
                    }
                }

                if (isInStableState)
                {
                    break;
                }
            }

            layer1.HtmModules.Add("tm", tm);

            //
            // Now training with SP+TM. SP is pretrained on the given input pattern set.
            for (int i = 0; i < maxCycles; i++)
            {
                matches = 0;

                cycle++;

                Debug.WriteLine($"-------------- Cycle {cycle} ---------------");

                foreach (var input in inputs)
                {
                    Debug.WriteLine($"-------------- {input} ---------------");

                    var lyrOut = layer1.Compute(input, learn) as ComputeCycle;

                    // lyrOut is null when the TM is added to the layer inside of HPC callback by entering of the stable state.
                    //if (isInStableState && lyrOut != null)
                    {
                        var activeColumns = layer1.GetResult("sp") as int[];

                        //layer2.Compute(lyrOut.WinnerCells, true);
                        //activeColumnsLst[input].Add(activeColumns.ToList());

                        previousInputs.Add(input.ToString());
                        if (previousInputs.Count > (maxPrevInputs + 1))
                        {
                            previousInputs.RemoveAt(0);
                        }

                        // In the pretrained SP with HPC, the TM will quickly learn cells for patterns
                        // In that case the starting sequence 4-5-6 might have the sam SDR as 1-2-3-4-5-6,
                        // Which will result in returning of 4-5-6 instead of 1-2-3-4-5-6.
                        // HtmClassifier allways return the first matching sequence. Because 4-5-6 will be as first
                        // memorized, it will match as the first one.
                        if (previousInputs.Count < maxPrevInputs)
                        {
                            continue;
                        }

                        string key = GetKey(previousInputs, input);

                        List <Cell> actCells;

                        if (lyrOut.ActiveCells.Count == lyrOut.WinnerCells.Count)
                        {
                            actCells = lyrOut.ActiveCells;
                        }
                        else
                        {
                            actCells = lyrOut.WinnerCells;
                        }

                        cls.Learn(key, actCells.ToArray());

                        if (learn == false)
                        {
                            Debug.WriteLine($"Inference mode");
                        }

                        Debug.WriteLine($"Col  SDR: {Helpers.StringifyVector(lyrOut.ActivColumnIndicies)}");
                        Debug.WriteLine($"Cell SDR: {Helpers.StringifyVector(actCells.Select(c => c.Index).ToArray())}");

                        if (key == lastPredictedValue)
                        {
                            matches++;
                            Debug.WriteLine($"Match. Actual value: {key} - Predicted value: {lastPredictedValue}");
                        }
                        else
                        {
                            Debug.WriteLine($"Missmatch! Actual value: {key} - Predicted value: {lastPredictedValue}");
                        }

                        if (lyrOut.PredictiveCells.Count > 0)
                        {
                            var predictedInputValue = cls.GetPredictedInputValue(lyrOut.PredictiveCells.ToArray());

                            Debug.WriteLine($"Current Input: {input} \t| Predicted Input: {predictedInputValue}");

                            lastPredictedValue = predictedInputValue;
                        }
                        else
                        {
                            Debug.WriteLine($"NO CELLS PREDICTED for next cycle.");
                            lastPredictedValue = String.Empty;
                        }
                    }
                }

                // The brain does not do that this way, so we don't use it.
                // tm1.reset(mem);

                double accuracy = (double)matches / (double)inputs.Length * 100.0;

                Debug.WriteLine($"Cycle: {cycle}\tMatches={matches} of {inputs.Length}\t {accuracy}%");

                if (accuracy == 100.0)
                {
                    maxMatchCnt++;
                    Debug.WriteLine($"100% accuracy reched {maxMatchCnt} times.");
                    //
                    // Experiment is completed if we are 30 cycles long at the 100% accuracy.
                    if (maxMatchCnt >= 30)
                    {
                        sw.Stop();
                        Debug.WriteLine($"Exit experiment in the stable state after 30 repeats with 100% of accuracy. Elapsed time: {sw.ElapsedMilliseconds / 1000 / 60} min.");
                        learn = false;
                        break;
                    }
                }
                else if (maxMatchCnt > 0)
                {
                    Debug.WriteLine($"At 100% accuracy after {maxMatchCnt} repeats we get a drop of accuracy with {accuracy}. This indicates instable state. Learning will be continued.");
                    maxMatchCnt = 0;
                }
            }

            Debug.WriteLine("------------ END ------------");
        }
Exemple #28
0
        /// <summary>
        ///
        /// </summary>
        private static void RunExperiment(int inputBits, HtmConfig cfg, EncoderBase encoder, List <double> inputValues)
        {
            Stopwatch sw = new Stopwatch();

            sw.Start();

            int  maxMatchCnt = 0;
            bool learn       = true;

            CortexNetwork       net     = new CortexNetwork("my cortex");
            List <CortexRegion> regions = new List <CortexRegion>();
            CortexRegion        region0 = new CortexRegion("1st Region");

            regions.Add(region0);

            var  mem = new Connections(cfg);
            bool isInStableState;

            HtmClassifier <string, ComputeCycle> cls = new HtmClassifier <string, ComputeCycle>();

            var numInputs = inputValues.Distinct <double>().ToList().Count;

            TemporalMemory tm1 = new TemporalMemory();

            HomeostaticPlasticityController hpa = new HomeostaticPlasticityController(mem, numInputs * 55, (isStable, numPatterns, actColAvg, seenInputs) =>
            {
                if (isStable)
                {
                    // Event should be fired when entering the stable state.
                    Debug.WriteLine($"STABLE: Patterns: {numPatterns}, Inputs: {seenInputs}, iteration: {seenInputs / numPatterns}");
                }
                else
                {
                    // Ideal SP should never enter unstable state after stable state.
                    Debug.WriteLine($"INSTABLE: Patterns: {numPatterns}, Inputs: {seenInputs}, iteration: {seenInputs / numPatterns}");
                }

                if (numPatterns != numInputs)
                {
                    throw new InvalidOperationException("Stable state must observe all input patterns");
                }

                isInStableState = true;
                cls.ClearState();

                tm1.Reset(mem);
            }, numOfCyclesToWaitOnChange: 25);


            SpatialPoolerMT sp1 = new SpatialPoolerMT(hpa);

            sp1.Init(mem, new DistributedMemory()
            {
                ColumnDictionary = new InMemoryDistributedDictionary <int, NeoCortexApi.Entities.Column>(1),
            });

            tm1.Init(mem);

            CortexLayer <object, object> layer1 = new CortexLayer <object, object>("L1");

            region0.AddLayer(layer1);
            layer1.HtmModules.Add("encoder", encoder);
            layer1.HtmModules.Add("sp", sp1);
            layer1.HtmModules.Add("tm", tm1);

            double[] inputs = inputValues.ToArray();

            int[] prevActiveCols = new int[0];

            int cycle   = 0;
            int matches = 0;

            string lastPredictedValue = "0";
            String prediction         = null;

            Dictionary <double, List <List <int> > > activeColumnsLst = new Dictionary <double, List <List <int> > >();

            foreach (var input in inputs)
            {
                if (activeColumnsLst.ContainsKey(input) == false)
                {
                    activeColumnsLst.Add(input, new List <List <int> >());
                }
            }

            int           maxCycles      = 3500;
            int           maxPrevInputs  = inputValues.Count - 1;
            List <string> previousInputs = new List <string>();

            previousInputs.Add("-1.0");

            //
            // Now training with SP+TM. SP is pretrained on the given input pattern.
            for (int i = 0; i < maxCycles; i++)
            {
                matches = 0;

                cycle++;

                Debug.WriteLine($"-------------- Cycle {cycle} ---------------");

                foreach (var input in inputs)
                {
                    Debug.WriteLine($"-------------- {input} ---------------");

                    var lyrOut = layer1.Compute(input, learn) as ComputeCycle;

                    var activeColumns = layer1.GetResult("sp") as int[];

                    activeColumnsLst[input].Add(activeColumns.ToList());

                    previousInputs.Add(input.ToString());
                    if (previousInputs.Count > (maxPrevInputs + 1))
                    {
                        previousInputs.RemoveAt(0);
                    }

                    string key = GetKey(previousInputs, input);

                    cls.Learn(key, lyrOut.ActiveCells.ToArray());

                    if (learn == false)
                    {
                        Debug.WriteLine($"Inference mode");
                    }

                    Debug.WriteLine($"Col  SDR: {Helpers.StringifyVector(lyrOut.ActivColumnIndicies)}");
                    Debug.WriteLine($"Cell SDR: {Helpers.StringifyVector(lyrOut.ActiveCells.Select(c => c.Index).ToArray())}");

                    if (key == lastPredictedValue)
                    {
                        matches++;
                        Debug.WriteLine($"Match. Actual value: {key} - Predicted value: {lastPredictedValue}");
                    }
                    else
                    {
                        Debug.WriteLine($"Missmatch! Actual value: {key} - Predicted value: {lastPredictedValue}");
                    }

                    if (lyrOut.PredictiveCells.Count > 0)
                    {
                        var predictedInputValue = cls.GetPredictedInputValues(lyrOut.PredictiveCells.ToArray(), 3);

                        Debug.WriteLine($"Current Input: {input}");
                        Debug.WriteLine("The predictions with similarity greater than 50% are");

                        foreach (var t in predictedInputValue)
                        {
                            if (t.Similarity >= (double)50.00)
                            {
                                Debug.WriteLine($"Predicted Input: {string.Join(", ", t.PredictedInput)},\tSimilarity Percentage: {string.Join(", ", t.Similarity)}, \tNumber of Same Bits: {string.Join(", ", t.NumOfSameBits)}");
                            }
                        }
                        lastPredictedValue = predictedInputValue.First().PredictedInput;
                    }
                    else
                    {
                        Debug.WriteLine($"NO CELLS PREDICTED for next cycle.");
                        lastPredictedValue = String.Empty;
                    }
                }


                double accuracy = (double)matches / (double)inputs.Length * 100.0;

                Debug.WriteLine($"Cycle: {cycle}\tMatches={matches} of {inputs.Length}\t {accuracy}%");

                if (accuracy == 100.0)
                {
                    maxMatchCnt++;
                    Debug.WriteLine($"100% accuracy reched {maxMatchCnt} times.");
                    if (maxMatchCnt >= 30)
                    {
                        sw.Stop();
                        Debug.WriteLine($"Exit experiment in the stable state after 30 repeats with 100% of accuracy. Elapsed time: {sw.ElapsedMilliseconds / 1000 / 60} min.");
                        learn = false;
                        break;
                    }
                }
                else if (maxMatchCnt > 0)
                {
                    Debug.WriteLine($"At 100% accuracy after {maxMatchCnt} repeats we get a drop of accuracy with {accuracy}. This indicates instable state. Learning will be continued.");
                    maxMatchCnt = 0;
                }
            }

            Debug.WriteLine("---- cell state trace ----");

            cls.TraceState($"cellState_MinPctOverlDuty-{cfg.MinPctOverlapDutyCycles}_MaxBoost-{cfg.MaxBoost}.csv");

            Debug.WriteLine("---- Spatial Pooler column state  ----");

            foreach (var input in activeColumnsLst)
            {
                using (StreamWriter colSw = new StreamWriter($"ColumState_MinPctOverlDuty-{cfg.MinPctOverlapDutyCycles}_MaxBoost-{cfg.MaxBoost}_input-{input.Key}.csv"))
                {
                    Debug.WriteLine($"------------ {input.Key} ------------");

                    foreach (var actCols in input.Value)
                    {
                        Debug.WriteLine(Helpers.StringifyVector(actCols.ToArray()));
                        colSw.WriteLine(Helpers.StringifyVector(actCols.ToArray()));
                    }
                }
            }

            Debug.WriteLine("------------ END ------------");

            Console.WriteLine("\n Please enter a number that has been learnt");
            int inputNumber = Convert.ToInt16(Console.ReadLine());

            Inference(inputNumber, false, layer1, cls);
        }
Exemple #29
0
        public static void MusicNotesExperiment()
        {
            int           inputBits   = 100;
            int           numColumns  = 2048;
            List <double> inputValues = inputValues = new List <double>(new double[] { });
            HtmConfig     cfg         = new HtmConfig(new int[] { inputBits }, new int[] { numColumns })
            {
                Random = new ThreadSafeRandom(42),

                CellsPerColumn             = 25,
                GlobalInhibition           = true,
                LocalAreaDensity           = -1,
                NumActiveColumnsPerInhArea = 0.02 * numColumns,
                PotentialRadius            = (int)(0.15 * inputBits),
                //InhibitionRadius = 15,

                MaxBoost                = 10.0,
                DutyCyclePeriod         = 25,
                MinPctOverlapDutyCycles = 0.75,
                MaxSynapsesPerSegment   = (int)(0.02 * numColumns),

                ActivationThreshold = 15,
                ConnectedPermanence = 0.5,

                // Learning is slower than forgetting in this case.
                PermanenceDecrement = 0.25,
                PermanenceIncrement = 0.15,

                // Used by punishing of segments.
                PredictedSegmentDecrement = 0.1
            };

            double max = 20;

            Dictionary <string, object> settings = new Dictionary <string, object>()
            {
                { "W", 15 },
                { "N", inputBits },
                { "Radius", -1.0 },
                { "MinVal", 0.0 },
                { "Periodic", false },
                { "Name", "scalar" },
                { "ClipInput", false },
                { "MaxVal", max }
            };

            EncoderBase encoder = new ScalarEncoder(settings);

            // Stable and reached 100% accuracy with 2577 cycles
            // List<double> inputValues = new List<double>(new double[] { 0.0, 1.0, 0.0, 2.0, 3.0, 4.0, 5.0, 6.0, 5.0, 4.0, 3.0, 7.0, 1.0, 9.0, 12.0, 11.0, 12.0, 13.0, 14.0, 11.0, 12.0, 14.0, 5.0, 7.0, 6.0, 9.0, 3.0, 4.0, 3.0, 4.0, 3.0, 4.0 });

            // Stable and reached 100% accuracy with 2554 cycles
            // List<double> inputValues = new List<double>(new double[] { 0.0, 1.0, 2.0, 3.0, 3.0, 2.0, 1.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 0.0, 1.0, 2.0, 3.0, 3.0, 2.0, 1.0, 0.0, 1.0});

            // Stable and reached 100% accuracy with 3560 cycles
            // List<double> inputValues = new List<double>(new double[] { 0.0, 1.0, 0.0, 2.0, 3.0, 4.0, 5.0, 6.0, 5.0, 4.0, 3.0, 7.0, 1.0, 9.0, 12.0, 11.0, 12.0, 13.0, 14.0, 11.0, 12.0, 14.0, 5.0, 7.0, 6.0, 9.0, 3.0, 4.0 });

            // Stable and reached 100% accuracy with 3401 cycles
            // List<double> inputValues = new List<double>(new double[] { 0.0, 1.0, 0.0, 2.0, 3.0, 4.0, 5.0, 6.0, 5.0, 4.0, 3.0, 7.0, 1.0, 9.0, 12.0, 11.0, 12.0, 13.0, 14.0, 11.0, 12.0, 14.0, 5.0, 7.0, 6.0, 9.0 });

            // Stable and 100% accuracy reached in with 2040 cycles
            // List<double> inputValues = new List<double>(new double[] { 0.0, 1.0, 0.0, 2.0, 3.0, 4.0, 5.0, 6.0, 5.0, 4.0, 3.0, 7.0, 1.0, 9.0, 12.0, 11.0, 12.0, 13.0, 14.0, 11.0, 12.0, 14.0 });

            // Stable and 100% accuracy reached in with 55 cycles
            // List<double> inputValues = new List<double>(new double[] { 0.0, 1.0, 0.0, 2.0, 3.0, 4.0, 5.0, 6.0, 5.0, 4.0, 3.0, 7.0, 1.0, 9.0, 12.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 12.0 });

            // Stable and reached 100% accuracy with 112 cycles.
            // List<double> inputValues = new List<double>(new double[] { 0.0, 1.0, 0.0, 2.0, 3.0, 4.0, 5.0, 6.0, 5.0, 4.0, 3.0, 7.0, 1.0, 9.0, 12.0, 11.0, 12.0, 13.0, 14.0, 15.0, 7.0, 5.0 });

            // Stable and reached 100% accuracy with 70 cycles.
            // var inputValues = new List<double>(new double[] {1.0,2.0,3.0,1.0,5.0,1.0,6.0});

            // Music Notes C-0, D-1, E-2, F-3, G-4, H-5
            // http://sea-01.cit.frankfurt-university.de:32224/?dmVyPTEuMDAxJiYwYzg1N2MyNmFmMzIyMjc0OD02MDlGQkRBOF83Njg0Nl8xNTU0N18xJiZmYjFlMzlhNWZmYWYyNDE9MTIzMyYmdXJsPWh0dHBzJTNBJTJGJTJGd3d3JTJFYmV0aHNub3Rlc3BsdXMlMkVjb20lMkYyMDEzJTJGMDglMkZ0d2lua2xlLXR3aW5rbGUtbGl0dGxlLXN0YXIlMkVodG1sJTBE
            // 1Stable and reached 100% accuracy with 1024 cycles.
            // var inputValues = new List<double>( new double[] { 0.0, 0.0, 4.0, 4.0, 5.0, 5.0, 4.0, 3.0, 3.0, 2.0, 2.0, 1.0, 1.0, 0.0 });

            // Stable and reached 100% accuracy with 531 cycles.
            // var inputValues = new List<double>(new double[] {0.0, 1.0, 0.0, 2.0, 3.0, 4.0, 5.0, 6.0, 5.0, 4.0, 3.0, 7.0, 1.0, 9.0, 12.0, 11.0}

            // Calling Method to input values
            inputValues = InputSequence(inputValues);

            // Sequence with multiple possibilties
            // Stable and reached 100% accuracy with 542 cycles.
            //var inputValues = new List<double>(new double[] {1.0, 2.0, 3.0, 4.0, 3.0, 2.0, 4.0, 5.0, 6.0, 1.0, 7.0});

            // Stable and reached 100% accuracy with 650 cycles.
            // var inputValues = new List<double>(new double[] { 2.0, 3.0, 2.0, 5.0, 2.0, 6.0, 2.0, 6.0, 2.0, 5.0, 2.0, 3.0, 2.0, 3.0, 2.0, 5.0, 2.0, 6.0 });

            RunExperiment(inputBits, cfg, encoder, inputValues);
        }
        /// <summary>
        /// Implements the experiment.
        /// </summary>
        /// <param name="cfg"></param>
        /// <param name="encoder"></param>
        /// <param name="inputValues"></param>
        private static void RunExperiment(HtmConfig cfg, EncoderBase encoder, List <int[]> inputValues)
        {
            // Creates the htm memory.
            var mem = new Connections(cfg);

            bool isInStableState = false;

            //
            // HPC extends the default Spatial Pooler algorithm.
            // The purpose of HPC is to set the SP in the new-born stage at the begining of the learning process.
            // In this stage the boosting is very active, but the SP behaves instable. After this stage is over
            // (defined by the second argument) the HPC is controlling the learning process of the SP.
            // Once the SDR generated for every input gets stable, the HPC will fire event that notifies your code
            // that SP is stable now.
            HomeostaticPlasticityController hpa = new HomeostaticPlasticityController(mem, inputValues.Count * 40,
                                                                                      (isStable, numPatterns, actColAvg, seenInputs) =>
            {
                // Event should only be fired when entering the stable state.
                // Ideal SP should never enter unstable state after stable state.
                if (isStable == false)
                {
                    Debug.WriteLine($"INSTABLE STATE");
                    // This should usually not happen.
                    isInStableState = false;
                }
                else
                {
                    Debug.WriteLine($"STABLE STATE");
                    // Here you can perform any action if required.
                    isInStableState = true;
                }
            }, requiredSimilarityThreshold: 0.975);

            // It creates the instance of Spatial Pooler Multithreaded version.
            SpatialPooler sp = new SpatialPoolerMT(hpa);

            // Initializes the
            sp.Init(mem);

            // Holds the indicies of active columns of the SDR.
            Dictionary <string, int[]> prevActiveColIndicies = new Dictionary <string, int[]>();

            // Holds the active column SDRs.
            Dictionary <string, int[]> prevActiveCols = new Dictionary <string, int[]>();

            // Will hold the similarity of SDKk and SDRk-1 fro every input.
            Dictionary <string, double> prevSimilarity = new Dictionary <string, double>();

            //
            // Initiaize start similarity to zero.
            for (int i = 0; i < inputValues.Count; i++)
            {
                string inputKey = GetInputGekFromIndex(i);
                prevSimilarity.Add(inputKey, 0.0);
                prevActiveColIndicies.Add(inputKey, new int[0]);
            }

            // Learning process will take 1000 iterations (cycles)
            int maxSPLearningCycles = 1000;

            for (int cycle = 0; cycle < maxSPLearningCycles; cycle++)
            {
                //Debug.WriteLine($"Cycle  ** {cycle} ** Stability: {isInStableState}");

                //
                // This trains the layer on input pattern.
                for (int inputIndx = 0; inputIndx < inputValues.Count; inputIndx++)
                {
                    string inputKey = GetInputGekFromIndex(inputIndx);
                    int[]  input    = inputValues[inputIndx];

                    double similarity;

                    int[] activeColumns = new int[(int)cfg.NumColumns];

                    // Learn the input pattern.
                    // Output lyrOut is the output of the last module in the layer.
                    sp.compute(input, activeColumns, true);
                    // DrawImages(cfg, inputKey, input, activeColumns);

                    var actColsIndicies = ArrayUtils.IndexWhere(activeColumns, c => c == 1);

                    similarity = MathHelpers.CalcArraySimilarity(actColsIndicies, prevActiveColIndicies[inputKey]);

                    Debug.WriteLine($"[i={inputKey}, cols=:{actColsIndicies.Length} s={similarity}] SDR: {Helpers.StringifyVector(actColsIndicies)}");

                    prevActiveCols[inputKey]        = activeColumns;
                    prevActiveColIndicies[inputKey] = actColsIndicies;
                    prevSimilarity[inputKey]        = similarity;

                    if (isInStableState)
                    {
                        GenerateResult(cfg, inputValues, prevActiveColIndicies, prevActiveCols);
                        return;
                    }
                }
            }
        }