From a6c24f54cebe3d445410784763bdacefafdaf787 Mon Sep 17 00:00:00 2001 From: David Keeney Date: Tue, 19 Nov 2019 17:10:46 -0800 Subject: [PATCH 01/10] hotgym implemented using NetworkAPI --- src/CMakeLists.txt | 25 ++++ src/examples/hotgym_NetworkAPI/README.md | 80 +++++++++++ .../hotgym_NetworkAPI/hotgym_napi.cpp | 132 ++++++++++++++++++ src/htm/utils/Random.hpp | 2 +- 4 files changed, 238 insertions(+), 1 deletion(-) create mode 100644 src/examples/hotgym_NetworkAPI/README.md create mode 100644 src/examples/hotgym_NetworkAPI/hotgym_napi.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d505a2e299..4a682d2c0e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -185,6 +185,7 @@ set(examples_files examples/hotgym/Hotgym.cpp # contains conflicting main() examples/hotgym/HelloSPTP.cpp examples/hotgym/HelloSPTP.hpp + examples/hotgym_NetworkAPI/hotgym_napi.cpp examples/mnist/MNIST_SP.cpp ) @@ -356,6 +357,30 @@ else() ${EXTERNAL_INCLUDES} ) endif() + +######################################################### +## NetworkAPI version of hotgym + +set(src_executable_hotgym_napi hotgym_napi) +add_executable(${src_executable_hotgym_napi} examples/hotgym_NetworkAPI/hotgym_napi.cpp) +# link with the static library +target_link_libraries(${src_executable_hotgym_napi} + ${INTERNAL_LINKER_FLAGS} + ${core_library} + ${COMMON_OS_LIBS} +) +target_compile_options( ${src_executable_hotgym_napi} PUBLIC ${INTERNAL_CXX_FLAGS}) +target_compile_definitions(${src_executable_hotgym_napi} PRIVATE ${COMMON_COMPILER_DEFINITIONS}) +target_include_directories(${src_executable_hotgym_napi} PRIVATE + ${CORE_LIB_INCLUDES} + ${EXTERNAL_INCLUDES} + ) +add_custom_target(hotgym_napi_run + COMMAND ${src_executable_hotgym_napi} + DEPENDS ${src_executable_hotgym_napi} + COMMENT "Executing ${src_executable_hotgym_napi}" + VERBATIM) + ######################################################### ## MNIST Spatial Pooler Example # diff --git a/src/examples/hotgym_NetworkAPI/README.md b/src/examples/hotgym_NetworkAPI/README.md new file mode 100644 index 0000000000..597347fc41 --- /dev/null +++ b/src/examples/hotgym_NetworkAPI/README.md @@ -0,0 +1,80 @@ +# C++ example using Network API +The program `hotgym_napi` is an example of an app using the Network API tools available in the htm.core library. In this example we generate a sin wave with some noise as the input. This is passed to an encoder to turn that into SDR format. This is passed to two instances of SpatialPooler (SP), one is configured for local inhibition and one for global inhibition. The output of the SP for global inhibition is passed on to the temporalMemory (TM) algorithm. The output of the TM can be written to a file so that it can be plotted. + +``` + /////////////////////////////////////////////////////////////// + // + // .------------------. + // | encoder | + // data--->| (RDSERegion) | + // | | + // `------------------' + // | | + // .------------------. .------------------. + // | SP (local) | | SP (global) | + // | (SPRegion) | | (SPRegion) | + // | | | | + // `------------------' `------------------' + // | + // .------------------. + // | TM | + // | (TMRegion) | + // | | + // `------------------' + // + ////////////////////////////////////////////////////////////////// +``` + +Each "region" is a wrapper around an algorithm. This wrapper provides a uniform interface that can be plugged into the Network API engine for execution. The htm.core library contains regions for each of the primary algorithms in the library. The user can create their own algorithms and corresponding regions and plug them into the Network API engine by registering them with the Network class. The following chart shows the 'built-in' C++ regions. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Built-in RegionAlgorithm
ScalarSensorScalarEncoder; Original encoder for numeric values
RDSERegionRandomDistributedScalarEncoder (RDSE); advanced encoder for numeric values.
SPRegionSpatialPooler (SP)
TMRegionTemporalMemory (TM)
VectorFileSensorfor reading from a file
VectorFileEffectorfor writing to a file
+ +## Usage + +``` + hotgym_napi [iterations [filename]] +``` +- *iterations* is the number of times to execute the regions configured into the network. The default is 5000. +- *filename* is the path for a file to be written which contains the following for each iteration. The default is no file written. +``` + , , \n +``` + +## Plotting + +The `hotgym_napi` program can output data if a filename is specified. Any plotting program can be used to display this CSD data. + +## Experimentation +It is intended that this program be used as a launching point for experimenting with combinations of the regions and using different parameters. Try it and see what happens... \ No newline at end of file diff --git a/src/examples/hotgym_NetworkAPI/hotgym_napi.cpp b/src/examples/hotgym_NetworkAPI/hotgym_napi.cpp new file mode 100644 index 0000000000..30afe065b1 --- /dev/null +++ b/src/examples/hotgym_NetworkAPI/hotgym_napi.cpp @@ -0,0 +1,132 @@ +/* --------------------------------------------------------------------- + * HTM Community Edition of NuPIC + * Copyright (C) 2013-2015, Numenta, Inc. + * + * 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. + * --------------------------------------------------------------------- */ + +#include +#include +#include +#include + +using namespace htm; + +static bool verbose = false; +#define VERBOSE if (verbose) std::cout << " " + + +//this runs as an executable + +int main(int argc, char* argv[]) { + htm::UInt EPOCHS = 5000; // number of iterations (calls to encoder/SP/TP compute() ) + const UInt DIM_INPUT = 1000; // Width of encoder output + const UInt COLS = 2048; // number of columns in SP, TP + const UInt CELLS = 8; // cells per column in TP + Random rnd(42); // uses fixed seed for deterministic output + std::ofstream ofs; + + // Runtime arguments: hotgym_napi [epochs [filename]] + if(argc >= 2) { + EPOCHS = std::stoi(argv[1]); // number of iterations (default 5000) + } + if (argc >= 3) { + ofs.open(argv[2], std::ios::out); // output filename (for plotting) + } + + try { + + std::cout << "initializing\n"; + + Network net; + + // Declare the regions to use + std::string encoder_parameters = "{size: " + std::to_string(DIM_INPUT) + ", activeBits: 4, radius: 0.5, seed: 2019 }"; + std::shared_ptr region1 = net.addRegion("region1", "RDSERegion", encoder_parameters); + std::shared_ptr region2a = net.addRegion("region2a", "SPRegion", "{columnCount: " + std::to_string(COLS) + "}"); + std::shared_ptr region2b = net.addRegion("region2b", "SPRegion", "{columnCount: " + std::to_string(COLS) + ", globalInhibition: true}"); + std::shared_ptr region3 = net.addRegion("region3", "TMRegion", "{activationThreshold: 9, cellsPerColumn: " + std::to_string(CELLS) + "}"); + + // Setup data flows between regions + net.link("region1", "region2a", "", "", "encoded", "bottomUpIn"); + net.link("region1", "region2b", "", "", "encoded", "bottomUpIn"); + net.link("region2b", "region3", "", "", "bottomUpOut", "bottomUpIn"); + + net.initialize(); + + /////////////////////////////////////////////////////////////// + // + // .------------------. + // | encoder | + // data--->| (RDSERegion) | + // | | + // `------------------' + // | | + // .------------------. .------------------. + // | SP (local) | | SP (global) | + // | | | | + // | | | | + // `------------------' `------------------' + // | + // .------------------. + // | TM | + // | (TMRegion) | + // | | + // `------------------' + // + ////////////////////////////////////////////////////////////////// + + + // enable this to see a trace as it executes + // net.setLogLevel(LogLevel::LogLevel_Verbose); + + std::cout << "Running: \n"; + // RUN + for (size_t i = 0; i < EPOCHS; i++) { + // genarate some data to send to the encoder + // -- A sin wave, one degree rotation per iteration, 1% noise added + double data = std::sin(i * (3.1415 / 180)) + (double)rnd.realRange(-0.01f, +0.1f); + region1->setParameterReal64("sensedValue", data); // feed data into RDSE encoder for this iteration. + + // Execute an iteration. + net.run(1); + + // output values + double an = ((double *)region3->getOutputData("anomaly").getBuffer())[0]; + VERBOSE << "Epoch = " << i << std::endl; + VERBOSE << " Data = " << data << std::endl; + VERBOSE << " Encoder out = " << region1->getOutputData("encoded").getSDR() << std::endl; + VERBOSE << " SP (local) = " << region2a->getOutputData("bottomUpOut").getSDR() << std::endl; + VERBOSE << " SP (global) = " << region2b->getOutputData("bottomUpOut").getSDR() << std::endl; + VERBOSE << " TM output = " << region3->getOutputData("bottomUpOut").getSDR() << std::endl; + VERBOSE << " ActiveCells = " << region3->getOutputData("activeCells").getSDR() << std::endl; + VERBOSE << " winners = " << region3->getOutputData("predictedActiveCells").getSDR() << std::endl; + VERBOSE << " Anomaly = " << an << std::endl; + + // Save the data for plotting. , , \n + if (ofs.is_open()) + ofs << i << "," << data << "," << an << std::endl; + } + if (ofs.is_open()) + ofs.close(); + + } catch (Exception &e) { + std::cerr << e.what(); + if (ofs.is_open()) + ofs.close(); + return 1; + } + + return 0; +} + diff --git a/src/htm/utils/Random.hpp b/src/htm/utils/Random.hpp index 03c79c00e3..a5c0bb8fa9 100644 --- a/src/htm/utils/Random.hpp +++ b/src/htm/utils/Random.hpp @@ -129,7 +129,7 @@ class Random : public Serializable { * return random from range [from, to) */ Real realRange(Real from, Real to) { - NTA_ASSERT(from <= to); + NTA_ASSERT(from <= to) << "realRange: invalid range."; const Real split = to - from; return from + static_cast(split * getReal64()); } From e60a84cff2284a1b3c536932bbeeaae877c71150 Mon Sep 17 00:00:00 2001 From: David Keeney Date: Thu, 21 Nov 2019 09:28:30 -0800 Subject: [PATCH 02/10] Clean up and change name to napi_sine --- src/CMakeLists.txt | 24 ++++---- .../README.md | 14 +++-- .../napi_sine.cpp} | 57 ++++++++++--------- 3 files changed, 52 insertions(+), 43 deletions(-) rename src/examples/{hotgym_NetworkAPI => napi_sine}/README.md (78%) rename src/examples/{hotgym_NetworkAPI/hotgym_napi.cpp => napi_sine/napi_sine.cpp} (60%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4a682d2c0e..b343845c59 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -185,7 +185,7 @@ set(examples_files examples/hotgym/Hotgym.cpp # contains conflicting main() examples/hotgym/HelloSPTP.cpp examples/hotgym/HelloSPTP.hpp - examples/hotgym_NetworkAPI/hotgym_napi.cpp + examples/napi_sine/napi_sine.cpp examples/mnist/MNIST_SP.cpp ) @@ -359,26 +359,26 @@ else() endif() ######################################################### -## NetworkAPI version of hotgym +## NetworkAPI version of benchmark_sine -set(src_executable_hotgym_napi hotgym_napi) -add_executable(${src_executable_hotgym_napi} examples/hotgym_NetworkAPI/hotgym_napi.cpp) +set(src_executable_napi_sine napi_sine) +add_executable(${src_executable_napi_sine} examples/napi_sine/napi_sine.cpp) # link with the static library -target_link_libraries(${src_executable_hotgym_napi} +target_link_libraries(${src_executable_napi_sine} ${INTERNAL_LINKER_FLAGS} ${core_library} ${COMMON_OS_LIBS} ) -target_compile_options( ${src_executable_hotgym_napi} PUBLIC ${INTERNAL_CXX_FLAGS}) -target_compile_definitions(${src_executable_hotgym_napi} PRIVATE ${COMMON_COMPILER_DEFINITIONS}) -target_include_directories(${src_executable_hotgym_napi} PRIVATE +target_compile_options( ${src_executable_napi_sine} PUBLIC ${INTERNAL_CXX_FLAGS}) +target_compile_definitions(${src_executable_napi_sine} PRIVATE ${COMMON_COMPILER_DEFINITIONS}) +target_include_directories(${src_executable_napi_sine} PRIVATE ${CORE_LIB_INCLUDES} ${EXTERNAL_INCLUDES} ) -add_custom_target(hotgym_napi_run - COMMAND ${src_executable_hotgym_napi} - DEPENDS ${src_executable_hotgym_napi} - COMMENT "Executing ${src_executable_hotgym_napi}" +add_custom_target(sine_napi_run + COMMAND ${src_executable_napi_sine} + DEPENDS ${src_executable_napi_sine} + COMMENT "Executing ${src_executable_napi_sine}" VERBATIM) ######################################################### diff --git a/src/examples/hotgym_NetworkAPI/README.md b/src/examples/napi_sine/README.md similarity index 78% rename from src/examples/hotgym_NetworkAPI/README.md rename to src/examples/napi_sine/README.md index 597347fc41..f5d166e4c1 100644 --- a/src/examples/hotgym_NetworkAPI/README.md +++ b/src/examples/napi_sine/README.md @@ -1,5 +1,12 @@ # C++ example using Network API -The program `hotgym_napi` is an example of an app using the Network API tools available in the htm.core library. In this example we generate a sin wave with some noise as the input. This is passed to an encoder to turn that into SDR format. This is passed to two instances of SpatialPooler (SP), one is configured for local inhibition and one for global inhibition. The output of the SP for global inhibition is passed on to the temporalMemory (TM) algorithm. The output of the TM can be written to a file so that it can be plotted. +The program `sine_napi` is an example of an app using the Network API tools +available in the htm.core library. In this example we generate a sine wave +with some noise as the input. This is passed to an encoder to turn that +into SDR format. This is passed to two instances of SpatialPooler (SP), +one is configured for local inhibition and one for global inhibition. + +The output of the SP for global inhibition is passed on to the temporalMemory (TM) +algorithm. The output of the TM can be written to a file so that it can be plotted. ``` /////////////////////////////////////////////////////////////// @@ -64,7 +71,7 @@ Each "region" is a wrapper around an algorithm. This wrapper provides a uniform ## Usage ``` - hotgym_napi [iterations [filename]] + sine_napi [iterations [filename]] ``` - *iterations* is the number of times to execute the regions configured into the network. The default is 5000. - *filename* is the path for a file to be written which contains the following for each iteration. The default is no file written. @@ -72,9 +79,6 @@ Each "region" is a wrapper around an algorithm. This wrapper provides a uniform , , \n ``` -## Plotting - -The `hotgym_napi` program can output data if a filename is specified. Any plotting program can be used to display this CSD data. ## Experimentation It is intended that this program be used as a launching point for experimenting with combinations of the regions and using different parameters. Try it and see what happens... \ No newline at end of file diff --git a/src/examples/hotgym_NetworkAPI/hotgym_napi.cpp b/src/examples/napi_sine/napi_sine.cpp similarity index 60% rename from src/examples/hotgym_NetworkAPI/hotgym_napi.cpp rename to src/examples/napi_sine/napi_sine.cpp index 30afe065b1..3bccf075a4 100644 --- a/src/examples/hotgym_NetworkAPI/hotgym_napi.cpp +++ b/src/examples/napi_sine/napi_sine.cpp @@ -18,27 +18,33 @@ #include #include #include +#include #include using namespace htm; -static bool verbose = false; +static bool verbose = true; #define VERBOSE if (verbose) std::cout << " " //this runs as an executable int main(int argc, char* argv[]) { - htm::UInt EPOCHS = 5000; // number of iterations (calls to encoder/SP/TP compute() ) - const UInt DIM_INPUT = 1000; // Width of encoder output - const UInt COLS = 2048; // number of columns in SP, TP + htm::UInt EPOCHS = 10; // number of iterations (calls to encoder/SP/TP compute() ) + const UInt DIM_INPUT = 50; // Width of encoder output + const UInt COLS = 100; // number of columns in SP, TP const UInt CELLS = 8; // cells per column in TP Random rnd(42); // uses fixed seed for deterministic output std::ofstream ofs; - // Runtime arguments: hotgym_napi [epochs [filename]] + std::string encoder_params = "{size: " + std::to_string(DIM_INPUT) + ", activeBits: 4, radius: 0.5, seed: 2019 }"; + std::string sp_local_params = "{columnCount: " + std::to_string(COLS) + "}"; + std::string sp_global_params = "{columnCount: " + std::to_string(COLS) + ", globalInhibition: true}"; + std::string tm_params = "{activationThreshold: 9, cellsPerColumn: " + std::to_string(CELLS) + "}"; + + // Runtime arguments: napi_sine [epochs [filename]] if(argc >= 2) { - EPOCHS = std::stoi(argv[1]); // number of iterations (default 5000) + EPOCHS = std::stoi(argv[1]); // number of iterations (default 500) } if (argc >= 3) { ofs.open(argv[2], std::ios::out); // output filename (for plotting) @@ -51,16 +57,15 @@ int main(int argc, char* argv[]) { Network net; // Declare the regions to use - std::string encoder_parameters = "{size: " + std::to_string(DIM_INPUT) + ", activeBits: 4, radius: 0.5, seed: 2019 }"; - std::shared_ptr region1 = net.addRegion("region1", "RDSERegion", encoder_parameters); - std::shared_ptr region2a = net.addRegion("region2a", "SPRegion", "{columnCount: " + std::to_string(COLS) + "}"); - std::shared_ptr region2b = net.addRegion("region2b", "SPRegion", "{columnCount: " + std::to_string(COLS) + ", globalInhibition: true}"); - std::shared_ptr region3 = net.addRegion("region3", "TMRegion", "{activationThreshold: 9, cellsPerColumn: " + std::to_string(CELLS) + "}"); + std::shared_ptr encoder = net.addRegion("encoder", "RDSERegion", encoder_params); + std::shared_ptr sp_local = net.addRegion("sp_local", "SPRegion", sp_local_params); + std::shared_ptr sp_global = net.addRegion("sp_global", "SPRegion", sp_global_params); + std::shared_ptr tm = net.addRegion("tm", "TMRegion", tm_params); // Setup data flows between regions - net.link("region1", "region2a", "", "", "encoded", "bottomUpIn"); - net.link("region1", "region2b", "", "", "encoded", "bottomUpIn"); - net.link("region2b", "region3", "", "", "bottomUpOut", "bottomUpIn"); + net.link("encoder", "sp_local", "", "", "encoded", "bottomUpIn"); + net.link("encoder", "sp_global", "", "", "encoded", "bottomUpIn"); + net.link("sp_global", "tm", "", "", "bottomUpOut", "bottomUpIn"); net.initialize(); @@ -73,13 +78,13 @@ int main(int argc, char* argv[]) { // `------------------' // | | // .------------------. .------------------. - // | SP (local) | | SP (global) | - // | | | | + // | sp_local | | sp_global | + // | (SPRegion) | | (SPRegion) | // | | | | // `------------------' `------------------' // | // .------------------. - // | TM | + // | tm | // | (TMRegion) | // | | // `------------------' @@ -88,7 +93,7 @@ int main(int argc, char* argv[]) { // enable this to see a trace as it executes - // net.setLogLevel(LogLevel::LogLevel_Verbose); + //net.setLogLevel(LogLevel::LogLevel_Verbose); std::cout << "Running: \n"; // RUN @@ -96,21 +101,21 @@ int main(int argc, char* argv[]) { // genarate some data to send to the encoder // -- A sin wave, one degree rotation per iteration, 1% noise added double data = std::sin(i * (3.1415 / 180)) + (double)rnd.realRange(-0.01f, +0.1f); - region1->setParameterReal64("sensedValue", data); // feed data into RDSE encoder for this iteration. + encoder->setParameterReal64("sensedValue", data); // feed data into RDSE encoder for this iteration. // Execute an iteration. net.run(1); // output values - double an = ((double *)region3->getOutputData("anomaly").getBuffer())[0]; + float an = ((float *)tm->getOutputData("anomaly").getBuffer())[0]; VERBOSE << "Epoch = " << i << std::endl; VERBOSE << " Data = " << data << std::endl; - VERBOSE << " Encoder out = " << region1->getOutputData("encoded").getSDR() << std::endl; - VERBOSE << " SP (local) = " << region2a->getOutputData("bottomUpOut").getSDR() << std::endl; - VERBOSE << " SP (global) = " << region2b->getOutputData("bottomUpOut").getSDR() << std::endl; - VERBOSE << " TM output = " << region3->getOutputData("bottomUpOut").getSDR() << std::endl; - VERBOSE << " ActiveCells = " << region3->getOutputData("activeCells").getSDR() << std::endl; - VERBOSE << " winners = " << region3->getOutputData("predictedActiveCells").getSDR() << std::endl; + VERBOSE << " Encoder out = " << encoder->getOutputData("encoded").getSDR(); + VERBOSE << " SP (local) = " << sp_local->getOutputData("bottomUpOut").getSDR(); + VERBOSE << " SP (global) = " << sp_global->getOutputData("bottomUpOut").getSDR(); + VERBOSE << " TM output = " << tm->getOutputData("bottomUpOut").getSDR(); + VERBOSE << " ActiveCells = " << tm->getOutputData("activeCells").getSDR(); + VERBOSE << " winners = " << tm->getOutputData("predictedActiveCells").getSDR(); VERBOSE << " Anomaly = " << an << std::endl; // Save the data for plotting. , , \n From ce55d3aba5c1b4ade8a0e2701812c5f3bbae5bd6 Mon Sep 17 00:00:00 2001 From: David Keeney Date: Thu, 21 Nov 2019 09:42:05 -0800 Subject: [PATCH 03/10] commented out SP (local) --- src/examples/napi_sine/napi_sine.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/examples/napi_sine/napi_sine.cpp b/src/examples/napi_sine/napi_sine.cpp index 3bccf075a4..c86979e0d7 100644 --- a/src/examples/napi_sine/napi_sine.cpp +++ b/src/examples/napi_sine/napi_sine.cpp @@ -23,22 +23,22 @@ using namespace htm; -static bool verbose = true; +static bool verbose = false; #define VERBOSE if (verbose) std::cout << " " //this runs as an executable int main(int argc, char* argv[]) { - htm::UInt EPOCHS = 10; // number of iterations (calls to encoder/SP/TP compute() ) - const UInt DIM_INPUT = 50; // Width of encoder output - const UInt COLS = 100; // number of columns in SP, TP + htm::UInt EPOCHS = 5000; // number of iterations (calls to encoder/SP/TP compute() ) + const UInt DIM_INPUT = 1000; // Width of encoder output + const UInt COLS = 2048; // number of columns in SP, TP const UInt CELLS = 8; // cells per column in TP Random rnd(42); // uses fixed seed for deterministic output std::ofstream ofs; std::string encoder_params = "{size: " + std::to_string(DIM_INPUT) + ", activeBits: 4, radius: 0.5, seed: 2019 }"; - std::string sp_local_params = "{columnCount: " + std::to_string(COLS) + "}"; +// std::string sp_local_params = "{columnCount: " + std::to_string(COLS) + "}"; std::string sp_global_params = "{columnCount: " + std::to_string(COLS) + ", globalInhibition: true}"; std::string tm_params = "{activationThreshold: 9, cellsPerColumn: " + std::to_string(CELLS) + "}"; @@ -58,12 +58,12 @@ int main(int argc, char* argv[]) { // Declare the regions to use std::shared_ptr encoder = net.addRegion("encoder", "RDSERegion", encoder_params); - std::shared_ptr sp_local = net.addRegion("sp_local", "SPRegion", sp_local_params); +// std::shared_ptr sp_local = net.addRegion("sp_local", "SPRegion", sp_local_params); std::shared_ptr sp_global = net.addRegion("sp_global", "SPRegion", sp_global_params); std::shared_ptr tm = net.addRegion("tm", "TMRegion", tm_params); // Setup data flows between regions - net.link("encoder", "sp_local", "", "", "encoded", "bottomUpIn"); +// net.link("encoder", "sp_local", "", "", "encoded", "bottomUpIn"); net.link("encoder", "sp_global", "", "", "encoded", "bottomUpIn"); net.link("sp_global", "tm", "", "", "bottomUpOut", "bottomUpIn"); @@ -111,7 +111,7 @@ int main(int argc, char* argv[]) { VERBOSE << "Epoch = " << i << std::endl; VERBOSE << " Data = " << data << std::endl; VERBOSE << " Encoder out = " << encoder->getOutputData("encoded").getSDR(); - VERBOSE << " SP (local) = " << sp_local->getOutputData("bottomUpOut").getSDR(); +// VERBOSE << " SP (local) = " << sp_local->getOutputData("bottomUpOut").getSDR(); VERBOSE << " SP (global) = " << sp_global->getOutputData("bottomUpOut").getSDR(); VERBOSE << " TM output = " << tm->getOutputData("bottomUpOut").getSDR(); VERBOSE << " ActiveCells = " << tm->getOutputData("activeCells").getSDR(); @@ -124,6 +124,8 @@ int main(int argc, char* argv[]) { } if (ofs.is_open()) ofs.close(); + std::cout << "finished\n"; + } catch (Exception &e) { std::cerr << e.what(); From ca035fb47babbb92d7054df3a0fc0a0370008bb6 Mon Sep 17 00:00:00 2001 From: David Keeney Date: Fri, 22 Nov 2019 06:07:02 -0800 Subject: [PATCH 04/10] documentation changes --- src/examples/napi_sine/README.md | 29 ++++++++++---------- src/examples/napi_sine/napi_sine.cpp | 40 +++++++++++++--------------- 2 files changed, 32 insertions(+), 37 deletions(-) diff --git a/src/examples/napi_sine/README.md b/src/examples/napi_sine/README.md index f5d166e4c1..ca2a497bd6 100644 --- a/src/examples/napi_sine/README.md +++ b/src/examples/napi_sine/README.md @@ -2,26 +2,25 @@ The program `sine_napi` is an example of an app using the Network API tools available in the htm.core library. In this example we generate a sine wave with some noise as the input. This is passed to an encoder to turn that -into SDR format. This is passed to two instances of SpatialPooler (SP), -one is configured for local inhibition and one for global inhibition. +into a quantized format. This is passed to an instance of SpatialPooler (SP). -The output of the SP for global inhibition is passed on to the temporalMemory (TM) -algorithm. The output of the TM can be written to a file so that it can be plotted. +The output of the SP passed on to the temporalMemory (TM) algorithm. The +output of the TM can be written to a file so that it can be plotted. ``` /////////////////////////////////////////////////////////////// // - // .------------------. - // | encoder | - // data--->| (RDSERegion) | - // | | - // `------------------' - // | | - // .------------------. .------------------. - // | SP (local) | | SP (global) | - // | (SPRegion) | | (SPRegion) | - // | | | | - // `------------------' `------------------' + // .------------------. + // | encoder | + // data--->| (RDSERegion) | + // | | + // `------------------' + // | + // .------------------. + // | SP (global) | + // | (SPRegion) | + // | | + // `------------------' // | // .------------------. // | TM | diff --git a/src/examples/napi_sine/napi_sine.cpp b/src/examples/napi_sine/napi_sine.cpp index c86979e0d7..f00ac2ac70 100644 --- a/src/examples/napi_sine/napi_sine.cpp +++ b/src/examples/napi_sine/napi_sine.cpp @@ -38,13 +38,12 @@ int main(int argc, char* argv[]) { std::ofstream ofs; std::string encoder_params = "{size: " + std::to_string(DIM_INPUT) + ", activeBits: 4, radius: 0.5, seed: 2019 }"; -// std::string sp_local_params = "{columnCount: " + std::to_string(COLS) + "}"; std::string sp_global_params = "{columnCount: " + std::to_string(COLS) + ", globalInhibition: true}"; std::string tm_params = "{activationThreshold: 9, cellsPerColumn: " + std::to_string(CELLS) + "}"; // Runtime arguments: napi_sine [epochs [filename]] if(argc >= 2) { - EPOCHS = std::stoi(argv[1]); // number of iterations (default 500) + EPOCHS = std::stoi(argv[1]); // number of iterations (default 5000) } if (argc >= 3) { ofs.open(argv[2], std::ios::out); // output filename (for plotting) @@ -58,12 +57,10 @@ int main(int argc, char* argv[]) { // Declare the regions to use std::shared_ptr encoder = net.addRegion("encoder", "RDSERegion", encoder_params); -// std::shared_ptr sp_local = net.addRegion("sp_local", "SPRegion", sp_local_params); std::shared_ptr sp_global = net.addRegion("sp_global", "SPRegion", sp_global_params); std::shared_ptr tm = net.addRegion("tm", "TMRegion", tm_params); // Setup data flows between regions -// net.link("encoder", "sp_local", "", "", "encoded", "bottomUpIn"); net.link("encoder", "sp_global", "", "", "encoded", "bottomUpIn"); net.link("sp_global", "tm", "", "", "bottomUpOut", "bottomUpIn"); @@ -71,23 +68,23 @@ int main(int argc, char* argv[]) { /////////////////////////////////////////////////////////////// // - // .------------------. - // | encoder | - // data--->| (RDSERegion) | - // | | - // `------------------' - // | | - // .------------------. .------------------. - // | sp_local | | sp_global | - // | (SPRegion) | | (SPRegion) | - // | | | | - // `------------------' `------------------' - // | - // .------------------. - // | tm | - // | (TMRegion) | - // | | - // `------------------' + // .----------------. + // | encoder | + // data--->| (RDSERegion) | + // | | + // `-----------------' + // | + // .-----------------. + // | sp_global | + // | (SPRegion) | + // | | + // `-----------------' + // | + // .-----------------. + // | tm | + // | (TMRegion) | + // | | + // `-----------------' // ////////////////////////////////////////////////////////////////// @@ -111,7 +108,6 @@ int main(int argc, char* argv[]) { VERBOSE << "Epoch = " << i << std::endl; VERBOSE << " Data = " << data << std::endl; VERBOSE << " Encoder out = " << encoder->getOutputData("encoded").getSDR(); -// VERBOSE << " SP (local) = " << sp_local->getOutputData("bottomUpOut").getSDR(); VERBOSE << " SP (global) = " << sp_global->getOutputData("bottomUpOut").getSDR(); VERBOSE << " TM output = " << tm->getOutputData("bottomUpOut").getSDR(); VERBOSE << " ActiveCells = " << tm->getOutputData("activeCells").getSDR(); From 76e0abb66a6408437d5b88ba297246d3933e6f6b Mon Sep 17 00:00:00 2001 From: David Keeney Date: Mon, 25 Nov 2019 14:32:22 -0800 Subject: [PATCH 05/10] napi_sine now is the same as HelloSPTP --- src/CMakeLists.txt | 1 + src/examples/hotgym/HelloSPTP.cpp | 16 +++--- src/examples/hotgym/HelloSPTP.hpp | 2 +- src/examples/napi_sine/napi_sine.cpp | 74 +++++++++++++++++++--------- src/htm/algorithms/SpatialPooler.hpp | 15 +++--- src/htm/regions/RDSERegion.cpp | 21 ++++++-- src/htm/regions/RDSERegion.hpp | 6 +++ src/htm/regions/SPRegion.cpp | 6 +-- src/htm/regions/TMRegion.cpp | 33 ++++++++----- 9 files changed, 115 insertions(+), 59 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b343845c59..4ca0259b75 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -417,6 +417,7 @@ install(TARGETS install(TARGETS ${src_executable_hotgym} + ${src_executable_napi_sine} ${src_executable_mnistsp} RUNTIME DESTINATION bin LIBRARY DESTINATION lib diff --git a/src/examples/hotgym/HelloSPTP.cpp b/src/examples/hotgym/HelloSPTP.cpp index 59582e6f1e..176e110c59 100644 --- a/src/examples/hotgym/HelloSPTP.cpp +++ b/src/examples/hotgym/HelloSPTP.cpp @@ -121,7 +121,7 @@ EPOCHS = 2; // make test faster in Debug input.addNoise(0.01f, rnd); //change 1% of the SDR for each iteration, this makes a random sequence, but seemingly stable tRng.stop(); - //SP (global x local) + //SP (global and local) if(useSPlocal) { tSPloc.start(); spLocal.compute(input, true, outSPlocal); @@ -154,7 +154,7 @@ EPOCHS = 2; // make test faster in Debug avgAnomOld_ = avgAnom10.getCurrentAvg(); //update } tAnLikelihood.start(); - anLikelihood.anomalyProbability(an); //FIXME AnLikelihood is 0.0, probably not working correctly + anLikely = anLikelihood.anomalyProbability(an); //FIXME AnLikelihood is 0.0, probably not working correctly tAnLikelihood.stop(); @@ -173,13 +173,14 @@ EPOCHS = 2; // make test faster in Debug << "\n"; // output values - cout << "Epoch = " << e << endl; + cout << "Epoch = " << e+1 << 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 <(avgAnom10.getCurrentAvg() * 10000.0f) == static_cast(goldAnAvg * 10000.0f)) << "Deterministic average anom score failed:" << avgAnom10.getCurrentAvg() << " should be: " << goldAnAvg; + std::cout << "outputs match\n"; } #endif diff --git a/src/examples/hotgym/HelloSPTP.hpp b/src/examples/hotgym/HelloSPTP.hpp index 1db974fa94..6332ce75ab 100644 --- a/src/examples/hotgym/HelloSPTP.hpp +++ b/src/examples/hotgym/HelloSPTP.hpp @@ -16,7 +16,7 @@ class BenchmarkHotgym { public: Real64 run( UInt EPOCHS = 5000, - bool useSPlocal=true, //can toggle which (long running) components are tested, default all + bool useSPlocal=false, //can toggle which (long running) components are tested, default all bool useSPglobal=true, bool useTM=true, const UInt COLS = 2048, // number of columns in SP, TP diff --git a/src/examples/napi_sine/napi_sine.cpp b/src/examples/napi_sine/napi_sine.cpp index f00ac2ac70..ecb8253a90 100644 --- a/src/examples/napi_sine/napi_sine.cpp +++ b/src/examples/napi_sine/napi_sine.cpp @@ -19,11 +19,13 @@ #include #include #include +#include "htm/utils/MovingAverage.hpp" +#include "htm/algorithms/AnomalyLikelihood.hpp" #include using namespace htm; -static bool verbose = false; +static bool verbose = true; #define VERBOSE if (verbose) std::cout << " " @@ -31,15 +33,19 @@ static bool verbose = false; int main(int argc, char* argv[]) { htm::UInt EPOCHS = 5000; // number of iterations (calls to encoder/SP/TP compute() ) +#ifndef NDEBUG + EPOCHS = 2; // make test faster in Debug +#endif + const UInt DIM_INPUT = 1000; // Width of encoder output const UInt COLS = 2048; // number of columns in SP, TP const UInt CELLS = 8; // cells per column in TP Random rnd(42); // uses fixed seed for deterministic output std::ofstream ofs; - std::string encoder_params = "{size: " + std::to_string(DIM_INPUT) + ", activeBits: 4, radius: 0.5, seed: 2019 }"; + std::string encoder_params = "{size: " + std::to_string(DIM_INPUT) + ", sparsity: 0.2, radius: 0.03, seed: 2019, noise: 0.01}"; std::string sp_global_params = "{columnCount: " + std::to_string(COLS) + ", globalInhibition: true}"; - std::string tm_params = "{activationThreshold: 9, cellsPerColumn: " + std::to_string(CELLS) + "}"; + std::string tm_params = "{cellsPerColumn: " + std::to_string(CELLS) + ", orColumnOutputs: true}"; // Runtime arguments: napi_sine [epochs [filename]] if(argc >= 2) { @@ -51,7 +57,7 @@ int main(int argc, char* argv[]) { try { - std::cout << "initializing\n"; + std::cout << "initializing. DIM_INPUT=" << DIM_INPUT << ", COLS=" << COLS << ", CELLS=" << CELLS << "\n"; Network net; @@ -66,6 +72,7 @@ int main(int argc, char* argv[]) { net.initialize(); + /////////////////////////////////////////////////////////////// // // .----------------. @@ -92,39 +99,60 @@ int main(int argc, char* argv[]) { // enable this to see a trace as it executes //net.setLogLevel(LogLevel::LogLevel_Verbose); - std::cout << "Running: \n"; + std::cout << "Running: " << EPOCHS << " Iterations.\n "; + + float anLikely = 0.0f; + MovingAverage avgAnomaly(1000); + AnomalyLikelihood anLikelihood; + // RUN - for (size_t i = 0; i < EPOCHS; i++) { + float x = 0.00f; + for (size_t e = 0; e < EPOCHS; e++) { // genarate some data to send to the encoder - // -- A sin wave, one degree rotation per iteration, 1% noise added - double data = std::sin(i * (3.1415 / 180)) + (double)rnd.realRange(-0.01f, +0.1f); + + // -- A sine wave, one degree rotation per iteration (an alternate function) + //double data = std::sin(i * (3.1415 / 180)); + + // -- sine wave, 0.01 radians per iteration (Note: first iteration is for x=0.01, not 0) + x += 0.01f; // step size for fn(x) + double data = std::sin(x); encoder->setParameterReal64("sensedValue", data); // feed data into RDSE encoder for this iteration. // Execute an iteration. net.run(1); - // output values float an = ((float *)tm->getOutputData("anomaly").getBuffer())[0]; - VERBOSE << "Epoch = " << i << std::endl; - VERBOSE << " Data = " << data << std::endl; - VERBOSE << " Encoder out = " << encoder->getOutputData("encoded").getSDR(); - VERBOSE << " SP (global) = " << sp_global->getOutputData("bottomUpOut").getSDR(); - VERBOSE << " TM output = " << tm->getOutputData("bottomUpOut").getSDR(); - VERBOSE << " ActiveCells = " << tm->getOutputData("activeCells").getSDR(); - VERBOSE << " winners = " << tm->getOutputData("predictedActiveCells").getSDR(); - VERBOSE << " Anomaly = " << an << std::endl; - - // Save the data for plotting. , , \n - if (ofs.is_open()) - ofs << i << "," << data << "," << an << std::endl; + avgAnomaly.compute(an); + anLikely = anLikelihood.anomalyProbability(an); + + + // Save the data for plotting. , , , \n + if (ofs.is_open()) { + ofs << e << "," << data << "," << an << "," << anLikely << std::endl; + } + + if (e == EPOCHS - 1) + { + + // output values + float final_an = ((float *)tm->getOutputData("anomaly").getBuffer())[0]; + VERBOSE << "Result after " << e + 1 << " iterations.\n"; + VERBOSE << " Anomaly(avg) = " << avgAnomaly.getCurrentAvg() << std::endl; + VERBOSE << " Anomaly(Likelihood) = " << anLikely << endl; + VERBOSE << " Encoder out = " << encoder->getOutputData("encoded").getSDR(); + VERBOSE << " SP (global) = " << sp_global->getOutputData("bottomUpOut").getSDR(); + VERBOSE << " TM predictive = " << tm->getOutputData("predictiveCells").getSDR(); + } } if (ofs.is_open()) ofs.close(); + + std::cout << "finished\n"; - } catch (Exception &e) { - std::cerr << e.what(); + } catch (Exception &ex) { + std::cerr << ex.what(); if (ofs.is_open()) ofs.close(); return 1; diff --git a/src/htm/algorithms/SpatialPooler.hpp b/src/htm/algorithms/SpatialPooler.hpp index b27eed0226..1df58372a2 100644 --- a/src/htm/algorithms/SpatialPooler.hpp +++ b/src/htm/algorithms/SpatialPooler.hpp @@ -66,17 +66,18 @@ class SpatialPooler : public Serializable SpatialPooler(); SpatialPooler(const vector inputDimensions, const vector columnDimensions, - UInt potentialRadius = 16u, Real potentialPct = 0.5f, - bool globalInhibition = true, + UInt potentialRadius = 16u, + Real potentialPct = 0.5f, + bool globalInhibition = false, Real localAreaDensity = 0.05f, //5% - UInt stimulusThreshold = 0u, + UInt stimulusThreshold = 0u, Real synPermInactiveDec = 0.008f, - Real synPermActiveInc = 0.05f, + Real synPermActiveInc = 0.05f, Real synPermConnected = 0.1f, - Real minPctOverlapDutyCycles = 0.001f, - UInt dutyCyclePeriod = 1000u, + Real minPctOverlapDutyCycles = 0.001f, + UInt dutyCyclePeriod = 1000u, Real boostStrength = 0.0f, - Int seed = 1, + Int seed = 1, UInt spVerbosity = 0u, bool wrapAround = true); diff --git a/src/htm/regions/RDSERegion.cpp b/src/htm/regions/RDSERegion.cpp index 34e8e617cc..fa8532f7b7 100644 --- a/src/htm/regions/RDSERegion.cpp +++ b/src/htm/regions/RDSERegion.cpp @@ -28,6 +28,7 @@ #include #include #include +#include "htm/utils/Random.hpp" #include #include @@ -47,18 +48,23 @@ namespace htm { resolution: {type: Real32, default: "0.0"}, category: {type: Bool, default: "false"}, seed: {type: UInt32, default: "0"}, - sensedValue: {type: Real64, default: "0.0", access: ReadWrite }}, + noise: {description: "amount of noise to add to the output SDR. 0.01 is 1%", + type: Real32, default: "0.0"}, + sensedValue: {description: "The value to encode. Overriden by input 'values'.", + type: Real64, default: "0.0", access: ReadWrite }}, inputs: { - values: {type: Real64, count: 1, isDefaultInput: yes, isRegionLevel: yes}}, + values: {description: "Values to encode. Overrides sensedValue.", + type: Real64, count: 1, isDefaultInput: yes, isRegionLevel: yes}}, outputs: { - encoded: {type: SDR, count: 0, isDefaultOutput: yes, isRegionLevel: yes }}} )"); + encoded: {description: "Encoded bits. Not a true Sparse Data Representation.", + type: SDR, count: 0, isDefaultOutput: yes, isRegionLevel: yes }}} )"); return ns; } RDSERegion::RDSERegion(const ValueMap &par, Region *region) : RegionImpl(region) { - + rnd_ = Random(42); spec_.reset(createSpec()); ValueMap params = ValidateParameters(par, spec_.get()); @@ -73,7 +79,7 @@ RDSERegion::RDSERegion(const ValueMap &par, Region *region) : RegionImpl(region) encoder_ = std::make_shared(args); sensedValue_ = params.getScalarT("sensedValue"); - + noise_ = params.getScalarT("noise"); } RDSERegion::RDSERegion(ArWrapper &wrapper, Region *region) @@ -99,6 +105,11 @@ void RDSERegion::compute() { } SDR &output = getOutput("encoded")->getData().getSDR(); encoder_->encode((Real64)sensedValue_, output); + + // Add some noise. + // noise_ = 0.01 means change 1% of the SDR for each iteration, this makes a random sequence, but seemingly stable + if (noise_ != 0.0f) + output.addNoise(noise_, rnd_); } diff --git a/src/htm/regions/RDSERegion.hpp b/src/htm/regions/RDSERegion.hpp index c0b86a56f2..46c690fa4d 100644 --- a/src/htm/regions/RDSERegion.hpp +++ b/src/htm/regions/RDSERegion.hpp @@ -67,6 +67,8 @@ class RDSERegion : public RegionImpl, Serializable { template void save_ar(Archive& ar) const { ar(CEREAL_NVP(sensedValue_)); + ar(CEREAL_NVP(noise_)); + ar(CEREAL_NVP(rnd_)); ar(cereal::make_nvp("encoder", encoder_)); } // FOR Cereal Deserialization @@ -77,6 +79,8 @@ class RDSERegion : public RegionImpl, Serializable { template void load_ar(Archive& ar) { ar(CEREAL_NVP(sensedValue_)); + ar(CEREAL_NVP(noise_)); + ar(CEREAL_NVP(rnd_)); ar(cereal::make_nvp("encoder", encoder_)); setDimensions(encoder_->dimensions); } @@ -89,6 +93,8 @@ class RDSERegion : public RegionImpl, Serializable { private: Real64 sensedValue_; + Real32 noise_; + Random rnd_; std::shared_ptr encoder_; }; } // namespace htm diff --git a/src/htm/regions/SPRegion.cpp b/src/htm/regions/SPRegion.cpp index 18268b4fb0..e813c7bc37 100644 --- a/src/htm/regions/SPRegion.cpp +++ b/src/htm/regions/SPRegion.cpp @@ -43,7 +43,7 @@ SPRegion::SPRegion(const ValueMap &values, Region *region) // parameters out of the map and set aside so we can pass them to the SpatialPooler // algorithm when we create it during initialization(). args_.columnCount = values.getScalarT("columnCount", 0); - args_.potentialRadius = values.getScalarT("potentialRadius", 0); + args_.potentialRadius = values.getScalarT("potentialRadius", 16u); args_.potentialPct = values.getScalarT("potentialPct", 0.5); args_.globalInhibition = values.getScalarT("globalInhibition", false); args_.localAreaDensity = values.getScalarT("localAreaDensity", 0.05f); @@ -54,7 +54,7 @@ SPRegion::SPRegion(const ValueMap &values, Region *region) args_.minPctOverlapDutyCycles = values.getScalarT("minPctOverlapDutyCycles", 0.001f); args_.dutyCyclePeriod = values.getScalarT("dutyCyclePeriod", 1000); args_.boostStrength = values.getScalarT("boostStrength", 0.0f); - args_.seed = values.getScalarT("seed", -1); + args_.seed = values.getScalarT("seed", 1); args_.spVerbosity = values.getScalarT("spVerbosity", 0); args_.wrapAround = values.getScalarT("wrapAround", true); spatialImp_ = values.getString("spatialImp", ""); @@ -235,7 +235,7 @@ Spec *SPRegion::createSpec() { NTA_BasicType_UInt32, // type 1, // elementCount "", // constraints - "0", // defaultValue + "16", // defaultValue ParameterSpec::ReadWriteAccess)); // access ns->parameters.add( diff --git a/src/htm/regions/TMRegion.cpp b/src/htm/regions/TMRegion.cpp index cef3cd3e11..b5ddac84d6 100644 --- a/src/htm/regions/TMRegion.cpp +++ b/src/htm/regions/TMRegion.cpp @@ -43,18 +43,18 @@ TMRegion::TMRegion(const ValueMap ¶ms, Region *region) // algorithm when we create it during initialization(). memset((char *)&args_, 0, sizeof(args_)); args_.numberOfCols = params.getScalarT("numberOfCols", 0); // normally not passed in. - args_.cellsPerColumn = params.getScalarT("cellsPerColumn", 32); - args_.activationThreshold = params.getScalarT("activationThreshold", 13); + args_.cellsPerColumn = params.getScalarT("cellsPerColumn", 32u); + args_.activationThreshold = params.getScalarT("activationThreshold", 13u); args_.initialPermanence = params.getScalarT("initialPermanence", 0.21f); args_.connectedPermanence = params.getScalarT("connectedPermanence", 0.50f); - args_.minThreshold = params.getScalarT("minThreshold", 8); - args_.maxNewSynapseCount = params.getScalarT("maxNewSynapseCount", 20); + args_.minThreshold = params.getScalarT("minThreshold", 10u); + args_.maxNewSynapseCount = params.getScalarT("maxNewSynapseCount", 20u); args_.permanenceIncrement = params.getScalarT("permanenceIncrement", 0.10f); args_.permanenceDecrement = params.getScalarT("permanenceDecrement", 0.10f); args_.predictedSegmentDecrement = params.getScalarT("predictedSegmentDecrement", 0.0f); args_.seed = params.getScalarT("seed", 42); - args_.maxSegmentsPerCell = params.getScalarT("maxSegmentsPerCell", 255); - args_.maxSynapsesPerSegment = params.getScalarT("maxSynapsesPerSegment", 255); + args_.maxSegmentsPerCell = params.getScalarT("maxSegmentsPerCell", 255u); + args_.maxSynapsesPerSegment = params.getScalarT("maxSynapsesPerSegment", 255u); args_.checkInputs = params.getScalarT("checkInputs", true); args_.orColumnOutputs = params.getScalarT("orColumnOutputs", false); args_.externalPredictiveInputs = 0; // will be obtained from externalPredictiveInputs inputs dimensions. @@ -102,6 +102,8 @@ Dimensions TMRegion::askImplForOutputDimensions(const std::string &name) { if (name == "bottomUpOut" && args_.orColumnOutputs) { // It's size is numberOfCols. return region_dim; + } else if (name == "predictiveCells" && args_.orColumnOutputs) { + return region_dim; } else if (name == "bottomUpOut" || name == "activeCells" || name == "predictedActiveCells" || name == "predictiveCells") { // It's size is numberOfCols * args_.cellsPerColumn. @@ -234,12 +236,13 @@ void TMRegion::compute() { out = getOutput("bottomUpOut"); //call Network::setLogLevel(LogLevel::LogLevel_Verbose); // to output the NTA_DEBUG statements below - SDR& sdr = out->getData().getSDR(); - tm_->getActiveCells(sdr); //active cells - if (args_.orColumnOutputs) { //output as columns - sdr = tm_->cellsToColumns(sdr); - } - NTA_DEBUG << "compute "<< *out << std::endl; + SDR active({args_.numberOfCols, args_.cellsPerColumn}); + tm_->getActiveCells(active); //active cells + if (args_.orColumnOutputs) // output as columns + out->getData().getSDR() = tm_->cellsToColumns(active); + else + out->getData().getSDR() = active; + NTA_DEBUG << "compute " << *out << std::endl; out = getOutput("activeCells"); tm_->getActiveCells(out->getData().getSDR()); @@ -256,7 +259,11 @@ void TMRegion::compute() { NTA_DEBUG << "compute "<< *out << std::endl; out = getOutput("predictiveCells"); - out->getData().getSDR() = tm_->getPredictiveCells(); + SDR predictive = tm_->getPredictiveCells(); + if (args_.orColumnOutputs) // output as columns + out->getData().getSDR() = tm_->cellsToColumns(predictive); + else + out->getData().getSDR() = predictive; NTA_DEBUG << "compute " << *out << std::endl; } From ea5245b1219eca0ceb4933fca851951a2828261b Mon Sep 17 00:00:00 2001 From: David Keeney Date: Mon, 25 Nov 2019 14:48:33 -0800 Subject: [PATCH 06/10] got rid if the unused variable --- src/examples/napi_sine/napi_sine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/examples/napi_sine/napi_sine.cpp b/src/examples/napi_sine/napi_sine.cpp index ecb8253a90..bc66eb9463 100644 --- a/src/examples/napi_sine/napi_sine.cpp +++ b/src/examples/napi_sine/napi_sine.cpp @@ -135,8 +135,8 @@ int main(int argc, char* argv[]) { { // output values - float final_an = ((float *)tm->getOutputData("anomaly").getBuffer())[0]; VERBOSE << "Result after " << e + 1 << " iterations.\n"; + VERBOSE << " Anomaly = " << an << std::endl; VERBOSE << " Anomaly(avg) = " << avgAnomaly.getCurrentAvg() << std::endl; VERBOSE << " Anomaly(Likelihood) = " << anLikely << endl; VERBOSE << " Encoder out = " << encoder->getOutputData("encoded").getSDR(); From d296444afc4fd7b50542e7e9c723ec885fc79924 Mon Sep 17 00:00:00 2001 From: David Keeney Date: Mon, 25 Nov 2019 16:35:34 -0800 Subject: [PATCH 07/10] fixed unit tests (default parameters where changed). --- src/htm/regions/RDSERegion.cpp | 7 ++++++- src/htm/regions/RDSERegion.hpp | 3 ++- src/htm/regions/SPRegion.cpp | 2 +- src/htm/regions/TMRegion.cpp | 2 +- src/test/unit/engine/CppRegionTest.cpp | 4 +--- src/test/unit/regions/RDSERegionTest.cpp | 2 +- src/test/unit/regions/TMRegionTest.cpp | 6 ++---- 7 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/htm/regions/RDSERegion.cpp b/src/htm/regions/RDSERegion.cpp index fa8532f7b7..2d823cfa4c 100644 --- a/src/htm/regions/RDSERegion.cpp +++ b/src/htm/regions/RDSERegion.cpp @@ -49,7 +49,7 @@ namespace htm { category: {type: Bool, default: "false"}, seed: {type: UInt32, default: "0"}, noise: {description: "amount of noise to add to the output SDR. 0.01 is 1%", - type: Real32, default: "0.0"}, + type: Real32, default: "0.0", access: ReadWrite }, sensedValue: {description: "The value to encode. Overriden by input 'values'.", type: Real64, default: "0.0", access: ReadWrite }}, inputs: { @@ -117,6 +117,10 @@ void RDSERegion::setParameterReal64(const std::string &name, Int64 index, Real64 if (name == "sensedValue") sensedValue_ = value; else RegionImpl::setParameterReal64(name, index, value); } +void RDSERegion::setParameterReal32(const std::string &name, Int64 index, Real32 value) { + if (name == "noise") noise_ = value; + else RegionImpl::setParameterReal32(name, index, value); +} Real64 RDSERegion::getParameterReal64(const std::string &name, Int64 index) { if (name == "sensedValue") { return sensedValue_;} @@ -125,6 +129,7 @@ Real64 RDSERegion::getParameterReal64(const std::string &name, Int64 index) { Real32 RDSERegion::getParameterReal32(const std::string &name, Int64 index) { if (name == "resolution") return encoder_->parameters.resolution; + else if (name == "noise") return noise_; else if (name == "radius") return encoder_->parameters.radius; else if (name == "sparsity") return encoder_->parameters.sparsity; else return RegionImpl::getParameterReal32(name, index); diff --git a/src/htm/regions/RDSERegion.hpp b/src/htm/regions/RDSERegion.hpp index 46c690fa4d..57c8852fec 100644 --- a/src/htm/regions/RDSERegion.hpp +++ b/src/htm/regions/RDSERegion.hpp @@ -55,7 +55,8 @@ class RDSERegion : public RegionImpl, Serializable { virtual Real32 getParameterReal32(const std::string &name, Int64 index = -1) override; virtual UInt32 getParameterUInt32(const std::string &name, Int64 index = -1) override; virtual bool getParameterBool(const std::string &name, Int64 index = -1) override; - virtual void setParameterReal64(const std::string &name, Int64 index, Real64 value) override; + virtual void setParameterReal32(const std::string &name, Int64 index, Real32 value) override; + virtual void setParameterReal64(const std::string &name, Int64 index, Real64 value) override; virtual void initialize() override; void compute() override; diff --git a/src/htm/regions/SPRegion.cpp b/src/htm/regions/SPRegion.cpp index e813c7bc37..ab1d5dccd4 100644 --- a/src/htm/regions/SPRegion.cpp +++ b/src/htm/regions/SPRegion.cpp @@ -425,7 +425,7 @@ Spec *SPRegion::createSpec() { NTA_BasicType_Int32, // type 1, // elementCount "", // constraints - "-1", // defaultValue + "1", // defaultValue ParameterSpec::CreateAccess)); // access ns->parameters.add( diff --git a/src/htm/regions/TMRegion.cpp b/src/htm/regions/TMRegion.cpp index b5ddac84d6..38ce1e0ad6 100644 --- a/src/htm/regions/TMRegion.cpp +++ b/src/htm/regions/TMRegion.cpp @@ -343,7 +343,7 @@ Spec *TMRegion::createSpec() { NTA_BasicType_UInt32, // type 1, // elementCount "", // constraints - "8", // defaultValue + "10", // defaultValue ParameterSpec::CreateAccess)); // access ns->parameters.add( diff --git a/src/test/unit/engine/CppRegionTest.cpp b/src/test/unit/engine/CppRegionTest.cpp index 258070c5db..6b3c740586 100644 --- a/src/test/unit/engine/CppRegionTest.cpp +++ b/src/test/unit/engine/CppRegionTest.cpp @@ -152,9 +152,7 @@ TEST(CppRegionTest, testCppLinkingSDR) { << "Expected dimensions on the output to match dimensions on the buffer."; VERBOSE << r2OutputArray << "\n"; SDR exp({20u, 3u}); - exp.setSparse(SDR_sparse_t{ - 4, 21, 32, 46 - }); + exp.setSparse(SDR_sparse_t { 10, 18, 28, 38, 45, 57 }); EXPECT_EQ(r2OutputArray, exp.getDense()) << "got " << r2OutputArray; } diff --git a/src/test/unit/regions/RDSERegionTest.cpp b/src/test/unit/regions/RDSERegionTest.cpp index 7bd317405e..477ce40d2e 100644 --- a/src/test/unit/regions/RDSERegionTest.cpp +++ b/src/test/unit/regions/RDSERegionTest.cpp @@ -52,7 +52,7 @@ #define VERBOSE if(verbose)std::cerr << "[ ] " static bool verbose = false; // turn this on to print extra stuff for debugging the test. -const UInt EXPECTED_SPEC_COUNT = 8u; // The number of parameters expected in the RDSERegion Spec +const UInt EXPECTED_SPEC_COUNT = 9u; // The number of parameters expected in the RDSERegion Spec using namespace htm; namespace testing diff --git a/src/test/unit/regions/TMRegionTest.cpp b/src/test/unit/regions/TMRegionTest.cpp index 89ab022a27..13699afa24 100644 --- a/src/test/unit/regions/TMRegionTest.cpp +++ b/src/test/unit/regions/TMRegionTest.cpp @@ -213,7 +213,7 @@ TEST(TMRegionTest, testLinking) { std::shared_ptr region1 = net.addRegion("region1", "VectorFileSensor",parameters); std::shared_ptr region2 = net.addRegion("region2", "SPRegion", "{dim: [2,10]}"); std::shared_ptr region3 = net.addRegion("region3", "TMRegion", - "{activationThreshold: 9, cellsPerColumn: 5}"); + "{activationThreshold: 11, cellsPerColumn: 5}"); std::shared_ptr region4 = net.addRegion("region4", "VectorFileEffector", "{outputFile: '" + test_output_file + "'}"); @@ -316,9 +316,7 @@ TEST(TMRegionTest, testLinking) { << numberOfCols << " * " << cellsPerColumn; VERBOSE << " " << r3OutputArray << ")\n"; std::vector expected3outa = VectorHelpers::sparseToBinary( - { - 95, 96, 97, 98, 99 - }, (UInt32)r3OutputArray.getCount()); + {70, 71, 72, 73, 74 }, (UInt32)r3OutputArray.getCount()); EXPECT_EQ(r3OutputArray, expected3outa) << r3OutputArray; From 83cf73ab79e09fbd6cdc500c1ace4e6eafdf9e4c Mon Sep 17 00:00:00 2001 From: David Keeney Date: Tue, 26 Nov 2019 05:46:16 -0800 Subject: [PATCH 08/10] GlobalInibition should be the default for SP --- src/htm/algorithms/SpatialPooler.hpp | 2 +- src/htm/regions/SPRegion.cpp | 4 ++-- src/test/unit/engine/CppRegionTest.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/htm/algorithms/SpatialPooler.hpp b/src/htm/algorithms/SpatialPooler.hpp index 1df58372a2..04f29a036d 100644 --- a/src/htm/algorithms/SpatialPooler.hpp +++ b/src/htm/algorithms/SpatialPooler.hpp @@ -68,7 +68,7 @@ class SpatialPooler : public Serializable SpatialPooler(const vector inputDimensions, const vector columnDimensions, UInt potentialRadius = 16u, Real potentialPct = 0.5f, - bool globalInhibition = false, + bool globalInhibition = true, Real localAreaDensity = 0.05f, //5% UInt stimulusThreshold = 0u, Real synPermInactiveDec = 0.008f, diff --git a/src/htm/regions/SPRegion.cpp b/src/htm/regions/SPRegion.cpp index ab1d5dccd4..7efaa434b2 100644 --- a/src/htm/regions/SPRegion.cpp +++ b/src/htm/regions/SPRegion.cpp @@ -45,7 +45,7 @@ SPRegion::SPRegion(const ValueMap &values, Region *region) args_.columnCount = values.getScalarT("columnCount", 0); args_.potentialRadius = values.getScalarT("potentialRadius", 16u); args_.potentialPct = values.getScalarT("potentialPct", 0.5); - args_.globalInhibition = values.getScalarT("globalInhibition", false); + args_.globalInhibition = values.getScalarT("globalInhibition", true); args_.localAreaDensity = values.getScalarT("localAreaDensity", 0.05f); args_.stimulusThreshold = values.getScalarT("stimulusThreshold", 0); args_.synPermInactiveDec = values.getScalarT("synPermInactiveDec", 0.008f); @@ -274,7 +274,7 @@ Spec *SPRegion::createSpec() { NTA_BasicType_Bool, // type 1, // elementCount "bool", // constraints - "false", // defaultValue + "true", // defaultValue ParameterSpec::ReadWriteAccess)); // access ns->parameters.add( diff --git a/src/test/unit/engine/CppRegionTest.cpp b/src/test/unit/engine/CppRegionTest.cpp index 6b3c740586..ad818ea6e3 100644 --- a/src/test/unit/engine/CppRegionTest.cpp +++ b/src/test/unit/engine/CppRegionTest.cpp @@ -152,7 +152,7 @@ TEST(CppRegionTest, testCppLinkingSDR) { << "Expected dimensions on the output to match dimensions on the buffer."; VERBOSE << r2OutputArray << "\n"; SDR exp({20u, 3u}); - exp.setSparse(SDR_sparse_t { 10, 18, 28, 38, 45, 57 }); + exp.setSparse(SDR_sparse_t{10, 38, 57}); EXPECT_EQ(r2OutputArray, exp.getDense()) << "got " << r2OutputArray; } From df86af2f5da222a5763cb641b4b19f5ba7151644 Mon Sep 17 00:00:00 2001 From: David Keeney Date: Tue, 26 Nov 2019 06:20:17 -0800 Subject: [PATCH 09/10] corrected .py tests resulting from change in defaults --- bindings/py/tests/regions/network_test.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/bindings/py/tests/regions/network_test.py b/bindings/py/tests/regions/network_test.py index d91b62671f..534d8b1867 100644 --- a/bindings/py/tests/regions/network_test.py +++ b/bindings/py/tests/regions/network_test.py @@ -32,8 +32,9 @@ TEST_DATA = [0,1,2,3,4] EXPECTED_RESULT1 = [ 4, 5 ] -EXPECTED_RESULT2 = [ 4, 11, 28, 42, 43, 87, 89, 93, 110, 127, 132, 137, 149, 187, 193] -EXPECTED_RESULT3 = [ 134, 371, 924, 1358, 1386, 2791, 2876, 2996, 3526, 4089, 4242, 4406, 4778, 5994, 6199] +#EXPECTED_RESULT2 = [ 4, 11, 28, 42, 43, 87, 89, 93, 110, 127, 132, 137, 149, 187, 193] +EXPECTED_RESULT2 = [ 16, 32, 44, 81, 104, 109, 114, 166, 197, 198 ] +EXPECTED_RESULT3 = [ 518, 1043, 1436, 2606, 3338, 3495, 3676, 5332, 6310, 6361 ] class LinkRegion(PyRegion): @@ -312,12 +313,13 @@ def testBuiltInRegions(self): sp_output = sp.getOutputArray("bottomUpOut") sdr = sp_output.getSDR() + #print(sdr) self.assertTrue(np.array_equal(sdr.sparse, EXPECTED_RESULT2)) tm_output = tm.getOutputArray("predictedActiveCells") sdr = tm_output.getSDR() - print(sdr.sparse) - print(EXPECTED_RESULT3) + #print(sdr) + #print(EXPECTED_RESULT3) self.assertTrue(np.array_equal(sdr.sparse, EXPECTED_RESULT3)) def testExecuteCommand1(self): From b162f834f22c10c8fe98adbd36d39246968c16ed Mon Sep 17 00:00:00 2001 From: David Keeney Date: Wed, 27 Nov 2019 06:47:48 -0800 Subject: [PATCH 10/10] requested fixes --- src/examples/hotgym/HelloSPTP.cpp | 2 +- src/examples/hotgym/HelloSPTP.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/examples/hotgym/HelloSPTP.cpp b/src/examples/hotgym/HelloSPTP.cpp index 176e110c59..8a0b153a3e 100644 --- a/src/examples/hotgym/HelloSPTP.cpp +++ b/src/examples/hotgym/HelloSPTP.cpp @@ -154,7 +154,7 @@ EPOCHS = 2; // make test faster in Debug avgAnomOld_ = avgAnom10.getCurrentAvg(); //update } tAnLikelihood.start(); - anLikely = anLikelihood.anomalyProbability(an); //FIXME AnLikelihood is 0.0, probably not working correctly + anLikely = anLikelihood.anomalyProbability(an); tAnLikelihood.stop(); diff --git a/src/examples/hotgym/HelloSPTP.hpp b/src/examples/hotgym/HelloSPTP.hpp index 6332ce75ab..1db974fa94 100644 --- a/src/examples/hotgym/HelloSPTP.hpp +++ b/src/examples/hotgym/HelloSPTP.hpp @@ -16,7 +16,7 @@ class BenchmarkHotgym { public: Real64 run( UInt EPOCHS = 5000, - bool useSPlocal=false, //can toggle which (long running) components are tested, default all + bool useSPlocal=true, //can toggle which (long running) components are tested, default all bool useSPglobal=true, bool useTM=true, const UInt COLS = 2048, // number of columns in SP, TP