-
Notifications
You must be signed in to change notification settings - Fork 82
TM Connections integration #537
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
Changes from 15 commits
103e8fc
b6a103a
cc476a9
21c315c
cdcf5df
dd45567
34401b4
8607710
f6f029e
14871c9
a25040c
9648ae0
e20c267
24b2c36
abb8f96
cbf0d38
dac487a
47eb418
cccc3e5
8a1e871
e8fb520
37e7a13
023ed97
629db2f
d7ba1a9
60a384e
0188242
c95c177
4672daf
95b8b6d
b5498f3
6e07f06
184ad2c
36ed0ca
be38786
d20c9e8
2f16fb3
5fe3697
425f12c
d3186ed
fc38d89
5b368d8
065b467
24983cf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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); | ||
| } | ||
|
|
||
|
|
@@ -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_ ? | ||
|
|
||
| //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.
Outdated
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.
Outdated
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(); | ||
|
|
@@ -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); | ||
|
|
@@ -103,6 +118,7 @@ Segment Connections::createSegment(CellIdx cell) { | |
| return segment; | ||
| } | ||
|
|
||
|
|
||
| Synapse Connections::createSynapse(Segment segment, | ||
| CellIdx presynapticCell, | ||
| Permanence permanence) { | ||
|
|
@@ -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; | ||
|
|
@@ -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); | ||
|
|
@@ -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); | ||
|
|
@@ -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 ); | ||
|
|
@@ -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 { | ||
|
|
@@ -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]; | ||
|
|
@@ -391,6 +384,7 @@ void Connections::reset() | |
| currentUpdates_.clear(); | ||
| } | ||
|
|
||
|
|
||
| void Connections::computeActivity( | ||
| vector<SynapseIdx> &numActiveConnectedSynapsesForSegment, | ||
| const vector<CellIdx> &activePresynapticCells) | ||
|
|
@@ -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; | ||
|
|
@@ -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); | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. prune "dead" synapses that reached 0.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.