Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TM, SP: fix possible underflow in seed. Default random (0) seed. #799

Open
wants to merge 25 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
e8217a9
TM, SP: fix possible underflow in seed. Default random (0) seed.
breznak Apr 22, 2020
7faf388
Merge branch 'master_community' into seeds
breznak Apr 22, 2020
e159de9
Fix random seed for RDSERegion
breznak Apr 23, 2020
a4a4283
Random: improve rng serialization tests
breznak Apr 23, 2020
d66c1e9
Random: simplify seeding for random seed (=0)
breznak Apr 23, 2020
3995e40
Random: remove serialization via operator<<
breznak Apr 23, 2020
26a5d0f
Random: remove serialization via operator<<
breznak Apr 23, 2020
b0c2909
SP: test is more descriptive, on Serialization
breznak Apr 23, 2020
c029f61
HelloSPTP: formatting
breznak Apr 23, 2020
a7420a5
SP: equals with detailed checks
breznak Apr 24, 2020
e0fdb49
Connections: add Serializable interface to *Data structures
breznak Apr 24, 2020
fa46037
Connections: rework equals operator==
breznak Apr 24, 2020
bd84c41
Connection: serialization err fixed
breznak Apr 27, 2020
ce72ea7
SP: debugging HelloSPTP equals, save
breznak Apr 27, 2020
ea7b88d
Random: small cleanup
breznak Apr 27, 2020
be4c661
Merge branch 'master_community' into seeds
breznak Jun 3, 2020
9dc9954
Merge branch 'master_community' into seeds
breznak Jun 4, 2020
284dc2e
SP enable == checks
breznak Jun 4, 2020
8b6c6a3
Merge branch 'master_community' into seeds
breznak Jun 4, 2020
c1a1b3d
Merge branch 'master_community' into seeds
breznak Jun 4, 2020
d034207
Merge branch 'master_community' into seeds
breznak Jun 7, 2020
d5d4b69
Merge branch 'master_community' into seeds
breznak Sep 3, 2020
bd6c275
update seed in expected results for SP,TMRegion tests
breznak Sep 3, 2020
3ce080e
debugging SP-Connections-Segments serialization
breznak Sep 3, 2020
6247c61
Merge branch 'master_community' into seeds
breznak Sep 8, 2020
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
6 changes: 3 additions & 3 deletions bindings/py/cpp_src/bindings/algorithms/py_SpatialPooler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,9 +173,9 @@ Argument boostStrength A number greater or equal than 0, used to
too much boosting may also lead to instability of SP outputs.


Argument seed Seed for our random number generator. If seed is < 0
Argument seed Seed for our random number generator. If seed is 0
Copy link
Member Author

Choose a reason for hiding this comment

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

corrected the doc strings

a randomly generated seed is used. The behavior of the spatial
pooler is deterministic once the seed is set.
pooler is deterministic once the seed is set > 0.

Argument spVerbosity spVerbosity level: 0, 1, 2, or 3

Expand All @@ -197,7 +197,7 @@ Argument wrapAround boolean value that determines whether or not inputs
, py::arg("minPctOverlapDutyCycle") = 0.001
, py::arg("dutyCyclePeriod") = 1000
, py::arg("boostStrength") = 0.0
, py::arg("seed") = 1
, py::arg("seed") = 0
Copy link
Member Author

Choose a reason for hiding this comment

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

changed the defaults to "random" (0) in cpp, py, NetworkAPI

, py::arg("spVerbosity") = 0
, py::arg("wrapAround") = true
);
Expand Down
5 changes: 3 additions & 2 deletions bindings/py/cpp_src/bindings/algorithms/py_TemporalMemory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,8 @@ Argument predictedSegmentDecrement
0.01 = 0.0004

Argument seed
Seed for the random number generator.
Seed for the random number generator. Default (0) means truly random,
> 0 is a fixed pseudorandom-sequence. See Random.hpp.

Argument maxSegmentsPerCell
The maximum number of segments per cell.
Expand Down Expand Up @@ -146,7 +147,7 @@ Argument anomalyMode (optional, default ANMode::RAW) selects mode for `TM.anomal
, py::arg("permanenceIncrement") = 0.1
, py::arg("permanenceDecrement") = 0.1
, py::arg("predictedSegmentDecrement") = 0.0
, py::arg("seed") = 42
, py::arg("seed") = 0
, py::arg("maxSegmentsPerCell") = 255
, py::arg("maxSynapsesPerSegment") = 255
, py::arg("checkInputs") = true
Expand Down
11 changes: 8 additions & 3 deletions src/examples/hello/HelloSPTP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,7 @@ EPOCHS = 2; // make test faster in Debug
SpatialPooler spLocal(enc.dimensions, vector<UInt>{COLS}); // Spatial pooler with local inh
spGlobal.setGlobalInhibition(true);
spLocal.setGlobalInhibition(false);
Random rnd(42); //uses fixed seed for deterministic output checks


TemporalMemory tm(vector<UInt>{COLS}, CELLS);

AnomalyLikelihood anLikelihood;
Expand All @@ -94,6 +93,12 @@ EPOCHS = 2; // make test faster in Debug
Metrics statsSPglobal(outSPglobal, 1000);
Metrics statsTM(outTM, 1000);

//uses fixed seed for deterministic output checks:
Random rnd(42);
spGlobal.setSeed(1);
Copy link
Member Author

Choose a reason for hiding this comment

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

a strange thing is happening here, I set the rng_ to fixed seed (1 used to be used before) ...but determ. output is still changing!

spLocal.setSeed(1);
tm.setSeed(42);

/*
* For example: fn = sin(x) -> periodic >= 2Pi ~ 6.3 && x+=0.01 -> 630 steps to 1st period -> window >= 630
*/
Expand Down Expand Up @@ -201,7 +206,7 @@ EPOCHS = 2; // make test faster in Debug

SDR goldSP({COLS});
const SDR_sparse_t deterministicSP{
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
66, 70, 72, 75, 76, 82, 83, 85, 99, 297, 300, 301, 303, 305, 306, 308, 309, 311, 316, 320, 321, 323, 324, 325, 327, 329, 330, 343, 345, 347, 363, 508, 1084, 1110, 1112, 1115, 1120, 1131, 1522, 1532, 1535, 1634, 1684, 1697, 1732, 1769, 1777, 1778, 1800, 1801, 1803, 1817, 1818, 1823, 1830, 1834, 1836, 1844, 1847, 1851, 1855, 1859, 1860, 1862, 1866, 1882, 1886, 1897,1906, 1918, 1921, 1922, 1931, 1936, 1954, 1961, 1964, 1965, 1966, 1967, 1968, 1970, 1971, 1972, 1973, 1975, 1977, 1978, 1980, 1981, 1987, 1989, 1990, 2001, 2006, 2007, 2009, 2015, 2016, 2018, 2020, 2042
};
goldSP.setSparse(deterministicSP);

Expand Down
4 changes: 2 additions & 2 deletions src/htm/algorithms/SpatialPooler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ SpatialPooler::SpatialPooler(
Real localAreaDensity, UInt numActiveColumnsPerInhArea,
UInt stimulusThreshold, Real synPermInactiveDec, Real synPermActiveInc,
Real synPermConnected, Real minPctOverlapDutyCycles, UInt dutyCyclePeriod,
Real boostStrength, Int seed, UInt spVerbosity, bool wrapAround)
Real boostStrength, UInt seed, UInt spVerbosity, bool wrapAround)
: SpatialPooler::SpatialPooler()
{
// The current version number for serialzation.
Expand Down Expand Up @@ -381,7 +381,7 @@ void SpatialPooler::initialize(
Real minPctOverlapDutyCycles,
UInt dutyCyclePeriod,
Real boostStrength,
Int seed,
UInt seed,
UInt spVerbosity,
bool wrapAround) {

Expand Down
26 changes: 19 additions & 7 deletions src/htm/algorithms/SpatialPooler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ class SpatialPooler : public Serializable
Real minPctOverlapDutyCycles = 0.001f,
UInt dutyCyclePeriod = 1000u,
Real boostStrength = 0.0f,
Int seed = 1,
UInt seed = 0u, //random
UInt spVerbosity = 0u,
bool wrapAround = true);

Expand Down Expand Up @@ -200,9 +200,9 @@ class SpatialPooler : public Serializable
too much boosting may also lead to instability of SP outputs.


@param seed Seed for our random number generator. If seed is < 0
@param seed Seed for our random number generator. If seed is 0,
a randomly generated seed is used. The behavior of the spatial
pooler is deterministic once the seed is set.
pooler is deterministic once the seed is fixed to > 0.

@param spVerbosity spVerbosity level: 0, 1, 2, or 3

Expand All @@ -220,10 +220,15 @@ class SpatialPooler : public Serializable
Real localAreaDensity = 0.05f,
UInt numActiveColumnsPerInhArea = 0,
UInt stimulusThreshold = 0u,
Real synPermInactiveDec = 0.01f, Real synPermActiveInc = 0.1f,
Real synPermConnected = 0.1f, Real minPctOverlapDutyCycles = 0.001f,
UInt dutyCyclePeriod = 1000u, Real boostStrength = 0.0f,
Int seed = 1, UInt spVerbosity = 0u, bool wrapAround = true);
Real synPermInactiveDec = 0.01f,
Real synPermActiveInc = 0.1f,
Real synPermConnected = 0.1f,
Real minPctOverlapDutyCycles = 0.001f,
UInt dutyCyclePeriod = 1000u,
Real boostStrength = 0.0f,
UInt seed = 0u,
UInt spVerbosity = 0u,
bool wrapAround = true);


/**
Expand Down Expand Up @@ -769,6 +774,13 @@ class SpatialPooler : public Serializable
*/
void getConnectedCounts(UInt connectedCounts[]) const;

/** set seed for internal random number generator.
* See @ref `seed` arg in the constructor.
*/
void setSeed(UInt seed) {
rng_ = Random(seed);
}


/**
Returns the boosted overlap score for each column.
Expand Down
4 changes: 2 additions & 2 deletions src/htm/algorithms/TemporalMemory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ TemporalMemory::TemporalMemory(
Permanence permanenceIncrement,
Permanence permanenceDecrement,
Permanence predictedSegmentDecrement,
Int seed,
UInt seed,
SegmentIdx maxSegmentsPerCell,
SynapseIdx maxSynapsesPerSegment,
bool checkInputs,
Expand All @@ -90,7 +90,7 @@ void TemporalMemory::initialize(
Permanence permanenceIncrement,
Permanence permanenceDecrement,
Permanence predictedSegmentDecrement,
Int seed,
UInt seed,
SegmentIdx maxSegmentsPerCell,
SynapseIdx maxSynapsesPerSegment,
bool checkInputs,
Expand Down
14 changes: 11 additions & 3 deletions src/htm/algorithms/TemporalMemory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ class TemporalMemory : public Serializable
* something like 4% * 0.01 = 0.0004).
*
* @param seed
* Seed for the random number generator.
* Seed for the random number generator. 0 (default) means truly random,
* use > 0 for fixed pseudo-random.
*
* @param maxSegmentsPerCell
* The maximum number of segments per cell.
Expand Down Expand Up @@ -144,7 +145,7 @@ class TemporalMemory : public Serializable
Permanence permanenceIncrement = 0.10,
Permanence permanenceDecrement = 0.10,
Permanence predictedSegmentDecrement = 0.0,
Int seed = 42,
UInt seed = 0, //random
SegmentIdx maxSegmentsPerCell = 255,
SynapseIdx maxSynapsesPerSegment = 255,
bool checkInputs = true,
Expand All @@ -164,7 +165,7 @@ class TemporalMemory : public Serializable
Permanence permanenceIncrement = 0.10,
Permanence permanenceDecrement = 0.10,
Permanence predictedSegmentDecrement = 0.0,
Int seed = 42,
UInt seed = 0,
SegmentIdx maxSegmentsPerCell = 255,
SynapseIdx maxSynapsesPerSegment = 255,
bool checkInputs = true,
Expand Down Expand Up @@ -595,6 +596,10 @@ class TemporalMemory : public Serializable
virtual bool operator==(const TemporalMemory &other) const;
inline bool operator!=(const TemporalMemory &other) const { return not this->operator==(other); }

void setSeed(UInt seed) {
rng_ = Random(seed);
}

//----------------------------------------------------------------------
// Debugging helpers
//----------------------------------------------------------------------
Expand Down Expand Up @@ -638,6 +643,9 @@ class TemporalMemory : public Serializable
*
*/
SDR cellsToColumns(const SDR& cells) const;



private:
void punishPredictedColumn_(vector<Segment>::const_iterator columnMatchingSegmentsBegin,
vector<Segment>::const_iterator columnMatchingSegmentsEnd,
Expand Down
6 changes: 3 additions & 3 deletions src/htm/regions/RDSEEncoderRegion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ namespace htm {


RDSEEncoderRegion::RDSEEncoderRegion(const ValueMap &par, Region *region) : RegionImpl(region) {
rnd_ = Random(42);
rnd_ = Random(42); //TODO use seed value here?
spec_.reset(createSpec());
ValueMap params = ValidateParameters(par, spec_.get());

Expand All @@ -78,8 +78,8 @@ RDSEEncoderRegion::RDSEEncoderRegion(const ValueMap &par, Region *region) : Regi
args.sparsity = params.getScalarT<Real32>("sparsity");
args.radius = params.getScalarT<Real32>("radius");
args.resolution = params.getScalarT<Real32>("resolution");
args.category = params.getScalarT<bool>("category");
args.seed = params.getScalarT<UInt32>("seed");
args.category = params.getScalarT<bool>("category", false);
args.seed = params.getScalarT<UInt32>("seed", 0);

encoder_ = std::make_shared<RandomDistributedScalarEncoder>(args);
sensedValue_ = params.getScalarT<Real64>("sensedValue");
Expand Down
6 changes: 3 additions & 3 deletions src/htm/regions/SPRegion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ SPRegion::SPRegion(const ValueMap &values, Region *region)
args_.minPctOverlapDutyCycles = values.getScalarT<Real32>("minPctOverlapDutyCycles", 0.001f);
args_.dutyCyclePeriod = values.getScalarT<UInt32>("dutyCyclePeriod", 1000);
args_.boostStrength = values.getScalarT<Real32>("boostStrength", 0.0f);
args_.seed = values.getScalarT<Int32>("seed", 1);
args_.seed = values.getScalarT<Int32>("seed", 0u);
args_.spVerbosity = values.getScalarT<UInt32>("spVerbosity", 0);
args_.wrapAround = values.getScalarT<bool>("wrapAround", true);
spatialImp_ = values.getString("spatialImp", "");
Expand Down Expand Up @@ -452,11 +452,11 @@ Spec *SPRegion::createSpec() {
"seed",
ParameterSpec(
"(int)\n"
"Seed for our own pseudo - random number generator. Default ``-1``.",
"Seed for our own pseudo - random number generator. Default ``0``(=random), >0 means fixed.",
NTA_BasicType_Int32, // type
1, // elementCount
"", // constraints
"1", // defaultValue
"0", // defaultValue
ParameterSpec::CreateAccess)); // access

ns->parameters.add(
Expand Down
2 changes: 1 addition & 1 deletion src/htm/regions/SPRegion.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ class SPRegion : public RegionImpl, Serializable
Real minPctOverlapDutyCycles;
UInt dutyCyclePeriod;
Real boostStrength;
Int seed;
UInt seed;
UInt spVerbosity;
bool wrapAround;
bool learningMode;
Expand Down
6 changes: 3 additions & 3 deletions src/htm/regions/TMRegion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ TMRegion::TMRegion(const ValueMap &params, Region *region)
args_.permanenceIncrement = params.getScalarT<Real32>("permanenceIncrement", 0.10f);
args_.permanenceDecrement = params.getScalarT<Real32>("permanenceDecrement", 0.10f);
args_.predictedSegmentDecrement = params.getScalarT<Real32>("predictedSegmentDecrement", 0.0f);
args_.seed = params.getScalarT<Int32>("seed", 42);
args_.seed = params.getScalarT<Int32>("seed", 0);
args_.maxSegmentsPerCell = params.getScalarT<UInt32>("maxSegmentsPerCell", 255u);
args_.maxSynapsesPerSegment = params.getScalarT<UInt32>("maxSynapsesPerSegment", 255u);
args_.checkInputs = params.getScalarT<bool>("checkInputs", true);
Expand Down Expand Up @@ -416,11 +416,11 @@ Spec *TMRegion::createSpec() {
"seed",
ParameterSpec("(int) Random number generator seed. The seed affects the random "
"aspects of initialization like the initial permanence values. A "
"fixed value ensures a reproducible result.",
"fixed value > 0 ensures a reproducible result.",
NTA_BasicType_Int32, // type
1, // elementCount
"", // constraints
"42", // defaultValue
"0", // defaultValue
ParameterSpec::CreateAccess)); // access

///////// Parameters not part of the calling arguments //////////
Expand Down
2 changes: 1 addition & 1 deletion src/htm/regions/TMRegion.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ class TMRegion : public RegionImpl, Serializable {
Real32 permanenceIncrement;
Real32 permanenceDecrement;
Real32 predictedSegmentDecrement;
Int32 seed;
UInt32 seed;
Int32 maxSegmentsPerCell;
Int32 maxSynapsesPerSegment;
UInt32 externalPredictiveInputs;
Expand Down
15 changes: 6 additions & 9 deletions src/test/unit/algorithms/SpatialPoolerTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1944,27 +1944,24 @@ TEST(SpatialPoolerTest, testSerialization_ar) {

SpatialPooler sp1;
sp1.initialize(inputDims, colDims);
sp1.setSeed(1);

SDR input(inputDims);
SDR output(colDims);

//burn-in the SP
for (UInt i = 0; i < 100; ++i) {
input.randomize(0.05f, random); //5% random ON
sp1.compute(input, true, output);
}

// Now we reuse the last input to test after serialization

auto activeColumnsBefore = output.getSparse();

// Save initial trained model
stringstream ss;
ss.precision(std::numeric_limits<double>::digits10 + 1);
ss.precision(std::numeric_limits<float>::digits10 + 1);
sp1.save(ss);

SpatialPooler sp2;

htm::Timer testTimer;

for (UInt i = 0; i < 6; ++i) {
Expand All @@ -1975,26 +1972,26 @@ TEST(SpatialPoolerTest, testSerialization_ar) {
SDR outputBaseline(output);
sp1.compute(input, true, outputBaseline);

// C - Next do old version
// C - Next, verify the same results come from the de/serialized version
{
SpatialPooler spTemp;
testTimer.start();

// Deserialize
ss.seekg(0);
spTemp.load(ss);
EXPECT_NO_THROW(spTemp.load(ss));

// Feed new record through
SDR outputC({numColumns});
spTemp.compute(input, true, outputC);

// Serialize
ss.clear();
spTemp.save(ss);
EXPECT_NO_THROW(spTemp.save(ss));

testTimer.stop();

EXPECT_EQ(outputBaseline, outputC);
EXPECT_EQ(outputBaseline, outputC); //FIXME this test randomly fails. (De/serialization of rng_ is correct?)
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 another test that is inconsistent! Sometimes it passes, sometimes crashes on different outputs. I can't see why would that be, the test is relatively simple and seems correct.
I'm suspecting something with serizalization of Random?
Even more confusing is why HellpSPTP fails undeterministically now?

}
}
ss.clear();
Expand Down
2 changes: 1 addition & 1 deletion src/test/unit/engine/CppRegionTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ TEST(CppRegionTest, testCppLinkingSDR) {
Network net;

std::shared_ptr<Region> region1 = net.addRegion("region1", "ScalarEncoderRegion", "{dim: [6,1], n: 6, w: 2}");
std::shared_ptr<Region> region2 = net.addRegion("region2", "SPRegion", "{dim: [20,3]}");
std::shared_ptr<Region> region2 = net.addRegion("region2", "SPRegion", "{dim: [20,3], seed: 1}"); //seed is fixed for deterministic results in tests

net.link("region1", "region2");

Expand Down
6 changes: 3 additions & 3 deletions src/test/unit/regions/ClassifierRegionTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ TEST(ClassifierRegionTest, asCategoryDecoder) {
Network net;

std::shared_ptr<Region> encoder = net.addRegion("encoder", "RDSEEncoderRegion", "{size: 400, seed: 42, category: true, activeBits: 40}");
std::shared_ptr<Region> sp = net.addRegion("sp", "SPRegion", "{columnCount: 1000, globalInhibition: true}");
std::shared_ptr<Region> sp = net.addRegion("sp", "SPRegion", "{columnCount: 1000, globalInhibition: true, seed: 1}");
std::shared_ptr<Region> classifier = net.addRegion("classifier", "ClassifierRegion", "{learn: true}");

net.link("encoder", "sp", "", "", "encoded", "bottomUpIn");
Expand Down Expand Up @@ -144,7 +144,7 @@ TEST(ClassifierRegionTest, asRealDecoder) {
Network net;

std::shared_ptr<Region> encoder = net.addRegion("encoder", "RDSEEncoderRegion", "{size: 400, radius: 0.1, seed: 42, activeBits: 40}");
std::shared_ptr<Region> sp = net.addRegion("sp", "SPRegion", "{columnCount: 1000, globalInhibition: true}");
std::shared_ptr<Region> sp = net.addRegion("sp", "SPRegion", "{columnCount: 1000, globalInhibition: true, seed: 1}");
std::shared_ptr<Region> classifier = net.addRegion("classifier", "ClassifierRegion", "{learn: true}");

net.link("encoder", "sp", "", "", "encoded", "bottomUpIn");
Expand Down Expand Up @@ -244,4 +244,4 @@ TEST(ClassifierRegionTest, testSerialization) {
Directory::removeTree("TestOutputDir", true);
}

} // namespace testing
} // namespace testing
Loading