Skip to content

Commit bb4f7a6

Browse files
Merge pull request #549 from htm-community/sp_rm_numActiveColumnsPerInhArea
SP: remove numActiveColumnsPerInhArea
2 parents 09d5391 + 8a64688 commit bb4f7a6

File tree

12 files changed

+208
-306
lines changed

12 files changed

+208
-306
lines changed

API_CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ This is obsolete. Use getRegion('name') instead.
105105

106106
We also renamed the namespaces from `namespace nupic` to `namespace htm`.
107107

108+
* SpatialPooler: removed param `numActiveColumnsPerInhArea`, as replaced by `localAreaDensity` which has better properties
109+
(constant sparsity). PR #TODO
110+
108111

109112
## Python API Changes
110113

CommonCompilerConfig.cmake

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -239,13 +239,22 @@ else()
239239

240240
#
241241
# Set linker (ld)
242-
# use ld.gold if available
242+
# These linkers are tried for faster linking performance
243+
# use ld.gold, or lld if available
243244
#
244-
execute_process(COMMAND ld.gold --version RESULT_VARIABLE EXIT_CODE)
245-
if(EXIT_CODE EQUAL 0)
245+
execute_process(COMMAND ld.gold --version RESULT_VARIABLE EXIT_CODE_GOLD)
246+
if(EXIT_CODE_GOLD EQUAL 0)
246247
message("Using ld.gold as LINKER.")
247248
set(CMAKE_LINKER "ld.gold")
249+
set(optimization_flags_cc ${optimization_flags_cc} -fuse-ld=gold)
248250
endif()
251+
execute_process(COMMAND ld.lld --version RESULT_VARIABLE EXIT_CODE_LLD)
252+
execute_process(COMMAND ld.lld-9 --version RESULT_VARIABLE EXIT_CODE_LLD9)
253+
if(EXIT_CODE_LLD EQUAL 0 OR EXIT_CODE_LLD9 EQUAL 0)
254+
message("Using ld.lld as LINKER.")
255+
set(CMAKE_LINKER "ld.lld")
256+
set(optimization_flags_cc ${optimization_flags_cc} -fuse-ld=lld)
257+
endif()
249258

250259

251260
#
@@ -344,11 +353,10 @@ else()
344353
set(optimization_flags_cc ${optimization_flags_cc} -mtune=generic)
345354
endif()
346355
if(${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU" AND NOT MINGW)
347-
set(optimization_flags_cc ${optimization_flags_cc} -fuse-ld=gold)
348356
# NOTE -flto must go together in both cc and ld flags; also, it's presently incompatible
349357
# with the -g option in at least some GNU compilers (saw in `man gcc` on Ubuntu)
350-
set(optimization_flags_cc ${optimization_flags_cc} -fuse-linker-plugin -flto-report -flto) #TODO fix LTO for clang
351-
set(optimization_flags_lt ${optimization_flags_lt} -flto) #TODO LTO for clang too
358+
set(optimization_flags_cc ${optimization_flags_cc} -fuse-linker-plugin -flto-report -flto -fno-fat-lto-objects) #TODO fix LTO for clang
359+
set(optimization_flags_lt ${optimization_flags_lt} -flto -fno-fat-lto-objects) #TODO LTO for clang too
352360
endif()
353361

354362

bindings/py/cpp_src/bindings/algorithms/py_SpatialPooler.cpp

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ using namespace htm;
5050
, Real
5151
, bool
5252
, Real
53-
, Int
5453
, UInt
5554
, Real
5655
, Real
@@ -112,22 +111,6 @@ Argument localAreaDensity The desired density of active columns within
112111
most N columns remain ON within a local inhibition area, where
113112
N = localAreaDensity * (total number of columns in inhibition
114113
area).
115-
If localAreaDensity is set to any value less than 0,
116-
output sparsity will be determined by the numActivePerInhArea.
117-
118-
Argument numActiveColumnsPerInhArea An alternate way to control the sparsity of
119-
active columns. When numActivePerInhArea > 0, the inhibition logic will insure that
120-
at most 'numActivePerInhArea' columns remain ON within a local
121-
inhibition area (the size of which is set by the internally
122-
calculated inhibitionRadius). When using this method, as columns
123-
learn and grow their effective receptive fields, the
124-
inhibitionRadius will grow, and hence the net density of the
125-
active columns will *decrease*. This is in contrast to the
126-
localAreaDensity method, which keeps the density of active
127-
columns the same regardless of the size of their receptive
128-
fields.
129-
If numActivePerInhArea is specified then
130-
localAreaDensity must be < 0, and vice versa.
131114
132115
Argument stimulusThreshold This is a number specifying the minimum
133116
number of synapses that must be active in order for a column to
@@ -188,7 +171,6 @@ Argument wrapAround boolean value that determines whether or not inputs
188171
, py::arg("potentialPct") = 0.5
189172
, py::arg("globalInhibition") = false
190173
, py::arg("localAreaDensity") = 0.02f
191-
, py::arg("numActiveColumnsPerInhArea") = -1
192174
, py::arg("stimulusThreshold") = 0
193175
, py::arg("synPermInactiveDec") = 0.01
194176
, py::arg("synPermActiveInc") = 0.1
@@ -212,8 +194,6 @@ Argument wrapAround boolean value that determines whether or not inputs
212194
py_SpatialPooler.def("getGlobalInhibition", &SpatialPooler::getGlobalInhibition);
213195
py_SpatialPooler.def("setGlobalInhibition", &SpatialPooler::setGlobalInhibition);
214196

215-
py_SpatialPooler.def("getNumActiveColumnsPerInhArea", &SpatialPooler::getNumActiveColumnsPerInhArea);
216-
py_SpatialPooler.def("setNumActiveColumnsPerInhArea", &SpatialPooler::setNumActiveColumnsPerInhArea);
217197
py_SpatialPooler.def("getLocalAreaDensity", &SpatialPooler::getLocalAreaDensity);
218198
py_SpatialPooler.def("setLocalAreaDensity", &SpatialPooler::setLocalAreaDensity);
219199
py_SpatialPooler.def("getStimulusThreshold", &SpatialPooler::getStimulusThreshold);

src/examples/hotgym/HelloSPTP.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -172,23 +172,24 @@ Real64 BenchmarkHotgym::run(UInt EPOCHS, bool useSPlocal, bool useSPglobal, bool
172172

173173
SDR goldSP({COLS});
174174
const SDR_sparse_t deterministicSP{
175-
72, 308, 337, 1512, 1518, 1956, 1965, 1975, 1994, 2008
175+
62, 72, 73, 82, 85, 102, 263, 277, 287, 303, 306, 308, 309, 322, 337, 339, 340, 352, 370, 493, 1094, 1095, 1114, 1115, 1120, 1463, 1512, 1518, 1647, 1651, 1691, 1694, 1729, 1745, 1746, 1760, 1770, 1774, 1775, 1781, 1797, 1798, 1803, 1804, 1805, 1812, 1827, 1828, 1831, 1832, 1858, 1859, 1860, 1861, 1862, 1875, 1878, 1880, 1881, 1898, 1918, 1923, 1929, 1931,1936, 1950, 1953, 1956, 1958, 1961, 1964, 1965, 1967, 1971, 1973, 1975, 1976, 1979, 1980, 1981, 1982, 1984, 1985, 1986, 1988, 1991, 1994, 1996, 1997, 1998, 1999, 2002, 2006, 2008, 2011, 2012, 2013, 2017, 2019, 2022, 2027, 2030
176176
};
177177
goldSP.setSparse(deterministicSP);
178178

179179
SDR goldSPlocal({COLS});
180180
const SDR_sparse_t deterministicSPlocal{
181-
12, 17, 36, 39, 62, 71, 72, 74, 75, 82, 83, 85, 93, 102, 131, 147, 171, 179, 186, 188, 189, 192, 194, 201, 260, 263, 277, 287, 298, 308, 319, 322, 323, 326, 334, 337, 340, 355, 365, 407, 422, 423, 425, 427, 429, 432, 434, 443, 445, 493, 494, 498, 502, 508, 513, 523, 534, 540, 542, 554, 559, 580, 585, 586, 610, 611, 612, 629, 631, 637, 644, 645, 646, 647, 691, 697, 698, 702, 703, 707, 709, 746, 749, 767, 806, 809, 810, 811, 825, 832, 833, 838, 839, 847, 889, 906, 920, 923, 928, 929, 931, 934, 935, 936, 952, 989, 1003, 1005, 1018, 1073, 1076, 1078, 1089, 1094, 1095, 1100, 1102, 1114, 1115, 1133, 1134, 1147, 1168, 1169, 1184, 1193, 1196, 1203, 1204, 1209, 1232, 1233, 1236, 1244, 1253, 1254, 1268, 1278, 1284, 1294, 1297, 1298, 1303, 1306, 1310, 1331, 1342, 1402, 1410, 1415, 1423, 1427, 1428, 1430, 1434, 1463, 1487, 1488, 1494, 1507, 1508, 1512, 1515, 1518, 1532, 1547, 1550, 1561, 1563, 1564, 1612, 1622, 1623, 1624, 1626, 1627, 1630, 1640, 1647, 1651, 1689, 1691, 1694, 1703, 1711, 1714, 1729, 1745, 1746, 1760, 1771, 1797, 1803, 1804, 1805, 1812, 1827, 1828, 1831, 1858, 1859, 1860, 1861, 1862, 1880, 1918, 1929, 1937, 1956, 1961, 1965, 1967, 1971, 1980, 1985, 1994, 2008, 2011, 2013
181+
12, 13, 71, 72, 75, 78, 82, 85, 131, 171, 182, 186, 189, 194, 201, 263, 277, 287, 308, 319, 323, 337, 339, 365, 407, 423, 429, 432, 434, 445, 493, 494, 502, 508, 523, 542, 554, 559, 585, 586, 610, 611, 612, 644, 645, 647, 691, 698, 699, 701, 702, 707, 777, 809, 810, 811, 833, 839, 841, 920, 923, 928, 929, 935, 955, 1003, 1005, 1073, 1076, 1094, 1095, 1114,1115, 1133, 1134, 1184, 1203, 1214, 1232, 1233, 1244, 1253, 1268, 1278, 1291, 1294, 1306, 1309, 1331, 1402, 1410, 1427, 1434, 1442, 1463, 1508, 1512, 1514, 1515, 1518, 1561, 1564, 1590, 1623, 1626, 1630, 1647, 1651, 1691, 1694, 1729, 1745, 1746, 1760, 1797, 1804, 1805, 1812, 1827, 1858, 1860, 1861, 1862, 1918, 1956, 1961, 1965, 1971, 1975, 1994, 2012
182182
};
183183
goldSPlocal.setSparse(deterministicSPlocal);
184184

185185
SDR goldTM({COLS});
186186
const SDR_sparse_t deterministicTM{
187-
1965 //FIXME this is a really bad representation -> improve the params
187+
51, 62, 72, 77, 102, 155, 287, 306, 337, 340, 370, 493, 542, 952, 1089, 1110, 1115, 1193, 1463, 1488, 1507, 1518, 1547, 1626, 1668, 1694, 1781, 1803, 1805, 1827, 1841, 1858,1859, 1860, 1861, 1862, 1878, 1881, 1915, 1918, 1923, 1929, 1933, 1939, 1941, 1953, 1955, 1956, 1958, 1961, 1965, 1968, 1975, 1976, 1980, 1981, 1985, 1986, 1987, 1991, 1992, 1994, 1997, 2002, 2006, 2008, 2012, 2013, 2040, 2042
188188
};
189189
goldTM.setSparse(deterministicTM);
190190

191-
const float goldAn = 1.0f;
191+
const float goldAn = 0.745098f;
192+
const float goldAnAvg = 0.408286f;
192193

193194
if(EPOCHS == 5000) { //these hand-written values are only valid for EPOCHS = 5000 (default), but not for debug and custom runs.
194195
NTA_CHECK(input == goldEnc) << "Deterministic output of Encoder failed!\n" << input << "should be:\n" << goldEnc;
@@ -197,7 +198,8 @@ Real64 BenchmarkHotgym::run(UInt EPOCHS, bool useSPlocal, bool useSPglobal, bool
197198
if(useTM) { NTA_CHECK(outTM == goldTM) << "Deterministic output of TM failed!\n" << outTM << "should be:\n" << goldTM; }
198199
NTA_CHECK(static_cast<UInt>(an *10000.0f) == static_cast<UInt>(goldAn *10000.0f)) //compare to 4 decimal places
199200
<< "Deterministic output of Anomaly failed! " << an << "should be: " << goldAn;
200-
NTA_CHECK(avgAnom10.getCurrentAvg() <= 0.8f) << "Deterministic average anom score failed:" << avgAnom10.getCurrentAvg();
201+
NTA_CHECK(static_cast<UInt>(avgAnom10.getCurrentAvg() * 10000.0f) == static_cast<UInt>(goldAnAvg * 10000.0f))
202+
<< "Deterministic average anom score failed:" << avgAnom10.getCurrentAvg() << " should be: " << goldAnAvg;
201203
}
202204

203205
// check runtime speed

src/examples/mnist/MNIST_SP.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@ void setup() {
8484
/* potentialPct */ 0.1f, //we have only 10 classes, and << #columns. So we want to force each col to specialize. Cca 0.3 w "7" above, or very small (0.1) for "no topology". Cannot be too small due to internal checks. Speed++
8585
/* globalInhibition */ true, //Speed+++++++; SDR quality-- (global does have active nearby cols, which we want to avoid (local)); Results+-0
8686
/* localAreaDensity */ 0.1f, // % active bits
87-
/* numActiveColumnsPerInhArea */ -1,
8887
/* stimulusThreshold */ 6u,
8988
/* synPermInactiveDec */ 0.002f, //FIXME inactive decay permanence plays NO role, investigate! (slightly better w/o it)
9089
/* synPermActiveInc */ 0.14f, //takes upto 5x steps to get dis/connected

src/htm/algorithms/SpatialPooler.cpp

Lines changed: 27 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ SpatialPooler::SpatialPooler() {
7373
SpatialPooler::SpatialPooler(
7474
const vector<UInt> inputDimensions, const vector<UInt> columnDimensions,
7575
UInt potentialRadius, Real potentialPct, bool globalInhibition,
76-
Real localAreaDensity, Int numActiveColumnsPerInhArea,
76+
Real localAreaDensity,
7777
UInt stimulusThreshold, Real synPermInactiveDec, Real synPermActiveInc,
7878
Real synPermConnected, Real minPctOverlapDutyCycles, UInt dutyCyclePeriod,
7979
Real boostStrength, Int seed, UInt spVerbosity, bool wrapAround)
@@ -88,7 +88,6 @@ SpatialPooler::SpatialPooler(
8888
potentialPct,
8989
globalInhibition,
9090
localAreaDensity,
91-
numActiveColumnsPerInhArea,
9291
stimulusThreshold,
9392
synPermInactiveDec,
9493
synPermActiveInc,
@@ -133,22 +132,14 @@ void SpatialPooler::setGlobalInhibition(bool globalInhibition) {
133132
globalInhibition_ = globalInhibition;
134133
}
135134

136-
Int SpatialPooler::getNumActiveColumnsPerInhArea() const {
137-
return numActiveColumnsPerInhArea_;
138-
}
139-
140-
void SpatialPooler::setNumActiveColumnsPerInhArea(UInt numActiveColumnsPerInhArea) {
141-
NTA_CHECK(numActiveColumnsPerInhArea > 0u && numActiveColumnsPerInhArea <= numColumns_); //TODO this boundary could be smarter
142-
numActiveColumnsPerInhArea_ = numActiveColumnsPerInhArea;
143-
localAreaDensity_ = DISABLED; //MUTEX with localAreaDensity
144-
}
145135

146136
Real SpatialPooler::getLocalAreaDensity() const { return localAreaDensity_; }
147137

148-
void SpatialPooler::setLocalAreaDensity(Real localAreaDensity) {
138+
void SpatialPooler::setLocalAreaDensity(const Real localAreaDensity) {
149139
NTA_CHECK(localAreaDensity > 0.0f && localAreaDensity <= 1.0f);
140+
NTA_CHECK(static_cast<UInt>(localAreaDensity * getNumColumns()) > 0)
141+
<< "Too small density or sp.getNumColumns() -> would have zero active output columns.";
150142
localAreaDensity_ = localAreaDensity;
151-
numActiveColumnsPerInhArea_ = DISABLED; //MUTEX with numActiveColumnsPerInhArea
152143
}
153144

154145
UInt SpatialPooler::getStimulusThreshold() const { return stimulusThreshold_; }
@@ -374,12 +365,22 @@ const vector<Real> &SpatialPooler::getBoostedOverlaps() const {
374365
}
375366

376367
void SpatialPooler::initialize(
377-
const vector<UInt> inputDimensions, const vector<UInt> columnDimensions,
378-
UInt potentialRadius, Real potentialPct, bool globalInhibition,
379-
Real localAreaDensity, Int numActiveColumnsPerInhArea,
380-
UInt stimulusThreshold, Real synPermInactiveDec, Real synPermActiveInc,
381-
Real synPermConnected, Real minPctOverlapDutyCycles, UInt dutyCyclePeriod,
382-
Real boostStrength, Int seed, UInt spVerbosity, bool wrapAround) {
368+
const vector<UInt>& inputDimensions,
369+
const vector<UInt>& columnDimensions,
370+
UInt potentialRadius,
371+
Real potentialPct,
372+
bool globalInhibition,
373+
Real localAreaDensity,
374+
UInt stimulusThreshold,
375+
Real synPermInactiveDec,
376+
Real synPermActiveInc,
377+
Real synPermConnected,
378+
Real minPctOverlapDutyCycles,
379+
UInt dutyCyclePeriod,
380+
Real boostStrength,
381+
Int seed,
382+
UInt spVerbosity,
383+
bool wrapAround) {
383384

384385
numInputs_ = 1u;
385386
inputDimensions_.clear();
@@ -401,12 +402,8 @@ void SpatialPooler::initialize(
401402
// 1D input produces 1D output; 2D => 2D, etc. //TODO allow nD -> mD conversion
402403
NTA_CHECK(inputDimensions_.size() == columnDimensions_.size());
403404

404-
NTA_CHECK((numActiveColumnsPerInhArea > 0 && localAreaDensity < 0) ||
405-
(localAreaDensity > 0 && localAreaDensity <= MAX_LOCALAREADENSITY
406-
&& numActiveColumnsPerInhArea < 0)
407-
) << numActiveColumnsPerInhArea << " vs " << localAreaDensity;
408-
numActiveColumnsPerInhArea_ = numActiveColumnsPerInhArea;
409-
localAreaDensity_ = localAreaDensity;
405+
NTA_CHECK(localAreaDensity > 0 && localAreaDensity <= MAX_LOCALAREADENSITY);
406+
setLocalAreaDensity(localAreaDensity);
410407

411408
rng_ = Random(seed);
412409

@@ -596,7 +593,7 @@ void SpatialPooler::updateInhibitionRadius_() {
596593

597594
void SpatialPooler::updateMinDutyCycles_() {
598595
if (globalInhibition_ ||
599-
inhibitionRadius_ >
596+
inhibitionRadius_ >=
600597
*max_element(columnDimensions_.begin(), columnDimensions_.end())) {
601598
updateMinDutyCyclesGlobal_();
602599
} else {
@@ -763,17 +760,7 @@ void applyBoosting_(const UInt i,
763760

764761

765762
void SpatialPooler::updateBoostFactorsGlobal_() {
766-
Real targetDensity;
767-
if (numActiveColumnsPerInhArea_ > 0) {
768-
UInt inhibitionArea =
769-
(UInt)(pow((Real)(2 * inhibitionRadius_ + 1), (Real)columnDimensions_.size()));
770-
inhibitionArea = min(inhibitionArea, numColumns_);
771-
NTA_ASSERT(inhibitionArea > 0);
772-
targetDensity = ((Real)numActiveColumnsPerInhArea_) / inhibitionArea;
773-
targetDensity = min(targetDensity, (Real)MAX_LOCALAREADENSITY);
774-
} else {
775-
targetDensity = localAreaDensity_;
776-
}
763+
const Real targetDensity = localAreaDensity_;
777764

778765
for (UInt i = 0; i < numColumns_; ++i) {
779766
applyBoosting_(i, targetDensity, activeDutyCycles_, boostStrength_, boostFactors_);
@@ -821,14 +808,7 @@ void SpatialPooler::calculateOverlap_(const SDR &input,
821808

822809
void SpatialPooler::inhibitColumns_(const vector<Real> &overlaps,
823810
vector<CellIdx> &activeColumns) const {
824-
Real density = localAreaDensity_;
825-
if (numActiveColumnsPerInhArea_ > 0) {
826-
UInt inhibitionArea =
827-
(UInt)(pow((Real)(2 * inhibitionRadius_ + 1), (Real)columnDimensions_.size()));
828-
inhibitionArea = min(inhibitionArea, numColumns_);
829-
density = ((Real)numActiveColumnsPerInhArea_) / inhibitionArea;
830-
density = min(density, (Real)MAX_LOCALAREADENSITY);
831-
}
811+
const Real density = localAreaDensity_;
832812

833813
if (globalInhibition_ ||
834814
inhibitionRadius_ >
@@ -899,7 +879,8 @@ void SpatialPooler::inhibitColumnsLocal_(const vector<Real> &overlaps,
899879

900880

901881
if (wrapAround_) {
902-
for(auto neighbor: WrappingNeighborhood(column, inhibitionRadius_,columnDimensions_)) {
882+
for(auto neighbor: WrappingNeighborhood(column, inhibitionRadius_,columnDimensions_)) { //TODO if we don't change inh radius (changes only every isUpdateRound()),
883+
// then these values can be cached -> faster local inh
903884
if (neighbor == column) {
904885
continue;
905886
}
@@ -957,7 +938,6 @@ void SpatialPooler::printParameters(std::ostream& out) const {
957938
<< "iterationLearnNum = " << getIterationLearnNum() << std::endl
958939
<< "numInputs = " << getNumInputs() << std::endl
959940
<< "numColumns = " << getNumColumns() << std::endl
960-
<< "numActiveColumnsPerInhArea = " << getNumActiveColumnsPerInhArea()
961941
<< std::endl
962942
<< "potentialPct = " << getPotentialPct() << std::endl
963943
<< "globalInhibition = " << getGlobalInhibition() << std::endl
@@ -1008,7 +988,6 @@ bool SpatialPooler::operator==(const SpatialPooler& o) const{
1008988
if (potentialPct_ != o.potentialPct_) return false;
1009989
if (initConnectedPct_ != o.initConnectedPct_) return false;
1010990
if (globalInhibition_ != o.globalInhibition_) return false;
1011-
if (numActiveColumnsPerInhArea_ != o.numActiveColumnsPerInhArea_) return false;
1012991
if (localAreaDensity_ != o.localAreaDensity_) return false;
1013992
if (stimulusThreshold_ != o.stimulusThreshold_) return false;
1014993
if (inhibitionRadius_ != o.inhibitionRadius_) return false;

0 commit comments

Comments
 (0)