/// <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); }
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)); } }
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))); }
/// <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); }
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); }
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)); }
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); } }
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)); }
/// <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); }
/// <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); }
/// <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); }
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); }
/// <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); }
/// <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); } }
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); }); }
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); }
/// <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 ------------"); }
/// <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); }
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; } } } }