Table of ContentsPreviousNextIndex

Put your logo here!


3 Constructing an HTM Network

This chapter explains how you can use the Numenta Python APIs to create an untrained HTM Network and save that network to an HTM Network file.

Topics

HTM Programming Steps Overview

This section briefly discusses the complete development process to help you understand the relationship between your HTM Network's structure (encapsulated by a Network instance) and the RuntimeNetwork that is used during training and inference.

Figure 3 HTM Development Process Overview

Network Instance Creation Tasks

The rest of this chapter explains how you can create an untrained network (the Network object and all associated objects). Here's an overview of the steps:

Table 3: Overview of Network Creation Tasks
Step
Task
Discussed in
1
Create the empty HTM Network
2
Create and configure nodes, add them to the HTM Network
3
Create regions, add them to the HTM Network
4
Link network elements
5
Save the HTM Network to a file

Understanding HTM Network Components

HTM Networks are data-driven learning systems.

The untrained network has no inherent capability and cannot be used to perform inference. The untrained network is like a scaffold that describes the flow of data and other aspects of analysis at runtime. This scaffold information includes, for example, the number of nodes and levels, characteristics of the nodes, and how the nodes' inputs and outputs are connected.

Figure 5 shows a sample HTM Network, which consists of a number of different nodes. While the sample network shown below is small and highly symmetrical, an HTM Network can actually have an arbitrary number of levels and connections, and it does not need to be symmetrical.

Figure 4 Sample HTM Network

All the elements in Figure 4 together form an HTM Network. The HTM Network consists of nodes, links, and, optionally, regions.

Nodes

A node - sensor, effector, or learning node - is the basic unit of a Numenta HTM Network. Each node is implemented as a Python or C++ plugin to NuPIC. Numenta nodes are usually created and manipulated using classes in the Python NuPIC API, as discussed in Constructing an HTM Network.

The general node categories are:

Each node has a number of attributes:

Regions

A region is an array of nodes that have precisely the same parameters, including the same phase. The sample network in Figure 4 does not include a region, but most larger HTM Networks do include regions.

Figure 5 1-D region of four nodes (top) and 2-D region of 2x3 nodes (bottom).

Links

Links determine the flow of information in the HTM Network. You can specify links between individual nodes, or link arrays of nodes at once using a link policy. See Link Policies.

Creating the Network and Node Objects

You use the Network class to create the initial untrained networks. You can create a network and populate it by creating node objects, regions, or both. The untrained HTM Network describes the structure of an HTM Network similar to the way a database schema describes the structure of a database. Creating the untrained network using node objects consists of these steps, discussed with code fragments below:

1. Import the nupic.network Python package

2. Create an Empty Network

3. Create and Configure the Nodes

4. Add the Nodes to the Network Object

After you've completed these steps, you can link the different nodes, as discussed in Linking the Elements of the Network.

1 Import the nupic.network Python package

The nupic.network package contains all the classes you need for creating your network. For example:

from nupic.network import Network, CreateNode, Region, SimpleFanIn,\ 
   SimpleSensorLink, 

Here are some of the classes and functions from nupic.network:

Network
Container class. You can create an instance of Network, and then add the network elements (nodes or regions).
CreateNode 
Used to create nodes explicitly using the node class and its methods. See NuPIC Node Types on page 32 in Advanced NuPIC Programming for an overview of node types. See Affecting Learning Node Behavior With Node Parameters on page 42 in Advanced NuPIC Programming for an introduction to node parameters.
Region 
To create arrays of nodes based on a template, you use the Region class. See Creating Regions.
SimpleFanIn 
SimpleSensorLink 
In the simplest case, you link nodes by specifying output of the source node and the input of the target node. You can use link policies to link multiple nodes. For example, if you are connecting regions to each other or to nodes, you must specify a link policy.

For information about any of the classes, you can use pydoc, as discussed in Getting Node Help.

2 Create an Empty Network

After you've imported the appropriate classes, you can create an empty network to serve as container for network elements and links. For example:

myNet = Network() 
3 Create and Configure the Nodes

The CreateNode() function allows you to create and configure a node with one call.

For each node, you can specify a node type and all node parameters. Some parameters are required, as indicated in the online help. If you make a mistake, CreateNode() warns you immediately by throwing a Python exception.

The following code fragment creates a node using CreateNode() and specifies its parameters:

myNode = CreateNode (nodeType='Zeta1Node', 
   phase=1, 
   spatialPoolerAlgorithm='gaussian',  
   symmetricTime=True,  
   transitionMemory=4,  
   topNeighbors=3,  
   maxGroupSize=50, 
   temporalPoolerAlgorithm='sumProp',  
   maxDistance=0.05, 
   bottomUpOut=8) 
4 Add the Nodes to the Network Object

After you've created the node(s), you can add them to the network as follows:

myNet.addElement ("<unique_element_name>", myNode) 

Here,

For example:

myNode = CreateNode (nodeType='Zeta1Node', 
   phase=1, 
   spatialPoolerAlgorithm='gaussian',  
   symmetricTime=True,  
   transitionMemory=4,  
   topNeighbors=3,  
   maxGroupSize=50, 
   temporalPoolerAlgorithm='sumProp',  
   bottomUpOut=8,  
   maxDistance=0.05) 
myNet.addElement ("Level1Node", myNode) 
You must remember the name you assign in this call and use it later when linking nodes or regions.

Network.addElement() keeps a copy of the element added. Modifications to the original do not affect the copy inside the HTM Network. You should make all modifications, for example, to phase, output element counts, or parameters, before you call addElement().

Creating Regions

Creating a region involves a few simple steps.

1 Create a Node that Serves as the Template

Use CreateNode() to create a node template. Set all parameters as part of node creation.

myTemplateNode = CreateNode(nodeType = "Zeta1Node", ...) 
2 Create a Region Using the Template and Specifying the Dimensions

You create a 1-D region that consists of four nodes as follows:

myRegion = Region (4, myTemplateNode) 

You create a 2-D region of six nodes arranged in a grid with two rows and three columns (see Figure 5) as follows:

myRegion = Region ([2,3], myTemplateNode) 
3 Add the Region to the Network

Adding a region to an HTM Network is identical to adding a node to a network.

myNet.addElement("<unique_region_name>", myRegion) 

After you've completed these steps, you can link the region to other regions or to nodes, as discussed in Linking the Elements of the Network.

Node Names

All the node names for a 1-D region are <region_name>[<num>]

where <num> is a number between 0 and the number of nodes in the region, minus 1.

All the node names for a 2-D region are <region_name>[num,num]

where the two numbers are the indices into the region. Note that there is no space between the two numbers.

You can use node names when setting up more advanced links, or when analyzing individual nodes in a trained network.

Region Example

Figure 6, Regions represented by the Pictures example, shows an example of regions. The code fragment in Example 1, Using regions in the Pictures example, shows how the regions can be created.

Figure 6 Regions represented by the Pictures example

Linking the Elements of the Network

After you've added nodes to a Network, you must link the nodes together. Each node can have multiple named outputs and named inputs. Links connect from a source node and named output to a destination node and named input. See Links on page 36 in Advanced NuPIC Programming for an introduction to links.

You perform the linking in one of two ways.

   myNet.link ("<source_node_name>", "<output_name>","<dest_node_name>",\ 
      "<input_name>", ) 
 

If the nodes have only one input and output, you can omit the input or output name and the system defaults appropriately, as follows:

   myNet.link ("<source_node_name>", "<dest_node_name>")
   myNet.link ("<source_region_name", "<dest_region_name>", <link_policy> ) 
   myNet.link ("<source_node_name", "<dest_node_name>", <link_policy> ) 
 

Here, you use the constructor for a link policy, e.g. SimpleFanIn() as the third argument.

Link Policies

This section discusses the SimpleSensorLink and SimpleFanIn link policies.

Figure 7 SimpleSensorLink Link Policy.

For example, if the sensor output is an array of 64 elements, and the region consists of four nodes, the first 16 data values go to the first node, the next 16 data values go to the second node, and so on.

To link a sensor with a 1-D region, use code like the following:

   myNet.link ("<source_node_name", "<dest_region_name>", SimpleSensorLink () ) 
 

To link a sensor with a 2-D region, use code like the following:

   myNet.link ("<source_node_name", "<dest_region_name>",                  SimpleSensorLink (sensor_dimenson) )

sensor_dimension is a list, e.g. [32, 32] if the sensor outputs 1024 elements that should be treated as a 32x32 array.

If necessary, you can specify the additional arguments for the link policy by calling the constructor, which has this prototype:

   SimpleSensorLink (list_of_sensor_dimensions,                      output_name, input_name)

Figure 8 SimpleFanIn Link Policy

   myNet.link ("<source_region_name", "<dest_region_name>", SimpleFanIn () ) 

Overlapping Connections

There are variants of SimpleSensorLink and SimpleFanin that allow overlapping connections.

OverlapFanIn

OverlapFanIn allows you to link nodes at two levels using a specified overlap, for example:

link ("level1", "level2", OverlapFanIn ("bottomUpOut", [1], "bottomUpIn), 

The arguments to OverlapFanIn are, in order, the source output name, the overlap as a list, and the destination input name.

Figure 9 OverlapFanIn Example

The system calculates the fan-in using the source element (or region) dimension, destination element (or region) dimension, and overlap. The overlap, which is a list to allow for multi-dimensional HTM Networks, specifies the number of source nodes shared by any two adjacent destination nodes.

OverlapSensorLink

OverlapSensorLink allows you to divide a single sensor output array equally across the nodes of the destination region, for example:

link ("sensor", "level1", OverlapSensorLink ([18], "dataOut", [2], "bottomUpIn")) 

Figure 10 OverlapSensorLink Example

In this example, the sensor output array has 18 array elements, which are divided across four nodes. Each node receives the output of six array elements, with adjacent nodes getting the input from two shared elements each.

Creating and Linking Regions: The Pictures Example

The following code fragment comes from the Pictures example. It creates template nodes, regions, and link policies for each level. The net_construction example included with NuPIC contains many example scripts for creating HTM Networks.

Example 1 Using regions in the Pictures example

# Import modules from Numenta Tools 
from nupic.network import Network, CreateNode, Region 
from nupic.network import SimpleFanIn, SimpleSensorLink 
 
# Create the Numenta network object 
net = Network() 
 
# Create and add one input sensor to the network 
sensorNode = CreateNode('VectorFileSensor', phase=0, dataOut=1024) 
net.addElement("sensor", sensorNode) 
 
# Create Level 1  
L1Template = CreateNode(nodeType='Zeta1Node',  
  phase=1, 
  spatialPoolerAlgorithm='gaussian',      
  symmetricTime=False, 
  topNeighbors=2,                  
  transitionMemory=4, 
  maxGroupSize=50,                 
  temporalPoolerAlgorithm='sumProp',  
  bottomUpOut=1024,         
  maxDistance=0.1) 
 
net.addElement("level1", Region([8, 8], L1Template)) 
 
# Create Level 2 
L2Template = CreateNode(nodeType='Zeta1Node',  
  phase=2, 
  spatialPoolerAlgorithm='product',       
  symmetricTime=False, 
  transitionMemory=4,              
  topNeighbors=2, 
  maxGroupSize=50,                 
  temporalPoolerAlgorithm='sumProp',  
  bottomUpOut=48) 
 
net.addElement("level2", Region([4, 4], L2Template)) 
 
# Create Level 3 
L3Template = CreateNode('Zeta1TopNode',  
  phase=3, 
  categoriesOut=48,           
  mapperAlgorithm='sumProp') 
 
net.addElement("level3", Region(1, L3Template)) 
 
# Link all the levels 
net.link("sensor", "level1", SimpleSensorLink([32,32])) 
net.link("level1", "level2", SimpleFanIn("bottomUpOut", "bottomUpIn")) 
net.link("level2", "level3", SimpleFanIn("bottomUpOut", "bottomUpIn")) 
 
# Write out the file 
net.writeXML("SampleNet.xml") 

Saving the Network to a File

NuPIC allows you to save untrained and trained HTM Networks.

When you export a network to an HTM Network File on disk, the system creates an XML file that contains information on all the nodes and links in the HTM Network.

myNet.writeXML("<untrained_htm_network_filename>.xml")  

When you call writeXML(), the system saves the HTM Network to an XML file (extension .xml) using custom XML tags and attributes. HTM files can be quite large, so they can be zip-compressed by calling the command as follows:

myNet.writeXML("<untrained_htm_network_filename>.xml.gz")  

During training, testing, and debugging, the network file is loaded in the NRE, and a trained network file can be saved by the NRE. Trained network files use the same XML file format and can also be used with RuntimeNetwork. See Using the RuntimeNetwork Object to Perform Training.


Numenta
www.Numenta.com
Table of ContentsPreviousNextIndex