-
Notifications
You must be signed in to change notification settings - Fork 74
TM anomaly #406
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 anomaly #406
Changes from all commits
ad718f1
02a2364
e2f21cc
16a3461
af467a5
f6d3730
52e8ab5
0a9ba95
372cc57
8556107
f3c5157
dbf7f73
3a34e6c
affb657
fea3d2c
a3557eb
187e5c9
43f52c5
96e8211
1072e63
6e48cff
90c4985
a47c145
eab394b
367f682
d75b87f
f1c1810
2d96289
9f9e013
9cba16e
a1dac2e
047f0e4
df42923
c53a255
8a05797
d7cae2b
759cf29
5f8bd08
da7ccea
01675a2
7d172b1
e73b54b
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 |
---|---|---|
|
@@ -20,15 +20,8 @@ | |
* --------------------------------------------------------------------- | ||
*/ | ||
|
||
#include <algorithm> | ||
#include <iterator> | ||
#include <numeric> | ||
#include <set> | ||
#include <vector> | ||
|
||
#include "nupic/algorithms/Anomaly.hpp" | ||
#include "nupic/utils/Log.hpp" | ||
#include "nupic/types/Sdr.hpp" | ||
|
||
using namespace std; | ||
using namespace nupic; | ||
|
@@ -42,92 +35,18 @@ namespace anomaly { | |
Real computeRawAnomalyScore(const SDR& active, | ||
const SDR& predicted) { | ||
|
||
NTA_ASSERT(active.dimensions == predicted.dimensions); | ||
|
||
// Return 0 if no active columns are present | ||
if (active.getSum() == 0) { | ||
return 0.0f; | ||
} | ||
|
||
NTA_CHECK(active.dimensions == predicted.dimensions); | ||
|
||
// Calculate and return percent of active columns that were not predicted. | ||
SDR both(active.dimensions); | ||
both.intersection(active, predicted); | ||
|
||
return (active.getSum() - both.getSum()) / Real(active.getSum()); | ||
} | ||
|
||
Real computeRawAnomalyScore(vector<UInt>& active, | ||
vector<UInt>& predicted) | ||
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. Can we keep this overload? 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.
We could keep it, 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. Ok, I we can drop this method, but the rest of my criticism stands.
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.
I thought you wanted me to get rid of the old Anomaly class and replace it with as simple as possibleimplementation in TM (?), which I ended up liking.
I'll avoid 'friend access' when moving to a separate new/old file.
Yes, and it is intended. And about other refactoring in Anomaly class *):
TL;DR: the proper configuration and ordering is too complicated in a wrapper Anomaly class, while relatively easy hand-tailored by user (with tools we provide).
Externals break it in the way the they add "cell indices out of scope of the current TM" (idx in <numberOfCells() , numOfCells + extra>). 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.
My goal is to have convenient way to print out everything interesting about the TM to a human readable string, and from it to determine if the TM is working. I see the anomaly metric as a diagnostic tool.
Agreed,
|
||
{ | ||
// Don't divide by zero. Return 0 if no active columns are present. | ||
if (active.size() == 0) { | ||
return 0.0f; | ||
} | ||
|
||
vector<UInt> correctPredictions; | ||
sort( active.begin(), active.end()); | ||
sort( predicted.begin(), predicted.end()); | ||
set_intersection(active.begin(), active.end(), | ||
predicted.begin(), predicted.end(), | ||
back_inserter( correctPredictions )); | ||
|
||
return (Real) (active.size() - correctPredictions.size()) / active.size(); | ||
} | ||
|
||
}}} // End namespace | ||
|
||
Anomaly::Anomaly(UInt slidingWindowSize, AnomalyMode mode, Real binaryAnomalyThreshold) | ||
: binaryThreshold_(binaryAnomalyThreshold) | ||
{ | ||
NTA_CHECK(binaryAnomalyThreshold >= 0 && binaryAnomalyThreshold <= 1) << "binaryAnomalyThreshold must be within [0.0,1.0]"; | ||
mode_ = mode; | ||
if (slidingWindowSize > 0) { | ||
movingAverage_.reset(new nupic::util::MovingAverage(slidingWindowSize)); | ||
} | ||
} | ||
|
||
|
||
Real Anomaly::compute(const SDR& active, const SDR& predicted, int timestamp) | ||
{ return compute(active.getSparse(), predicted.getSparse(), timestamp); } | ||
|
||
Real Anomaly::compute(vector<UInt>& active, vector<UInt>& predicted, int timestamp) | ||
{ | ||
Real anomalyScore = computeRawAnomalyScore(active, predicted); | ||
Real likelihood = 0.5; | ||
Real score = anomalyScore; | ||
switch(mode_) | ||
{ | ||
case AnomalyMode::PURE: | ||
score = anomalyScore; | ||
break; | ||
case AnomalyMode::LIKELIHOOD: | ||
likelihood = likelihood_.anomalyProbability(anomalyScore, timestamp); | ||
score = 1 - likelihood; | ||
break; | ||
case AnomalyMode::WEIGHTED: | ||
likelihood = likelihood_.anomalyProbability(anomalyScore, timestamp); | ||
score = anomalyScore * (1 - likelihood); | ||
break; | ||
} | ||
|
||
if (movingAverage_) { | ||
score = movingAverage_->compute(score); | ||
} | ||
|
||
if (binaryThreshold_) { | ||
score = (score >= binaryThreshold_) ? 1.0f : 0.0f; | ||
} | ||
|
||
return score; | ||
} | ||
|
||
bool Anomaly::operator==(const Anomaly &a) const { | ||
if (mode_ != a.mode_) return false; | ||
if (binaryThreshold_ != a.binaryThreshold_) return false; | ||
if (movingAverage_ != nullptr && a.movingAverage_ == nullptr) return false; | ||
if (movingAverage_ == nullptr && a.movingAverage_ != nullptr) return false; | ||
if (movingAverage_ != nullptr && *(movingAverage_.get()) != *(a.movingAverage_.get())) return false; | ||
if (likelihood_ != a.likelihood_) return false; | ||
return true; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TM.anomaly py binding