From fbd2f921cc5aed3b2da65def57e6bb7a9901d254 Mon Sep 17 00:00:00 2001 From: ctrl-z-9000-times Date: Fri, 22 Mar 2019 18:35:18 -0400 Subject: [PATCH 1/8] Removed class ClassifierResult --- .../bindings/algorithms/py_SDRClassifier.cpp | 7 +- src/CMakeLists.txt | 2 - src/examples/mnist/MNIST_SP.cpp | 5 +- src/nupic/algorithms/SDRClassifier.cpp | 52 +++++---- src/nupic/algorithms/SDRClassifier.hpp | 28 +++-- src/nupic/types/ClassifierResult.cpp | 83 ------------- src/nupic/types/ClassifierResult.hpp | 110 ------------------ .../unit/algorithms/SDRClassifierTest.cpp | 54 ++++----- 8 files changed, 82 insertions(+), 259 deletions(-) delete mode 100644 src/nupic/types/ClassifierResult.cpp delete mode 100644 src/nupic/types/ClassifierResult.hpp diff --git a/bindings/py/cpp_src/bindings/algorithms/py_SDRClassifier.cpp b/bindings/py/cpp_src/bindings/algorithms/py_SDRClassifier.cpp index 133a43bf3c..169d138124 100644 --- a/bindings/py/cpp_src/bindings/algorithms/py_SDRClassifier.cpp +++ b/bindings/py/cpp_src/bindings/algorithms/py_SDRClassifier.cpp @@ -41,7 +41,6 @@ namespace nupic_ext namespace py = pybind11; using namespace nupic; using namespace nupic::algorithms::sdr_classifier; -using nupic::types::PDF; void init_SDR_Classifier(py::module& m) { @@ -67,7 +66,7 @@ using nupic::types::PDF; py::dict dict; - for (map::const_iterator it = result.begin(); it != result.end(); ++it) + for (map::const_iterator it = result.begin(); it != result.end(); ++it) { std::string key = "actualValues"; @@ -77,9 +76,9 @@ using nupic::types::PDF; } py::list value; - for (UInt i = 0; i < it->second->size(); ++i) + for (UInt i = 0; i < it->second.size(); ++i) { - value.append(it->second->at(i)); + value.append(it->second.at(i)); } dict[key.c_str()] = value; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5361d49433..f1881c947d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -194,8 +194,6 @@ set(regions_files set(types_files nupic/types/BasicType.cpp nupic/types/BasicType.hpp - nupic/types/ClassifierResult.cpp - nupic/types/ClassifierResult.hpp nupic/types/Exception.hpp nupic/types/Serializable.hpp nupic/types/Types.hpp diff --git a/src/examples/mnist/MNIST_SP.cpp b/src/examples/mnist/MNIST_SP.cpp index 8b79c394ae..28136b6244 100644 --- a/src/examples/mnist/MNIST_SP.cpp +++ b/src/examples/mnist/MNIST_SP.cpp @@ -40,7 +40,7 @@ using namespace nupic; using nupic::algorithms::spatial_pooler::SpatialPooler; using nupic::algorithms::sdr_classifier::SDRClassifier; -using nupic::types::ClassifierResult; +using nupic::algorithms::sdr_classifier::ClassifierResult; class MNIST { @@ -157,7 +157,8 @@ void test() { /* infer */ true, result); // Check results - const auto cls = result.getClass(); + // const auto cls = result.getClass(); + UInt cls = -1; // TODO FIXME ADD METHOD getClass BACK TO SDRC! if(cls == label) score += 1; n_samples += 1; if( verbosity && i % 1000 == 0 ) cout << "." << flush; diff --git a/src/nupic/algorithms/SDRClassifier.cpp b/src/nupic/algorithms/SDRClassifier.cpp index 1fae256d4b..2d9c74748d 100644 --- a/src/nupic/algorithms/SDRClassifier.cpp +++ b/src/nupic/algorithms/SDRClassifier.cpp @@ -1,8 +1,10 @@ /* --------------------------------------------------------------------- * Numenta Platform for Intelligent Computing (NuPIC) - * Copyright (C) 2016, Numenta, Inc. Unless you have an agreement - * with Numenta, Inc., for a separate license for this software code, the - * following terms and conditions apply: + * Copyright (C) 2016, Numenta, Inc. + * 2019, David McDougall + * + * Unless you have an agreement with Numenta, Inc., for a separate license for + * this software code, the following terms and conditions apply: * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero Public License version 3 as @@ -17,8 +19,7 @@ * along with this program. If not, see http://www.gnu.org/licenses. * * http://numenta.org/licenses/ - * --------------------------------------------------------------------- - */ + * --------------------------------------------------------------------- */ #include //exp #include @@ -193,35 +194,42 @@ size_t SDRClassifier::persistentSize() const { void SDRClassifier::infer_(const vector &patternNZ, const vector &actValue, - ClassifierResult &result) { - // add the actual values to the return value. For buckets that haven't + ClassifierResult &result) +{ + // Add the actual values to the return value. For buckets that haven't // been seen yet, the actual value doesn't matter since it will have // zero likelihood. - vector *actValueVector = - result.createVector(-1, (UInt)actualValues_.size(), 0.0); - for (UInt i = 0; i < (UInt)actualValues_.size(); ++i) { + vector &actValueVector = result[-1]; + actValueVector.reserve( actualValues_.size() ); + + for( UInt i = 0; i < (UInt)actualValues_.size(); ++i ) { if (actualValuesSet_[i]) { - (*actValueVector)[i] = actualValues_[i]; - } else { + actValueVector.push_back( actualValues_[i] ); + } + else { // if doing 0-step ahead prediction, we shouldn't use any // knowledge of the classification input during inference - if (steps_.at(0) == 0) { - (*actValueVector)[i] = 0; - } else { - (*actValueVector)[i] = actValue[0]; + if( steps_.at(0) == 0 ) { + actValueVector.push_back( 0.0f ); + } + else { + actValueVector.push_back( actValue[0] ); } } } - for (auto nSteps = steps_.begin(); nSteps != steps_.end(); ++nSteps) { - vector* likelihoods = result.createVector(*nSteps, maxBucketIdx_ + 1, 0.0); - for (const auto& bit : patternNZ) { + for( auto nSteps = steps_.begin(); nSteps != steps_.end(); ++nSteps ) + { + vector &likelihoods = result[ *nSteps ]; + likelihoods.assign( maxBucketIdx_ + 1, 0.0f ); + + for( const auto& bit : patternNZ ) { const Matrix& w = weightMatrix_.at(*nSteps); - for(UInt i =0; i< (UInt)likelihoods->size(); i++) { - likelihoods->at(i) += get_(w, bit, i); + for( UInt i = 0; i < (UInt) likelihoods.size(); i++ ) { + likelihoods.at(i) += get_(w, bit, i); } } - softmax_(likelihoods->begin(), likelihoods->end()); + softmax_( likelihoods.begin(), likelihoods.end() ); } } diff --git a/src/nupic/algorithms/SDRClassifier.hpp b/src/nupic/algorithms/SDRClassifier.hpp index bfa9494e80..812fcdfc57 100644 --- a/src/nupic/algorithms/SDRClassifier.hpp +++ b/src/nupic/algorithms/SDRClassifier.hpp @@ -1,8 +1,10 @@ /* --------------------------------------------------------------------- * Numenta Platform for Intelligent Computing (NuPIC) - * Copyright (C) 2016, Numenta, Inc. Unless you have an agreement - * with Numenta, Inc., for a separate license for this software code, the - * following terms and conditions apply: + * Copyright (C) 2016, Numenta, Inc. + * 2019, David McDougall + * + * Unless you have an agreement with Numenta, Inc., for a separate license for + * this software code, the following terms and conditions apply: * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero Public License version 3 as @@ -17,8 +19,7 @@ * along with this program. If not, see http://www.gnu.org/licenses. * * http://numenta.org/licenses/ - * --------------------------------------------------------------------- - */ + * --------------------------------------------------------------------- */ /** @file * Definitions for the SDRClassifier. @@ -33,20 +34,29 @@ #include #include -#include #include #include namespace nupic { namespace algorithms { namespace sdr_classifier { -using namespace std; -using nupic::types::ClassifierResult; +using namespace std; // TODO: REMOVE THIS! + const UInt sdrClassifierVersion = 2; /** - * 2d map used to store the data. + * PDF - Probability Density Function, distribution of likelihood of values + */ +using PDF = std::vector; + +/** + * + */ +using ClassifierResult = std::map; + +/** + * 2d map used to store the data. * write with Matrix m; m[i][j] = 1.0; //map will always allocate for new i,j index * access/read with get_(&m, i, j): as it handles missing values i,j and returns 0.0 for them */ diff --git a/src/nupic/types/ClassifierResult.cpp b/src/nupic/types/ClassifierResult.cpp deleted file mode 100644 index 47a6c63b74..0000000000 --- a/src/nupic/types/ClassifierResult.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* --------------------------------------------------------------------- - * Numenta Platform for Intelligent Computing (NuPIC) - * Copyright (C) 2013-2015, Numenta, Inc. Unless you have an agreement - * with Numenta, Inc., for a separate license for this software code, the - * following terms and conditions apply: - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero Public License version 3 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Affero Public License for more details. - * - * You should have received a copy of the GNU Affero Public License - * along with this program. If not, see http://www.gnu.org/licenses. - * - * http://numenta.org/licenses/ - * --------------------------------------------------------------------- - */ - -#include -#include - -#include -#include - - -namespace nupic { -namespace types { - -using namespace std; - -ClassifierResult::~ClassifierResult() { - for (map::const_iterator it = result_.begin(); - it != result_.end(); ++it) { - delete it->second; - } -} - - -PDF *ClassifierResult::createVector(Int step, UInt size, Real64 value) { - NTA_CHECK(result_.count(step) == 0) << "The ClassifierResult cannot be reused!"; - PDF *v = new PDF(size, value); - result_.insert(pair(step, v)); - return v; -} - - -bool ClassifierResult::operator==(const ClassifierResult &other) const { - for (auto it = result_.begin(); it != result_.end(); it++) { - const auto thisVec = it->second; - const auto otherVec = other.result_.at(it->first); - if (otherVec == nullptr || thisVec->size() != otherVec->size()) { - return false; - } - for (UInt i = 0; i < thisVec->size(); i++) { - if (fabs(thisVec->at(i) - otherVec->at(i)) > 0.000001) { - return false; - } - } - } - return true; -} - - -UInt ClassifierResult::getClass(const UInt stepsAhead) const { - NTA_CHECK(stepsAhead < result_.size()) << "ClassifierResult is not for steps " << stepsAhead; - for(auto iter : this->result_) { - if( iter.first == (Int)stepsAhead ) { //entry at nth step (0==current) - const auto *pdf = iter.second; //probability distribution of the classes - const auto max = std::max_element(pdf->cbegin(), pdf->cend()); - const UInt cls = (UInt32)(max - pdf->cbegin()); - return cls; - } - } - NTA_THROW << "ClassifierResult did not match"; //should not come here -} - - -} // end namespace algorithms -} // end namespace nupic diff --git a/src/nupic/types/ClassifierResult.hpp b/src/nupic/types/ClassifierResult.hpp deleted file mode 100644 index d0dc7bf08e..0000000000 --- a/src/nupic/types/ClassifierResult.hpp +++ /dev/null @@ -1,110 +0,0 @@ -/* --------------------------------------------------------------------- - * Numenta Platform for Intelligent Computing (NuPIC) - * Copyright (C) 2013-2015, Numenta, Inc. Unless you have an agreement - * with Numenta, Inc., for a separate license for this software code, the - * following terms and conditions apply: - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero Public License version 3 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Affero Public License for more details. - * - * You should have received a copy of the GNU Affero Public License - * along with this program. If not, see http://www.gnu.org/licenses. - * - * http://numenta.org/licenses/ - * --------------------------------------------------------------------- - */ - -#ifndef NTA_classifier_result_HPP -#define NTA_classifier_result_HPP - -#include -#include - -#include - - -namespace nupic { -namespace types { - -using PDF = std::vector; //PDF..probability density function, distribution of likelihood of values - -/** CLA classifier result class. - * - * @b Responsibility - * The ClassifierResult is responsible for storing result data and - * cleaning up the data when deleted. - * - */ -class ClassifierResult { - -public: - /** - * Constructor. - */ - ClassifierResult() {} - - /** - * Destructor - frees memory allocated during lifespan. - */ - virtual ~ClassifierResult(); - - /** - * Creates and returns a vector for a given step. - * - * The vectors created are stored and can be accessed with the - * iterator methods. The vectors are owned by this class and are - * deleted in the destructor. - * - * @param step The prediction step to create a vector for. If -1, then - * a vector for the actual values to use for each bucket - * is returned. - * @param size The size of the desired vector. - * @param value The value to populate the vector with. - * - * @returns The specified vector. - */ - virtual PDF *createVector(Int step, UInt size, Real64 value); - - /** - * get the most probable class (classification, label) from results. - * @param stepsAhead - for nth prediction (0=current) - */ - UInt getClass(const UInt stepsAhead=0u) const; - - /** - * Checks if the other instance has the exact same values. - * - * @param other The other instance to compare to. - * @returns True iff the other instance has the same values. - */ - virtual bool operator==(const ClassifierResult &other) const; - - /** - * Iterator method begin. - */ - virtual std::map::const_iterator begin() { - return result_.begin(); - } - - /** - * Iterator method end. - */ - virtual std::map::const_iterator end() { - return result_.end(); - } - -private: - std::map result_; //TODO do not use pointer T*, but T in this class - -}; // end class ClassifierResult - -} // end namespace algorithms -} // end namespace nupic - -#endif // NTA_classifier_result_HPP diff --git a/src/test/unit/algorithms/SDRClassifierTest.cpp b/src/test/unit/algorithms/SDRClassifierTest.cpp index 3978be419b..a885f8cd81 100644 --- a/src/test/unit/algorithms/SDRClassifierTest.cpp +++ b/src/test/unit/algorithms/SDRClassifierTest.cpp @@ -85,21 +85,21 @@ TEST_F(SDRClassifierTest, Basic) { // The -1 key is used for the actual values ASSERT_FALSE(foundMinus1) << "Already found key -1 in classifier result"; foundMinus1 = true; - ASSERT_EQ(5ul, it->second->size()) + ASSERT_EQ(5ul, it->second.size()) << "Expected five buckets since it has only seen bucket 4 (so it " << "Has buckets 0-4)."; - ASSERT_LT(fabs(it->second->at(4) - 34.7f), 0.000001f) + ASSERT_LT(fabs(it->second.at(4) - 34.7f), 0.000001f) << "Incorrect actual value for bucket 4"; } else if (it->first == 1) { // Check the one-step prediction ASSERT_FALSE(found1) << "Already found key 1 in classifier result"; found1 = true; - ASSERT_EQ(5ul, it->second->size()) << "Expected five bucket predictions"; - ASSERT_NEAR(it->second->at(0u), 0.2f, 0.000001f) << "Incorrect prediction for bucket 0"; - ASSERT_NEAR(it->second->at(1u), 0.2f, 0.000001f) << "Incorrect prediction for bucket 1"; - ASSERT_NEAR(it->second->at(2u), 0.2f, 0.000001f) << "Incorrect prediction for bucket 2"; - ASSERT_NEAR(it->second->at(3u), 0.2f, 0.000001f) << "Incorrect prediction for bucket 3"; - ASSERT_NEAR(it->second->at(4u), 0.2f, 0.000001f) << "Incorrect prediction for bucket 4"; + ASSERT_EQ(5ul, it->second.size()) << "Expected five bucket predictions"; + ASSERT_NEAR(it->second.at(0u), 0.2f, 0.000001f) << "Incorrect prediction for bucket 0"; + ASSERT_NEAR(it->second.at(1u), 0.2f, 0.000001f) << "Incorrect prediction for bucket 1"; + ASSERT_NEAR(it->second.at(2u), 0.2f, 0.000001f) << "Incorrect prediction for bucket 2"; + ASSERT_NEAR(it->second.at(3u), 0.2f, 0.000001f) << "Incorrect prediction for bucket 3"; + ASSERT_NEAR(it->second.at(4u), 0.2f, 0.000001f) << "Incorrect prediction for bucket 4"; } } ASSERT_TRUE(foundMinus1) << "Key -1 not found in classifier result"; @@ -117,19 +117,19 @@ TEST_F(SDRClassifierTest, SingleValue) { vector input1{1u, 5u, 9u}; vector bucketIdxList{4u}; vector actValueList{34.7f}; - ClassifierResult result1; + ClassifierResult result1; // TODO: REVIEW THIS TESTCASE, POTENTIAL SCOPING ISSUES? for (UInt i = 0u; i < 10u; ++i) { - ClassifierResult result1; + ClassifierResult result1; // SHADOWS? c.compute(i, input1, bucketIdxList, actValueList, false, true, true, result1); } { for (auto it = result1.begin(); it != result1.end(); ++it) { if (it->first == -1) { - ASSERT_LT(fabs(it->second->at(4u) - 10.0f), 0.000001f) + ASSERT_LT(fabs(it->second.at(4u) - 10.0f), 0.000001f) << "Incorrect actual value for bucket 4"; } else if (it->first == 1) { - ASSERT_GT(it->second->at(4u), 0.9f) + ASSERT_GT(it->second.at(4u), 0.9f) << "Incorrect prediction for bucket 4"; } } @@ -195,30 +195,30 @@ TEST_F(SDRClassifierTest, ComputeComplex) { ASSERT_FALSE(foundMinus1) << "Already found key -1 in classifier result"; foundMinus1 = true; - ASSERT_EQ(6ul, it->second->size()) + ASSERT_EQ(6ul, it->second.size()) << "Expected six buckets since it has only seen bucket 4-5 (so it " << "has buckets 0-5)."; - ASSERT_LT(fabs(it->second->at(4u) - 35.520000457763672f), 0.000001f) + ASSERT_LT(fabs(it->second.at(4u) - 35.520000457763672f), 0.000001f) << "Incorrect actual value for bucket 4"; - ASSERT_LT(fabs(it->second->at(5u) - 42.020000457763672f), 0.000001f) + ASSERT_LT(fabs(it->second.at(5u) - 42.020000457763672f), 0.000001f) << "Incorrect actual value for bucket 5"; } else if (it->first == 1) { // Check the one-step prediction ASSERT_FALSE(found1) << "Already found key 1 in classifier result"; found1 = true; - ASSERT_EQ(6ul, it->second->size()) << "Expected six bucket predictions"; - ASSERT_LT(fabs(it->second->at(0u) - 0.034234f), 0.000001f) + ASSERT_EQ(6ul, it->second.size()) << "Expected six bucket predictions"; + ASSERT_LT(fabs(it->second.at(0u) - 0.034234f), 0.000001f) << "Incorrect prediction for bucket 0"; - ASSERT_LT(fabs(it->second->at(1u) - 0.034234f), 0.000001f) + ASSERT_LT(fabs(it->second.at(1u) - 0.034234f), 0.000001f) << "Incorrect prediction for bucket 1"; - ASSERT_LT(fabs(it->second->at(2u) - 0.034234f), 0.000001f) + ASSERT_LT(fabs(it->second.at(2u) - 0.034234f), 0.000001f) << "Incorrect prediction for bucket 2"; - ASSERT_LT(fabs(it->second->at(3u) - 0.034234f), 0.000001f) + ASSERT_LT(fabs(it->second.at(3u) - 0.034234f), 0.000001f) << "Incorrect prediction for bucket 3"; - ASSERT_LT(fabs(it->second->at(4u) - 0.093058f), 0.000001f) + ASSERT_LT(fabs(it->second.at(4u) - 0.093058f), 0.000001f) << "Incorrect prediction for bucket 4"; - ASSERT_LT(fabs(it->second->at(5u) - 0.770004f), 0.000001f) + ASSERT_LT(fabs(it->second.at(5u) - 0.770004f), 0.000001f) << "Incorrect prediction for bucket 5"; } } @@ -266,18 +266,18 @@ TEST_F(SDRClassifierTest, MultipleCategory) { for (auto it = result1.begin(); it != result1.end(); ++it) { if (it->first == 0) { - ASSERT_LT(fabs(it->second->at(0u) - 0.5f), 0.1f) + ASSERT_LT(fabs(it->second.at(0u) - 0.5f), 0.1f) << "Incorrect prediction for bucket 0 (expected=0.5)"; - ASSERT_LT(fabs(it->second->at(1u) - 0.5f), 0.1f) + ASSERT_LT(fabs(it->second.at(1u) - 0.5f), 0.1f) << "Incorrect prediction for bucket 1 (expected=0.5)"; } } for (auto it = result2.begin(); it != result2.end(); ++it) { if (it->first == 0) { - ASSERT_LT(fabs(it->second->at(2u) - 0.5f), 0.1f) + ASSERT_LT(fabs(it->second.at(2u) - 0.5f), 0.1f) << "Incorrect prediction for bucket 2 (expected=0.5)"; - ASSERT_LT(fabs(it->second->at(3u) - 0.5f), 0.1f) + ASSERT_LT(fabs(it->second.at(3u) - 0.5f), 0.1f) << "Incorrect prediction for bucket 3 (expected=0.5)"; } } @@ -306,7 +306,7 @@ TEST_F(SDRClassifierTest, SaveLoad) { c1.compute(1u, input1, bucketIdxList1, actValueList1, false, true, true, result1); c2.compute(1u, input1, bucketIdxList1, actValueList1, false, true, true, result2); - ASSERT_EQ(result1, result2); + ASSERT_EQ(result1[1u], result2[1]); } From e18aaac310a5f970857be0d794d3af250fc7e53a Mon Sep 17 00:00:00 2001 From: ctrl-z-9000-times Date: Sat, 6 Apr 2019 14:33:53 -0400 Subject: [PATCH 2/8] Remove "using namespace std" from header SDRClassifier.hpp --- .../bindings/algorithms/py_SDRClassifier.cpp | 1 + src/examples/mnist/MNIST_SP.cpp | 3 +- src/nupic/algorithms/SDRClassifier.hpp | 35 ++++++++++--------- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/bindings/py/cpp_src/bindings/algorithms/py_SDRClassifier.cpp b/bindings/py/cpp_src/bindings/algorithms/py_SDRClassifier.cpp index 169d138124..cd5e4f4fa8 100644 --- a/bindings/py/cpp_src/bindings/algorithms/py_SDRClassifier.cpp +++ b/bindings/py/cpp_src/bindings/algorithms/py_SDRClassifier.cpp @@ -39,6 +39,7 @@ PyBind11 bindings for SDRClassifier class namespace nupic_ext { namespace py = pybind11; +using namespace std; using namespace nupic; using namespace nupic::algorithms::sdr_classifier; diff --git a/src/examples/mnist/MNIST_SP.cpp b/src/examples/mnist/MNIST_SP.cpp index 28136b6244..afdd053336 100644 --- a/src/examples/mnist/MNIST_SP.cpp +++ b/src/examples/mnist/MNIST_SP.cpp @@ -157,8 +157,7 @@ void test() { /* infer */ true, result); // Check results - // const auto cls = result.getClass(); - UInt cls = -1; // TODO FIXME ADD METHOD getClass BACK TO SDRC! + UInt cls = max_element(result[0].begin(), result[0].end()) - result[0].begin(); if(cls == label) score += 1; n_samples += 1; if( verbosity && i % 1000 == 0 ) cout << "." << flush; diff --git a/src/nupic/algorithms/SDRClassifier.hpp b/src/nupic/algorithms/SDRClassifier.hpp index c28c645bcb..d261935df1 100644 --- a/src/nupic/algorithms/SDRClassifier.hpp +++ b/src/nupic/algorithms/SDRClassifier.hpp @@ -40,7 +40,6 @@ namespace nupic { namespace algorithms { namespace sdr_classifier { -using namespace std; // TODO: REMOVE THIS! const UInt sdrClassifierVersion = 2; @@ -51,7 +50,9 @@ const UInt sdrClassifierVersion = 2; using PDF = std::vector; /** - * + * The key is the step, for predicting multiple time steps into the future. + * The key -1 contains the estimate of the actual values. + * The value is a PDF of the result being in each bucket. */ using ClassifierResult = std::map; @@ -72,7 +73,7 @@ class SDRClassifier : public Serializable * Constructor for use when deserializing. */ SDRClassifier() {} - void initialize(const vector &steps, Real64 alpha, Real64 actValueAlpha, + void initialize(const std::vector &steps, Real64 alpha, Real64 actValueAlpha, UInt verbosity); /** @@ -84,7 +85,7 @@ class SDRClassifier : public Serializable * values for each bucket. * @param verbosity The logging verbosity. */ - SDRClassifier(const vector &steps, Real64 alpha, Real64 actValueAlpha, + SDRClassifier(const std::vector &steps, Real64 alpha, Real64 actValueAlpha, UInt verbosity); /** @@ -109,9 +110,9 @@ class SDRClassifier : public Serializable * values for key 0 correspond to the actual values to * used when predicting each bucket. */ - virtual void compute(UInt recordNum, const vector &patternNZ, - const vector &bucketIdxList, - const vector &actValueList, bool category, + virtual void compute(UInt recordNum, const std::vector &patternNZ, + const std::vector &bucketIdxList, + const std::vector &actValueList, bool category, bool learn, bool infer, ClassifierResult &result); /** @@ -151,18 +152,18 @@ class SDRClassifier : public Serializable private: // Helper function for inference mode - void infer_(const vector &patternNZ, const vector &actValue, + void infer_(const std::vector &patternNZ, const std::vector &actValue, ClassifierResult &result); // Helper function to compute the error signal in learning mode - vector calculateError_(const vector &bucketIdxList, - const vector patternNZ, UInt step); + std::vector calculateError_(const std::vector &bucketIdxList, + const std::vector patternNZ, UInt step); // softmax function - void softmax_(vector::iterator begin, vector::iterator end); + void softmax_(std::vector::iterator begin, std::vector::iterator end); // The list of prediction steps to learn and infer. - vector steps_; + std::vector steps_; // The alpha used to decay the duty cycles in the BitHistorys. Real64 alpha_; @@ -175,11 +176,11 @@ class SDRClassifier : public Serializable // Stores the input pattern history, starting with the previous input // and containing _maxSteps total input patterns. - deque> patternNZHistory_; - deque recordNumHistory_; + std::deque> patternNZHistory_; + std::deque recordNumHistory_; // Weight matrices for the classifier (one per prediction step) - map weightMatrix_; + std::map weightMatrix_; // The highest input bit that the classifier has seen so far. UInt maxInputIdx_; @@ -189,11 +190,11 @@ class SDRClassifier : public Serializable // The current actual values used for each bucket index. The index of // the actual value matches the index of the bucket. - vector actualValues_; + std::vector actualValues_; // A boolean that distinguishes between actual values that have been // seen and those that have not. - vector actualValuesSet_; + std::vector actualValuesSet_; // Version and verbosity. UInt version_; From 9ed30836ac0a9cd5936341648b624a42eb99e083 Mon Sep 17 00:00:00 2001 From: ctrl-z-9000-times Date: Sun, 7 Apr 2019 14:12:26 -0400 Subject: [PATCH 3/8] SDR-Classifier unit test fix --- src/test/unit/algorithms/SDRClassifierTest.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/test/unit/algorithms/SDRClassifierTest.cpp b/src/test/unit/algorithms/SDRClassifierTest.cpp index a885f8cd81..21b43cc7fe 100644 --- a/src/test/unit/algorithms/SDRClassifierTest.cpp +++ b/src/test/unit/algorithms/SDRClassifierTest.cpp @@ -117,20 +117,23 @@ TEST_F(SDRClassifierTest, SingleValue) { vector input1{1u, 5u, 9u}; vector bucketIdxList{4u}; vector actValueList{34.7f}; - ClassifierResult result1; // TODO: REVIEW THIS TESTCASE, POTENTIAL SCOPING ISSUES? + ClassifierResult result1; for (UInt i = 0u; i < 10u; ++i) { - ClassifierResult result1; // SHADOWS? c.compute(i, input1, bucketIdxList, actValueList, false, true, true, result1); } { for (auto it = result1.begin(); it != result1.end(); ++it) { if (it->first == -1) { - ASSERT_LT(fabs(it->second.at(4u) - 10.0f), 0.000001f) + ASSERT_LT(fabs(it->second.at(4u) - 34.7f), 0.000001f) << "Incorrect actual value for bucket 4"; } else if (it->first == 1) { - ASSERT_GT(it->second.at(4u), 0.9f) + auto pdf = it->second; + auto argmax = max_element(pdf.begin(), pdf.end()) - pdf.begin(); + ASSERT_EQ( argmax, 4u ) << "Incorrect prediction for bucket 4"; + } else { + FAIL(); } } } From 00ec934e2605bfae8307fecd83e2636137a579c4 Mon Sep 17 00:00:00 2001 From: ctrl-z-9000-times Date: Sun, 7 Apr 2019 14:14:37 -0400 Subject: [PATCH 4/8] SDR Classifier: New symbol ACTUAL_VALUES Also now uses size_t where appropriate --- src/nupic/algorithms/SDRClassifier.cpp | 10 +++++----- src/nupic/algorithms/SDRClassifier.hpp | 3 ++- src/test/unit/algorithms/SDRClassifierTest.cpp | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/nupic/algorithms/SDRClassifier.cpp b/src/nupic/algorithms/SDRClassifier.cpp index f32816161f..fa30ca1a2a 100644 --- a/src/nupic/algorithms/SDRClassifier.cpp +++ b/src/nupic/algorithms/SDRClassifier.cpp @@ -173,7 +173,7 @@ void SDRClassifier::compute(UInt recordNum, const vector &patternNZ, Matrix& w = weightMatrix_.at(nSteps); NTA_ASSERT(alpha_ > 0.0); for (const auto& bit : learnPatternNZ) { - for(UInt i = 0; i < error.size(); i++) { + for(size_t i = 0; i < error.size(); i++) { const auto val = get_(w, bit, i) + alpha_ * error[i]; if(val == 0) continue; w[bit][i] = val; @@ -191,10 +191,10 @@ void SDRClassifier::infer_(const vector &patternNZ, // Add the actual values to the return value. For buckets that haven't // been seen yet, the actual value doesn't matter since it will have // zero likelihood. - vector &actValueVector = result[-1]; + vector &actValueVector = result[ACTUAL_VALUES]; actValueVector.reserve( actualValues_.size() ); - for( UInt i = 0; i < (UInt)actualValues_.size(); ++i ) { + for( size_t i = 0; i < actualValues_.size(); ++i ) { if (actualValuesSet_[i]) { actValueVector.push_back( actualValues_[i] ); } @@ -217,7 +217,7 @@ void SDRClassifier::infer_(const vector &patternNZ, for( const auto& bit : patternNZ ) { const Matrix& w = weightMatrix_.at(*nSteps); - for( UInt i = 0; i < (UInt) likelihoods.size(); i++ ) { + for( size_t i = 0; i < likelihoods.size(); i++ ) { likelihoods.at(i) += get_(w, bit, i); } } @@ -246,7 +246,7 @@ vector SDRClassifier::calculateError_(const vector &bucketIdxList, targetDistribution[bucketIdxList[i]] = 1.0 / numCategories; NTA_ASSERT(likelihoods.size() == targetDistribution.size()); - for(UInt i = 0; i < likelihoods.size(); i++) { + for(size_t i = 0; i < likelihoods.size(); i++) { likelihoods[i] = targetDistribution[i] - likelihoods[i]; } return likelihoods; diff --git a/src/nupic/algorithms/SDRClassifier.hpp b/src/nupic/algorithms/SDRClassifier.hpp index d261935df1..e0da2b33e2 100644 --- a/src/nupic/algorithms/SDRClassifier.hpp +++ b/src/nupic/algorithms/SDRClassifier.hpp @@ -51,9 +51,10 @@ using PDF = std::vector; /** * The key is the step, for predicting multiple time steps into the future. - * The key -1 contains the estimate of the actual values. + * The key ACTUAL_VALUES contains an estimate of the actual values. * The value is a PDF of the result being in each bucket. */ +const Int ACTUAL_VALUES = -1; using ClassifierResult = std::map; /** diff --git a/src/test/unit/algorithms/SDRClassifierTest.cpp b/src/test/unit/algorithms/SDRClassifierTest.cpp index 21b43cc7fe..32f06bec06 100644 --- a/src/test/unit/algorithms/SDRClassifierTest.cpp +++ b/src/test/unit/algorithms/SDRClassifierTest.cpp @@ -124,7 +124,7 @@ TEST_F(SDRClassifierTest, SingleValue) { { for (auto it = result1.begin(); it != result1.end(); ++it) { - if (it->first == -1) { + if (it->first == ACTUAL_VALUES) { ASSERT_LT(fabs(it->second.at(4u) - 34.7f), 0.000001f) << "Incorrect actual value for bucket 4"; } else if (it->first == 1) { From 1b2b9b0f18178692807fcc1489b8a8402266f7ad Mon Sep 17 00:00:00 2001 From: ctrl-z-9000-times Date: Sun, 7 Apr 2019 14:29:31 -0400 Subject: [PATCH 5/8] New function getClassification(PDF)->UInt for SDR-Classifier --- src/examples/mnist/MNIST_SP.cpp | 5 +++-- src/nupic/algorithms/SDRClassifier.cpp | 5 +++++ src/nupic/algorithms/SDRClassifier.hpp | 5 +++++ src/test/unit/algorithms/SDRClassifierTest.cpp | 4 +--- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/examples/mnist/MNIST_SP.cpp b/src/examples/mnist/MNIST_SP.cpp index afdd053336..40e4993484 100644 --- a/src/examples/mnist/MNIST_SP.cpp +++ b/src/examples/mnist/MNIST_SP.cpp @@ -41,6 +41,7 @@ using namespace nupic; using nupic::algorithms::spatial_pooler::SpatialPooler; using nupic::algorithms::sdr_classifier::SDRClassifier; using nupic::algorithms::sdr_classifier::ClassifierResult; +using nupic::algorithms::sdr_classifier::getClassification; class MNIST { @@ -157,8 +158,8 @@ void test() { /* infer */ true, result); // Check results - UInt cls = max_element(result[0].begin(), result[0].end()) - result[0].begin(); - if(cls == label) score += 1; + if(getClassification( result[0] ) == label) + score += 1; n_samples += 1; if( verbosity && i % 1000 == 0 ) cout << "." << flush; } diff --git a/src/nupic/algorithms/SDRClassifier.cpp b/src/nupic/algorithms/SDRClassifier.cpp index fa30ca1a2a..3a52050a3d 100644 --- a/src/nupic/algorithms/SDRClassifier.cpp +++ b/src/nupic/algorithms/SDRClassifier.cpp @@ -44,6 +44,11 @@ namespace sdr_classifier { using namespace std; + +UInt getClassification( const PDF & data ) + { return max_element( data.begin(), data.end() ) - data.begin(); } + + /** * get(x,y) accessor interface for Matrix; handles sparse (missing) values * @return return value stored at map[row][col], or defaultVal if such field does not exist diff --git a/src/nupic/algorithms/SDRClassifier.hpp b/src/nupic/algorithms/SDRClassifier.hpp index e0da2b33e2..d6b9d146a9 100644 --- a/src/nupic/algorithms/SDRClassifier.hpp +++ b/src/nupic/algorithms/SDRClassifier.hpp @@ -49,6 +49,11 @@ const UInt sdrClassifierVersion = 2; */ using PDF = std::vector; +/** + * Returns the class with the greatest probablility. + */ +UInt getClassification( const PDF & ); + /** * The key is the step, for predicting multiple time steps into the future. * The key ACTUAL_VALUES contains an estimate of the actual values. diff --git a/src/test/unit/algorithms/SDRClassifierTest.cpp b/src/test/unit/algorithms/SDRClassifierTest.cpp index 32f06bec06..ddab13a5e6 100644 --- a/src/test/unit/algorithms/SDRClassifierTest.cpp +++ b/src/test/unit/algorithms/SDRClassifierTest.cpp @@ -128,9 +128,7 @@ TEST_F(SDRClassifierTest, SingleValue) { ASSERT_LT(fabs(it->second.at(4u) - 34.7f), 0.000001f) << "Incorrect actual value for bucket 4"; } else if (it->first == 1) { - auto pdf = it->second; - auto argmax = max_element(pdf.begin(), pdf.end()) - pdf.begin(); - ASSERT_EQ( argmax, 4u ) + ASSERT_EQ( getClassification( it->second ), 4u ) << "Incorrect prediction for bucket 4"; } else { FAIL(); From d01e4deaf029604ea89921432dcc178ed3fadc81 Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Mon, 8 Apr 2019 01:06:31 +0200 Subject: [PATCH 6/8] SDRClassifier comment --- src/nupic/algorithms/SDRClassifier.hpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/nupic/algorithms/SDRClassifier.hpp b/src/nupic/algorithms/SDRClassifier.hpp index d6b9d146a9..3844370b75 100644 --- a/src/nupic/algorithms/SDRClassifier.hpp +++ b/src/nupic/algorithms/SDRClassifier.hpp @@ -57,7 +57,8 @@ UInt getClassification( const PDF & ); /** * The key is the step, for predicting multiple time steps into the future. * The key ACTUAL_VALUES contains an estimate of the actual values. - * The value is a PDF of the result being in each bucket. + * The value is a PDF(probability density function, list of probabilities of outcomes) + * of the result being in each bucket. */ const Int ACTUAL_VALUES = -1; using ClassifierResult = std::map; @@ -67,7 +68,8 @@ using ClassifierResult = std::map; * write with Matrix m; m[i][j] = 1.0; //map will always allocate for new i,j index * access/read with get_(&m, i, j): as it handles missing values i,j and returns 0.0 for them */ -typedef std::map> Matrix; //Matrix[r][c] = 0.0d +using Matrix = std::map>; //Matrix[r][c] = 0.0d + class SDRClassifier : public Serializable { From 7b9252546eb24a9ee2278b6ec6442d4db58e4ac0 Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Mon, 8 Apr 2019 01:11:35 +0200 Subject: [PATCH 7/8] SDRClassifier getClassification() now a member method moved from static --- src/examples/mnist/MNIST_SP.cpp | 3 +-- src/nupic/algorithms/SDRClassifier.cpp | 2 +- src/nupic/algorithms/SDRClassifier.hpp | 10 +++++----- src/test/unit/algorithms/SDRClassifierTest.cpp | 2 +- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/examples/mnist/MNIST_SP.cpp b/src/examples/mnist/MNIST_SP.cpp index 40e4993484..fde153b020 100644 --- a/src/examples/mnist/MNIST_SP.cpp +++ b/src/examples/mnist/MNIST_SP.cpp @@ -41,7 +41,6 @@ using namespace nupic; using nupic::algorithms::spatial_pooler::SpatialPooler; using nupic::algorithms::sdr_classifier::SDRClassifier; using nupic::algorithms::sdr_classifier::ClassifierResult; -using nupic::algorithms::sdr_classifier::getClassification; class MNIST { @@ -158,7 +157,7 @@ void test() { /* infer */ true, result); // Check results - if(getClassification( result[0] ) == label) + if(clsr.getClassification( result[0] ) == label) score += 1; n_samples += 1; if( verbosity && i % 1000 == 0 ) cout << "." << flush; diff --git a/src/nupic/algorithms/SDRClassifier.cpp b/src/nupic/algorithms/SDRClassifier.cpp index 3a52050a3d..e73236ef5f 100644 --- a/src/nupic/algorithms/SDRClassifier.cpp +++ b/src/nupic/algorithms/SDRClassifier.cpp @@ -45,7 +45,7 @@ namespace sdr_classifier { using namespace std; -UInt getClassification( const PDF & data ) +UInt SDRClassifier::getClassification( const PDF & data ) const { return max_element( data.begin(), data.end() ) - data.begin(); } diff --git a/src/nupic/algorithms/SDRClassifier.hpp b/src/nupic/algorithms/SDRClassifier.hpp index 3844370b75..221612a232 100644 --- a/src/nupic/algorithms/SDRClassifier.hpp +++ b/src/nupic/algorithms/SDRClassifier.hpp @@ -49,11 +49,6 @@ const UInt sdrClassifierVersion = 2; */ using PDF = std::vector; -/** - * Returns the class with the greatest probablility. - */ -UInt getClassification( const PDF & ); - /** * The key is the step, for predicting multiple time steps into the future. * The key ACTUAL_VALUES contains an estimate of the actual values. @@ -123,6 +118,11 @@ class SDRClassifier : public Serializable const std::vector &actValueList, bool category, bool learn, bool infer, ClassifierResult &result); + /** + * Returns the class with the greatest probablility. + */ + UInt getClassification( const PDF & ) const; + /** * Gets the version number */ diff --git a/src/test/unit/algorithms/SDRClassifierTest.cpp b/src/test/unit/algorithms/SDRClassifierTest.cpp index ddab13a5e6..59b966e7cf 100644 --- a/src/test/unit/algorithms/SDRClassifierTest.cpp +++ b/src/test/unit/algorithms/SDRClassifierTest.cpp @@ -128,7 +128,7 @@ TEST_F(SDRClassifierTest, SingleValue) { ASSERT_LT(fabs(it->second.at(4u) - 34.7f), 0.000001f) << "Incorrect actual value for bucket 4"; } else if (it->first == 1) { - ASSERT_EQ( getClassification( it->second ), 4u ) + ASSERT_EQ( c.getClassification( it->second ), 4u ) << "Incorrect prediction for bucket 4"; } else { FAIL(); From 8df3a33e5ed10ff51cbb79d1a0887af195570b91 Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Mon, 8 Apr 2019 01:30:42 +0200 Subject: [PATCH 8/8] Classifier: move Matrix type within class --- src/nupic/algorithms/SDRClassifier.cpp | 16 +++------------- src/nupic/algorithms/SDRClassifier.hpp | 21 ++++++++++++++------- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/src/nupic/algorithms/SDRClassifier.cpp b/src/nupic/algorithms/SDRClassifier.cpp index e73236ef5f..fa70828c07 100644 --- a/src/nupic/algorithms/SDRClassifier.cpp +++ b/src/nupic/algorithms/SDRClassifier.cpp @@ -38,10 +38,8 @@ #include -namespace nupic { -namespace algorithms { -namespace sdr_classifier { - +using namespace nupic; +using namespace nupic::algorithms::sdr_classifier; using namespace std; @@ -49,11 +47,7 @@ UInt SDRClassifier::getClassification( const PDF & data ) const { return max_element( data.begin(), data.end() ) - data.begin(); } -/** - * get(x,y) accessor interface for Matrix; handles sparse (missing) values - * @return return value stored at map[row][col], or defaultVal if such field does not exist - **/ -Real64 get_(const Matrix& m, const UInt row, const UInt col, const Real64 defaultVal=0.0) { +Real64 SDRClassifier::get_(const Matrix& m, const UInt row, const UInt col, const Real64 defaultVal) const { try { return m.at(row).at(col); } catch(std::exception& ex ) { @@ -513,7 +507,3 @@ bool SDRClassifier::operator==(const SDRClassifier &other) const { return true; } - -} // namespace sdr_classifier -} // namespace algorithms -} // namespace nupic diff --git a/src/nupic/algorithms/SDRClassifier.hpp b/src/nupic/algorithms/SDRClassifier.hpp index 221612a232..f2fed73cff 100644 --- a/src/nupic/algorithms/SDRClassifier.hpp +++ b/src/nupic/algorithms/SDRClassifier.hpp @@ -58,19 +58,20 @@ using PDF = std::vector; const Int ACTUAL_VALUES = -1; using ClassifierResult = std::map; -/** - * 2d map used to store the data. - * write with Matrix m; m[i][j] = 1.0; //map will always allocate for new i,j index - * access/read with get_(&m, i, j): as it handles missing values i,j and returns 0.0 for them - */ -using Matrix = std::map>; //Matrix[r][c] = 0.0d - class SDRClassifier : public Serializable { // Make test class friend so it can unit test private members directly friend class SDRClassifierTest; + /** + * 2d map used to store the data. + * write with Matrix m; m[i][j] = 1.0; //map will always allocate for new i,j index + * access/read with get_(&m, i, j): as it handles missing values i,j and returns 0.0 for them + */ + using Matrix = std::map>; //Matrix[r][c] = 0.0d + + public: /** * Constructor for use when deserializing. @@ -170,6 +171,12 @@ class SDRClassifier : public Serializable // softmax function void softmax_(std::vector::iterator begin, std::vector::iterator end); + /** + * get(x,y) accessor interface for Matrix; handles sparse (missing) values + * @return return value stored at map[row][col], or defaultVal if such field does not exist + **/ + Real64 get_(const Matrix& m, const UInt row, const UInt col, const Real64 defaultVal=0.0) const; + // The list of prediction steps to learn and infer. std::vector steps_;