-
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 all 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 |
---|---|---|
|
@@ -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 | ||
tm.setAnomalyMode(mod) | ||
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,23 @@ 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]*/)*100); //precision on 2 dec places | ||
} | ||
Real categoryToReal_(const UInt bin) { | ||
const Real rl = static_cast<Real>((bin/100.0f)-1.0f); | ||
std::cout << "RL =" << bin << std::endl; | ||
return rl; | ||
} | ||
|
||
// 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 +86,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( {0,100}); //predict 0 (=classify current), 100 steps ahead | ||
|
||
AnomalyLikelihood anLikelihood; | ||
tInit.stop(); | ||
|
||
// data for processing input | ||
|
@@ -85,7 +98,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 +111,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 +123,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 +160,25 @@ 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(); | ||
const auto label = realToCategory_(data); | ||
pred.learn(e, outTM, { label }); //FIXME fails with bad_alloc if label is too large! PDF should use map, instead of a vector | ||
const auto recovered = categoryToReal_(argmax(pred.infer(outTM)[0])); | ||
NTA_CHECK(label == recovered); | ||
tCls.stop(); | ||
|
||
|
||
if (e == EPOCHS - 1) { | ||
tAll.stop(); | ||
pred.reset(); | ||
|
||
//print connections stats | ||
cout << "\nInput :\n" << statsInput | ||
|
@@ -176,10 +194,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 +211,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}); | ||
|
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
?