From 5585038afe6b6f3a17eb34ac7af4adfa3b855515 Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Wed, 18 Sep 2019 10:05:02 +0200 Subject: [PATCH 01/11] TM.anomaly: add python convergence tests, setAnomalyMode --- .../bindings/algorithms/py_TemporalMemory.cpp | 4 +++- .../tests/algorithms/temporal_memory_test.py | 21 +++++++++++++++++- src/htm/algorithms/TemporalMemory.cpp | 6 ++++- src/htm/algorithms/TemporalMemory.hpp | 22 ++++++++++++++----- 4 files changed, 45 insertions(+), 8 deletions(-) diff --git a/bindings/py/cpp_src/bindings/algorithms/py_TemporalMemory.cpp b/bindings/py/cpp_src/bindings/algorithms/py_TemporalMemory.cpp index 8c8fcd76b4..a407d90556 100644 --- a/bindings/py/cpp_src/bindings/algorithms/py_TemporalMemory.cpp +++ b/bindings/py/cpp_src/bindings/algorithms/py_TemporalMemory.cpp @@ -47,7 +47,7 @@ Example usage: TODO )"); - py::enum_(m, "ANMode") + py::enum_(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); + py_HTM.def("__str__", [](HTM_t &self) { std::stringstream buf; diff --git a/bindings/py/tests/algorithms/temporal_memory_test.py b/bindings/py/tests/algorithms/temporal_memory_test.py index a4938ccd6a..bad695889c 100755 --- a/bindings/py/tests/algorithms/temporal_memory_test.py +++ b/bindings/py/tests/algorithms/temporal_memory_test.py @@ -171,6 +171,25 @@ 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) + #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) + def _print(txt): @@ -178,4 +197,4 @@ def _print(txt): print(txt) if __name__ == "__main__": - unittest.main() \ No newline at end of file + unittest.main() diff --git a/src/htm/algorithms/TemporalMemory.cpp b/src/htm/algorithms/TemporalMemory.cpp index 38d7b7cb8c..a8f3e77e06 100644 --- a/src/htm/algorithms/TemporalMemory.cpp +++ b/src/htm/algorithms/TemporalMemory.cpp @@ -537,7 +537,7 @@ void TemporalMemory::reset(void) { activeSegments_.clear(); matchingSegments_.clear(); segmentsValid_ = false; - tmAnomaly_.anomaly_ = -1.0f; //TODO reset rather to 0.5 as default (undecided) anomaly + tmAnomaly_.reset(); } // ============================== @@ -718,6 +718,10 @@ SynapseIdx TemporalMemory::getMaxSynapsesPerSegment() const { UInt TemporalMemory::version() const { return TM_VERSION; } +void TemporalMemory::setAnomalyMode(ANMode mode) { + tmAnomaly_.reset(); + tmAnomaly_.mode_ = mode; +} static set> getComparableSegmentSet(const Connections &connections, diff --git a/src/htm/algorithms/TemporalMemory.hpp b/src/htm/algorithms/TemporalMemory.hpp index 4eedb4f8e2..04bf2343cd 100644 --- a/src/htm/algorithms/TemporalMemory.hpp +++ b/src/htm/algorithms/TemporalMemory.hpp @@ -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(); + } + } 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 From d8856534a324c8a6260d6dbb9db45e4cebbd30cf Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Wed, 18 Sep 2019 10:35:13 +0200 Subject: [PATCH 02/11] Hotgym: use TM.anomaly with different modes remove explicit AnomalyLikelihood --- src/examples/hotgym/HelloSPTP.cpp | 16 ++++------------ src/examples/hotgym/HelloSPTP.hpp | 2 +- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/src/examples/hotgym/HelloSPTP.cpp b/src/examples/hotgym/HelloSPTP.cpp index 7edea90645..ed7c284fd7 100644 --- a/src/examples/hotgym/HelloSPTP.cpp +++ b/src/examples/hotgym/HelloSPTP.cpp @@ -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" @@ -75,8 +75,8 @@ EPOCHS = 2; // make test faster in Debug Random rnd(42); //uses fixed seed for deterministic output checks TemporalMemory tm(vector{COLS}, CELLS); + tm.setAnomalyMode(TemporalMemory::ANMode::RAW); //set other modes here - AnomalyLikelihood anLikelihood; tInit.stop(); // data for processing input @@ -85,7 +85,7 @@ EPOCHS = 2; // make test faster in Debug SDR outSPlocal(spLocal.getColumnDimensions()); //for SPlocal SDR outSP(vector{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 +98,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); @@ -148,14 +145,11 @@ 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(); // print @@ -176,7 +170,6 @@ 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 < Date: Wed, 18 Sep 2019 12:02:35 +0200 Subject: [PATCH 03/11] Hotgym: use SDRClassifier, Predictor WIP but Predictor learn() crashes in Release, however does not in Debug (-> hard to investigate) --- src/examples/hotgym/HelloSPTP.cpp | 26 +++++++++++++++++++++++--- src/examples/hotgym/HelloSPTP.hpp | 2 +- src/htm/algorithms/SDRClassifier.hpp | 2 +- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/examples/hotgym/HelloSPTP.cpp b/src/examples/hotgym/HelloSPTP.cpp index ed7c284fd7..367e68f48b 100644 --- a/src/examples/hotgym/HelloSPTP.cpp +++ b/src/examples/hotgym/HelloSPTP.cpp @@ -36,12 +36,18 @@ 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(r*1000); //precision on 3 dec places +} // 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__ @@ -77,6 +83,8 @@ EPOCHS = 2; // make test faster in Debug TemporalMemory tm(vector{COLS}, CELLS); tm.setAnomalyMode(TemporalMemory::ANMode::RAW); //set other modes here + Predictor pred( vector{0,1,2,10}); //predict 0 (=classify current), 1,2 & 10 steps ahead + tInit.stop(); // data for processing input @@ -110,11 +118,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(); @@ -151,10 +161,16 @@ EPOCHS = 2; // make test faster in Debug avgAnomOld_ = avgAnom10.getCurrentAvg(); //update } + //Classifier, Predictor + tCls.start(); + //! pred.learn(e, outTM, { realToCategory_(data) }); //FIXME fails with bad_alloc in Release, no crash in Debug?! + tCls.stop(); + // print if (e == EPOCHS - 1) { tAll.stop(); + pred.reset(); //print connections stats cout << "\nInput :\n" << statsInput @@ -173,6 +189,9 @@ EPOCHS = 2; // make test faster in Debug cout << "SP (g)= " << outSP << endl; cout << "SP (l)= " << outSPlocal < Date: Fri, 20 Sep 2019 03:05:15 +0200 Subject: [PATCH 04/11] Hotgym: debugged crash with Predictor crash was on bad_alloc (memory allocation failed). Our encoding to labels (realToCategory_()) had undeflow which resulted in a huge UInt -> tried to allocate extremely large vector -> failed. --- src/examples/hotgym/HelloSPTP.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/examples/hotgym/HelloSPTP.cpp b/src/examples/hotgym/HelloSPTP.cpp index 367e68f48b..2fc79772de 100644 --- a/src/examples/hotgym/HelloSPTP.cpp +++ b/src/examples/hotgym/HelloSPTP.cpp @@ -40,7 +40,10 @@ using namespace htm; * helper to transform (Real) data to categories (UInt) for Classifier/Predictor **/ UInt realToCategory_(const Real r) { - return static_cast(r*1000); //precision on 3 dec places + return static_cast((r+1.0f /*map sin(x):[-1,1] map it to [0,2]*/)*1000); //precision on 3 dec places +} +Real categoryToReal_(const UInt bin) { + return static_cast((bin/1000.0f)-1.0f); } // work-load @@ -163,7 +166,7 @@ EPOCHS = 10; // make test faster in Debug //Classifier, Predictor tCls.start(); - //! pred.learn(e, outTM, { realToCategory_(data) }); //FIXME fails with bad_alloc in Release, no crash in Debug?! + pred.learn(e, outTM, { realToCategory_(data) }); //FIXME fails with bad_alloc if label is too large! PDF should use map, instead of a vector tCls.stop(); @@ -189,8 +192,8 @@ EPOCHS = 10; // make test faster in Debug cout << "SP (g)= " << outSP << endl; cout << "SP (l)= " << outSPlocal < Date: Fri, 20 Sep 2019 10:25:24 +0200 Subject: [PATCH 07/11] Predictor: add reproducible test for large labels this crashes the Predictor. Likely a stack-overflow, --- src/test/unit/algorithms/SDRClassifierTest.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/test/unit/algorithms/SDRClassifierTest.cpp b/src/test/unit/algorithms/SDRClassifierTest.cpp index 6f935d940a..d242113b3c 100644 --- a/src/test/unit/algorithms/SDRClassifierTest.cpp +++ b/src/test/unit/algorithms/SDRClassifierTest.cpp @@ -59,6 +59,19 @@ TEST(SDRClassifierTest, ExampleUsageClassifier) } +TEST(SDRClassifierTest, HandleLargeLabels) +{ + // Make a random SDR and associate it with the category B. + SDR inputData({ 1000u }); + inputData.randomize(0.02f); + Classifier clsr; + + UInt hugeLabel = numeric_limits::max(); + EXPECT_NO_THROW(clsr.learn( inputData, { hugeLabel } )); + ASSERT_EQ( argmax( clsr.infer( inputData ) ), hugeLabel ); +} + + TEST(SDRClassifierTest, ExampleUsagePredictor) { // Predict 1 and 2 time steps into the future. From 285490b4f02f896f87631919672d9f80609d5613 Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Fri, 20 Sep 2019 10:53:00 +0200 Subject: [PATCH 08/11] Predictor: use type StepsAheadT for steps_ limit to unsingned short (from UInt) --- .../bindings/algorithms/py_SDRClassifier.cpp | 4 ++-- src/examples/hotgym/HelloSPTP.cpp | 2 +- src/htm/algorithms/SDRClassifier.cpp | 5 +++-- src/htm/algorithms/SDRClassifier.hpp | 16 +++++++++------- src/test/unit/algorithms/SDRClassifierTest.cpp | 8 ++++---- 5 files changed, 19 insertions(+), 16 deletions(-) diff --git a/bindings/py/cpp_src/bindings/algorithms/py_SDRClassifier.cpp b/bindings/py/cpp_src/bindings/algorithms/py_SDRClassifier.cpp index 27dfe5f29c..05c4eb1e10 100644 --- a/bindings/py/cpp_src/bindings/algorithms/py_SDRClassifier.cpp +++ b/bindings/py/cpp_src/bindings/algorithms/py_SDRClassifier.cpp @@ -147,7 +147,7 @@ Example Usage: numpy.argmax( B[2] ) -> labels[3] )"); - py_Predictor.def(py::init &, Real>(), + py_Predictor.def(py::init &, Real>(), R"(Argument steps is the number of steps into the future to learn and predict. The Predictor accepts a list of steps. @@ -182,7 +182,7 @@ This may also be a list for when the input has multiple categories.)", py::arg("pattern"), py::arg("classification")); - py_Predictor.def("learn", [](Predictor &self, UInt recordNum, const SDR &pattern, UInt categoryIdx) + py_Predictor.def("learn", [](Predictor &self, UInt recordNum, const SDR &pattern, UInt categoryIdx) //override for using UInt category, instead of {UInt} { self.learn( recordNum, pattern, {categoryIdx} ); }, py::arg("recordNum"), py::arg("pattern"), diff --git a/src/examples/hotgym/HelloSPTP.cpp b/src/examples/hotgym/HelloSPTP.cpp index 397a655d9e..1760c943a9 100644 --- a/src/examples/hotgym/HelloSPTP.cpp +++ b/src/examples/hotgym/HelloSPTP.cpp @@ -86,7 +86,7 @@ EPOCHS = 10; // make test faster in Debug TemporalMemory tm(vector{COLS}, CELLS); tm.setAnomalyMode(TemporalMemory::ANMode::RAW); //set other modes here - Predictor pred( vector{0,100}); //predict 0 (=classify current), 100 steps ahead + Predictor pred( {0,100}); //predict 0 (=classify current), 100 steps ahead tInit.stop(); diff --git a/src/htm/algorithms/SDRClassifier.cpp b/src/htm/algorithms/SDRClassifier.cpp index 45d6573b6d..0e9e366106 100644 --- a/src/htm/algorithms/SDRClassifier.cpp +++ b/src/htm/algorithms/SDRClassifier.cpp @@ -138,10 +138,11 @@ void htm::softmax(PDF::iterator begin, PDF::iterator end) { /******************************************************************************/ -Predictor::Predictor(const vector &steps, const Real alpha) +Predictor::Predictor(const vector &steps, const Real alpha) { initialize(steps, alpha); } -void Predictor::initialize(const vector &steps, const Real alpha) + +void Predictor::initialize(const vector &steps, const Real alpha) { NTA_CHECK( not steps.empty() ) << "Required argument steps is empty!"; steps_ = steps; diff --git a/src/htm/algorithms/SDRClassifier.hpp b/src/htm/algorithms/SDRClassifier.hpp index 7b662925e3..0fef6e49a2 100644 --- a/src/htm/algorithms/SDRClassifier.hpp +++ b/src/htm/algorithms/SDRClassifier.hpp @@ -135,7 +135,8 @@ class Classifier : public Serializable * Learn from example data. * * @param pattern: The active input bit SDR. - * @param categoryIdxList: The current categories or bucket indices. + * @param categoryIdxList: The current categories (or bucket indices) + * that should be associated with this pattern. */ void learn(const SDR & pattern, const std::vector & categoryIdxList); @@ -180,12 +181,13 @@ void softmax(PDF::iterator begin, PDF::iterator end); /******************************************************************************/ +using StepsAheadT = unsigned short; /** * The key is the step, for predicting multiple time steps into the future. * The value is a PDF (probability distribution function, of the result being in * each bucket or category). */ -using Predictions = std::unordered_map; +using Predictions = std::unordered_map; /** * The Predictor class does N-Step ahead predictions. @@ -209,7 +211,7 @@ using Predictions = std::unordered_map; * vector labels = { 4, 5, 6, 7 }; * * // Make a Predictor and train it. - * Predictor pred( vector{ 1, 2 } ); + * Predictor pred( vector{ 1, 2 } ); * pred.learn( 0, sequence[0], { labels[0] } ); * pred.learn( 1, sequence[1], { labels[1] } ); * pred.learn( 2, sequence[2], { labels[2] } ); @@ -238,13 +240,13 @@ class Predictor : public Serializable * A larger alpha results in faster adaptation to the data. * (The default value will likely be OK in most cases.) */ - Predictor(const std::vector &steps, Real alpha = 0.001f ); + Predictor(const std::vector &steps, Real alpha = 0.001f ); /** * Constructor for use when deserializing. */ Predictor() {} - void initialize(const std::vector &steps, Real alpha = 0.001f ); + void initialize(const std::vector &steps, Real alpha = 0.001f ); /** * For use with time series datasets. @@ -288,7 +290,7 @@ class Predictor : public Serializable private: // The list of prediction steps to learn and infer. - std::vector steps_; + std::vector steps_; // Stores the input pattern history, starting with the previous input. std::deque patternHistory_; @@ -296,7 +298,7 @@ class Predictor : public Serializable void checkMonotonic_(UInt recordNum) const; // One per prediction step - std::unordered_map classifiers_; + std::unordered_map classifiers_; }; // End of Predictor class diff --git a/src/test/unit/algorithms/SDRClassifierTest.cpp b/src/test/unit/algorithms/SDRClassifierTest.cpp index d242113b3c..c5c126f8b6 100644 --- a/src/test/unit/algorithms/SDRClassifierTest.cpp +++ b/src/test/unit/algorithms/SDRClassifierTest.cpp @@ -85,7 +85,7 @@ TEST(SDRClassifierTest, ExampleUsagePredictor) vector labels = { 4, 5, 6, 7 }; // Make a Predictor and train it. - Predictor pred( vector{ 1, 2 } ); + Predictor pred( vector{ 1, 2 } ); pred.learn( 0, sequence[0], { labels[0] } ); pred.learn( 1, sequence[1], { labels[1] } ); pred.learn( 2, sequence[2], { labels[2] } ); @@ -107,7 +107,7 @@ TEST(SDRClassifierTest, ExampleUsagePredictor) TEST(SDRClassifierTest, SingleValue) { // Feed the same input 10 times, the corresponding probability should be // very high - vector steps{1u}; + vector steps{1}; Predictor c(steps, 0.1f); // Create a vector of input bit indices @@ -128,7 +128,7 @@ TEST(SDRClassifierTest, SingleValue) { TEST(SDRClassifierTest, ComputeComplex) { // More complex classification // This test is ported from the Python unit test - Predictor c({1u}, 1.0f); + Predictor c({1}, 1.0f); // Create a input vector SDR input1({ 20u }); @@ -210,7 +210,7 @@ TEST(SDRClassifierTest, MultipleCategories) { TEST(SDRClassifierTest, SaveLoad) { - vector steps{ 1u }; + vector steps{ 1 }; Predictor c1(steps, 0.1f); // Train a Predictor with a few different things. From 06f9701a7e286a898c25a4bd9b8892298a834810 Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Fri, 20 Sep 2019 11:09:24 +0200 Subject: [PATCH 09/11] Classifier: numCategories_ is size_t to avoid overflow for large labels --- src/htm/algorithms/SDRClassifier.cpp | 2 +- src/htm/algorithms/SDRClassifier.hpp | 2 +- src/test/unit/algorithms/SDRClassifierTest.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/htm/algorithms/SDRClassifier.cpp b/src/htm/algorithms/SDRClassifier.cpp index 0e9e366106..d731e1dccf 100644 --- a/src/htm/algorithms/SDRClassifier.cpp +++ b/src/htm/algorithms/SDRClassifier.cpp @@ -79,7 +79,7 @@ void Classifier::learn(const SDR &pattern, const vector &categoryIdxList) NTA_ASSERT(pattern.size == dimensions_) << "Input SDR does not match previously seen size!"; // Check if this is a new category & resize the weights table to hold it. - const auto maxCategoryIdx = *max_element(categoryIdxList.cbegin(), categoryIdxList.cend()); + const size_t maxCategoryIdx = *max_element(categoryIdxList.cbegin(), categoryIdxList.cend()); if( maxCategoryIdx >= numCategories_ ) { numCategories_ = maxCategoryIdx + 1; for( auto & vec : weights_ ) { diff --git a/src/htm/algorithms/SDRClassifier.hpp b/src/htm/algorithms/SDRClassifier.hpp index 0fef6e49a2..99358d2d2d 100644 --- a/src/htm/algorithms/SDRClassifier.hpp +++ b/src/htm/algorithms/SDRClassifier.hpp @@ -157,7 +157,7 @@ class Classifier : public Serializable private: Real alpha_; UInt dimensions_; - UInt numCategories_; + size_t numCategories_; /** * 2D map used to store the data. diff --git a/src/test/unit/algorithms/SDRClassifierTest.cpp b/src/test/unit/algorithms/SDRClassifierTest.cpp index c5c126f8b6..e99df18765 100644 --- a/src/test/unit/algorithms/SDRClassifierTest.cpp +++ b/src/test/unit/algorithms/SDRClassifierTest.cpp @@ -66,7 +66,7 @@ TEST(SDRClassifierTest, HandleLargeLabels) inputData.randomize(0.02f); Classifier clsr; - UInt hugeLabel = numeric_limits::max(); + UInt hugeLabel = numeric_limits::max() -2; EXPECT_NO_THROW(clsr.learn( inputData, { hugeLabel } )); ASSERT_EQ( argmax( clsr.infer( inputData ) ), hugeLabel ); } From f80a76561c3737da1d9242eef8c5573cf99f0716 Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Wed, 6 Nov 2019 14:21:07 +0100 Subject: [PATCH 10/11] fix bindings for setAnomalyMode needed to specify the argument for the signiture to be correct --- .../py/cpp_src/bindings/algorithms/py_TemporalMemory.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/bindings/py/cpp_src/bindings/algorithms/py_TemporalMemory.cpp b/bindings/py/cpp_src/bindings/algorithms/py_TemporalMemory.cpp index a407d90556..f3c6faaf60 100644 --- a/bindings/py/cpp_src/bindings/algorithms/py_TemporalMemory.cpp +++ b/bindings/py/cpp_src/bindings/algorithms/py_TemporalMemory.cpp @@ -372,7 +372,12 @@ R"()"); "Anomaly score updated with each TM::compute() call. " ); - py_HTM.def("setAnomalyMode", &HTM_t::setAnomalyMode); + py_HTM.def("setAnomalyMode", [](HTM_t &self, TemporalMemory::ANMode mode){ + self.setAnomalyMode(mode); + }, + "set anomaly mode used by TM.anomaly", + py::arg("mode") = TemporalMemory::ANMode::RAW + ); py_HTM.def("__str__", [](HTM_t &self) { From 865f7e0546c2906156b0a12e6e0b83b51379310c Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Thu, 7 Nov 2019 01:51:12 +0100 Subject: [PATCH 11/11] progress --- bindings/py/tests/algorithms/temporal_memory_test.py | 4 ++-- src/examples/hotgym/HelloSPTP.cpp | 11 ++++++++--- src/htm/algorithms/SDRClassifier.cpp | 2 ++ src/test/unit/algorithms/SDRClassifierTest.cpp | 4 ++-- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/bindings/py/tests/algorithms/temporal_memory_test.py b/bindings/py/tests/algorithms/temporal_memory_test.py index bad695889c..fb4613f10d 100644 --- a/bindings/py/tests/algorithms/temporal_memory_test.py +++ b/bindings/py/tests/algorithms/temporal_memory_test.py @@ -180,8 +180,8 @@ def testAnomaly(self): 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) - #print("testing {}".format(mod)) + 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 diff --git a/src/examples/hotgym/HelloSPTP.cpp b/src/examples/hotgym/HelloSPTP.cpp index 81cadfecf7..87dfc8c4eb 100644 --- a/src/examples/hotgym/HelloSPTP.cpp +++ b/src/examples/hotgym/HelloSPTP.cpp @@ -40,10 +40,12 @@ using namespace htm; * helper to transform (Real) data to categories (UInt) for Classifier/Predictor **/ UInt realToCategory_(const Real r) { - return static_cast((r+1.0f /*map sin(x):[-1,1] map it to [0,2]*/)*1000); //precision on 3 dec places + return static_cast((r+1.0f /*map sin(x):[-1,1] map it to [0,2]*/)*100); //precision on 2 dec places } Real categoryToReal_(const UInt bin) { - return static_cast((bin/1000.0f)-1.0f); + const Real rl = static_cast((bin/100.0f)-1.0f); + std::cout << "RL =" << bin << std::endl; + return rl; } // work-load @@ -166,7 +168,10 @@ EPOCHS = 10; // make test faster in Debug //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 + 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(); diff --git a/src/htm/algorithms/SDRClassifier.cpp b/src/htm/algorithms/SDRClassifier.cpp index af528974ad..e0f436bddb 100644 --- a/src/htm/algorithms/SDRClassifier.cpp +++ b/src/htm/algorithms/SDRClassifier.cpp @@ -82,6 +82,8 @@ void Classifier::learn(const SDR &pattern, const vector &categoryIdxList) // Check if this is a new category & resize the weights table to hold it. const size_t maxCategoryIdx = *max_element(categoryIdxList.cbegin(), categoryIdxList.cend()); + NTA_CHECK(maxCategoryIdx < 1000) << "TODO for now we only support limited number of labels (<1000)."; + if( maxCategoryIdx >= numCategories_ ) { numCategories_ = maxCategoryIdx + 1; for( auto & vec : weights_ ) { diff --git a/src/test/unit/algorithms/SDRClassifierTest.cpp b/src/test/unit/algorithms/SDRClassifierTest.cpp index e99df18765..4c9955a6f9 100644 --- a/src/test/unit/algorithms/SDRClassifierTest.cpp +++ b/src/test/unit/algorithms/SDRClassifierTest.cpp @@ -67,8 +67,8 @@ TEST(SDRClassifierTest, HandleLargeLabels) Classifier clsr; UInt hugeLabel = numeric_limits::max() -2; - EXPECT_NO_THROW(clsr.learn( inputData, { hugeLabel } )); - ASSERT_EQ( argmax( clsr.infer( inputData ) ), hugeLabel ); + EXPECT_ANY_THROW(clsr.learn( inputData, { hugeLabel } )); + //ASSERT_EQ( argmax( clsr.infer( inputData ) ), hugeLabel ); }