From 3a6ab04d8c7fc399335a84f8707d32261f9f27b0 Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Thu, 4 Jul 2019 08:14:48 +0200 Subject: [PATCH 01/26] SP: use log boosting does not require parameter --- CommonCompilerConfig.cmake | 2 +- src/examples/mnist/MNIST_SP.cpp | 2 +- src/htm/algorithms/SpatialPooler.cpp | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CommonCompilerConfig.cmake b/CommonCompilerConfig.cmake index 39a2813f50..bac44c1f33 100644 --- a/CommonCompilerConfig.cmake +++ b/CommonCompilerConfig.cmake @@ -341,7 +341,7 @@ else() set(optimization_flags_cc ${optimization_flags_cc} -pipe -O3) set(optimization_flags_lt ${optimization_flags_lt} -O3) if(NOT ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "armv7l") - set(optimization_flags_cc ${optimization_flags_cc} -mtune=generic) + set(optimization_flags_cc ${optimization_flags_cc} -march=native) endif() if(${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU" AND NOT MINGW) set(optimization_flags_cc ${optimization_flags_cc} -fuse-ld=gold) diff --git a/src/examples/mnist/MNIST_SP.cpp b/src/examples/mnist/MNIST_SP.cpp index 35c46fae1b..57593ddaf1 100644 --- a/src/examples/mnist/MNIST_SP.cpp +++ b/src/examples/mnist/MNIST_SP.cpp @@ -67,7 +67,7 @@ class MNIST { public: UInt verbosity = 1; - const UInt train_dataset_iterations = 2u; //epochs somewhat help, at linear time + const UInt train_dataset_iterations = 1u; //epochs somewhat help, at linear time void setup() { diff --git a/src/htm/algorithms/SpatialPooler.cpp b/src/htm/algorithms/SpatialPooler.cpp index 2d1df6a536..50c641d260 100644 --- a/src/htm/algorithms/SpatialPooler.cpp +++ b/src/htm/algorithms/SpatialPooler.cpp @@ -766,7 +766,8 @@ void applyBoosting_(const UInt i, const Real boost, vector& output) { if(boost < htm::Epsilon) return; //skip for disabled boosting - output[i] = exp((targetDensity - actualDensity[i]) * boost); //TODO doc this code + //output[i] = exp((targetDensity - actualDensity[i]) * boost); //exponential boosting, default for Numenta + output[i] = log(actualDensity[i]) / log(targetDensity); } From b250f30824cf85f01d131a57620afb7ae0b3e5da Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Thu, 4 Jul 2019 09:19:11 +0200 Subject: [PATCH 02/26] SP: updateInhArea() only needed for local inhibition for global it's always const max of dimensions --- src/htm/algorithms/SpatialPooler.cpp | 40 +++++++++++++++++++--------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/src/htm/algorithms/SpatialPooler.cpp b/src/htm/algorithms/SpatialPooler.cpp index 50c641d260..a59ed52524 100644 --- a/src/htm/algorithms/SpatialPooler.cpp +++ b/src/htm/algorithms/SpatialPooler.cpp @@ -471,14 +471,21 @@ void SpatialPooler::initialize( void SpatialPooler::compute(const SDR &input, const bool learn, SDR &active) { input.reshape( inputDimensions_ ); active.reshape( columnDimensions_ ); + updateBookeepingVars_(learn); calculateOverlap_(input, overlaps_); calculateOverlapPct_(overlaps_, overlapsPct_); + + auto &activeVector = active.getSparse(); + //boosting boostOverlaps_(overlaps_, boostedOverlaps_); - - auto &activeVector = active.getSparse(); + //update inhibition radius if it's time, only changes in local inh + if(!globalInhibition_ and isUpdateRound_()) { + updateInhibitionRadius_(); + } inhibitColumns_(boostedOverlaps_, activeVector); + // Notify the active SDR that its internal data vector has changed. Always // call SDR's setter methods even if when modifying the SDR's own data // inplace. @@ -491,7 +498,6 @@ void SpatialPooler::compute(const SDR &input, const bool learn, SDR &active) { bumpUpWeakColumns_(); updateBoostFactors_(); if (isUpdateRound_()) { - updateInhibitionRadius_(); updateMinDutyCycles_(); } } @@ -583,7 +589,7 @@ vector SpatialPooler::initPermanence_(const vector &potential, //TOD void SpatialPooler::updateInhibitionRadius_() { - if (globalInhibition_) { + if (globalInhibition_) { //always const for global inh inhibitionRadius_ = *max_element(columnDimensions_.cbegin(), columnDimensions_.cend()); return; @@ -772,16 +778,15 @@ void applyBoosting_(const UInt i, void SpatialPooler::updateBoostFactorsGlobal_() { - Real targetDensity; + Real targetDensity = localAreaDensity_; if (numActiveColumnsPerInhArea_ > 0) { UInt inhibitionArea = - (UInt)(pow((Real)(2 * inhibitionRadius_ + 1), (Real)columnDimensions_.size())); + (UInt)(pow((Real)(2 * inhibitionRadius_ + 1), (Real)columnDimensions_.size())); //FIXME this is broken + // for nD. SP{2000, 1, 1} has ^3 bigger area -> smaller target density inhibitionArea = min(inhibitionArea, numColumns_); NTA_ASSERT(inhibitionArea > 0); targetDensity = ((Real)numActiveColumnsPerInhArea_) / inhibitionArea; targetDensity = min(targetDensity, (Real)MAX_LOCALAREADENSITY); - } else { - targetDensity = localAreaDensity_; } for (UInt i = 0; i < numColumns_; ++i) { @@ -853,9 +858,7 @@ void SpatialPooler::inhibitColumns_(const vector &overlaps, density = min(density, (Real)MAX_LOCALAREADENSITY); } - if (globalInhibition_ || - inhibitionRadius_ > - *max_element(columnDimensions_.begin(), columnDimensions_.end())) { + if (globalInhibition_) { inhibitColumnsGlobal_(overlaps, density, activeColumns); } else { inhibitColumnsLocal_(overlaps, density, activeColumns); @@ -903,16 +906,26 @@ void SpatialPooler::inhibitColumnsGlobal_(const vector &overlaps, while( !activeColumns.empty() && overlaps[activeColumns.back()] < stimulusThreshold_) activeColumns.pop_back(); + + //FIXME not numDesired } void SpatialPooler::inhibitColumnsLocal_(const vector &overlaps, - Real density, + const Real density, vector &activeColumns) const { + + //optimization hack: call faster global inh if radius stretches over the whole input field, + //but this should not occur too ofthen because we want to do local inh + if(inhibitionRadius_ > *max_element(columnDimensions_.begin(), columnDimensions_.end())) { + inhibitColumnsGlobal_(overlaps, density, activeColumns); + //slow path normal local inhibition + } else { + activeColumns.clear(); // Tie-breaking: when overlaps are equal, columns that have already been - // selected are treated as "bigger". + // selected are treated as "bigger". //TODO move this idea to the sort/comparison logic vector activeColumnsDense(numColumns_, false); for (UInt column = 0; column < numColumns_; column++) { @@ -956,6 +969,7 @@ void SpatialPooler::inhibitColumnsLocal_(const vector &overlaps, activeColumnsDense[column] = true; } } + } } From f167d5581e22ebe21a78c1f76d9f627c8e1b8cdb Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Thu, 4 Jul 2019 10:05:51 +0200 Subject: [PATCH 03/26] SP updateInhibitionRadius_() returns UInt and is const --- src/htm/algorithms/SpatialPooler.cpp | 16 +++++++++------- src/htm/algorithms/SpatialPooler.hpp | 8 +++++--- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/htm/algorithms/SpatialPooler.cpp b/src/htm/algorithms/SpatialPooler.cpp index a59ed52524..7654464209 100644 --- a/src/htm/algorithms/SpatialPooler.cpp +++ b/src/htm/algorithms/SpatialPooler.cpp @@ -459,7 +459,7 @@ void SpatialPooler::initialize( connections_.raisePermanencesToThreshold( (Segment)i, stimulusThreshold_ ); } - updateInhibitionRadius_(); + inhibitionRadius_ = updateInhibitionRadius_(); if (spVerbosity_ > 0) { printParameters(); @@ -480,9 +480,11 @@ void SpatialPooler::compute(const SDR &input, const bool learn, SDR &active) { //boosting boostOverlaps_(overlaps_, boostedOverlaps_); + + //inhibition //update inhibition radius if it's time, only changes in local inh if(!globalInhibition_ and isUpdateRound_()) { - updateInhibitionRadius_(); + inhibitionRadius_ = updateInhibitionRadius_(); } inhibitColumns_(boostedOverlaps_, activeVector); @@ -494,6 +496,7 @@ void SpatialPooler::compute(const SDR &input, const bool learn, SDR &active) { if (learn) { adaptSynapses_(input, active); + //boosting updateDutyCycles_(overlaps_, active); bumpUpWeakColumns_(); updateBoostFactors_(); @@ -588,11 +591,9 @@ vector SpatialPooler::initPermanence_(const vector &potential, //TOD } -void SpatialPooler::updateInhibitionRadius_() { +UInt SpatialPooler::updateInhibitionRadius_() const { if (globalInhibition_) { //always const for global inh - inhibitionRadius_ = - *max_element(columnDimensions_.cbegin(), columnDimensions_.cend()); - return; + return *max_element(columnDimensions_.cbegin(), columnDimensions_.cend()); } Real connectedSpan = 0.0f; @@ -604,7 +605,8 @@ void SpatialPooler::updateInhibitionRadius_() { const Real diameter = connectedSpan * columnsPerInput; Real radius = (diameter - 1) / 2.0f; radius = max((Real)1.0, radius); - inhibitionRadius_ = UInt(round(radius)); + + return UInt(round(radius)); } diff --git a/src/htm/algorithms/SpatialPooler.hpp b/src/htm/algorithms/SpatialPooler.hpp index 7201bd7a0e..f32682110c 100644 --- a/src/htm/algorithms/SpatialPooler.hpp +++ b/src/htm/algorithms/SpatialPooler.hpp @@ -1010,10 +1010,12 @@ class SpatialPooler : public Serializable determine this quantity by first figuring out how many *inputs* a column is connected to, and then multiplying it by the total number of columns that exist for each input. For multiple dimension the aforementioned - calculations are averaged over all dimensions of inputs and columns. This - value is meaningless if global inhibition is enabled. + calculations are averaged over all dimensions of inputs and columns. + This value is meaningless if global inhibition is enabled. + + @return update value for `inhibitionRadius_` */ - void updateInhibitionRadius_(); + UInt updateInhibitionRadius_() const; /** REturns the average number of columns per input, taking into account the From a459829615bbfa71b4c21d8f367f1b70b0a87bb0 Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Thu, 4 Jul 2019 10:22:39 +0200 Subject: [PATCH 04/26] SP try boosting completely removed this results in 20% faster code!, but worse results 93,26% on MNIST (from 95.%) --- src/htm/algorithms/SpatialPooler.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/htm/algorithms/SpatialPooler.cpp b/src/htm/algorithms/SpatialPooler.cpp index 7654464209..49a1a8ba50 100644 --- a/src/htm/algorithms/SpatialPooler.cpp +++ b/src/htm/algorithms/SpatialPooler.cpp @@ -479,6 +479,7 @@ void SpatialPooler::compute(const SDR &input, const bool learn, SDR &active) { auto &activeVector = active.getSparse(); //boosting + boostStrength_ = 0.0; boostOverlaps_(overlaps_, boostedOverlaps_); //inhibition @@ -497,12 +498,12 @@ void SpatialPooler::compute(const SDR &input, const bool learn, SDR &active) { if (learn) { adaptSynapses_(input, active); //boosting - updateDutyCycles_(overlaps_, active); - bumpUpWeakColumns_(); - updateBoostFactors_(); - if (isUpdateRound_()) { - updateMinDutyCycles_(); - } +// updateDutyCycles_(overlaps_, active); +// bumpUpWeakColumns_(); +// updateBoostFactors_(); +// if (isUpdateRound_()) { +// updateMinDutyCycles_(); +// } } } From 5e9abd7dd882c5143c2d9ff07ccb439b0466ca08 Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Thu, 4 Jul 2019 11:59:13 +0200 Subject: [PATCH 05/26] SP: bumpUpWeakColumns move all related timekeeping into this method. Also remove updateDutyCycles_() and decuple it to updateDutyCyclesOverlaps_(), and update duty cycles active (which is a one liner) Sugestion to disable bumpUpWeakColumns, as it brings about 0.1% better SP results (in MNIST) but costs about 18% time! --- src/htm/algorithms/SpatialPooler.cpp | 66 +++++++++++-------- src/htm/algorithms/SpatialPooler.hpp | 21 +++--- .../unit/algorithms/SpatialPoolerTest.cpp | 12 ++-- 3 files changed, 54 insertions(+), 45 deletions(-) diff --git a/src/htm/algorithms/SpatialPooler.cpp b/src/htm/algorithms/SpatialPooler.cpp index 49a1a8ba50..e2b064560a 100644 --- a/src/htm/algorithms/SpatialPooler.cpp +++ b/src/htm/algorithms/SpatialPooler.cpp @@ -479,7 +479,7 @@ void SpatialPooler::compute(const SDR &input, const bool learn, SDR &active) { auto &activeVector = active.getSparse(); //boosting - boostStrength_ = 0.0; +// boostStrength_ = 0.0; boostOverlaps_(overlaps_, boostedOverlaps_); //inhibition @@ -498,12 +498,19 @@ void SpatialPooler::compute(const SDR &input, const bool learn, SDR &active) { if (learn) { adaptSynapses_(input, active); //boosting -// updateDutyCycles_(overlaps_, active); + + //update active duty cycles //TODO move where needed + /** +Updates the duty cycles for each column. The ACTIVITY duty cycles is +a moving average of the frequency of activation for each column. + +@param active A SDR of active columns which survived inhibition +*/ + const UInt period = std::min(dutyCyclePeriod_, iterationNum_); + updateDutyCyclesHelper_(activeDutyCycles_, active, period); + // bumpUpWeakColumns_(); -// updateBoostFactors_(); -// if (isUpdateRound_()) { -// updateMinDutyCycles_(); -// } + updateBoostFactors_(); } } @@ -652,26 +659,6 @@ void SpatialPooler::updateMinDutyCyclesLocal_() { } -void SpatialPooler::updateDutyCycles_(const vector &overlaps, - SDR &active) { - - // Turn the overlaps array into an SDR. Convert directly to flat-sparse to - // avoid copies and type convertions. - SDR newOverlap({ numColumns_ }); - auto &overlapsSparseVec = newOverlap.getSparse(); - for (UInt i = 0; i < numColumns_; i++) { - if( overlaps[i] != 0 ) - overlapsSparseVec.push_back( i ); - } - newOverlap.setSparse( overlapsSparseVec ); - - const UInt period = std::min(dutyCyclePeriod_, iterationNum_); - - updateDutyCyclesHelper_(overlapDutyCycles_, newOverlap, period); - updateDutyCyclesHelper_(activeDutyCycles_, active, period); -} - - Real SpatialPooler::avgColumnsPerInput_() const { const size_t numDim = max(columnDimensions_.size(), inputDimensions_.size()); Real columnsPerInput = 0.0f; @@ -730,11 +717,38 @@ void SpatialPooler::adaptSynapses_(const SDR &input, void SpatialPooler::bumpUpWeakColumns_() { for (UInt i = 0; i < numColumns_; i++) { + // skip columns (segments) that are already performing OK if (overlapDutyCycles_[i] >= minOverlapDutyCycles_[i]) { continue; } + //bump the weak connections_.bumpSegment( i, synPermBelowStimulusInc_ ); } + + //do updates: + + // update overlap duty cycles (each round) + updateDutyCyclesOverlaps_(overlaps_); + + //update minOverlapDutyCycles_ (on update round only) + if (isUpdateRound_()) { + updateMinDutyCycles_(); + } +} + + +void SpatialPooler::updateDutyCyclesOverlaps_(const vector& overlaps) { + SDR newOverlap({ numColumns_ }); + auto &overlapsSparseVec = newOverlap.getSparse(); + + for (UInt i = 0; i < numColumns_; i++) { + if( overlaps[i] > Epsilon ) + overlapsSparseVec.push_back( i ); + } + newOverlap.setSparse( overlapsSparseVec ); + + const UInt period = std::min(dutyCyclePeriod_, iterationNum_); + updateDutyCyclesHelper_(overlapDutyCycles_, newOverlap, period); } diff --git a/src/htm/algorithms/SpatialPooler.hpp b/src/htm/algorithms/SpatialPooler.hpp index f32682110c..dc1629673f 100644 --- a/src/htm/algorithms/SpatialPooler.hpp +++ b/src/htm/algorithms/SpatialPooler.hpp @@ -1092,21 +1092,18 @@ class SpatialPooler : public Serializable const SDR &newValues, const UInt period); - /** - Updates the duty cycles for each column. The OVERLAP duty cycle is a moving - average of the number of inputs which overlapped with the each column. The - ACTIVITY duty cycles is a moving average of the frequency of activation for - each column. - @param overlaps an int vector containing the overlap score for each - column. The overlap score for a column is defined as the number of synapses in - a "connected state" (connected synapses) that are connected to input bits - which are turned on. + /** + Updates the duty cycles for each column. The OVERLAP duty cycle is a moving + average of the number of inputs which overlapped with the each column. - @param activeArray An int array containing the indices of the active columns, - the sprase set of columns which survived inhibition + @param overlaps_ an int vector containing the overlap score for each + column. The overlap score for a column is defined as the number of synapses in + a "connected state" (connected synapses) that are connected to input bits + which are turned on. */ - void updateDutyCycles_(const vector &overlaps, SDR &active); + void updateDutyCyclesOverlaps_(const vector& overlaps); + /** Update the boost factors for all columns. The boost factors are used to diff --git a/src/test/unit/algorithms/SpatialPoolerTest.cpp b/src/test/unit/algorithms/SpatialPoolerTest.cpp index 28fe20a133..5184c10231 100644 --- a/src/test/unit/algorithms/SpatialPoolerTest.cpp +++ b/src/test/unit/algorithms/SpatialPoolerTest.cpp @@ -267,7 +267,7 @@ TEST(SpatialPoolerTest, testUpdateInhibitionRadius) { UInt trueInhibitionRadius = 6; // ((3 * 4) - 1)/2 => round up sp.updateInhibitionRadius_(); - ASSERT_TRUE(trueInhibitionRadius == sp.getInhibitionRadius()); + ASSERT_EQ(trueInhibitionRadius, sp.getInhibitionRadius()); colDim.clear(); inputDim.clear(); @@ -290,7 +290,7 @@ TEST(SpatialPoolerTest, testUpdateInhibitionRadius) { } trueInhibitionRadius = 1; sp.updateInhibitionRadius_(); - ASSERT_TRUE(trueInhibitionRadius == sp.getInhibitionRadius()); + ASSERT_EQ(trueInhibitionRadius, sp.getInhibitionRadius()); colDim.clear(); inputDim.clear(); @@ -311,7 +311,7 @@ TEST(SpatialPoolerTest, testUpdateInhibitionRadius) { trueInhibitionRadius = 2; // ((2.4 * 2) - 1)/2 => round up sp.updateInhibitionRadius_(); - ASSERT_TRUE(trueInhibitionRadius == sp.getInhibitionRadius()); + ASSERT_EQ(trueInhibitionRadius, sp.getInhibitionRadius()); } TEST(SpatialPoolerTest, testUpdateMinDutyCycles) { @@ -511,16 +511,14 @@ TEST(SpatialPoolerTest, testUpdateDutyCycles) { UInt numColumns = 5; setup(sp, numInputs, numColumns); vector overlaps; - SDR active({numColumns}); Real initOverlapArr1[] = {1, 1, 1, 1, 1}; sp.setOverlapDutyCycles(initOverlapArr1); UInt overlapNewVal1[] = {1, 5, 7, 0, 0}; overlaps.assign(overlapNewVal1, overlapNewVal1 + numColumns); - active.setDense(vector({0, 0, 0, 0, 0})); sp.setIterationNum(2); - sp.updateDutyCycles_(overlaps, active); + sp.updateDutyCyclesOverlaps_(overlaps); Real resultOverlapArr1[5]; sp.getOverlapDutyCycles(resultOverlapArr1); @@ -531,7 +529,7 @@ TEST(SpatialPoolerTest, testUpdateDutyCycles) { sp.setOverlapDutyCycles(initOverlapArr1); sp.setIterationNum(2000); sp.setUpdatePeriod(1000); - sp.updateDutyCycles_(overlaps, active); + sp.updateDutyCyclesOverlaps_(overlaps); Real resultOverlapArr2[5]; sp.getOverlapDutyCycles(resultOverlapArr2); From fa10af59455f45ec1215bb1830f39a4274ef8cd0 Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Thu, 4 Jul 2019 12:13:04 +0200 Subject: [PATCH 06/26] cleanup SP test --- .../unit/algorithms/SpatialPoolerTest.cpp | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/test/unit/algorithms/SpatialPoolerTest.cpp b/src/test/unit/algorithms/SpatialPoolerTest.cpp index 5184c10231..f82ee7af04 100644 --- a/src/test/unit/algorithms/SpatialPoolerTest.cpp +++ b/src/test/unit/algorithms/SpatialPoolerTest.cpp @@ -238,7 +238,10 @@ void setup(SpatialPooler &sp, UInt numInputs, UInt numColumns) { TEST(SpatialPoolerTest, testUpdateInhibitionRadius) { SpatialPooler sp; vector colDim, inputDim; - colDim.push_back(57); + + //test for global inhibition, this is trivial + { + colDim.push_back(57); //max SP dimension colDim.push_back(31); colDim.push_back(2); inputDim.push_back(1); @@ -247,14 +250,18 @@ TEST(SpatialPoolerTest, testUpdateInhibitionRadius) { sp.initialize(inputDim, colDim); sp.setGlobalInhibition(true); - ASSERT_TRUE(sp.getInhibitionRadius() == 57); + ASSERT_TRUE(sp.getInhibitionRadius() == 57) << "In global inh radius must match max dimension"; + } + + //tests for local inhibition + UInt numInputs = 3; + UInt numCols = 12; + { colDim.clear(); inputDim.clear(); // avgColumnsPerInput = 4 // avgConnectedSpanForColumn = 3 - UInt numInputs = 3; inputDim.push_back(numInputs); - UInt numCols = 12; colDim.push_back(numCols); sp.initialize(inputDim, colDim); sp.setGlobalInhibition(false); @@ -264,11 +271,12 @@ TEST(SpatialPoolerTest, testUpdateInhibitionRadius) { Real permArr[] = {1, 1, 1}; sp.setPermanence(i, permArr); } - UInt trueInhibitionRadius = 6; // ((3 * 4) - 1)/2 => round up sp.updateInhibitionRadius_(); - ASSERT_EQ(trueInhibitionRadius, sp.getInhibitionRadius()); + ASSERT_EQ(6u, sp.getInhibitionRadius()); + } + { colDim.clear(); inputDim.clear(); // avgColumnsPerInput = 1.2 @@ -288,10 +296,11 @@ TEST(SpatialPoolerTest, testUpdateInhibitionRadius) { } sp.setPermanence(i, permArr); } - trueInhibitionRadius = 1; sp.updateInhibitionRadius_(); - ASSERT_EQ(trueInhibitionRadius, sp.getInhibitionRadius()); + ASSERT_EQ(1u, sp.getInhibitionRadius()); + } + { colDim.clear(); inputDim.clear(); // avgColumnsPerInput = 2.4 @@ -308,10 +317,10 @@ TEST(SpatialPoolerTest, testUpdateInhibitionRadius) { Real permArr[] = {1, 1, 0, 0, 0}; sp.setPermanence(i, permArr); } - trueInhibitionRadius = 2; // ((2.4 * 2) - 1)/2 => round up sp.updateInhibitionRadius_(); - ASSERT_EQ(trueInhibitionRadius, sp.getInhibitionRadius()); + ASSERT_EQ(2u, sp.getInhibitionRadius()); + } } TEST(SpatialPoolerTest, testUpdateMinDutyCycles) { From ba4b61d9def21587c35e69a25a8d835169504d81 Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Thu, 4 Jul 2019 12:13:04 +0200 Subject: [PATCH 07/26] cleanup SP test --- .../unit/algorithms/SpatialPoolerTest.cpp | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/test/unit/algorithms/SpatialPoolerTest.cpp b/src/test/unit/algorithms/SpatialPoolerTest.cpp index 28fe20a133..ad720bd315 100644 --- a/src/test/unit/algorithms/SpatialPoolerTest.cpp +++ b/src/test/unit/algorithms/SpatialPoolerTest.cpp @@ -238,7 +238,10 @@ void setup(SpatialPooler &sp, UInt numInputs, UInt numColumns) { TEST(SpatialPoolerTest, testUpdateInhibitionRadius) { SpatialPooler sp; vector colDim, inputDim; - colDim.push_back(57); + + //test for global inhibition, this is trivial + { + colDim.push_back(57); //max SP dimension colDim.push_back(31); colDim.push_back(2); inputDim.push_back(1); @@ -247,14 +250,18 @@ TEST(SpatialPoolerTest, testUpdateInhibitionRadius) { sp.initialize(inputDim, colDim); sp.setGlobalInhibition(true); - ASSERT_TRUE(sp.getInhibitionRadius() == 57); + ASSERT_TRUE(sp.getInhibitionRadius() == 57) << "In global inh radius must match max dimension"; + } + + //tests for local inhibition + UInt numInputs = 3; + UInt numCols = 12; + { colDim.clear(); inputDim.clear(); // avgColumnsPerInput = 4 // avgConnectedSpanForColumn = 3 - UInt numInputs = 3; inputDim.push_back(numInputs); - UInt numCols = 12; colDim.push_back(numCols); sp.initialize(inputDim, colDim); sp.setGlobalInhibition(false); @@ -264,11 +271,12 @@ TEST(SpatialPoolerTest, testUpdateInhibitionRadius) { Real permArr[] = {1, 1, 1}; sp.setPermanence(i, permArr); } - UInt trueInhibitionRadius = 6; // ((3 * 4) - 1)/2 => round up sp.updateInhibitionRadius_(); - ASSERT_TRUE(trueInhibitionRadius == sp.getInhibitionRadius()); + ASSERT_EQ(6u, sp.getInhibitionRadius()); + } + { colDim.clear(); inputDim.clear(); // avgColumnsPerInput = 1.2 @@ -288,10 +296,11 @@ TEST(SpatialPoolerTest, testUpdateInhibitionRadius) { } sp.setPermanence(i, permArr); } - trueInhibitionRadius = 1; sp.updateInhibitionRadius_(); - ASSERT_TRUE(trueInhibitionRadius == sp.getInhibitionRadius()); + ASSERT_EQ(1u, sp.getInhibitionRadius()); + } + { colDim.clear(); inputDim.clear(); // avgColumnsPerInput = 2.4 @@ -308,10 +317,10 @@ TEST(SpatialPoolerTest, testUpdateInhibitionRadius) { Real permArr[] = {1, 1, 0, 0, 0}; sp.setPermanence(i, permArr); } - trueInhibitionRadius = 2; // ((2.4 * 2) - 1)/2 => round up sp.updateInhibitionRadius_(); - ASSERT_TRUE(trueInhibitionRadius == sp.getInhibitionRadius()); + ASSERT_EQ(2u, sp.getInhibitionRadius()); + } } TEST(SpatialPoolerTest, testUpdateMinDutyCycles) { From 1be7dcdebf38ee10bdea2edd6dc2ed518040a3a2 Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Thu, 4 Jul 2019 08:14:48 +0200 Subject: [PATCH 08/26] SP: use log boosting does not require parameter --- CommonCompilerConfig.cmake | 2 +- src/examples/mnist/MNIST_SP.cpp | 2 +- src/htm/algorithms/SpatialPooler.cpp | 3 +- .../unit/algorithms/SpatialPoolerTest.cpp | 28 ++++++------------- 4 files changed, 13 insertions(+), 22 deletions(-) diff --git a/CommonCompilerConfig.cmake b/CommonCompilerConfig.cmake index 39a2813f50..bac44c1f33 100644 --- a/CommonCompilerConfig.cmake +++ b/CommonCompilerConfig.cmake @@ -341,7 +341,7 @@ else() set(optimization_flags_cc ${optimization_flags_cc} -pipe -O3) set(optimization_flags_lt ${optimization_flags_lt} -O3) if(NOT ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "armv7l") - set(optimization_flags_cc ${optimization_flags_cc} -mtune=generic) + set(optimization_flags_cc ${optimization_flags_cc} -march=native) endif() if(${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU" AND NOT MINGW) set(optimization_flags_cc ${optimization_flags_cc} -fuse-ld=gold) diff --git a/src/examples/mnist/MNIST_SP.cpp b/src/examples/mnist/MNIST_SP.cpp index 35c46fae1b..57593ddaf1 100644 --- a/src/examples/mnist/MNIST_SP.cpp +++ b/src/examples/mnist/MNIST_SP.cpp @@ -67,7 +67,7 @@ class MNIST { public: UInt verbosity = 1; - const UInt train_dataset_iterations = 2u; //epochs somewhat help, at linear time + const UInt train_dataset_iterations = 1u; //epochs somewhat help, at linear time void setup() { diff --git a/src/htm/algorithms/SpatialPooler.cpp b/src/htm/algorithms/SpatialPooler.cpp index 2d1df6a536..50c641d260 100644 --- a/src/htm/algorithms/SpatialPooler.cpp +++ b/src/htm/algorithms/SpatialPooler.cpp @@ -766,7 +766,8 @@ void applyBoosting_(const UInt i, const Real boost, vector& output) { if(boost < htm::Epsilon) return; //skip for disabled boosting - output[i] = exp((targetDensity - actualDensity[i]) * boost); //TODO doc this code + //output[i] = exp((targetDensity - actualDensity[i]) * boost); //exponential boosting, default for Numenta + output[i] = log(actualDensity[i]) / log(targetDensity); } diff --git a/src/test/unit/algorithms/SpatialPoolerTest.cpp b/src/test/unit/algorithms/SpatialPoolerTest.cpp index ad720bd315..ea12af1851 100644 --- a/src/test/unit/algorithms/SpatialPoolerTest.cpp +++ b/src/test/unit/algorithms/SpatialPoolerTest.cpp @@ -980,24 +980,11 @@ TEST(SpatialPoolerTest, testUpdateBoostFactors) { sp.getBoostFactors(resultBoostFactors1.data()); ASSERT_TRUE(check_vector_eq(trueBoostFactors1, resultBoostFactors1)); - Real32 initActiveDutyCycles2[] = {0.1f, 0.3f, 0.02f, 0.04f, 0.7f, 0.12f}; - Real32 initBoostFactors2[] = {0, 0, 0, 0, 0, 0}; - vector trueBoostFactors2 = {3.10599f, 0.42035f, 6.91251f, - 5.65949f, 0.00769898f, 2.54297f}; - vector resultBoostFactors2(6, 0); - sp.setGlobalInhibition(false); - sp.setBoostStrength(10); - sp.setBoostFactors(initBoostFactors2); - sp.setActiveDutyCycles(initActiveDutyCycles2); - sp.updateBoostFactors_(); - sp.getBoostFactors(resultBoostFactors2.data()); - - ASSERT_TRUE(check_vector_eq(trueBoostFactors2, resultBoostFactors2)); Real32 initActiveDutyCycles3[] = {0.1f, 0.3f, 0.02f, 0.04f, 0.7f, 0.12f}; Real initBoostFactors3[] = {0, 0, 0, 0, 0, 0}; - vector trueBoostFactors3 = {1.25441f, 0.840857f, 1.47207f, - 1.41435f, 0.377822f, 1.20523f}; + vector trueBoostFactors3 = {1.49044f, 0.779321f, 2.53222f, + 2.08355f, 0.230873f, 1.37243f}; vector resultBoostFactors3(6, 0); sp.setWrapAround(true); sp.setGlobalInhibition(false); @@ -1011,10 +998,11 @@ TEST(SpatialPoolerTest, testUpdateBoostFactors) { ASSERT_TRUE(check_vector_eq(trueBoostFactors3, resultBoostFactors3)); + Real32 initActiveDutyCycles4[] = {0.1f, 0.3f, 0.02f, 0.04f, 0.7f, 0.12f}; Real32 initBoostFactors4[] = {0, 0, 0, 0, 0, 0}; - vector trueBoostFactors4 = {1.94773f, 0.263597f, 4.33476f, - 3.549f, 0.00482795f, 1.59467f}; + vector trueBoostFactors4 = {1.2851f, 0.67195f, 2.18334f, + 1.79649f, 0.199064f, 1.18334f}; vector resultBoostFactors4(6, 0); sp.setGlobalInhibition(true); sp.setBoostStrength(10); @@ -2103,14 +2091,16 @@ TEST(SpatialPoolerTest, testConstructorVsInitialize) { TEST(SpatialPoolerTest, ExactOutput) { // Silver is an SDR that is loaded by direct initalization from a vector. SDR silver_sdr({ 200 }); - SDR_sparse_t data = {23, 71, 113, 118, 129, 172, 178, 182, 185, 190}; + SDR_sparse_t data = { + 12, 51, 81, 113, 129, 133, 172, 175, 178, 190 + }; silver_sdr.setSparse(data); // Gold tests initalizing an SDR from a manually created string in JSON format. // hint: you can generate this string using // silver_sdr.save(std::cout, JSON); - string gold = "{\"dimensions\": [200],\"sparse\": [23,71,113,118,129,172,178,182,185,190]}"; + string gold = "{\"dimensions\": [200],\"sparse\": [12, 51, 81, 113, 129, 133, 172, 175, 178, 190]}"; std::stringstream gold_stream( gold ); SDR gold_sdr; gold_sdr.load( gold_stream, JSON ); From 824e738aa173f16b044109a43d59ca3b05e73112 Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Thu, 4 Jul 2019 12:34:49 +0200 Subject: [PATCH 09/26] fix bug in a test compared old/tested arrays, not the new values --- src/test/unit/algorithms/SpatialPoolerTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/unit/algorithms/SpatialPoolerTest.cpp b/src/test/unit/algorithms/SpatialPoolerTest.cpp index ea12af1851..49b9e197fe 100644 --- a/src/test/unit/algorithms/SpatialPoolerTest.cpp +++ b/src/test/unit/algorithms/SpatialPoolerTest.cpp @@ -1013,7 +1013,7 @@ TEST(SpatialPoolerTest, testUpdateBoostFactors) { sp.updateBoostFactors_(); sp.getBoostFactors(resultBoostFactors4.data()); - ASSERT_TRUE(check_vector_eq(trueBoostFactors3, resultBoostFactors3)); + ASSERT_TRUE(check_vector_eq(trueBoostFactors4, resultBoostFactors4)); } TEST(SpatialPoolerTest, testUpdateBookeepingVars) { From a23ee49ea2d221bae1ef6cfb800cb9afb77f39e6 Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Thu, 4 Jul 2019 13:40:46 +0200 Subject: [PATCH 10/26] SP fix boosting if strength == 0.0 --- src/examples/mnist/MNIST_SP.cpp | 4 ++-- src/htm/algorithms/SpatialPooler.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/examples/mnist/MNIST_SP.cpp b/src/examples/mnist/MNIST_SP.cpp index 57593ddaf1..a1fe87a573 100644 --- a/src/examples/mnist/MNIST_SP.cpp +++ b/src/examples/mnist/MNIST_SP.cpp @@ -73,7 +73,7 @@ class MNIST { void setup() { input.initialize({28, 28,1}); - columns.initialize({28, 28, 8}); //1D vs 2D no big difference, 2D seems more natural for the problem. Speed-----, Results+++++++++; #columns HIGHEST impact. + columns.initialize({28, 28, 16}); //1D vs 2D no big difference, 2D seems more natural for the problem. Speed-----, Results+++++++++; #columns HIGHEST impact. sp.initialize( /* inputDimensions */ input.dimensions, /* columnDimensions */ columns.dimensions, @@ -88,7 +88,7 @@ void setup() { /* synPermConnected */ 0.5f, //no difference, let's leave at 0.5 in the middle /* minPctOverlapDutyCycles */ 0.2f, //speed of re-learning? /* dutyCyclePeriod */ 1402, - /* boostStrength */ 2.0f, // Boosting does help, but entropy is high, on MNIST it does not matter, for learning with TM prefer boosting off (=0.0), or "neutral"=1.0 + /* boostStrength */ 0.0f, // Boosting does help, but entropy is high, on MNIST it does not matter, for learning with TM prefer boosting off (=0.0), or "neutral"=1.0 /* seed */ 4u, /* spVerbosity */ 1u, /* wrapAround */ true); // does not matter (helps slightly) diff --git a/src/htm/algorithms/SpatialPooler.cpp b/src/htm/algorithms/SpatialPooler.cpp index 50c641d260..970b499c9b 100644 --- a/src/htm/algorithms/SpatialPooler.cpp +++ b/src/htm/algorithms/SpatialPooler.cpp @@ -752,6 +752,7 @@ void SpatialPooler::updateDutyCyclesHelper_(vector &dutyCycles, void SpatialPooler::updateBoostFactors_() { + if(boostStrength_ < htm::Epsilon) return; //skip for disabled boosting if (globalInhibition_) { updateBoostFactorsGlobal_(); } else { @@ -765,7 +766,6 @@ void applyBoosting_(const UInt i, const vector& actualDensity, const Real boost, vector& output) { - if(boost < htm::Epsilon) return; //skip for disabled boosting //output[i] = exp((targetDensity - actualDensity[i]) * boost); //exponential boosting, default for Numenta output[i] = log(actualDensity[i]) / log(targetDensity); } From 171ceb2f7a8ad64eff84415ada5f25c3b305c2f6 Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Thu, 4 Jul 2019 14:04:23 +0200 Subject: [PATCH 11/26] SP updateBoostFactors_() move time-keeping logic inside this function --- src/htm/algorithms/SpatialPooler.cpp | 26 +++++++++++++------------- src/htm/algorithms/SpatialPooler.hpp | 4 +++- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/htm/algorithms/SpatialPooler.cpp b/src/htm/algorithms/SpatialPooler.cpp index 91156df70f..95ee49b47a 100644 --- a/src/htm/algorithms/SpatialPooler.cpp +++ b/src/htm/algorithms/SpatialPooler.cpp @@ -498,19 +498,8 @@ void SpatialPooler::compute(const SDR &input, const bool learn, SDR &active) { if (learn) { adaptSynapses_(input, active); //boosting - - //update active duty cycles //TODO move where needed - /** -Updates the duty cycles for each column. The ACTIVITY duty cycles is -a moving average of the frequency of activation for each column. - -@param active A SDR of active columns which survived inhibition -*/ - const UInt period = std::min(dutyCyclePeriod_, iterationNum_); - updateDutyCyclesHelper_(activeDutyCycles_, active, period); - // bumpUpWeakColumns_(); - updateBoostFactors_(); + updateBoostFactors_(active); } } @@ -774,8 +763,19 @@ void SpatialPooler::updateDutyCyclesHelper_(vector &dutyCycles, } -void SpatialPooler::updateBoostFactors_() { +void SpatialPooler::updateBoostFactors_(const SDR& active) { if(boostStrength_ < htm::Epsilon) return; //skip for disabled boosting + + /** + Updates the duty cycles for each column. The ACTIVITY duty cycles is + a moving average of the frequency of activation for each column. + + @param active A SDR of active columns which survived inhibition + @param period + */ + const UInt period = std::min(dutyCyclePeriod_, iterationNum_); + updateDutyCyclesHelper_(activeDutyCycles_, active, period); + if (globalInhibition_) { updateBoostFactorsGlobal_(); } else { diff --git a/src/htm/algorithms/SpatialPooler.hpp b/src/htm/algorithms/SpatialPooler.hpp index dc1629673f..c4d7595899 100644 --- a/src/htm/algorithms/SpatialPooler.hpp +++ b/src/htm/algorithms/SpatialPooler.hpp @@ -1133,8 +1133,10 @@ class SpatialPooler : public Serializable | targetDensity @endverbatim + + @param active SDR with active columns from compute(), after inhibition & learning */ - void updateBoostFactors_(); + void updateBoostFactors_(const SDR& active); /** Update boost factors when local inhibition is enabled. In this case, From e3246ea650c541dfe6b1c4562048eb54df70f985 Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Thu, 4 Jul 2019 14:25:22 +0200 Subject: [PATCH 12/26] SP remove unused calculateOverlapPct --- src/htm/algorithms/SpatialPooler.cpp | 16 ---------------- src/htm/algorithms/SpatialPooler.hpp | 3 --- 2 files changed, 19 deletions(-) diff --git a/src/htm/algorithms/SpatialPooler.cpp b/src/htm/algorithms/SpatialPooler.cpp index 95ee49b47a..874865a857 100644 --- a/src/htm/algorithms/SpatialPooler.cpp +++ b/src/htm/algorithms/SpatialPooler.cpp @@ -439,7 +439,6 @@ void SpatialPooler::initialize( minOverlapDutyCycles_.assign(numColumns_, 0.0); boostFactors_.assign(numColumns_, 1.0); //1 is neutral value for boosting overlaps_.resize(numColumns_); - overlapsPct_.resize(numColumns_); boostedOverlaps_.resize(numColumns_); inhibitionRadius_ = 0; @@ -474,7 +473,6 @@ void SpatialPooler::compute(const SDR &input, const bool learn, SDR &active) { updateBookeepingVars_(learn); calculateOverlap_(input, overlaps_); - calculateOverlapPct_(overlaps_, overlapsPct_); auto &activeVector = active.getSparse(); @@ -850,20 +848,6 @@ void SpatialPooler::calculateOverlap_(const SDR &input, } -void SpatialPooler::calculateOverlapPct_(const vector &overlaps, - vector &overlapPct) const { - overlapPct.assign(numColumns_, 0); - vector connectedCounts( numColumns_ ); - getConnectedCounts( connectedCounts.data() ); - - for (UInt i = 0; i < numColumns_; i++) { - if (connectedCounts[i] != 0) { - overlapPct[i] = ((Real)overlaps[i]) / connectedCounts[i]; - } - } -} - - void SpatialPooler::inhibitColumns_(const vector &overlaps, vector &activeColumns) const { Real density = localAreaDensity_; diff --git a/src/htm/algorithms/SpatialPooler.hpp b/src/htm/algorithms/SpatialPooler.hpp index c4d7595899..f6e15f6cbe 100644 --- a/src/htm/algorithms/SpatialPooler.hpp +++ b/src/htm/algorithms/SpatialPooler.hpp @@ -329,7 +329,6 @@ class SpatialPooler : public Serializable // initialize ephemeral members overlaps_.resize(numColumns_); - overlapsPct_.resize(numColumns_); boostedOverlaps_.resize(numColumns_); } @@ -904,7 +903,6 @@ class SpatialPooler : public Serializable input bits which are turned on. */ void calculateOverlap_(const SDR &input, vector &overlap); - void calculateOverlapPct_(const vector &overlaps, vector &overlapPct) const; /** Performs inhibition. This method calculates the necessary values needed to @@ -1233,7 +1231,6 @@ class SpatialPooler : public Serializable Connections connections_; vector overlaps_; - vector overlapsPct_; vector boostedOverlaps_; vector tieBreaker_; From 144c95f7ada434c498cac49a98216f7fd9a3e3e1 Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Thu, 4 Jul 2019 16:32:08 +0200 Subject: [PATCH 13/26] SP fix inhibition return desired number of active WIP the global inhibition should return numDesired active cols, but it returns much less once sub threshold cols are removed --- src/examples/mnist/MNIST_SP.cpp | 4 ++-- src/htm/algorithms/Connections.cpp | 3 ++- src/htm/algorithms/Connections.hpp | 4 ++-- src/htm/algorithms/SpatialPooler.cpp | 35 ++++++++++++++++++++++------ src/htm/algorithms/SpatialPooler.hpp | 6 +++-- 5 files changed, 38 insertions(+), 14 deletions(-) diff --git a/src/examples/mnist/MNIST_SP.cpp b/src/examples/mnist/MNIST_SP.cpp index a1fe87a573..fc0d0bd1da 100644 --- a/src/examples/mnist/MNIST_SP.cpp +++ b/src/examples/mnist/MNIST_SP.cpp @@ -73,7 +73,7 @@ class MNIST { void setup() { input.initialize({28, 28,1}); - columns.initialize({28, 28, 16}); //1D vs 2D no big difference, 2D seems more natural for the problem. Speed-----, Results+++++++++; #columns HIGHEST impact. + columns.initialize({28, 28, 8}); //1D vs 2D no big difference, 2D seems more natural for the problem. Speed-----, Results+++++++++; #columns HIGHEST impact. sp.initialize( /* inputDimensions */ input.dimensions, /* columnDimensions */ columns.dimensions, @@ -88,7 +88,7 @@ void setup() { /* synPermConnected */ 0.5f, //no difference, let's leave at 0.5 in the middle /* minPctOverlapDutyCycles */ 0.2f, //speed of re-learning? /* dutyCyclePeriod */ 1402, - /* boostStrength */ 0.0f, // Boosting does help, but entropy is high, on MNIST it does not matter, for learning with TM prefer boosting off (=0.0), or "neutral"=1.0 + /* boostStrength */ 7.0f, // Boosting does help, but entropy is high, on MNIST it does not matter, for learning with TM prefer boosting off (=0.0), or "neutral"=1.0 /* seed */ 4u, /* spVerbosity */ 1u, /* wrapAround */ true); // does not matter (helps slightly) diff --git a/src/htm/algorithms/Connections.cpp b/src/htm/algorithms/Connections.cpp index c3deb5d2cc..3c439be291 100644 --- a/src/htm/algorithms/Connections.cpp +++ b/src/htm/algorithms/Connections.cpp @@ -395,7 +395,8 @@ void Connections::computeActivity( vector &numActiveConnectedSynapsesForSegment, const vector &activePresynapticCells) { - NTA_ASSERT(numActiveConnectedSynapsesForSegment.size() == segments_.size()); + NTA_ASSERT(numActiveConnectedSynapsesForSegment.size() == segments_.size()) << "The output vector size must match "<< segments_.size(); + NTA_ASSERT(activePresynapticCells.size() < segments_.size()) << "Input is larger than our number of segments!"; if( timeseries_ ) { // Before each cycle of computation move the currentUpdates to the previous diff --git a/src/htm/algorithms/Connections.hpp b/src/htm/algorithms/Connections.hpp index 26243bb83b..84711e8ba9 100644 --- a/src/htm/algorithms/Connections.hpp +++ b/src/htm/algorithms/Connections.hpp @@ -392,11 +392,11 @@ class Connections : public Serializable * @param numActiveConnectedSynapsesForSegment * An output vector for active connected synapse counts per segment. * - * @param numActivePotentialSynapsesForSegment + * @param (optional) numActivePotentialSynapsesForSegment * An output vector for active potential synapse counts per segment. * * @param activePresynapticCells - * Active cells in the input. + * Active cells in the input as a sparse indices. */ void computeActivity(std::vector &numActiveConnectedSynapsesForSegment, std::vector &numActivePotentialSynapsesForSegment, diff --git a/src/htm/algorithms/SpatialPooler.cpp b/src/htm/algorithms/SpatialPooler.cpp index 874865a857..f625ffa822 100644 --- a/src/htm/algorithms/SpatialPooler.cpp +++ b/src/htm/algorithms/SpatialPooler.cpp @@ -866,10 +866,12 @@ void SpatialPooler::inhibitColumns_(const vector &overlaps, } } +static int missed = 0; + void SpatialPooler::inhibitColumnsGlobal_(const vector &overlaps, - Real density, - vector &activeColumns) const { + const Real density, + SDR_sparse_t &activeColumns) const { NTA_ASSERT(!overlaps.empty()); NTA_ASSERT(density > 0.0f && density <= 1.0f); @@ -879,28 +881,39 @@ void SpatialPooler::inhibitColumnsGlobal_(const vector &overlaps, overlaps_[i] += tieBreaker_[i]; activeColumns.clear(); - const UInt numDesired = (UInt)(density * numColumns_); + const UInt numDesired = static_cast(std::min(density*2.0f* (Real)activeColumns.size(), Real(numColumns_))); NTA_CHECK(numDesired > 0) << "Not enough columns (" << numColumns_ << ") " << "for desired density (" << density << ")."; // Sort the columns by the amount of overlap. First make a list of all of the // column indexes. activeColumns.reserve(numColumns_); + + int same_overlap = 0; for(UInt i = 0; i < numColumns_; i++) activeColumns.push_back(i); // Compare the column indexes by their overlap. - auto compare = [&overlaps_](const UInt &a, const UInt &b) -> bool - {return (overlaps_[a] == overlaps_[b]) ? a > b : overlaps_[a] > overlaps_[b];}; + auto compare = [&overlaps_, &same_overlap](const UInt &a, const UInt &b) -> bool + { + if (overlaps_[a] == overlaps_[b]) { + same_overlap++; + return a > b; //but we also need this for deterministic results + } else { + return overlaps_[a] > overlaps_[b]; //this is the main "sort columns by overlaps" + } + }; // Do a partial sort to divide the winners from the losers. This sort is // faster than a regular sort because it stops after it partitions the // elements about the Nth element, with all elements on their correct side of // the Nth element. - std::nth_element( +/* + std::nth_element( activeColumns.begin(), activeColumns.begin() + numDesired, activeColumns.end(), compare); // Remove the columns which lost the competition. activeColumns.resize(numDesired); + */ // Finish sorting the winner columns by their overlap. std::sort(activeColumns.begin(), activeColumns.end(), compare); // Remove sub-threshold winners @@ -908,7 +921,15 @@ void SpatialPooler::inhibitColumnsGlobal_(const vector &overlaps, overlaps[activeColumns.back()] < stimulusThreshold_) activeColumns.pop_back(); - //FIXME not numDesired + activeColumns.resize(std::min(numDesired, (UInt)activeColumns.size())); + + //FIXME not numDesired + if(iterationNum_ > 1000) { //need time for learning + if(activeColumns.size() != numDesired) { + missed++; + cout << "missed " << missed << " by " << (numDesired - activeColumns.size()) << " of " << numDesired << " same "<< same_overlap << "\n"; + } + } } diff --git a/src/htm/algorithms/SpatialPooler.hpp b/src/htm/algorithms/SpatialPooler.hpp index f6e15f6cbe..efad175314 100644 --- a/src/htm/algorithms/SpatialPooler.hpp +++ b/src/htm/algorithms/SpatialPooler.hpp @@ -942,7 +942,8 @@ class SpatialPooler : public Serializable @param activeColumns an int array containing the indices of the active columns. */ - void inhibitColumnsGlobal_(const vector &overlaps, Real density, + void inhibitColumnsGlobal_(const vector &overlaps, + const Real density, vector &activeColumns) const; /** @@ -971,7 +972,8 @@ class SpatialPooler : public Serializable @param activeColumns an int array containing the indices of the active columns. */ - void inhibitColumnsLocal_(const vector &overlaps, Real density, + void inhibitColumnsLocal_(const vector &overlaps, + const Real density, vector &activeColumns) const; /** From 5810e21737bafc674418021dce3127c20b60c7ed Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Sat, 6 Jul 2019 20:12:36 +0200 Subject: [PATCH 14/26] Revert "SP: use log boosting" This reverts commit 1be7dcdebf38ee10bdea2edd6dc2ed518040a3a2. --- CommonCompilerConfig.cmake | 2 +- src/examples/mnist/MNIST_SP.cpp | 2 +- src/htm/algorithms/SpatialPooler.cpp | 5 +++-- .../unit/algorithms/SpatialPoolerTest.cpp | 22 ++++++++++++++----- 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/CommonCompilerConfig.cmake b/CommonCompilerConfig.cmake index bac44c1f33..39a2813f50 100644 --- a/CommonCompilerConfig.cmake +++ b/CommonCompilerConfig.cmake @@ -341,7 +341,7 @@ else() set(optimization_flags_cc ${optimization_flags_cc} -pipe -O3) set(optimization_flags_lt ${optimization_flags_lt} -O3) if(NOT ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "armv7l") - set(optimization_flags_cc ${optimization_flags_cc} -march=native) + set(optimization_flags_cc ${optimization_flags_cc} -mtune=generic) endif() if(${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU" AND NOT MINGW) set(optimization_flags_cc ${optimization_flags_cc} -fuse-ld=gold) diff --git a/src/examples/mnist/MNIST_SP.cpp b/src/examples/mnist/MNIST_SP.cpp index fc0d0bd1da..81075b4865 100644 --- a/src/examples/mnist/MNIST_SP.cpp +++ b/src/examples/mnist/MNIST_SP.cpp @@ -67,7 +67,7 @@ class MNIST { public: UInt verbosity = 1; - const UInt train_dataset_iterations = 1u; //epochs somewhat help, at linear time + const UInt train_dataset_iterations = 2u; //epochs somewhat help, at linear time void setup() { diff --git a/src/htm/algorithms/SpatialPooler.cpp b/src/htm/algorithms/SpatialPooler.cpp index b9eeefdadb..315dc702a6 100644 --- a/src/htm/algorithms/SpatialPooler.cpp +++ b/src/htm/algorithms/SpatialPooler.cpp @@ -781,8 +781,9 @@ void applyBoosting_(const UInt i, const vector& actualDensity, const Real boost, vector& output) { - //output[i] = exp((targetDensity - actualDensity[i]) * boost); //exponential boosting, default for Numenta - output[i] = log(actualDensity[i]) / log(targetDensity); + if(boost < htm::Epsilon) return; //skip for disabled boosting + output[i] = exp((targetDensity - actualDensity[i]) * boost); //exponential boosting, default for Numenta + //output[i] = log(actualDensity[i]) / log(targetDensity); //log boosting } diff --git a/src/test/unit/algorithms/SpatialPoolerTest.cpp b/src/test/unit/algorithms/SpatialPoolerTest.cpp index c0c74a7e8b..ede030c1cb 100644 --- a/src/test/unit/algorithms/SpatialPoolerTest.cpp +++ b/src/test/unit/algorithms/SpatialPoolerTest.cpp @@ -978,11 +978,24 @@ TEST(SpatialPoolerTest, testUpdateBoostFactors) { sp.getBoostFactors(resultBoostFactors1.data()); ASSERT_TRUE(check_vector_eq(trueBoostFactors1, resultBoostFactors1)); + Real32 initActiveDutyCycles2[] = {0.1f, 0.3f, 0.02f, 0.04f, 0.7f, 0.12f}; + Real32 initBoostFactors2[] = {0, 0, 0, 0, 0, 0}; + vector trueBoostFactors2 = {3.10599f, 0.42035f, 6.91251f, + 5.65949f, 0.00769898f, 2.54297f}; + vector resultBoostFactors2(6, 0); + sp.setGlobalInhibition(false); + sp.setBoostStrength(10); + sp.setBoostFactors(initBoostFactors2); + sp.setActiveDutyCycles(initActiveDutyCycles2); + sp.updateBoostFactors_(); + sp.getBoostFactors(resultBoostFactors2.data()); + + ASSERT_TRUE(check_vector_eq(trueBoostFactors2, resultBoostFactors2)); Real32 initActiveDutyCycles3[] = {0.1f, 0.3f, 0.02f, 0.04f, 0.7f, 0.12f}; Real initBoostFactors3[] = {0, 0, 0, 0, 0, 0}; - vector trueBoostFactors3 = {1.49044f, 0.779321f, 2.53222f, - 2.08355f, 0.230873f, 1.37243f}; + vector trueBoostFactors3 = {1.25441f, 0.840857f, 1.47207f, + 1.41435f, 0.377822f, 1.20523f}; vector resultBoostFactors3(6, 0); sp.setWrapAround(true); sp.setGlobalInhibition(false); @@ -996,11 +1009,10 @@ TEST(SpatialPoolerTest, testUpdateBoostFactors) { ASSERT_TRUE(check_vector_eq(trueBoostFactors3, resultBoostFactors3)); - Real32 initActiveDutyCycles4[] = {0.1f, 0.3f, 0.02f, 0.04f, 0.7f, 0.12f}; Real32 initBoostFactors4[] = {0, 0, 0, 0, 0, 0}; - vector trueBoostFactors4 = {1.2851f, 0.67195f, 2.18334f, - 1.79649f, 0.199064f, 1.18334f}; + vector trueBoostFactors4 = {1.94773f, 0.263597f, 4.33476f, + 3.549f, 0.00482795f, 1.59467f}; vector resultBoostFactors4(6, 0); sp.setGlobalInhibition(true); sp.setBoostStrength(10); From 7bfb7bc26de60fc9b763082d86fdd56faa43c20d Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Sat, 6 Jul 2019 20:20:49 +0200 Subject: [PATCH 15/26] remove work for other PR --- src/examples/mnist/MNIST_SP.cpp | 2 +- src/htm/algorithms/SpatialPooler.cpp | 19 ++++--------------- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/src/examples/mnist/MNIST_SP.cpp b/src/examples/mnist/MNIST_SP.cpp index 81075b4865..fc0d0bd1da 100644 --- a/src/examples/mnist/MNIST_SP.cpp +++ b/src/examples/mnist/MNIST_SP.cpp @@ -67,7 +67,7 @@ class MNIST { public: UInt verbosity = 1; - const UInt train_dataset_iterations = 2u; //epochs somewhat help, at linear time + const UInt train_dataset_iterations = 1u; //epochs somewhat help, at linear time void setup() { diff --git a/src/htm/algorithms/SpatialPooler.cpp b/src/htm/algorithms/SpatialPooler.cpp index 315dc702a6..afbedc2d0f 100644 --- a/src/htm/algorithms/SpatialPooler.cpp +++ b/src/htm/algorithms/SpatialPooler.cpp @@ -871,7 +871,7 @@ void SpatialPooler::inhibitColumnsGlobal_(const vector &overlaps, NTA_ASSERT(density > 0.0f && density <= 1.0f); activeColumns.clear(); - const UInt numDesired = static_cast(std::min(density*2.0f* (Real)activeColumns.size(), Real(numColumns_))); + const UInt numDesired = static_cast(density * numColumns_); NTA_CHECK(numDesired > 0) << "Not enough columns (" << numColumns_ << ") " << "for desired density (" << density << ")."; // Sort the columns by the amount of overlap. First make a list of all of the @@ -882,13 +882,13 @@ void SpatialPooler::inhibitColumnsGlobal_(const vector &overlaps, for(UInt i = 0; i < numColumns_; i++) activeColumns.push_back(i); // Compare the column indexes by their overlap. - auto compare = [&overlaps_, &same_overlap](const UInt &a, const UInt &b) -> bool + auto compare = [&overlaps, &same_overlap](const UInt &a, const UInt &b) -> bool { - if (overlaps_[a] == overlaps_[b]) { + if (overlaps[a] == overlaps[b]) { same_overlap++; return a > b; //but we also need this for deterministic results } else { - return overlaps_[a] > overlaps_[b]; //this is the main "sort columns by overlaps" + return overlaps[a] > overlaps[b]; //this is the main "sort columns by overlaps" } }; @@ -896,7 +896,6 @@ void SpatialPooler::inhibitColumnsGlobal_(const vector &overlaps, // faster than a regular sort because it stops after it partitions the // elements about the Nth element, with all elements on their correct side of // the Nth element. -/* //TODO remove from this PR std::nth_element( activeColumns.begin(), activeColumns.begin() + numDesired, @@ -904,23 +903,13 @@ void SpatialPooler::inhibitColumnsGlobal_(const vector &overlaps, compare); // Remove the columns which lost the competition. activeColumns.resize(numDesired); - */ // Finish sorting the winner columns by their overlap. std::sort(activeColumns.begin(), activeColumns.end(), compare); // Remove sub-threshold winners while( !activeColumns.empty() && overlaps[activeColumns.back()] < stimulusThreshold_) activeColumns.pop_back(); - - activeColumns.resize(std::min(numDesired, (UInt)activeColumns.size())); - //FIXME not numDesired - if(iterationNum_ > 1000) { //need time for learning - if(activeColumns.size() != numDesired) { - missed++; - cout << "missed " << missed << " by " << (numDesired - activeColumns.size()) << " of " << numDesired << " same "<< same_overlap << "\n"; - } - } } From 0e6a63ffae6fbccee4f09f10669d48b054e58a50 Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Sat, 6 Jul 2019 20:28:05 +0200 Subject: [PATCH 16/26] SP move inhibitionRadius_ updates to inhibition function as inhibition is always ran first, this can be computed there. --- src/htm/algorithms/SpatialPooler.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/htm/algorithms/SpatialPooler.cpp b/src/htm/algorithms/SpatialPooler.cpp index afbedc2d0f..d4f6b308c9 100644 --- a/src/htm/algorithms/SpatialPooler.cpp +++ b/src/htm/algorithms/SpatialPooler.cpp @@ -472,14 +472,9 @@ void SpatialPooler::compute(const SDR &input, const bool learn, SDR &active) { auto &activeVector = active.getSparse(); //boosting -// boostStrength_ = 0.0; boostOverlaps_(overlaps_, boostedOverlaps_); //inhibition - //update inhibition radius if it's time, only changes in local inh - if(!globalInhibition_ and isUpdateRound_()) { - inhibitionRadius_ = updateInhibitionRadius_(); - } inhibitColumns_(boostedOverlaps_, activeVector); // Notify the active SDR that its internal data vector has changed. Always @@ -845,6 +840,13 @@ void SpatialPooler::calculateOverlap_(const SDR &input, void SpatialPooler::inhibitColumns_(const vector &overlaps, vector &activeColumns) const { + + //update inhibition radius if it's time, only changes in local inh + if(!globalInhibition_ and isUpdateRound_()) { + inhibitionRadius_ = updateInhibitionRadius_(); + } + + //compute density (desired output SDR sparsity) Real density = localAreaDensity_; if (numActiveColumnsPerInhArea_ > 0) { UInt inhibitionArea = From d5c6cc697286b857382a9cf4ffe8b40b0214172e Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Sat, 6 Jul 2019 20:31:16 +0200 Subject: [PATCH 17/26] Revert "SP move inhibitionRadius_ updates to inhibition function" This reverts commit 0e6a63ffae6fbccee4f09f10669d48b054e58a50. --- src/htm/algorithms/SpatialPooler.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/htm/algorithms/SpatialPooler.cpp b/src/htm/algorithms/SpatialPooler.cpp index d4f6b308c9..afbedc2d0f 100644 --- a/src/htm/algorithms/SpatialPooler.cpp +++ b/src/htm/algorithms/SpatialPooler.cpp @@ -472,9 +472,14 @@ void SpatialPooler::compute(const SDR &input, const bool learn, SDR &active) { auto &activeVector = active.getSparse(); //boosting +// boostStrength_ = 0.0; boostOverlaps_(overlaps_, boostedOverlaps_); //inhibition + //update inhibition radius if it's time, only changes in local inh + if(!globalInhibition_ and isUpdateRound_()) { + inhibitionRadius_ = updateInhibitionRadius_(); + } inhibitColumns_(boostedOverlaps_, activeVector); // Notify the active SDR that its internal data vector has changed. Always @@ -840,13 +845,6 @@ void SpatialPooler::calculateOverlap_(const SDR &input, void SpatialPooler::inhibitColumns_(const vector &overlaps, vector &activeColumns) const { - - //update inhibition radius if it's time, only changes in local inh - if(!globalInhibition_ and isUpdateRound_()) { - inhibitionRadius_ = updateInhibitionRadius_(); - } - - //compute density (desired output SDR sparsity) Real density = localAreaDensity_; if (numActiveColumnsPerInhArea_ > 0) { UInt inhibitionArea = From 03432c9cfe05b24d6023ff4ea8e0c4854b4a6614 Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Sat, 6 Jul 2019 20:36:10 +0200 Subject: [PATCH 18/26] comments --- src/htm/algorithms/SpatialPooler.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/htm/algorithms/SpatialPooler.cpp b/src/htm/algorithms/SpatialPooler.cpp index afbedc2d0f..a16fff9ee3 100644 --- a/src/htm/algorithms/SpatialPooler.cpp +++ b/src/htm/algorithms/SpatialPooler.cpp @@ -472,8 +472,8 @@ void SpatialPooler::compute(const SDR &input, const bool learn, SDR &active) { auto &activeVector = active.getSparse(); //boosting -// boostStrength_ = 0.0; - boostOverlaps_(overlaps_, boostedOverlaps_); + //must be done before inhibition + boostOverlaps_(overlaps_, boostedOverlaps_); //TODO consider removal, @1 //inhibition //update inhibition radius if it's time, only changes in local inh @@ -491,8 +491,8 @@ void SpatialPooler::compute(const SDR &input, const bool learn, SDR &active) { if (learn) { adaptSynapses_(input, active); //boosting -// bumpUpWeakColumns_(); - updateBoostFactors_(active); + bumpUpWeakColumns_(); //TODO suggest removal, low impact, long time + updateBoostFactors_(active); //helper for @1, computed after inh } } From 32c70fe9c168217bfb60676ff9f81a9768ba9966 Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Sat, 6 Jul 2019 21:22:53 +0200 Subject: [PATCH 19/26] fix test compiles --- src/test/unit/algorithms/SpatialPoolerTest.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/test/unit/algorithms/SpatialPoolerTest.cpp b/src/test/unit/algorithms/SpatialPoolerTest.cpp index ede030c1cb..54b2885431 100644 --- a/src/test/unit/algorithms/SpatialPoolerTest.cpp +++ b/src/test/unit/algorithms/SpatialPoolerTest.cpp @@ -965,6 +965,8 @@ TEST(SpatialPoolerTest, testUpdateDutyCyclesHelper) { TEST(SpatialPoolerTest, testUpdateBoostFactors) { SpatialPooler sp; setup(sp, 5, 6); + SDR dummy({6}); + dummy.setDense(SDR_dense_t{1,1,1,1,1,1}); //"full" SDR Real32 initActiveDutyCycles1[] = {0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f}; Real32 initBoostFactors1[] = {0, 0, 0, 0, 0, 0}; @@ -974,7 +976,7 @@ TEST(SpatialPoolerTest, testUpdateBoostFactors) { sp.setBoostStrength(10); sp.setBoostFactors(initBoostFactors1); sp.setActiveDutyCycles(initActiveDutyCycles1); - sp.updateBoostFactors_(); + sp.updateBoostFactors_(dummy); sp.getBoostFactors(resultBoostFactors1.data()); ASSERT_TRUE(check_vector_eq(trueBoostFactors1, resultBoostFactors1)); @@ -987,7 +989,7 @@ TEST(SpatialPoolerTest, testUpdateBoostFactors) { sp.setBoostStrength(10); sp.setBoostFactors(initBoostFactors2); sp.setActiveDutyCycles(initActiveDutyCycles2); - sp.updateBoostFactors_(); + sp.updateBoostFactors_(dummy); sp.getBoostFactors(resultBoostFactors2.data()); ASSERT_TRUE(check_vector_eq(trueBoostFactors2, resultBoostFactors2)); @@ -1004,7 +1006,7 @@ TEST(SpatialPoolerTest, testUpdateBoostFactors) { sp.setNumActiveColumnsPerInhArea(1); sp.setBoostFactors(initBoostFactors3); sp.setActiveDutyCycles(initActiveDutyCycles3); - sp.updateBoostFactors_(); + sp.updateBoostFactors_(dummy); sp.getBoostFactors(resultBoostFactors3.data()); ASSERT_TRUE(check_vector_eq(trueBoostFactors3, resultBoostFactors3)); @@ -1020,7 +1022,7 @@ TEST(SpatialPoolerTest, testUpdateBoostFactors) { sp.setInhibitionRadius(3); sp.setBoostFactors(initBoostFactors4); sp.setActiveDutyCycles(initActiveDutyCycles4); - sp.updateBoostFactors_(); + sp.updateBoostFactors_(dummy); sp.getBoostFactors(resultBoostFactors4.data()); ASSERT_TRUE(check_vector_eq(trueBoostFactors4, resultBoostFactors4)); From 57015ec796da44718682f67c4c4d8dd00b4b582c Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Sat, 6 Jul 2019 22:16:49 +0200 Subject: [PATCH 20/26] update inh radius on learn=true only --- src/htm/algorithms/SpatialPooler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/htm/algorithms/SpatialPooler.cpp b/src/htm/algorithms/SpatialPooler.cpp index a16fff9ee3..548093f091 100644 --- a/src/htm/algorithms/SpatialPooler.cpp +++ b/src/htm/algorithms/SpatialPooler.cpp @@ -477,7 +477,7 @@ void SpatialPooler::compute(const SDR &input, const bool learn, SDR &active) { //inhibition //update inhibition radius if it's time, only changes in local inh - if(!globalInhibition_ and isUpdateRound_()) { + if(!globalInhibition_ and isUpdateRound_() and learn) { inhibitionRadius_ = updateInhibitionRadius_(); } inhibitColumns_(boostedOverlaps_, activeVector); From 528cb2095b21164715769b9b5d05e074b3c2249c Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Sat, 6 Jul 2019 23:44:13 +0200 Subject: [PATCH 21/26] review feedback: remove unnecessary assert --- src/htm/algorithms/Connections.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/htm/algorithms/Connections.cpp b/src/htm/algorithms/Connections.cpp index 1fd76a9c34..e084089cb0 100644 --- a/src/htm/algorithms/Connections.cpp +++ b/src/htm/algorithms/Connections.cpp @@ -396,7 +396,6 @@ void Connections::computeActivity( const vector &activePresynapticCells) { NTA_ASSERT(numActiveConnectedSynapsesForSegment.size() == segments_.size()) << "The output vector size must match "<< segments_.size(); - NTA_ASSERT(activePresynapticCells.size() < segments_.size()) << "Input is larger than our number of segments!"; if( timeseries_ ) { // Before each cycle of computation move the currentUpdates to the previous @@ -406,9 +405,9 @@ void Connections::computeActivity( } // Iterate through all connected synapses. - for (const auto& cell : activePresynapticCells) { + for (const auto cell : activePresynapticCells) { if (connectedSegmentsForPresynapticCell_.count(cell)) { - for(const auto& segment : connectedSegmentsForPresynapticCell_.at(cell)) { + for(const auto segment : connectedSegmentsForPresynapticCell_.at(cell)) { ++numActiveConnectedSynapsesForSegment[segment]; } } From 6353d8b384b300db642fb5ad0342ef384d7c4497 Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Tue, 9 Jul 2019 13:20:55 +0200 Subject: [PATCH 22/26] rm unused variable --- src/htm/algorithms/SpatialPooler.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/htm/algorithms/SpatialPooler.cpp b/src/htm/algorithms/SpatialPooler.cpp index 548093f091..c4a01ef39a 100644 --- a/src/htm/algorithms/SpatialPooler.cpp +++ b/src/htm/algorithms/SpatialPooler.cpp @@ -861,8 +861,6 @@ void SpatialPooler::inhibitColumns_(const vector &overlaps, } } -static int missed = 0; - void SpatialPooler::inhibitColumnsGlobal_(const vector &overlaps, const Real density, From 36b7c48c856cc90568f883eaf4942eb363f8ca22 Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Tue, 9 Jul 2019 14:03:23 +0200 Subject: [PATCH 23/26] cleanup --- src/htm/algorithms/SpatialPooler.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/htm/algorithms/SpatialPooler.cpp b/src/htm/algorithms/SpatialPooler.cpp index c4a01ef39a..a2a1edbdfc 100644 --- a/src/htm/algorithms/SpatialPooler.cpp +++ b/src/htm/algorithms/SpatialPooler.cpp @@ -963,8 +963,8 @@ void SpatialPooler::inhibitColumnsLocal_(const vector &overlaps, } } - const UInt numActive = (UInt)(0.5f + (density * (numNeighbors + 1))); - if (numBigger < numActive) { + const UInt numDesired = static_cast(round(density * (numNeighbors + 1))); + if (numBigger < numDesired) { activeColumns.push_back(column); activeColumnsDense[column] = true; } From 9e4024ec6ee8d7938583b17148901f51f8b9518e Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Fri, 12 Jul 2019 16:47:55 +0200 Subject: [PATCH 24/26] small fixups --- src/htm/algorithms/SpatialPooler.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/htm/algorithms/SpatialPooler.cpp b/src/htm/algorithms/SpatialPooler.cpp index 9548e747c4..9ba555b8be 100644 --- a/src/htm/algorithms/SpatialPooler.cpp +++ b/src/htm/algorithms/SpatialPooler.cpp @@ -915,13 +915,6 @@ void SpatialPooler::inhibitColumnsLocal_(const vector &overlaps, const Real density, vector &activeColumns) const { - //optimization hack: call faster global inh if radius stretches over the whole input field, - //but this should not occur too ofthen because we want to do local inh - if(inhibitionRadius_ > *max_element(columnDimensions_.begin(), columnDimensions_.end())) { - inhibitColumnsGlobal_(overlaps, density, activeColumns); - //slow path normal local inhibition - } else { - activeColumns.clear(); // Tie-breaking: when overlaps are equal, columns that have already been @@ -963,13 +956,12 @@ void SpatialPooler::inhibitColumnsLocal_(const vector &overlaps, } } - const UInt numDesired = static_cast(round(density * (numNeighbors + 1))); + const UInt numDesired = static_cast(std::ceil(density * (numNeighbors + 1))); if (numBigger < numDesired) { activeColumns.push_back(column); activeColumnsDense[column] = true; } } - } } From 2462e7e915c0f59ea6485e2d756fac6ffff1d448 Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Fri, 21 Feb 2020 01:46:41 +0100 Subject: [PATCH 25/26] tidy test --- src/test/unit/algorithms/SpatialPoolerTest.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/unit/algorithms/SpatialPoolerTest.cpp b/src/test/unit/algorithms/SpatialPoolerTest.cpp index 4a8e3ebb60..e396e86b3d 100644 --- a/src/test/unit/algorithms/SpatialPoolerTest.cpp +++ b/src/test/unit/algorithms/SpatialPoolerTest.cpp @@ -912,7 +912,7 @@ TEST(SpatialPoolerTest, testBumpUpWeakColumns) { for (UInt i = 0; i < numColumns; i++) { const auto& perm = sp.getPermanence(i); for(UInt z = 0; z < numInputs; z++) - ASSERT_FLOAT_EQ( truePermArr[i][z], perm[z] ); + ASSERT_NEAR( truePermArr[i][z], perm[z], 0.0001f ); } } @@ -1276,7 +1276,7 @@ TEST(SpatialPoolerTest, testInhibitColumnsLocal) { sp.setInhibitionRadius(inhibitionRadius); sp.inhibitColumnsLocal_(overlaps, density, active); - ASSERT_TRUE(active.size() == 4); + ASSERT_EQ(active.size(), (Size)4); ASSERT_TRUE(check_vector_eq(trueActive3, active)); } From 6c7a8be2af80cb890c12288c988dbd338ca74556 Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Fri, 21 Feb 2020 02:01:50 +0100 Subject: [PATCH 26/26] SP rm unneeded overlaps_ --- src/htm/algorithms/SpatialPooler.cpp | 2 +- src/htm/algorithms/SpatialPooler.hpp | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/htm/algorithms/SpatialPooler.cpp b/src/htm/algorithms/SpatialPooler.cpp index 6c4b0f12d0..ff28cdc4f4 100644 --- a/src/htm/algorithms/SpatialPooler.cpp +++ b/src/htm/algorithms/SpatialPooler.cpp @@ -459,7 +459,7 @@ const vector SpatialPooler::compute(const SDR &input, const bool lea //boosting //must be done before inhibition const auto& overlaps = connections_.computeActivity(input.getSparse(), learn); - boostOverlaps_(overlaps, boostedOverlaps_); //TODO consider removal, @1 + boostOverlaps_(overlaps, boostedOverlaps_); // @1 //inhibition //update inhibition radius if it's time, only changes in local inh diff --git a/src/htm/algorithms/SpatialPooler.hpp b/src/htm/algorithms/SpatialPooler.hpp index 5ea0b50dec..df61940e39 100644 --- a/src/htm/algorithms/SpatialPooler.hpp +++ b/src/htm/algorithms/SpatialPooler.hpp @@ -1039,7 +1039,7 @@ class SpatialPooler : public Serializable Updates the duty cycles for each column. The OVERLAP duty cycle is a moving average of the number of inputs which overlapped with the each column. - @param overlaps_ an int vector containing the overlap score for each + @param overlaps an int vector containing the overlap score for each column. The overlap score for a column is defined as the number of synapses in a "connected state" (connected synapses) that are connected to input bits which are turned on. @@ -1181,7 +1181,6 @@ class SpatialPooler : public Serializable public: const Connections& connections = connections_; //for inspection of details in connections. Const, so users cannot break the SP internals. const Connections& getConnections() const { return connections_; } // as above, but for use in pybind11 - std::vector overlaps_; //TODO only used for 1 test: SPTest.inhibitColumnsLocal(), otherwise can be removed }; std::ostream & operator<<(std::ostream & out, const SpatialPooler &sp);