From 34dbc1b450e941c70b5bb888662a780a44b775a2 Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Thu, 4 Jul 2019 16:32:08 +0200 Subject: [PATCH 1/5] 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/htm/algorithms/Connections.cpp | 3 ++- src/htm/algorithms/Connections.hpp | 4 ++-- src/htm/algorithms/SpatialPooler.cpp | 35 +++++++++++++++++++++++----- src/htm/algorithms/SpatialPooler.hpp | 6 +++-- 4 files changed, 37 insertions(+), 11 deletions(-) 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 8b83b79e08..237bdc07a8 100644 --- a/src/htm/algorithms/SpatialPooler.cpp +++ b/src/htm/algorithms/SpatialPooler.cpp @@ -847,10 +847,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); @@ -860,34 +862,55 @@ void SpatialPooler::inhibitColumnsGlobal_(const vector &overlaps, overlaps_[i] += tieBreaker_[i]; activeColumns.clear(); - const UInt numDesired = (UInt)(density * 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 // 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 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"; + } + } } diff --git a/src/htm/algorithms/SpatialPooler.hpp b/src/htm/algorithms/SpatialPooler.hpp index dc3d41571c..fc49678dd4 100644 --- a/src/htm/algorithms/SpatialPooler.hpp +++ b/src/htm/algorithms/SpatialPooler.hpp @@ -943,7 +943,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; /** @@ -972,7 +973,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 a5441a0fa6f291c2aeb8ff0955aabff0d158d44f Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Thu, 4 Jul 2019 16:56:13 +0200 Subject: [PATCH 2/5] SP faster list initialize --- src/htm/algorithms/SpatialPooler.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/htm/algorithms/SpatialPooler.cpp b/src/htm/algorithms/SpatialPooler.cpp index 237bdc07a8..867c0ff845 100644 --- a/src/htm/algorithms/SpatialPooler.cpp +++ b/src/htm/algorithms/SpatialPooler.cpp @@ -867,11 +867,10 @@ void SpatialPooler::inhibitColumnsGlobal_(const vector &overlaps, << "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_); + activeColumns.resize(numColumns_); + std::iota(activeColumns.begin(), activeColumns.end(), 0); //0,1,2,..,numColumns_-1 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_, &same_overlap](const UInt &a, const UInt &b) -> bool { From b21dd1ed3d481bd32522a9f08d7bc644fa5ef985 Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Thu, 4 Jul 2019 18:30:29 +0200 Subject: [PATCH 3/5] make MNIST faster for testing --- src/examples/mnist/MNIST_SP.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/examples/mnist/MNIST_SP.cpp b/src/examples/mnist/MNIST_SP.cpp index 4f39fa09bd..68513b5a37 100644 --- a/src/examples/mnist/MNIST_SP.cpp +++ b/src/examples/mnist/MNIST_SP.cpp @@ -56,13 +56,13 @@ class MNIST { void setup() { - input.initialize({28 * 28}); - columns.initialize({10 * 1000}); + input.initialize({28, 28, 1}); + columns.initialize({28, 28, 8}); sp.initialize( /* inputDimensions */ input.dimensions, /* columnDimensions */ columns.dimensions, - /* potentialRadius */ 999999u, // No topology, all to all connections. - /* potentialPct */ 0.65f, + /* potentialRadius */ 7u, // No topology, all to all connections. + /* potentialPct */ 0.1f, /* globalInhibition */ true, /* localAreaDensity */ 0.05f, // % active bits /* numActiveColumnsPerInhArea */ -1, From a8373b53ba93b7aaef0e460b785263673aa91df0 Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Sat, 6 Jul 2019 18:21:55 +0200 Subject: [PATCH 4/5] Topology: comments --- src/htm/utils/Topology.hpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/htm/utils/Topology.hpp b/src/htm/utils/Topology.hpp index 35ac443992..a8a1dbca16 100644 --- a/src/htm/utils/Topology.hpp +++ b/src/htm/utils/Topology.hpp @@ -32,18 +32,18 @@ namespace htm { /** - * Topology_t is a function which returns the pool of potential synapses for a - * given cell. + * Topology_t is a function which returns the pool of potential synapses (input field) + * for a given cell C. * - * Argument 1: is an SDR representing the postsynaptic cell. Topology functions + * @param cell an SDR representing the postsynaptic cell C. Topology functions * return the inputs which may connect to this cell. This SDR contains a single * true bit. * - * Argument 2: is the dimensions of the presynaptic cells. + * @param inputDimension the dimensions of the presynaptic cells. * - * Argument 3: is a random number generator to use for reproducible results. + * @param rng a random number generator to use for reproducible results. * - * Returns: an SDR containing all presynaptic cells which are allowed to connect + * @returns SDR containing all presynaptic cells which are allowed to connect * to the postsynaptic cell. The dimensions of this SDR must equal argument 2. * * Example Usage: @@ -62,7 +62,9 @@ namespace htm { * }; * } */ -typedef std::function&, Random&)> Topology_t; +typedef std::function& inputDimensions, + Random& rng)> Topology_t; /** * @param potentialRadius: This parameter determines the extent of the From b8bae3e28ac167c78023b1ff5c6f49328534aef7 Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Sat, 6 Jul 2019 18:22:38 +0200 Subject: [PATCH 5/5] SpatialPooler: debugging global inhibition too few returned WIP globa inh does not return nDesired columns how it should, even if it could have. --- src/htm/algorithms/Connections.cpp | 2 +- src/htm/algorithms/SpatialPooler.cpp | 46 +++++++++++++++++++++++++--- 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/src/htm/algorithms/Connections.cpp b/src/htm/algorithms/Connections.cpp index c3deb5d2cc..fd61d37aaa 100644 --- a/src/htm/algorithms/Connections.cpp +++ b/src/htm/algorithms/Connections.cpp @@ -406,7 +406,7 @@ void Connections::computeActivity( // Iterate through all connected synapses. for (const auto& cell : activePresynapticCells) { - if (connectedSegmentsForPresynapticCell_.count(cell)) { + if (connectedSegmentsForPresynapticCell_.count(cell) > 0) { //there are connected segments for(const auto& segment : connectedSegmentsForPresynapticCell_.at(cell)) { ++numActiveConnectedSynapsesForSegment[segment]; } diff --git a/src/htm/algorithms/SpatialPooler.cpp b/src/htm/algorithms/SpatialPooler.cpp index 0fb969d151..bb62902086 100644 --- a/src/htm/algorithms/SpatialPooler.cpp +++ b/src/htm/algorithms/SpatialPooler.cpp @@ -861,6 +861,7 @@ void SpatialPooler::inhibitColumns_(const vector &overlaps, } } +static int missed = 0; void SpatialPooler::inhibitColumnsGlobal_(const vector &overlaps, Real density, @@ -879,12 +880,24 @@ void SpatialPooler::inhibitColumnsGlobal_(const vector &overlaps, << "for desired density (" << density << ")."; // Sort the columns by the amount of overlap. First make a list of all of the // column indexes. + int zero = 0; + int same = 0; + int sub = 0; activeColumns.reserve(numColumns_); - for(UInt i = 0; i < numColumns_; i++) + for(UInt i = 0; i < numColumns_; i++) { activeColumns.push_back(i); + //some statistics + if(overlaps[i] < Epsilon) {zero++; continue;} + if(overlaps[i] < stimulusThreshold_) sub++; + if(i==numColumns_-2) break; + if(fabs(overlaps[i]-overlaps[i+1]) < Epsilon) same++; + + } // 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](const UInt a, const UInt b) -> bool { + if(overlaps[a] == overlaps[b]) return a > b; + else return overlaps[a] > overlaps[b]; + }; // 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 @@ -895,13 +908,36 @@ void SpatialPooler::inhibitColumnsGlobal_(const vector &overlaps, activeColumns.end(), compare); // Remove the columns which lost the competition. - activeColumns.resize(numDesired); +//! 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_) + overlaps[activeColumns.back()] < stimulusThreshold_) { activeColumns.pop_back(); + } + + //FIXME not numDesired + if(iterationNum_ < 1000) return; //need time for learning + if(activeColumns.size() != numDesired) { + missed++; + int missing = max(0, (int)numDesired - (int)activeColumns.size()); + int ok = numColumns_ - sub - zero; + if(ok > (int)numDesired and missing > 0) + cout << "missed\t" << missed << "-times; by " << missing << "\tof " << numDesired + << " ;\tsame % " << (Real)same/numColumns_*100 << "; \tzero % " << ((Real)zero/numColumns_)*100 + << "\tsub threshold % " << (Real)sub/numColumns_*100 << "\n"; + + int same2=0; + for(size_t i = 0; i < activeColumns.size()-2; i++) { + if(activeColumns[i] == activeColumns[i+1]) same2++; + } + cout << "have same " << same2 << endl; //FIXME there are no same! + + } + //FIXME same values ok? + //FIXME sparse overlaps from conn + //FIXME conn perm inc/dec multiplied by *err (sigmoid)? }