Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
51 changes: 37 additions & 14 deletions src/examples/hello/HelloSPTP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,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 All @@ -112,6 +118,7 @@ EPOCHS = 2; // make test faster in Debug
for (UInt e = 0; e < EPOCHS; e++) { //FIXME EPOCHS is actually steps, there's just 1 pass through data/epoch.

//Encode
{
tEnc.start();
x+=0.01f; //step size for fn(x)
enc.encode(sin(x), input); //model sin(x) function //TODO replace with CSV data
Expand All @@ -121,32 +128,38 @@ EPOCHS = 2; // make test faster in Debug
tRng.start();
input.addNoise(0.01f, rnd); //change 1% of the SDR for each iteration, this makes a random sequence, but seemingly stable
tRng.stop();
}

//SP (global and local)
if(useSPlocal) {
tSPloc.start();
spLocal.compute(input, true, outSPlocal);
tSPloc.stop();
tSPloc.start();
spLocal.compute(input, true, outSPlocal);
tSPloc.stop();

outSP = outSPlocal;
}

if(useSPglobal) {
tSPglob.start();
spGlobal.compute(input, true, outSPglobal);
tSPglob.stop();
tSPglob.start();
spGlobal.compute(input, true, outSPglobal);
tSPglob.stop();

outSP = outSPglobal;
}
outSP = outSPglobal; //toggle if local/global SP is used further down the chain (TM, Anomaly)

// TM
if(useTM) {
tTM.start();
tTM.start();
tm.compute(outSP, true /*learn*/); //to uses output of SPglobal
tm.activateDendrites(); //required to enable tm.getPredictiveCells()
outTM = tm.cellsToColumns( tm.getPredictiveCells() );
tTM.stop();

outTM = tm.cellsToColumns( tm.getPredictiveCells() );
}


//Anomaly (pure x likelihood)
{
an = tm.anomaly;
avgAnom10.compute(an); //moving average
if(e % 1000 == 0) {
Expand All @@ -157,6 +170,7 @@ EPOCHS = 2; // make test faster in Debug
tAnLikelihood.start();
anLikely = anLikelihood.anomalyProbability(an);
tAnLikelihood.stop();
}


// print
Expand Down Expand Up @@ -202,27 +216,36 @@ 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
68, 79, 86, 98, 105, 257, 263, 286, 302, 306, 307, 309, 310, 313, 315, 317, 318, 320, 323, 325, 326, 329, 334, 350, 356, 363, 539, 935, 1089, 1093, 1098, 1111, 1112, 1118, 1120, 1124, 1133, 1508, 1513, 1521, 1624, 1746, 1765, 1774, 1775, 1776, 1780, 1784, 1787, 1802, 1804, 1811, 1813, 1815, 1819, 1844, 1845, 1865, 1876, 1884, 1891, 1900, 1903, 1904, 1908, 1909, 1925, 1926, 1928, 1932, 1933, 1943, 1947, 1952, 1955, 1959, 1961, 1962, 1964, 1966, 1967, 1969, 1970, 1971, 1973, 1975, 1977, 1980, 1981, 1982, 1983, 1985, 1987, 1991, 1994, 2002, 2004, 2011, 2027, 2030, 2031, 2045
};
goldSP.setSparse(deterministicSP);

SDR goldSPlocal({COLS});
const SDR_sparse_t deterministicSPlocal{
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, 429, 432, 434, 443, 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, 1232, 1233, 1244, 1253, 1268, 1278, 1291, 1294, 1306, 1309, 1331, 1402, 1410, 1427, 1434, 1442, 1463, 1508, 1512, 1514, 1515, 1518, 1561, 1564, 1623, 1626, 1630, 1640, 1647, 1691, 1694, 1729, 1745, 1746, 1760, 1797, 1804, 1805, 1812, 1827, 1831, 1858, 1861, 1862, 1918, 1956, 1961, 1965, 1971, 1975, 1994, 2012
17, 71, 75, 79, 81, 86, 89, 164, 189, 198, 203, 262, 297, 314, 324, 326, 329, 337, 360, 379, 432, 443, 448, 452, 509, 520, 525, 526, 529, 536, 612, 619, 624, 630, 649, 652, 693, 717, 719, 720, 754, 810, 813, 815, 835, 839, 849, 884, 890, 914, 925, 931, 937, 945, 971, 1016, 1088, 1089, 1095, 1105, 1109, 1133, 1159, 1209, 1214, 1228, 1235, 1241, 1244, 1273, 1295, 1314, 1329, 1336, 1342, 1427, 1435, 1436, 1448, 1461, 1486, 1496, 1500, 1523, 1561, 1572, 1576, 1603, 1610, 1624, 1635, 1649, 1664, 1685, 1725, 1732, 1741, 1758, 1800, 1804, 1811, 1824, 1862, 1870, 1882, 1883, 1887, 1903, 1956, 1963, 1971, 1977, 1984, 2015
};
goldSPlocal.setSparse(deterministicSPlocal);

SDR goldTM({COLS});
const SDR_sparse_t deterministicTM{
72, 85, 102, 114, 122, 126, 287, 308, 337, 339, 542, 920, 939, 952, 1268, 1507, 1508, 1518, 1546, 1547, 1626, 1627, 1633, 1668, 1727, 1804, 1805, 1827, 1832, 1844, 1859, 1862, 1918, 1920, 1924, 1931, 1933, 1945, 1961, 1965, 1966, 1968, 1970, 1973, 1975, 1976, 1977, 1979, 1986, 1987, 1991, 1992, 1996, 1998, 2002, 2006, 2008, 2012, 2042, 2045
79, 92, 98, 128, 136, 286, 307, 309, 310, 313, 315, 325, 356, 454, 539, 1093, 1111, 1112, 1120, 1237, 1278, 1467, 1497, 1508, 1513, 1521, 1614, 1624, 1635, 1668, 1669, 1673,1699, 1774, 1775, 1776, 1780, 1784, 1808, 1813, 1815, 1816, 1821, 1827, 1845, 1865, 1900, 1911, 1913, 1925, 1929, 1931, 1932, 1933, 1940, 1941, 1947, 1949, 1955, 1956, 1959, 1961, 1962, 1964, 1966, 1967, 1968, 1969, 1970, 1972, 1975, 1977, 1978, 1979, 1981, 1982, 1985, 1987, 1988, 1991, 1994, 2027, 2030, 2044, 2045
};
goldTM.setSparse(deterministicTM);

const float goldAn = 0.637255f; //Note: this value is for a (randomly picked) datapoint, it does not have to improve (decrease) with better algorithms
const float goldAnAvg = 0.40804f; // ...the averaged value, on the other hand, should improve/decrease.
const float goldAn = 0.470588f; //Note: this value is for a (randomly picked) datapoint, it does not have to improve (decrease) with better algorithms
const float goldAnAvg = 0.40961f; // ...the averaged value, on the other hand, should improve/decrease.

#ifdef _ARCH_DETERMINISTIC
if(e+1 == 5000) {
// For debugging serialization: save SP's state in 1 step, comment out, recompile, load SP and compare in another
// step 1:
spGlobal.saveToFile("/tmp/spG.save");
// step 2:
SpatialPooler resumedSP;
resumedSP.loadFromFile("/tmp/spG.save");
NTA_CHECK(spGlobal == resumedSP) << "SPs differ!";
// --end of debugging

//these hand-written values are only valid for EPOCHS = 5000 (default), but not for debug and custom runs.
NTA_CHECK(input == goldEnc) << "Deterministic output of Encoder failed!\n" << input << "should be:\n" << goldEnc;
if(useSPglobal) { NTA_CHECK(outSPglobal == goldSP) << "Deterministic output of SP (g) failed!\n" << outSP << "should be:\n" << goldSP; }
Expand Down
31 changes: 21 additions & 10 deletions src/htm/algorithms/Connections.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ using std::string;
using std::vector;
using namespace htm;

const Permanence MARK_SYNAPSE_AS_REMOVED = -1.0;

Connections::Connections(const CellIdx numCells,
const Permanence connectedThreshold,
const bool timeseries) {
Expand Down Expand Up @@ -210,14 +212,14 @@ bool Connections::synapseExists_(const Synapse synapse, bool fast) const {
const bool found = (std::find(synapsesOnSegment.begin(), synapsesOnSegment.end(), synapse) != synapsesOnSegment.end());
//validate the fast & slow methods for same result:
#ifdef NTA_ASSERTIONS_ON
const bool removed = synapses_[synapse].permanence == -1;
NTA_ASSERT( (removed and not found) or (not removed and found) );
const bool removed = fabs(synapses_[synapse].permanence - MARK_SYNAPSE_AS_REMOVED) < 0.001f;
NTA_CHECK( (removed and not found) or (not removed and found) );
#endif
return found;

} else {
//quick method. Relies on hack in destroySynapse() where we set synapseData.permanence == -1
return synapses_[synapse].permanence != -1;
return fabs(synapses_[synapse].permanence - MARK_SYNAPSE_AS_REMOVED) < 0.001f;
}
}

Expand Down Expand Up @@ -261,8 +263,8 @@ void Connections::destroySegment(const Segment segment) {
CellData &cellData = cells_[segmentData.cell];

const auto segmentOnCell = std::find(cellData.segments.cbegin(), cellData.segments.cend(), segment);
NTA_ASSERT(segmentOnCell != cellData.segments.cend()) << "Segment to be destroyed not found on the cell!";
NTA_ASSERT(*segmentOnCell == segment);
NTA_CHECK(segmentOnCell != cellData.segments.cend()) << "Segment to be destroyed not found on the cell!";
NTA_CHECK(*segmentOnCell == segment);

cellData.segments.erase(segmentOnCell);
destroyedSegments_++;
Expand Down Expand Up @@ -313,15 +315,18 @@ void Connections::destroySynapse(const Synapse synapse) {
[&](const Synapse a, const Synapse b) -> bool { return dataForSynapse(a).id < dataForSynapse(b).id;}
);

NTA_ASSERT(synapseOnSegment != segmentData.synapses.cend());
NTA_ASSERT(*synapseOnSegment == synapse);
NTA_CHECK(synapseOnSegment != segmentData.synapses.cend());
NTA_CHECK(*synapseOnSegment == synapse);

segmentData.synapses.erase(synapseOnSegment);
//Note: dataForSynapse(synapse) are not deleted, unfortunately. And are still accessible.
//To mark them as "removed", we set SynapseData.permanence = -1, this can be used for a quick check later
synapseData.permanence = -1; //marking as "removed"
synapseData.permanence = MARK_SYNAPSE_AS_REMOVED; //marking as "removed"
//actually erase from synapses_ :
//const auto it = synapses_.begin() + synapse;
//synapses_.erase(it); //slow
destroyedSynapses_++;
NTA_ASSERT(not synapseExists_(synapse));
NTA_ASSERT(not synapseExists_(synapse, false));
}


Expand Down Expand Up @@ -768,6 +773,7 @@ bool Connections::operator==(const Connections &o) const {
NTA_CHECK (cells_.size() == o.cells_.size()) << "Connections equals: cells_" << cells_.size() << " vs. " << o.cells_.size();
NTA_CHECK (cells_ == o.cells_) << "Connections equals: cells_" << cells_.size() << " vs. " << o.cells_.size();

NTA_CHECK (segments_.size() == o.segments_.size()) << "Connections equals: segments_ size: " << segments_.size() << " vs. " << o.segments_.size();
NTA_CHECK (segments_ == o.segments_ ) << "Connections equals: segments_";
NTA_CHECK (destroyedSegments_ == o.destroyedSegments_ ) << "Connections equals: destroyedSegments_";

Expand All @@ -777,6 +783,7 @@ bool Connections::operator==(const Connections &o) const {

//also check underlying datastructures (segments, and subsequently synapses). Can be time consuming.
//1.cells:
/*
for(const auto cellD : cells_) {
//2.segments:
const auto& segments = cellD.segments;
Expand All @@ -789,6 +796,7 @@ bool Connections::operator==(const Connections &o) const {
}
}
}
*/


NTA_CHECK (connectedThreshold_ == o.connectedThreshold_ ) << "Connections equals: connectedThreshold_";
Expand All @@ -810,7 +818,10 @@ bool Connections::operator==(const Connections &o) const {
NTA_CHECK (prunedSegs_ == o.prunedSegs_ ) << "Connections equals: prunedSegs_";

} catch(const htm::Exception& ex) {
std::cout << "Connection equals: differ! " << ex.what();
UNUSED(ex); //avoid warning if the debug below is not used.
//uncomment below to start debugging Connections op==. It's perfectly
//..normal for unequality here.
NTA_WARN << "Connection equals: differ! " << ex.what();
return false;
}
return true;
Expand Down
8 changes: 4 additions & 4 deletions src/htm/algorithms/Connections.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ struct SynapseData: public Serializable {
NTA_CHECK(id == o.id ) << "SynapseData equals: id";
} catch(const htm::Exception& ex) {
UNUSED(ex); // this avoids the warning if ex is not used.
//NTA_WARN << "SynapseData equals: " << ex.what(); //Note: uncomment for debug, tells you
NTA_WARN << "SynapseData equals: " << ex.what(); //Note: uncomment for debug, tells you
//where the diff is. It's perfectly OK for the "exception" to occur, as it just denotes
//that the data is NOT equal.
return false;
Expand Down Expand Up @@ -155,7 +155,7 @@ struct SegmentData: public Serializable {

} catch(const htm::Exception& ex) {
UNUSED(ex); // this avoids the warning if ex is not used.
//NTA_WARN << "SegmentData equals: " << ex.what();
NTA_WARN << "SegmentData equals: " << ex.what();
return false;
}
return true;
Expand Down Expand Up @@ -195,7 +195,7 @@ struct CellData : public Serializable {
NTA_CHECK( segments == o.segments ) << "CellData equals: segments";
} catch(const htm::Exception& ex) {
UNUSED(ex); // this avoids the warning if ex is not used.
//NTA_WARN << "CellData equals: " << ex.what();
NTA_WARN << "CellData equals: " << ex.what();
return false;
}
return true;
Expand Down Expand Up @@ -464,7 +464,7 @@ class Connections : public Serializable
* @retval Synapse data.
*/
inline const SynapseData& dataForSynapse(const Synapse synapse) const {
NTA_CHECK(synapseExists_(synapse, true));
NTA_CHECK(synapseExists_(synapse, false));
return synapses_[synapse];
}

Expand Down
Loading