From 1ef8c2bbe8ae2bb51f8b9ca2da0390f6f2fe821a Mon Sep 17 00:00:00 2001 From: Lupino Date: Sun, 3 May 2020 21:53:26 +0800 Subject: [PATCH 1/4] add learnPattern ClassifierRegion when I try the rest api, then ClassifierRegion learn with TM.activeCells and infer with TM.activeCells, the result is alway the same. I read the examples `hello_tm.py`, tm predict next value is predictedActiveCells. So ClassifierRegion need add an learnPattern for learning, and origin pattern for infer. --- src/htm/algorithms/SDRClassifier.cpp | 6 +++++- src/htm/regions/ClassifierRegion.cpp | 15 +++++++++------ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/htm/algorithms/SDRClassifier.cpp b/src/htm/algorithms/SDRClassifier.cpp index 277cca1ae4..5422c2214c 100644 --- a/src/htm/algorithms/SDRClassifier.cpp +++ b/src/htm/algorithms/SDRClassifier.cpp @@ -58,7 +58,11 @@ PDF Classifier::infer(const SDR & pattern) const { PDF probabilities( numCategories_, 0.0f ); for( const auto bit : pattern.getSparse() ) { for( size_t i = 0; i < numCategories_; i++ ) { - probabilities[i] += weights_[bit][i]; + if (weights_.size() > bit) { + if (weights_[bit].size() > i) { + probabilities[i] += weights_[bit][i]; + } + } } } diff --git a/src/htm/regions/ClassifierRegion.cpp b/src/htm/regions/ClassifierRegion.cpp index 9937b99d80..d799a9bb5a 100644 --- a/src/htm/regions/ClassifierRegion.cpp +++ b/src/htm/regions/ClassifierRegion.cpp @@ -78,10 +78,12 @@ namespace htm { }, inputs: { bucket: { description: "The quantized value of the current sample, one from each encoder if more than one, for the learn step", - type: Real64, count: 0}, - pattern: { description: "An SDR output bit pattern for a sample. Usually the output of the SP or TM. For example: activeCells from TM", - type: SDR, count: 0} - }, + type: Real64, count: 0}, + pattern: { description: "An SDR output bit pattern for a sample. Usually the output of the SP or TM. For example: activeCells from TM", + type: SDR, count: 0}, + learnPattern: { description: "An SDR output bit pattern for a sample. Usually the output of the SP or TM. For example: activeCells from TM", + type: SDR, count: 0} + }, outputs: { pdf: { description: "probability distribution function (pdf) for each category or bucket. Sorted by title. Warning, buffer length will grow.", type: Real64, count: 0}, @@ -143,12 +145,13 @@ void ClassifierRegion::compute() { // and SDRClassifier::infer() will throw an exception. if (learn_) { + SDR &learnPattern = getInput("learnPattern")->getData().getSDR(); Array &b = getInput("bucket")->getData(); // 'bucket' is a list of quantized samples being processed for this iteration. // There are one of these for each encoder (or value being encoded). // The values might not be consecutive, or in different ranges, or different things entirely. // We build a map and a corresponding vector containing the quantized samples actually used. - // This vector becomes the titles. The index into this list will be a consecutive list that + // This vector becomes the titles. The index into this list will be a consecutive list that // we can presented to the Classifier which produces the pdf. Note that the indexes used // by the classifier are not sorted by title but rather by the order in which an index is first seen. std::vector categoryIdxList; @@ -166,7 +169,7 @@ void ClassifierRegion::compute() { } categoryIdxList.push_back(c); } - classifier_->learn(pattern, categoryIdxList); + classifier_->learn(learnPattern, categoryIdxList); } PDF pdf = classifier_->infer(pattern); From b689460c4b2bc3a5148432ea745942cddb68c0d1 Mon Sep 17 00:00:00 2001 From: Lupino Date: Tue, 5 May 2020 08:29:26 +0800 Subject: [PATCH 2/4] use NTA_CHECK(pattern.size == dimensions_) --- src/htm/algorithms/SDRClassifier.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/htm/algorithms/SDRClassifier.cpp b/src/htm/algorithms/SDRClassifier.cpp index 5422c2214c..ac807da209 100644 --- a/src/htm/algorithms/SDRClassifier.cpp +++ b/src/htm/algorithms/SDRClassifier.cpp @@ -52,17 +52,13 @@ PDF Classifier::infer(const SDR & pattern) const { NTA_WARN << "Classifier: must call `learn` before `infer`."; return PDF(numCategories_, std::nan("")); //empty array [] } - NTA_ASSERT(pattern.size == dimensions_) << "Input SDR does not match previously seen size!"; + NTA_CHECK(pattern.size == dimensions_) << "Input SDR does not match previously seen size!"; // Accumulate feed forward input. PDF probabilities( numCategories_, 0.0f ); for( const auto bit : pattern.getSparse() ) { for( size_t i = 0; i < numCategories_; i++ ) { - if (weights_.size() > bit) { - if (weights_[bit].size() > i) { - probabilities[i] += weights_[bit][i]; - } - } + probabilities[i] += weights_[bit][i]; } } From 27aec54a141804c07637d40d3e0252898442d7b5 Mon Sep 17 00:00:00 2001 From: Lupino Date: Tue, 5 May 2020 10:11:30 +0800 Subject: [PATCH 3/4] change ClassifierRegion pattern -> inferPattern --- src/htm/regions/ClassifierRegion.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/htm/regions/ClassifierRegion.cpp b/src/htm/regions/ClassifierRegion.cpp index d799a9bb5a..ea3a0acc1f 100644 --- a/src/htm/regions/ClassifierRegion.cpp +++ b/src/htm/regions/ClassifierRegion.cpp @@ -79,7 +79,7 @@ namespace htm { inputs: { bucket: { description: "The quantized value of the current sample, one from each encoder if more than one, for the learn step", type: Real64, count: 0}, - pattern: { description: "An SDR output bit pattern for a sample. Usually the output of the SP or TM. For example: activeCells from TM", + inferPattern: { description: "An SDR output bit pattern for a sample. Usually the output of the SP or TM. For example: predictiveCells from TM", type: SDR, count: 0}, learnPattern: { description: "An SDR output bit pattern for a sample. Usually the output of the SP or TM. For example: activeCells from TM", type: SDR, count: 0} @@ -89,7 +89,7 @@ namespace htm { type: Real64, count: 0}, titles: { description: "Quantized values of used samples which are the Titles corresponding to the pdf indexes. Sorted by title. Warning, buffer length will grow.", type: Real64, count: 0}, - predicted: { description: "An index (into pdf and titles) with the highest probability of being the match with the current pattern.", + predicted: { description: "An index (into pdf and titles) with the highest probability of being the match with the current inferPattern.", type: UInt32, count: 1} } } @@ -140,10 +140,6 @@ Dimensions ClassifierRegion::askImplForOutputDimensions(const std::string &name) void ClassifierRegion::compute() { - SDR &pattern = getInput("pattern")->getData().getSDR(); - // Note: if there is no link to 'pattern' input, the 'pattern' SDR length is 0 - // and SDRClassifier::infer() will throw an exception. - if (learn_) { SDR &learnPattern = getInput("learnPattern")->getData().getSDR(); Array &b = getInput("bucket")->getData(); @@ -171,7 +167,12 @@ void ClassifierRegion::compute() { } classifier_->learn(learnPattern, categoryIdxList); } - PDF pdf = classifier_->infer(pattern); + + SDR &inferPattern = getInput("inferPattern")->getData().getSDR(); + // Note: if there is no link to 'inferPattern' input, the 'inferPattern' SDR length is 0 + // and SDRClassifier::infer() will throw an exception. + + PDF pdf = classifier_->infer(inferPattern); // Adjust the buffer size to match the pdf. if (getOutput("pdf")->getData().getCount() < pdf.size()) { @@ -192,7 +193,7 @@ void ClassifierRegion::compute() { size_t i = itm.second; if (pdf[i] > m) { m = pdf[i]; - predicted[0] = static_cast(j); // index of the quantized sample with the highest probability of matching the pattern + predicted[0] = static_cast(j); // index of the quantized sample with the highest probability of matching the inferPattern } out[j] = pdf[i]; titles[j] = bucketList[i]; From 2f47541b186d2f0c23d7de216c46b1d2970929b9 Mon Sep 17 00:00:00 2001 From: Lupino Date: Wed, 6 May 2020 16:05:28 +0800 Subject: [PATCH 4/4] revert pattern When learnPattern is set, use learnPattern. inferPattern is set, use inferPattern --- src/htm/regions/ClassifierRegion.cpp | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/htm/regions/ClassifierRegion.cpp b/src/htm/regions/ClassifierRegion.cpp index ea3a0acc1f..0db388e99b 100644 --- a/src/htm/regions/ClassifierRegion.cpp +++ b/src/htm/regions/ClassifierRegion.cpp @@ -79,6 +79,8 @@ namespace htm { inputs: { bucket: { description: "The quantized value of the current sample, one from each encoder if more than one, for the learn step", type: Real64, count: 0}, + pattern: { description: "An SDR output bit pattern for a sample. Usually the output of the SP or TM. For example: activeCells from TM", + type: SDR, count: 0}, inferPattern: { description: "An SDR output bit pattern for a sample. Usually the output of the SP or TM. For example: predictiveCells from TM", type: SDR, count: 0}, learnPattern: { description: "An SDR output bit pattern for a sample. Usually the output of the SP or TM. For example: activeCells from TM", @@ -140,8 +142,8 @@ Dimensions ClassifierRegion::askImplForOutputDimensions(const std::string &name) void ClassifierRegion::compute() { + SDR &pattern = getInput("pattern")->getData().getSDR(); if (learn_) { - SDR &learnPattern = getInput("learnPattern")->getData().getSDR(); Array &b = getInput("bucket")->getData(); // 'bucket' is a list of quantized samples being processed for this iteration. // There are one of these for each encoder (or value being encoded). @@ -165,14 +167,25 @@ void ClassifierRegion::compute() { } categoryIdxList.push_back(c); } - classifier_->learn(learnPattern, categoryIdxList); + + SDR &learnPattern = getInput("learnPattern")->getData().getSDR(); + if (learnPattern.size == 0) { + classifier_->learn(pattern, categoryIdxList); + } else { + classifier_->learn(learnPattern, categoryIdxList); + } } SDR &inferPattern = getInput("inferPattern")->getData().getSDR(); // Note: if there is no link to 'inferPattern' input, the 'inferPattern' SDR length is 0 // and SDRClassifier::infer() will throw an exception. - - PDF pdf = classifier_->infer(inferPattern); + // + PDF pdf; + if (inferPattern.size == 0) { + pdf = classifier_->infer(pattern); + } else { + pdf = classifier_->infer(inferPattern); + } // Adjust the buffer size to match the pdf. if (getOutput("pdf")->getData().getCount() < pdf.size()) {