Skip to content
This repository has been archived by the owner on Sep 1, 2023. It is now read-only.

Fix SP unstable output, synapse decay #1382

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/nupic/algorithms/SpatialPooler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,16 @@ const vector<Real>& SpatialPooler::getBoostedOverlaps() const
return boostedOverlaps_;
}

/** helper method that checks SP output is stable for given configuration */
bool checkUnstableParams_(SpatialPooler &sp) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the "stability check" that I suggest to run on each SP initialization. So far it has already identified many misconfigurations in our unit-tests.

vector<UInt> input(sp.getNumInputs(), 1); //auto size of input
vector<UInt> out1(sp.getNumColumns(), 0);
vector<UInt> out2(sp.getNumColumns(), 0);
sp.compute(input.data(), false, out1.data());
sp.compute(input.data(), false, out2.data());
return std::equal(std::begin(out1), std::end(out1), std::begin(out2)); //compare all, element wise
}

void SpatialPooler::initialize(vector<UInt> inputDimensions,
vector<UInt> columnDimensions,
UInt potentialRadius,
Expand Down Expand Up @@ -593,6 +603,9 @@ void SpatialPooler::initialize(vector<UInt> inputDimensions,
printParameters();
std::cout << "CPP SP seed = " << seed << std::endl;
}

//check for reasonable params
NTA_CHECK(checkUnstableParams_(*this)); //TODO the assert runs only at debug builds, make mandatory?
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: make this mandatory even for Release builds?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently the check crashes? on some instances, while already identifies some problematic instances in our unit-tests.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.. crash fixed in #1391

}

void SpatialPooler::compute(UInt inputArray[], bool learn,
Expand Down
50 changes: 50 additions & 0 deletions src/test/unit/algorithms/SpatialPoolerTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
* Implementation of unit tests for SpatialPooler
*/

#include <algorithm> //generate
#include <cstdlib> //rand
#include <cstring>
#include <fstream>
#include <stdio.h>
Expand Down Expand Up @@ -2222,6 +2224,54 @@ namespace {
EXPECT_EQ(0, countNonzero(activeColumns));
}


// function generator:
int RandomNumber01 () { return (rand()%2); } // returns random (binary) numbers from {0,1}

TEST(SpatialPoolerTest, testConstructorInitParamsUnstable)
{
/** this test exposes bug where c++ SP (wrongly) produces
different output for the same input.
XXX sensitive - marks (empirically!) discovered set of parameter
that produce the err behavior; changing any of the XXX params
may cause the SP to behave "normally"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test-case for unstable combination of init params

*/
SpatialPooler sp{std::vector<UInt>{1000} /* input*/, std::vector<UInt>{20}/* SP output cols XXX sensitive*/,
/*pot radius*/ 20, //each col sees
/*pot pct*/ 0.5, //XXX sensitive
/*global inhibition*/ false, //XXX sensitive
/*Real localAreaDensity=*/0.02, //2% active cols
/*UInt numActiveColumnsPerInhArea=*/0, //mutex with above ^^ //XXX sensitive
};
sp.setBoostStrength(0.0);

vector<UInt> input(sp.getNumInputs(), 1);
vector<UInt> out1(sp.getNumColumns(), 0);
vector<UInt> out2(sp.getNumColumns(), 0);

for(UInt i=0; i< 1800; i++) { //epochs
//burn in
for (UInt burnIn=1; burnIn < 90; burnIn++) {
generate(input.begin(), input.end(), RandomNumber01); //random input
sp.compute(input.data(), true, out1.data()); //burn in
cout<<".";
cout.flush();
}

//compare
for (UInt noLearn=1; noLearn < 90; noLearn++) {
generate(input.begin(), input.end(), RandomNumber01); //random input
sp.compute(input.data(), false, out1.data());
sp.compute(input.data(), false, out2.data());
EXPECT_EQ(out1, out2); //not necessary with the check in SP initialize(), but keep here as example
cout<<"=";
cout.flush();
}
cout<<endl;
}
}


TEST(SpatialPoolerTest, testSaveLoad)
{
const char* filename = "SpatialPoolerSerialization.tmp";
Expand Down