-
Notifications
You must be signed in to change notification settings - Fork 75
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
Hotgym predictor, anomaly tests #675
base: master
Are you sure you want to change the base?
Changes from 8 commits
5585038
d885653
432f98a
9f015f1
97023a8
ae192bd
0987941
0e1cc14
6c7678e
285490b
06f9701
4bed29d
f80a765
865f7e0
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 |
---|---|---|
|
@@ -47,7 +47,7 @@ Example usage: | |
TODO | ||
)"); | ||
|
||
py::enum_<TemporalMemory::ANMode>(m, "ANMode") | ||
py::enum_<TemporalMemory::ANMode>(m, "ANMode") //TODO currently htm.bindings.algorithms.ANMode, make ANMode part of algorithms.TemporalMemory | ||
.value("DISABLED", TemporalMemory::ANMode::DISABLED) | ||
.value("RAW", TemporalMemory::ANMode::RAW) | ||
.value("LIKELIHOOD", TemporalMemory::ANMode::LIKELIHOOD) | ||
|
@@ -372,6 +372,8 @@ R"()"); | |
"Anomaly score updated with each TM::compute() call. " | ||
); | ||
|
||
py_HTM.def("setAnomalyMode", &HTM_t::setAnomalyMode); | ||
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. defined, compiles, but not found in py test?! |
||
|
||
py_HTM.def("__str__", | ||
[](HTM_t &self) { | ||
std::stringstream buf; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -171,11 +171,30 @@ def testPredictiveCells(self): | |
_print("activeCols:"+str(len(activeColumnsA.sparse))) | ||
_print("activeCells:"+str(len(tm.getActiveCells().sparse))) | ||
_print("predictiveCells:"+str(len(predictiveCellsSDR.sparse))) | ||
|
||
|
||
def testAnomaly(self): | ||
"""test convergence of TM and quality of anomaly methods""" | ||
from htm.bindings.algorithms import ANMode | ||
tm = TM(columnDimensions=[2048], anomalyMode=ANMode.RAW) #FIXME likelihood is always 0.5?! .LIKELIHOOD) | ||
|
||
modes = [ANMode.RAW, ANMode.LIKELIHOOD, ANMode.LOGLIKELIHOOD] | ||
for mod in modes: #this block test convergence of TM and anomaly score for select mode | ||
#FIXME why not visible from bidngings? tm.setAnomalyMode(mod) | ||
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.
|
||
#print("testing {}".format(mod)) | ||
inp = SDR([2048]).randomize(0.05) #starting SDR with 5% bits ON | ||
|
||
#learn TM a bit, anomaly should be low | ||
for _ in range(200): | ||
inp.addNoise(0.02) #change 2% bits -> 98% overlap => anomaly should ideally be 2% | ||
tm.compute(inp, learn=True) | ||
self.assertLess(tm.anomaly, 0.08) | ||
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. new test that TM actually learns and anomalies converge. |
||
|
||
|
||
|
||
def _print(txt): | ||
if debugPrint: | ||
print(txt) | ||
|
||
if __name__ == "__main__": | ||
unittest.main() | ||
unittest.main() |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,7 +24,7 @@ | |
#include "htm/algorithms/TemporalMemory.hpp" | ||
#include "htm/algorithms/SpatialPooler.hpp" | ||
#include "htm/encoders/RandomDistributedScalarEncoder.hpp" | ||
#include "htm/algorithms/AnomalyLikelihood.hpp" | ||
#include "htm/algorithms/SDRClassifier.hpp" // Classifier, Predictor | ||
|
||
#include "htm/types/Sdr.hpp" | ||
#include "htm/utils/Random.hpp" | ||
|
@@ -36,12 +36,21 @@ namespace examples { | |
using namespace std; | ||
using namespace htm; | ||
|
||
/** | ||
* helper to transform (Real) data to categories (UInt) for Classifier/Predictor | ||
**/ | ||
UInt realToCategory_(const Real r) { | ||
return static_cast<UInt>((r+1.0f /*map sin(x):[-1,1] map it to [0,2]*/)*1000); //precision on 3 dec places | ||
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. the |
||
} | ||
Real categoryToReal_(const UInt bin) { | ||
return static_cast<Real>((bin/1000.0f)-1.0f); | ||
} | ||
|
||
// work-load | ||
Real64 BenchmarkHotgym::run(UInt EPOCHS, bool useSPlocal, bool useSPglobal, bool useTM, const UInt COLS, const UInt DIM_INPUT, const UInt CELLS) | ||
{ | ||
#ifndef NDEBUG | ||
EPOCHS = 2; // make test faster in Debug | ||
EPOCHS = 10; // make test faster in Debug | ||
#endif | ||
|
||
#if defined __aarch64__ || defined __arm__ | ||
|
@@ -75,8 +84,10 @@ EPOCHS = 2; // make test faster in Debug | |
Random rnd(42); //uses fixed seed for deterministic output checks | ||
|
||
TemporalMemory tm(vector<UInt>{COLS}, CELLS); | ||
tm.setAnomalyMode(TemporalMemory::ANMode::RAW); //set other modes here | ||
|
||
Predictor pred( vector<UInt>{0,100}); //predict 0 (=classify current), 100 steps ahead | ||
|
||
AnomalyLikelihood anLikelihood; | ||
tInit.stop(); | ||
|
||
// data for processing input | ||
|
@@ -85,7 +96,7 @@ EPOCHS = 2; // make test faster in Debug | |
SDR outSPlocal(spLocal.getColumnDimensions()); //for SPlocal | ||
SDR outSP(vector<UInt>{COLS}); | ||
SDR outTM(spGlobal.getColumnDimensions()); | ||
Real an = 0.0f, anLikely = 0.0f; //for anomaly: | ||
Real an = 0.0f; //for anomaly: | ||
MovingAverage avgAnom10(1000); //chose the window large enough so there's (some) periodicity in the patter, so TM can learn something | ||
|
||
//metrics | ||
|
@@ -98,9 +109,6 @@ EPOCHS = 2; // make test faster in Debug | |
* For example: fn = sin(x) -> periodic >= 2Pi ~ 6.3 && x+=0.01 -> 630 steps to 1st period -> window >= 630 | ||
*/ | ||
Real avgAnomOld_ = 1.0; | ||
NTA_CHECK(avgAnomOld_ >= avgAnom10.getCurrentAvg()) << "TM should learn and avg anomalies improve, but we got: " | ||
<< avgAnomOld_ << " and now: " << avgAnom10.getCurrentAvg(); //invariant | ||
|
||
|
||
// Start a stopwatch timer | ||
printf("starting: %d iterations.", EPOCHS); | ||
|
@@ -113,11 +121,13 @@ EPOCHS = 2; // make test faster in Debug | |
//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 | ||
// cout << x << "\n" << sin(x) << "\n" << input << "\n\n"; | ||
const Real data = sin(x); | ||
enc.encode(data, input); //model sin(x) function //TODO replace with CSV data | ||
// cout << x << "\n" << data << "\n" << input << "\n\n"; | ||
tEnc.stop(); | ||
|
||
tRng.start(); | ||
//TODO this is dropout: | ||
input.addNoise(0.01f, rnd); //change 1% of the SDR for each iteration, this makes a random sequence, but seemingly stable | ||
tRng.stop(); | ||
|
||
|
@@ -148,19 +158,22 @@ EPOCHS = 2; // make test faster in Debug | |
//Anomaly (pure x likelihood) | ||
an = tm.anomaly; | ||
avgAnom10.compute(an); //moving average | ||
if(e % 1000 == 0) { | ||
if(e % (500 + avgAnom10.getData().size() /*size of avg window for an*/) == 0) { | ||
NTA_CHECK(avgAnomOld_ >= avgAnom10.getCurrentAvg()) << "TM should learn and avg anomalies improve, but we got: " | ||
<< avgAnomOld_ << " and now: " << avgAnom10.getCurrentAvg(); //invariant | ||
avgAnomOld_ = avgAnom10.getCurrentAvg(); //update | ||
} | ||
tAnLikelihood.start(); | ||
anLikelihood.anomalyProbability(an); //FIXME AnLikelihood is 0.0, probably not working correctly | ||
tAnLikelihood.stop(); | ||
|
||
//Classifier, Predictor | ||
tCls.start(); | ||
pred.learn(e, outTM, { realToCategory_(data) }); //FIXME fails with bad_alloc if label is too large! PDF should use map, instead of a vector | ||
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. FIXME: this should be resolved in the Predictor. A large label should not crash the program (caused by huge PDF if label is large). See if PDF can use map. |
||
tCls.stop(); | ||
|
||
|
||
if (e == EPOCHS - 1) { | ||
tAll.stop(); | ||
pred.reset(); | ||
|
||
//print connections stats | ||
cout << "\nInput :\n" << statsInput | ||
|
@@ -176,10 +189,14 @@ EPOCHS = 2; // make test faster in Debug | |
cout << "Epoch = " << e << endl; | ||
cout << "Anomaly = " << an << endl; | ||
cout << "Anomaly (avg) = " << avgAnom10.getCurrentAvg() << endl; | ||
cout << "Anomaly (Likelihood) = " << anLikely << endl; | ||
cout << "SP (g)= " << outSP << endl; | ||
cout << "SP (l)= " << outSPlocal <<endl; | ||
cout << "TM= " << outTM << endl; | ||
cout << "Cls[0]= " << categoryToReal_(argmax(pred.infer(outTM)[0])) << endl; | ||
cout << "Cls[100]= " << categoryToReal_(argmax(pred.infer(outTM)[100])) << endl; | ||
|
||
NTA_CHECK( categoryToReal_(argmax(pred.infer(outTM)[0])) != -1) << "Classifier did not learn"; //FIXME Predictor is not learning, this should be ~ sin(49.99) | ||
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. FIXME: this is always 0, predictor/classifier is not learning! 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. @Thanh-Binh ping, can you please have a look at this PR and the test here? I'm getting 0s from the Classifier inference and not sure why. |
||
|
||
|
||
//timers | ||
cout << "==============TIMERS============" << endl; | ||
|
@@ -189,7 +206,7 @@ EPOCHS = 2; // make test faster in Debug | |
if(useSPlocal) cout << "SP (l):\t" << tSPloc.getElapsed()*1.0f << endl; | ||
if(useSPglobal) cout << "SP (g):\t" << tSPglob.getElapsed() << endl; | ||
if(useTM) cout << "TM:\t" << tTM.getElapsed() << endl; | ||
cout << "AN:\t" << tAnLikelihood.getElapsed() << endl; | ||
cout << "Cls:\t" << tCls.getElapsed() << endl; | ||
|
||
// check deterministic SP, TM output | ||
SDR goldEnc({DIM_INPUT}); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -129,7 +129,7 @@ class TemporalMemory : public Serializable | |
* cells and winner cells of these external inputs must be given to methods | ||
* TM.compute and TM.activateDendrites | ||
* | ||
* @param anomalyMode (optional, default `ANMode::RAW`)from enum ANMode, how is | ||
* @param anomalyMode (optional, default `TemporalMemory::ANMode::RAW`)from enum ANMode, how is | ||
* `TM.anomaly` computed. Options ANMode {DISABLED, RAW, LIKELIHOOD, LOGLIKELIHOOD} | ||
* | ||
*/ | ||
|
@@ -149,7 +149,7 @@ class TemporalMemory : public Serializable | |
SynapseIdx maxSynapsesPerSegment = 255, | ||
bool checkInputs = true, | ||
UInt externalPredictiveInputs = 0, | ||
ANMode anomalyMode = ANMode::RAW | ||
ANMode anomalyMode = TemporalMemory::ANMode::RAW | ||
); | ||
|
||
virtual void | ||
|
@@ -169,7 +169,7 @@ class TemporalMemory : public Serializable | |
SynapseIdx maxSynapsesPerSegment = 255, | ||
bool checkInputs = true, | ||
UInt externalPredictiveInputs = 0, | ||
ANMode anomalyMode = ANMode::RAW | ||
ANMode anomalyMode = TemporalMemory::ANMode::RAW | ||
); | ||
|
||
virtual ~TemporalMemory(); | ||
|
@@ -677,13 +677,17 @@ class TemporalMemory : public Serializable | |
Real anomaly_ = 0.5f; //default value | ||
ANMode mode_ = ANMode::RAW; | ||
AnomalyLikelihood anomalyLikelihood_; //TODO provide default/customizable params here | ||
}; | ||
void reset() { | ||
anomaly_ = 0.5f; | ||
mode_ = ANMode::RAW; | ||
//TODO provide anomalyLikelihood_.reset(); | ||
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. when calling |
||
} | ||
} tmAnomaly_; | ||
|
||
public: | ||
Connections connections; | ||
const UInt &externalPredictiveInputs = externalPredictiveInputs_; | ||
|
||
anomaly_tm tmAnomaly_; | ||
/* | ||
* anomaly score computed for the current inputs | ||
* (auto-updates after each call to TM::compute()) | ||
|
@@ -694,6 +698,14 @@ class TemporalMemory : public Serializable | |
const Real &anomaly = tmAnomaly_.anomaly_; //this is position dependant, the struct anomaly_tm must be defined before this use, | ||
// otherwise this surprisingly compiles, but a call to `tmAnomaly_.anomaly` segfaults! | ||
|
||
/** | ||
* set new mode for TM.anomaly computation. | ||
* This will reset existing anomaly. | ||
* | ||
* @param mode: Options TemporalMemory::ANMode {DISABLED, RAW, LIKELIHOOD, LOGLIKELIHOOD} | ||
*/ | ||
void setAnomalyMode(ANMode mode); | ||
|
||
}; | ||
|
||
} // namespace htm | ||
|
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.
nit, how would it be possible to make enum
ANMode
exposed as a part ofhtm.bindings.algorithms.TemporalMemory.ANMode
, and not the current..bindings.algorithms.ANMode
?