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 Connections integration #537

Merged
merged 44 commits into from
Jul 18, 2019
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
103e8fc
destroySynapse: const arg
breznak Jul 1, 2019
b6a103a
TM: fix when custom minPermanence
breznak Jul 1, 2019
cc476a9
COnnections: adaptSegment: deduplicate code for timeseries
breznak Jul 2, 2019
21c315c
Connections: adaptSegment fix hardcoded minPermanence
breznak Jul 2, 2019
cdcf5df
TM:adaptSegment make similar to connections'
breznak Jul 2, 2019
dd45567
TM:adaptSegment uses connections', WIP
breznak Jul 2, 2019
34401b4
Connections:adaptSegment allow to prune zero synapses
breznak Jul 2, 2019
8607710
TM: adaptSegment use SDR for prevActiveCells to match Connections
breznak Jul 2, 2019
f6f029e
Connections:adaptSegment remove empty segments
breznak Jul 2, 2019
14871c9
SegmentData has simple default constructor
breznak Jul 2, 2019
a25040c
Connections:createSegment can check for maxSegmentsPerCell
breznak Jul 2, 2019
9648ae0
TM: move lastUsedIterationForSegment to SegmentData.lastUsed
breznak Jul 2, 2019
e20c267
TM uses Connections' createSegment
breznak Jul 2, 2019
24b2c36
Connections: add const + fix tests
breznak Jul 2, 2019
abb8f96
comment
breznak Jul 2, 2019
cbf0d38
Hotgym: print connections stats for SP, TM
breznak Jul 3, 2019
dac487a
Connections: print stats on usage of pruned Segs, Syns
breznak Jul 3, 2019
47eb418
Hotgym: add Metrics for SDRs from SP, TM, Input
breznak Jul 3, 2019
cccc3e5
Connection:createSegment fix check for maxSegmentsPerCell
breznak Jul 5, 2019
8a1e871
COnnections:createSegment make sort deterministic
breznak Jul 5, 2019
e8fb520
Connections: make sort statements deterministic
breznak Jul 5, 2019
37e7a13
COnnections: make createSegment maxSegments default to disabled
breznak Jul 5, 2019
023ed97
Merge branch 'master_community' into tm_conn
breznak Jul 6, 2019
629db2f
Merge branch 'master_community' into tm_conn
breznak Jul 6, 2019
d7ba1a9
Merge branch 'master_community' into tm_conn
breznak Jul 9, 2019
60a384e
TM: optimize growSynapses
breznak Jul 9, 2019
0188242
Merge branch 'master_community' into tm_conn
breznak Jul 10, 2019
c95c177
Connections: guard adaptSegment remove segment with pruneZeroSynapses
breznak Jul 10, 2019
4672daf
Connections: move iteration from TM
breznak Jul 10, 2019
95b8b6d
Conn: segment ordinals are never same for a != b
breznak Jul 10, 2019
b5498f3
COnnections: prune segment if it never can connect again
breznak Jul 10, 2019
6e07f06
TM code comments
breznak Jul 10, 2019
184ad2c
TM:getLeastUsedCells improve doc
breznak Jul 11, 2019
36ed0ca
TM: add explanation for synapses only on new, unsynapsed segments
breznak Jul 12, 2019
be38786
Merge branch 'master_community' into tm_conn
breznak Jul 12, 2019
d20c9e8
Merge branch 'master' into tm_conn
breznak Jul 13, 2019
2f16fb3
Merge branch 'master_community' into tm_conn
breznak Jul 13, 2019
5fe3697
Connections: some more const
breznak Jul 13, 2019
425f12c
Merge branch 'tm_conn' of https://github.com/htm-community/nupic.core…
breznak Jul 13, 2019
d3186ed
update determ output results
breznak Jul 14, 2019
fc38d89
Conn: synapseOrdinals_ moved to SynapseData
breznak Jul 14, 2019
5b368d8
Conn: move segment ordinals (id) to SegmentData
breznak Jul 13, 2019
065b467
Merge branch 'master_community' into tm_conn
breznak Jul 18, 2019
24983cf
fixup Connections:destroySegment use find
breznak Jul 18, 2019
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
5 changes: 4 additions & 1 deletion bindings/py/cpp_src/bindings/algorithms/py_Connections.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,10 @@ R"(Compatibility Warning: This classes API is unstable and may change without wa
[](const Connections &self) { return self.getConnectedThreshold(); });

py_Connections.def("createSegment", &Connections::createSegment,
py::arg("cell"));
py::arg("cell"),
py::arg("maxSegmentsPerCell") = 0,
py::arg("iteration") = 0
);

py_Connections.def("destroySegment", &Connections::destroySegment);

Expand Down
116 changes: 59 additions & 57 deletions src/htm/algorithms/Connections.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ using std::string;
using std::vector;
using namespace htm;

Connections::Connections(CellIdx numCells, Permanence connectedThreshold, bool timeseries) {
Connections::Connections(const CellIdx numCells,
const Permanence connectedThreshold,
const bool timeseries) {
initialize(numCells, connectedThreshold, timeseries);
}

Expand Down Expand Up @@ -75,7 +77,23 @@ void Connections::unsubscribe(UInt32 token) {
eventHandlers_.erase(token);
}

Segment Connections::createSegment(CellIdx cell) {
Segment Connections::createSegment(const CellIdx cell,
const SegmentIdx maxSegmentsPerCell,
const UInt32 iteration) { //TODO move iteration to Connections.iteration_ ?
breznak marked this conversation as resolved.
Show resolved Hide resolved

//limit number of segmets per cell. If exceeded, remove the least recently used ones.
NTA_ASSERT(maxSegmentsPerCell > 0);
while (maxSegmentsPerCell > 1 && numSegments(cell) >= maxSegmentsPerCell) {
breznak marked this conversation as resolved.
Show resolved Hide resolved
const auto& destroyCandidates = segmentsForCell(cell);
const auto compareSegmentsByLRU = [&](const Segment a, const Segment b) {
return (dataForSegment(a).lastUsed < dataForSegment(b).lastUsed); };
breznak marked this conversation as resolved.
Show resolved Hide resolved
const auto leastRecentlyUsedSegment = std::min_element(destroyCandidates.cbegin(),
destroyCandidates.cend(), compareSegmentsByLRU);

destroySegment(*leastRecentlyUsedSegment);
}

//proceed to create a new segment
Segment segment;
if (!destroyedSegments_.empty() ) { //reuse old, destroyed segs
segment = destroyedSegments_.back();
Expand All @@ -84,17 +102,14 @@ Segment Connections::createSegment(CellIdx cell) {
NTA_CHECK(segments_.size() < std::numeric_limits<Segment>::max()) << "Add segment failed: Range of Segment (data-type) insufficinet size."
<< (size_t)segments_.size() << " < " << (size_t)std::numeric_limits<Segment>::max();
segment = static_cast<Segment>(segments_.size());
segments_.push_back(SegmentData());
const SegmentData& segmentData = SegmentData(cell, iteration);
segments_.push_back(segmentData);
segmentOrdinals_.push_back(0);
}

SegmentData &segmentData = segments_[segment];
segmentData.numConnected = 0;
segmentData.cell = cell;

CellData &cellData = cells_[cell];
segmentOrdinals_[segment] = nextSegmentOrdinal_++;
cellData.segments.push_back(segment);
cellData.segments.push_back(segment); //assign the new segment to its mother-cell

for (auto h : eventHandlers_) {
h.second->onCreateSegment(segment);
Expand All @@ -103,6 +118,7 @@ Segment Connections::createSegment(CellIdx cell) {
return segment;
}


Synapse Connections::createSynapse(Segment segment,
CellIdx presynapticCell,
Permanence permanence) {
Expand Down Expand Up @@ -144,14 +160,14 @@ Synapse Connections::createSynapse(Segment segment,
return synapse;
}

bool Connections::segmentExists_(Segment segment) const {
bool Connections::segmentExists_(const Segment segment) const {
const SegmentData &segmentData = segments_[segment];
const vector<Segment> &segmentsOnCell = cells_[segmentData.cell].segments;
return (std::find(segmentsOnCell.begin(), segmentsOnCell.end(), segment) !=
segmentsOnCell.end());
}

bool Connections::synapseExists_(Synapse synapse) const {
bool Connections::synapseExists_(const Synapse synapse) const {
const SynapseData &synapseData = synapses_[synapse];
const vector<Synapse> &synapsesOnSegment =
segments_[synapseData.segment].synapses;
Expand Down Expand Up @@ -181,7 +197,8 @@ void Connections::removeSynapseFromPresynapticMap_(
preSegments.pop_back();
}

void Connections::destroySegment(Segment segment) {

void Connections::destroySegment(const Segment segment) {
NTA_ASSERT(segmentExists_(segment));
for (auto h : eventHandlers_) {
h.second->onDestroySegment(segment);
Expand Down Expand Up @@ -210,7 +227,8 @@ void Connections::destroySegment(Segment segment) {
destroyedSegments_.push_back(segment);
}

void Connections::destroySynapse(Synapse synapse) {

void Connections::destroySynapse(const Synapse synapse) {
NTA_ASSERT(synapseExists_(synapse));
for (auto h : eventHandlers_) {
h.second->onDestroySynapse(synapse);
Expand Down Expand Up @@ -259,7 +277,8 @@ void Connections::destroySynapse(Synapse synapse) {
destroyedSynapses_.push_back(synapse);
}

void Connections::updateSynapsePermanence(Synapse synapse,

void Connections::updateSynapsePermanence(const Synapse synapse,
Permanence permanence) {
permanence = std::min(permanence, maxPermanence );
permanence = std::max(permanence, minPermanence );
Expand Down Expand Up @@ -311,30 +330,15 @@ void Connections::updateSynapsePermanence(Synapse synapse,
}
}

const vector<Segment> &Connections::segmentsForCell(CellIdx cell) const {
return cells_[cell].segments;
}

Segment Connections::getSegment(CellIdx cell, SegmentIdx idx) const {
return cells_[cell].segments[idx];
}

const vector<Synapse> &Connections::synapsesForSegment(Segment segment) const {
NTA_ASSERT(segment < segments_.size()) << "Segment out of bounds! " << segment;
return segments_[segment].synapses;
}

CellIdx Connections::cellForSegment(Segment segment) const {
return segments_[segment].cell;
}

SegmentIdx Connections::idxOnCellForSegment(Segment segment) const {
SegmentIdx Connections::idxOnCellForSegment(const Segment segment) const {
const vector<Segment> &segments = segmentsForCell(cellForSegment(segment));
const auto it = std::find(segments.begin(), segments.end(), segment);
NTA_ASSERT(it != segments.end());
return (SegmentIdx)std::distance(segments.begin(), it);
}


void Connections::mapSegmentsToCells(const Segment *segments_begin,
const Segment *segments_end,
CellIdx *cells_begin) const {
Expand All @@ -347,17 +351,6 @@ void Connections::mapSegmentsToCells(const Segment *segments_begin,
}
}

Segment Connections::segmentForSynapse(Synapse synapse) const {
return synapses_[synapse].segment;
}

const SegmentData &Connections::dataForSegment(Segment segment) const {
return segments_[segment];
}

const SynapseData &Connections::dataForSynapse(Synapse synapse) const {
return synapses_[synapse];
}

bool Connections::compareSegments(const Segment a, const Segment b) const {
const SegmentData &aData = segments_[a];
Expand Down Expand Up @@ -391,6 +384,7 @@ void Connections::reset()
currentUpdates_.clear();
}


void Connections::computeActivity(
vector<SynapseIdx> &numActiveConnectedSynapsesForSegment,
const vector<CellIdx> &activePresynapticCells)
Expand Down Expand Up @@ -443,15 +437,19 @@ void Connections::computeActivity(
void Connections::adaptSegment(const Segment segment,
const SDR &inputs,
const Permanence increment,
const Permanence decrement)
const Permanence decrement,
const bool pruneZeroSynapses)
{
const auto &inputArray = inputs.getDense();

if( timeseries_ ) {
previousUpdates_.resize( synapses_.size(), 0.0f );
currentUpdates_.resize( synapses_.size(), 0.0f );
previousUpdates_.resize( synapses_.size(), minPermanence );
currentUpdates_.resize( synapses_.size(), minPermanence );
}

for( const auto synapse : synapsesForSegment(segment) ) {
const auto& synapses = synapsesForSegment(segment);
for( size_t i = 0; i < synapses.size(); i++) {
const auto synapse = synapses[i];
const SynapseData &synapseData = dataForSynapse(synapse);

Permanence update;
Expand All @@ -461,28 +459,32 @@ void Connections::adaptSegment(const Segment segment,
update = -decrement;
}

//prune permanences that reached zero
if (pruneZeroSynapses && synapseData.permanence + update < htm::minPermanence + htm::Epsilon) {
destroySynapse(synapse);
Copy link
Member Author

Choose a reason for hiding this comment

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

prune "dead" synapses that reached 0.

  • from TM
  • is synapse really dead when reached 0? -> yes, because cannot get any activation.
    • TODO this should be ON even for SP(?!)
  • how does this relate to New method Connections::synapseCompetiton #466 synapse competition? Can I use that instead here?
  • TODO if we remove synapses, ensure we do NOT go under stimulusThreshold See Smarter SP parameters #536 . If we do:
    • grow new synapse(s)?
    • destroy segment, and create new?

Copy link
Member Author

Choose a reason for hiding this comment

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

@ctrl-z-9000-times how is #466 with biological plausibility? I like how the competition helps keep synapses better balanced, but I don't see a natural mechanism. For this reason I started question raisePermanencesToThreshold, see if/how it's plausible? Or replace these "raise to threshold" with synaptic death & growth of new. ?

Copy link
Collaborator

Choose a reason for hiding this comment

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

It seems plausible to me, that dendrites could have a desired number of synapses and that they could enforce this preference.

i--; // do not advance `i`, as `destroySynapse` just modified inplace the synapses_, so now a `synapses_[i]`
// is the "next" synapse.
continue;
}

//update synapse, but for TS only if changed
if(timeseries_) {
if( update != previousUpdates_[synapse] ) {
updateSynapsePermanence(synapse, synapseData.permanence + update);
}
currentUpdates_[ synapse ] = update;
} else {
updateSynapsePermanence(synapse, synapseData.permanence + update);
}
}
else {
for( const auto synapse : synapsesForSegment(segment) ) {
const SynapseData &synapseData = dataForSynapse(synapse);

Permanence permanence = synapseData.permanence;
if( inputArray[synapseData.presynapticCell] ) {
permanence += increment;
} else {
permanence -= decrement;
}

updateSynapsePermanence(synapse, permanence);
}
//destroy segment if it is empty
if(synapses.empty()) {
destroySegment(segment);
breznak marked this conversation as resolved.
Show resolved Hide resolved
}
}


/**
* Called for under-performing Segments (can have synapses pruned, etc.). After
* the call, Segment will have at least segmentThreshold synapses connected, so
Expand Down
Loading