Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Database region #860

Merged
merged 14 commits into from
Jul 9, 2020
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,9 @@ Community projects for working with HTM.
#### HTMPandaVis
This project aspires to create tool that helps **visualize HTM systems in 3D** by using opensource framework for 3D rendering https://www.panda3d.org/

NetworkAPI has region called "DatabaseRegion". This region can be used for generating SQLite file and later on read by PandaVis - DashVis feature,
to show interactive plots in web browser on localhost. See [napi_hello_database](https://github.com/htm-community/htm.core/tree/master/src/examples/napi_hello) for basic usage.

For more info, visit [repository of the project](https://github.com/htm-community/HTMpandaVis)
![pandaVis1](docs/images/pandaVis1.png)

Expand Down
24 changes: 23 additions & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,9 @@ set(regions_files
htm/regions/FileOutputRegion.cpp
htm/regions/FileOutputRegion.hpp
htm/regions/FileInputRegion.cpp
htm/regions/FileInputRegion.hpp
htm/regions/FileInputRegion.hpp
htm/regions/DatabaseRegion.cpp
htm/regions/DatabaseRegion.hpp
)

set(types_files
Expand Down Expand Up @@ -194,6 +196,7 @@ set(examples_files
examples/hello/HelloSPTP.cpp
examples/hello/HelloSPTP.hpp
examples/napi_hello/napi_hello.cpp
examples/napi_hello/napi_hello_database.cpp
examples/mnist/MNIST_SP.cpp
examples/rest/server_core.hpp
examples/rest/server.cpp
Expand Down Expand Up @@ -391,6 +394,24 @@ target_include_directories(${src_executable_napi_hello} PRIVATE
${EXTERNAL_INCLUDES}
)

#########################################################
## NetworkAPI version of hello with database

set(src_executable_napi_hello_database napi_hello_database)
add_executable(${src_executable_napi_hello_database} examples/napi_hello/napi_hello_database.cpp)
# link with the static library
target_link_libraries(${src_executable_napi_hello_database}
${INTERNAL_LINKER_FLAGS}
${core_library}
${COMMON_OS_LIBS}
)
target_compile_options( ${src_executable_napi_hello_database} PUBLIC ${INTERNAL_CXX_FLAGS})
target_compile_definitions(${src_executable_napi_hello_database} PRIVATE ${COMMON_COMPILER_DEFINITIONS})
target_include_directories(${src_executable_napi_hello_database} PRIVATE
${CORE_LIB_INCLUDES}
${EXTERNAL_INCLUDES}
)

#########################################################
## MNIST Spatial Pooler Example
#
Expand Down Expand Up @@ -454,6 +475,7 @@ install(TARGETS
install(TARGETS
${src_executable_hello}
${src_executable_napi_hello}
${src_executable_napi_hello_database}
${src_executable_mnistsp}
${src_executable_rest_server}
${src_executable_rest_client}
Expand Down
13 changes: 9 additions & 4 deletions src/examples/napi_hello/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,13 @@ output of the TM can be written to a file so that it can be plotted.
// |
// .------------------.
// | TM |
// | (TMRegion) |
// | (TMRegion) |----> CSV file(or SQLlite*)
// | |
// `------------------'
//
//////////////////////////////////////////////////////////////////
```
*\*Note: applies to napi_hello_database*

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.
<table>
Expand Down Expand Up @@ -57,13 +58,17 @@ Each "region" is a wrapper around an algorithm. This wrapper provides a uniform
<td>TemporalMemory (TM)</td>
</tr>
<tr>
<td>VectorFileSensor</td>
<td>FileInputRegion</td>
<td>for reading from a file</td>
</tr>
<tr>
<td>VectorFileEffector</td>
<td>FileOutputRegion</td>
<td>for writing to a file</td>
</tr>
<tr>
<td>DatabaseRegion</td>
<td>for writing to a SQLite3 database file</td>
</tr>
</tbody>
</table>

Expand All @@ -80,4 +85,4 @@ Each "region" is a wrapper around an algorithm. This wrapper provides a uniform


## 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...
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...
16 changes: 15 additions & 1 deletion src/examples/napi_hello/napi_hello.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,14 @@ int main(int argc, char* argv[]) {
std::string sp_global_params = "{columnCount: " + std::to_string(COLS) + ", globalInhibition: true}";
std::string tm_params = "{cellsPerColumn: " + std::to_string(CELLS) + ", orColumnOutputs: true}";


std::string output_file = "NapiOutputDir/Output.csv";


// make a place to put output data.
if (!Directory::exists("NapiOutputDir")) Directory::create("NapiOutputDir", false, true);
if (Path::exists(output_file)) Path::remove(output_file);

// Runtime arguments: napi_sine [epochs [filename]]
if(argc >= 2) {
EPOCHS = std::stoi(argv[1]); // number of iterations (default 5000)
Expand All @@ -65,10 +73,12 @@ int main(int argc, char* argv[]) {
std::shared_ptr<Region> encoder = net.addRegion("encoder", "RDSEEncoderRegion", encoder_params);
std::shared_ptr<Region> sp_global = net.addRegion("sp_global", "SPRegion", sp_global_params);
std::shared_ptr<Region> tm = net.addRegion("tm", "TMRegion", tm_params);
std::shared_ptr<Region> output = net.addRegion("output", "FileOutputRegion", "{outputFile: '"+ output_file + "'}");

// Setup data flows between regions
net.link("encoder", "sp_global", "", "", "encoded", "bottomUpIn");
net.link("sp_global", "tm", "", "", "bottomUpOut", "bottomUpIn");
net.link("tm", "output", "UniformLink", "", "bottomUpOut", "dataIn");
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: "UniformLink", or anything in this argument, is ignored. This is a hold-over from the NuPIC code.


net.initialize();

Expand All @@ -89,7 +99,7 @@ int main(int argc, char* argv[]) {
// |
// .-----------------.
// | tm |
// | (TMRegion) |
// | (TMRegion) |---->CSV file
// | |
// `-----------------'
//
Expand Down Expand Up @@ -147,6 +157,8 @@ int main(int argc, char* argv[]) {
if (ofs.is_open())
ofs.close();

// close output file
output->executeCommand({ "closeFile" });

std::cout << "finished\n";

Expand All @@ -158,6 +170,8 @@ int main(int argc, char* argv[]) {
return 1;
}



return 0;
}

179 changes: 179 additions & 0 deletions src/examples/napi_hello/napi_hello_database.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
/* ---------------------------------------------------------------------
* 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 <htm/engine/Network.hpp>
#include <htm/utils/Random.hpp>
#include <htm/utils/Log.hpp>
#include <htm/ntypes/Value.hpp>
#include <htm/utils/MovingAverage.hpp>
#include <htm/algorithms/AnomalyLikelihood.hpp>
#include <fstream>

using namespace htm;

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() )
#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) + ", 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 = "{cellsPerColumn: " + std::to_string(CELLS) + ", orColumnOutputs: true}";


std::string output_file = "NapiOutputDir/Output.db";


// make a place to put output data.
if (!Directory::exists("NapiOutputDir")) Directory::create("NapiOutputDir", false, true);
if (Path::exists(output_file)) Path::remove(output_file);

// Runtime arguments: napi_sine [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. DIM_INPUT=" << DIM_INPUT << ", COLS=" << COLS << ", CELLS=" << CELLS << "\n";

Network net;

// Declare the regions to use
std::shared_ptr<Region> encoder = net.addRegion("encoder", "RDSEEncoderRegion", encoder_params);
std::shared_ptr<Region> sp_global = net.addRegion("sp_global", "SPRegion", sp_global_params);
std::shared_ptr<Region> tm = net.addRegion("tm", "TMRegion", tm_params);
std::shared_ptr<Region> output = net.addRegion("output", "DatabaseRegion", "{outputFile: '"+ output_file + "'}");

// Setup data flows between regions
net.link("encoder", "sp_global", "", "", "encoded", "bottomUpIn");
net.link("sp_global", "tm", "", "", "bottomUpOut", "bottomUpIn");
net.link("tm", "output", "", "", "anomaly", "dataIn0");
net.link("encoder", "output", "", "", "bucket", "dataIn1");


net.initialize();


///////////////////////////////////////////////////////////////
//
// .------------------.
// | encoder |
// data--->|(RDSEEncoderRegion)|
// | |
// `-------------------'
// |
// .-----------------.
// | sp_global |
// | (SPRegion) |
// | |
// `-----------------'
// |
// .-----------------.
// | tm |
// | (TMRegion) |--->SQLite3
// | |
// `-----------------'
//
//////////////////////////////////////////////////////////////////


// enable this to see a trace as it executes
//net.setLogLevel(LogLevel::LogLevel_Verbose);

std::cout << "Running: " << EPOCHS << " Iterations.\n ";

float anLikely = 0.0f;
MovingAverage avgAnomaly(1000);
AnomalyLikelihood anLikelihood;

// RUN
float x = 0.00f;
for (size_t e = 0; e < EPOCHS; e++) {
// genarate some data to send to the encoder

// -- 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);

float an = ((float *)tm->getOutputData("anomaly").getBuffer())[0];
avgAnomaly.compute(an);
anLikely = anLikelihood.anomalyProbability(an);


// Save the data for plotting. <iteration>, <sin data>, <anomaly>, <likelyhood>\n
if (ofs.is_open()) {
ofs << e << "," << data << "," << an << "," << anLikely << std::endl;
}

if (e == EPOCHS - 1)
{

// output values
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();
VERBOSE << " SP (global) = " << sp_global->getOutputData("bottomUpOut").getSDR();
VERBOSE << " TM predictive = " << tm->getOutputData("predictiveCells").getSDR();
}
}
if (ofs.is_open())
ofs.close();

// close output file
output->executeCommand({ "closeFile" });

std::cout << "finished\n";


} catch (Exception &ex) {
std::cerr << ex.what();
if (ofs.is_open())
ofs.close();
return 1;
}



return 0;
}

2 changes: 2 additions & 0 deletions src/htm/engine/RegionImplFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include <htm/regions/RDSEEncoderRegion.hpp>
#include <htm/regions/FileOutputRegion.hpp>
#include <htm/regions/FileInputRegion.hpp>
#include <htm/regions/DatabaseRegion.hpp>
#include <htm/regions/SPRegion.hpp>
#include <htm/regions/TMRegion.hpp>
#include <htm/regions/ClassifierRegion.hpp>
Expand Down Expand Up @@ -95,6 +96,7 @@ RegionImplFactory &RegionImplFactory::getInstance() {
instance.addRegionType("TestNode", new RegisteredRegionImplCpp<TestNode>());
instance.addRegionType("FileOutputRegion", new RegisteredRegionImplCpp<FileOutputRegion>());
instance.addRegionType("FileInputRegion", new RegisteredRegionImplCpp<FileInputRegion>());
instance.addRegionType("DatabaseRegion", new RegisteredRegionImplCpp<DatabaseRegion>());
instance.addRegionType("SPRegion", new RegisteredRegionImplCpp<SPRegion>());
instance.addRegionType("TMRegion", new RegisteredRegionImplCpp<TMRegion>());
instance.addRegionType("ClassifierRegion", new RegisteredRegionImplCpp<ClassifierRegion>());
Expand Down
Loading