Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
ddobric committed Feb 22, 2021
2 parents 1c2e749 + d5d08cc commit 8d7d0a7
Show file tree
Hide file tree
Showing 14 changed files with 584 additions and 99 deletions.
2 changes: 2 additions & 0 deletions NeoCortexApi/NeoCortexApi/HomeostaticPlasticityController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ public bool Compute(int[] input, int[] output)

//this.htmMemory.updateMinPctOverlapDutyCycles(0.0);
this.m_HtmMemory.HtmConfig.MinPctOverlapDutyCycles = 0.0;

this.m_HtmMemory.HtmConfig.MinPctActiveDutyCycles = 0.0;
}

// If the input has been already seen, we calculate the similarity between already seen input
Expand Down
67 changes: 30 additions & 37 deletions NeoCortexApi/NeoCortexApi/SpatialPooler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -297,36 +297,27 @@ public void compute(int[] inputVector, int[] activeArray, bool learn)
// Gets overlap over every single column.
var overlaps = CalculateOverlap(this.connections, inputVector);

//var overlapsStr = Helpers.StringifyVector(overlaps);
//Debug.WriteLine("overlap: " + overlapsStr);

//totalOverlap = overlapActive * weightActive + overlapPredictedActive * weightPredictedActive

this.connections.Overlaps = overlaps;

double[] boostedOverlaps;

//
// We perform boosting here and right after that, we will recalculate bossted factors for next cycle.
// Here we boost calculated overlaps. This is related to Homeostatic Plasticity Mechanism.
// Boosting factors are calculated in the previous cycle.
if (learn)
{
//Debug.WriteLine("Boosted Factor: " + c.BoostFactors);
boostedOverlaps = ArrayUtils.Multiply(this.connections.BoostFactors, overlaps);
}
else
{
boostedOverlaps = ArrayUtils.ToDoubleArray(overlaps);
}

//Debug.WriteLine("BO: " + Helpers.StringifyVector(boostedOverlaps));

this.connections.BoostedOverlaps = boostedOverlaps;

int[] activeColumns = InhibitColumns(this.connections, boostedOverlaps);

//var indexes = ArrayUtils.IndexWhere(this.connections.BoostFactors.OrderBy(i => i).ToArray(), x => x > 1.0);
//Debug.WriteLine($"Boost factors: {indexes.Length} -" + Helpers.StringifyVector(indexes));


#if REPAIR_STABILITY
// REPAIR STABILITY FEATURE
var similarity = MathHelpers.CalcArraySimilarity(prevActCols, activeColumns);
Expand Down Expand Up @@ -461,19 +452,20 @@ public void UpdateMinDutyCycles(Connections c)
}

/// <summary>
/// Updates the minimum duty cycles in a global fashion. Sets the minimum duty cycles for the overlap and activation of all columns to be a percent of
/// the maximum in the region, specified by {@link Connections#getMinOverlapDutyCycles()} and minPctActiveDutyCycle respectively. Functionality it is
/// equivalent to <see cref="UpdateMinDutyCyclesLocal(Connections)"/>, but this function exploits the globalness of the computation to perform it in a
/// straightforward, and more efficient manner.
/// Updates the minimum duty cycles for SP that uses global inhibition.
/// Sets the minimum duty cycles for the overlap and activation of all columns to be a percent of
/// the maximum in the region, specified by MinOverlapDutyCycles and minPctActiveDutyCycle respectively.
/// Functionality it is equivalent to <see cref="UpdateMinDutyCyclesLocal(Connections)"/>,
/// but this function exploits the globalness of the computation to perform it in a straightforward, and more efficient manner.
/// </summary>
/// <param name="c"></param>
public void UpdateMinDutyCyclesGlobal(Connections c)
{
// Sets the minoverlaps to the MinPctOverlapDutyCycles * Maximal Overlap in the cortical column.
ArrayUtils.FillArray(c.HtmConfig.MinOverlapDutyCycles, (double)(c.HtmConfig.MinPctOverlapDutyCycles * ArrayUtils.Max(c.HtmConfig.OverlapDutyCycles)));
ArrayUtils.InitArray(c.HtmConfig.MinOverlapDutyCycles, (double)(c.HtmConfig.MinPctOverlapDutyCycles * ArrayUtils.Max(c.HtmConfig.OverlapDutyCycles)));

// Sets the mindutycycles to the MinPctActiveDutyCycles * Maximal Active Duty Cycles in the cortical column.
ArrayUtils.FillArray(c.HtmConfig.MinActiveDutyCycles, (double)(c.HtmConfig.MinPctActiveDutyCycles * ArrayUtils.Max(c.HtmConfig.ActiveDutyCycles)));
ArrayUtils.InitArray(c.HtmConfig.MinActiveDutyCycles, (double)(c.HtmConfig.MinPctActiveDutyCycles * ArrayUtils.Max(c.HtmConfig.ActiveDutyCycles)));
}

/// <summary>
Expand Down Expand Up @@ -508,8 +500,6 @@ public void UpdateMinDutyCyclesLocal(Connections c)
double[] overlapDutyCycles = c.HtmConfig.OverlapDutyCycles;
double minPctOverlapDutyCycles = c.HtmConfig.MinPctOverlapDutyCycles;

//Console.WriteLine($"{inhibitionRadius: inhibitionRadius}");

Parallel.For(0, len, (i) =>
{
int[] neighborhood = GetColumnNeighborhood(c, i, inhibitionRadius);
Expand All @@ -531,8 +521,6 @@ public void UpdateMinDutyCyclesLocal(Connections c)
//}
//sb.Append("]");
//Console.WriteLine($"{i} - maxOverl: {maxOverlapDuty}\t - {sb.ToString()}");
c.HtmConfig.MinActiveDutyCycles[i] = maxActiveDuty * minPctActiveDutyCycles;
c.HtmConfig.MinOverlapDutyCycles[i] = maxOverlapDuty * minPctOverlapDutyCycles;
Expand Down Expand Up @@ -580,7 +568,7 @@ public void UpdateDutyCycles(Connections c, int[] overlaps, int[] activeColumns)
c.HtmConfig.ActiveDutyCycles = UpdateDutyCyclesHelper(c, c.HtmConfig.ActiveDutyCycles, activeArray, period);
}

// TODO equation documentation

/// <summary>
/// Updates a duty cycle estimate with a new value. This is a helper function that is used to update several duty cycle variables in
/// the Column class, such as: overlapDutyCucle, activeDutyCycle, minPctDutyCycleBeforeInh, minPctDutyCycleAfterInh, etc. returns
Expand All @@ -595,6 +583,9 @@ public void UpdateDutyCycles(Connections c, int[] overlaps, int[] activeColumns)
/// <param name="dutyCycles">An array containing one or more duty cycle values that need to be updated</param>
/// <param name="newInput">A new numerical value used to update the duty cycle. Typically 1 or 0</param>
/// <param name="period">The period of the duty cycle</param>
/// <remarks>
/// This looks a bit complicate. But, simplified, dutycycle is simple counter that counts how many times the column was
/// connected to the non-zero input bit (in a case of the overlapp) or how often the column was active.</remarks>
/// <returns></returns>
public double[] UpdateDutyCyclesHelper(Connections c, double[] dutyCycles, double[] newInput, double period)
{
Expand Down Expand Up @@ -735,7 +726,7 @@ public virtual void AdaptSynapses(Connections c, int[] inputVector, int[] active

// First we initialize all permChanges to minimum decrement values,
// which are used in a case of none-connections to input.
ArrayUtils.FillArray(permChanges, -1 * c.HtmConfig.SynPermInactiveDec);
ArrayUtils.InitArray(permChanges, -1 * c.HtmConfig.SynPermInactiveDec);

// Then we update all connected permChanges to increment values for connected values.
// Permanences are set in conencted input bits to default incremental value.
Expand Down Expand Up @@ -1342,7 +1333,9 @@ public virtual int[] InhibitColumnsLocalNew(Connections c, double[] overlaps, do

/// <summary>
/// Update the boost factors for all columns. The boost factors are used to increase the overlap of inactive columns to improve
/// their chances of becoming active. and hence encourage participation of more columns in the learning process. This is a line defined as:
/// their chances of becoming active. and hence encourage participation of more columns in the learning process.
/// This is known as Homeostatc Plasticity Mechanism.
/// This is a line defined as:
/// y = mx + b
/// boost = (1-maxBoost)/minDuty * activeDutyCycle + maxBoost.
/// Intuitively this means that columns that have been active enough have a boost factor of 1, meaning their overlap is not boosted.
Expand All @@ -1367,13 +1360,13 @@ public void UpdateBoostFactors(Connections c)
double[] activeDutyCycles = c.HtmConfig.ActiveDutyCycles;
double[] minActiveDutyCycles = c.HtmConfig.MinActiveDutyCycles;

List<int> mask = new List<int>();
//List<int> mask = new List<int>();

for (int i = 0; i < minActiveDutyCycles.Length; i++)
{
if (minActiveDutyCycles[i] > 0)
mask.Add(i);
}
//for (int i = 0; i < minActiveDutyCycles.Length; i++)
//{
// if (minActiveDutyCycles[i] > 0)
// mask.Add(i);
//}

double[] boostInterim;

Expand All @@ -1386,26 +1379,26 @@ public void UpdateBoostFactors(Connections c)
else
{
double[] oneMinusMaxBoostFact = new double[c.HtmConfig.NumColumns];
ArrayUtils.FillArray(oneMinusMaxBoostFact, 1 - c.HtmConfig.MaxBoost);
ArrayUtils.InitArray(oneMinusMaxBoostFact, 1 - c.HtmConfig.MaxBoost);
boostInterim = ArrayUtils.Divide(oneMinusMaxBoostFact, minActiveDutyCycles, 0, 0);
boostInterim = ArrayUtils.Multiply(boostInterim, activeDutyCycles, 0, 0);
boostInterim = ArrayUtils.AddAmount(boostInterim, c.HtmConfig.MaxBoost);
}

// Filtered indexes are indexes of columns whose activeDutyCycles is larger than calculated minActiveDutyCycles of thet column.
List<int> filteredIndexes = new List<int>();
List<int> idxOfActiveColumns = new List<int>();

for (int i = 0; i < activeDutyCycles.Length; i++)
{
if (activeDutyCycles[i] > minActiveDutyCycles[i])
if (activeDutyCycles[i] >= minActiveDutyCycles[i])
{
filteredIndexes.Add(i);
idxOfActiveColumns.Add(i);
}
}

// Already very active columns will have boost factor 1.0. That mean their synapces on the proximal segment
// Already very active columns will have boost factor 1.0. That mean their synapses on the proximal segment
// will not be stimulated.
ArrayUtils.SetIndexesTo(boostInterim, filteredIndexes.ToArray(), 1.0d);
ArrayUtils.SetIndexesTo(boostInterim, idxOfActiveColumns.ToArray(), 1.0d);

c.BoostFactors = boostInterim;
}
Expand Down
2 changes: 1 addition & 1 deletion NeoCortexApi/NeoCortexApi/SpatialPoolerMT.cs
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ public override void AdaptSynapses(Connections c, int[] inputVector, int[] activ

// First we initialize all permChanges to minimum decrement values,
// which are used in a case of none-connections to input.
ArrayUtils.FillArray(permChanges, -1 * c.HtmConfig.SynPermInactiveDec);
ArrayUtils.InitArray(permChanges, -1 * c.HtmConfig.SynPermInactiveDec);

// Then we update all connected permChanges to increment values for connected values.
// Permanences are set in conencted input bits to default incremental value.
Expand Down
2 changes: 1 addition & 1 deletion NeoCortexApi/NeoCortexApi/SpatialPoolerParallel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ public override void AdaptSynapses(Connections c, int[] inputVector, int[] activ

// First we initialize all permChanges to minimum decrement values,
// which are used in a case of none-connections to input.
ArrayUtils.FillArray(permChanges, -1 * c.HtmConfig.SynPermInactiveDec);
ArrayUtils.InitArray(permChanges, -1 * c.HtmConfig.SynPermInactiveDec);

// Then we update all connected permChanges to increment values for connected values.
// Permanences are set in conencted input bits to default incremental value.
Expand Down
62 changes: 30 additions & 32 deletions NeoCortexApi/NeoCortexArrayLib/ArrayUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1387,18 +1387,6 @@ public static int[] Tail(int[] original)
return destination;
}

/// <summary>
/// Initializes the array with the specific value.
/// </summary>
/// <param name="array"></param>
/// <param name="val"></param>
public static void InitArray<T>(T[] array, T val)
{
for (int i = 0; i < array.Length; i++)
{
array[i] = val;
}
}

/// <summary>
/// Set <tt>value</tt> for <tt>array</tt> at specified position <tt>indexes</tt>.
Expand Down Expand Up @@ -1468,34 +1456,44 @@ public static void FillArray(Object array, int value)
}
}


/// <summary>
/// TODO to be added
/// Initializes the array with the specific value.
/// </summary>
/// <param name="array"></param>
/// <param name="value"></param>
public static void FillArray(object array, double value)
/// <param name="val"></param>
public static void InitArray<T>(T[] array, T val)
{
if (array is double[] doubleArray)
{
for (int i = 0; i < doubleArray.Length; i++)
{
doubleArray[i] = value;
}
}
else if (array is int[])
{
throw new NotSupportedException();
}
else
for (int i = 0; i < array.Length; i++)
{
//forea (Object agr in (Object[])array)
//{
// fillArray(agr, value);
//}
throw new NotSupportedException();
array[i] = val;
}
}

///// <summary>
///// Fills all elements of the array with the given value.
///// </summary>
///// <param name="array"></param>
///// <param name="value"></param>
//public static void FillArray(object array, double value)
//{
// if (array is double[] doubleArray)
// {
// for (int i = 0; i < doubleArray.Length; i++)
// {
// doubleArray[i] = value;
// }
// }
// else if (array is int[])
// {
// throw new NotSupportedException();
// }
// else
// {
// throw new NotSupportedException();
// }
//}


/// <summary>
/// Fills the array with specified value.
Expand Down
6 changes: 6 additions & 0 deletions NeoCortexApi/NeoCortexUtils/NeoCortexUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,12 @@ public static List<int> ReadCsvIntegers(String path)

private static Random rnd = new Random(42);

/// <summary>
/// Creates the random vector.
/// </summary>
/// <param name="bits"></param>
/// <param name="nonZeroPct"></param>
/// <returns></returns>
public static int[] CreateRandomVector(int bits, int nonZeroPct)
{
int[] inputVector = new int[bits];
Expand Down
Loading

0 comments on commit 8d7d0a7

Please sign in to comment.