def __init__(self, numColumns, L2Params, L4Params, L6aParams, repeat, logCalls=False): """ Create a network consisting of multiple columns. Each column contains one L2, one L4 and one L6a layers. In addition all the L2 columns are fully connected to each other through their lateral inputs. :param numColumns: Number of columns to create :type numColumns: int :param L2Params: constructor parameters for :class:`ColumnPoolerRegion` :type L2Params: dict :param L4Params: constructor parameters for :class:`ApicalTMPairRegion` :type L4Params: dict :param L6aParams: constructor parameters for :class:`GridCellLocationRegion` :type L6aParams: dict :param repeat: Number of times each pair should be seen to be learned :type repeat: int :param logCalls: If true, calls to main functions will be logged internally. The log can then be saved with saveLogs(). This allows us to recreate the complete network behavior using rerunExperimentFromLogfile which is very useful for debugging. :type logCalls: bool """ # Handle logging - this has to be done first self.logCalls = logCalls self.numColumns = numColumns self.repeat = repeat network = Network() self.network = createMultipleL246aLocationColumn(network=network, numberOfColumns=self.numColumns, L2Params=L2Params, L4Params=L4Params, L6aParams=L6aParams) network.initialize() self.sensorInput = [] self.motorInput = [] self.L2Regions = [] self.L4Regions = [] self.L6aRegions = [] for i in range(self.numColumns): col = str(i) self.sensorInput.append(network.getRegion("sensorInput_" + col)) self.motorInput.append(network.getRegion("motorInput_" + col)) self.L2Regions.append(network.getRegion("L2_" + col)) self.L4Regions.append(network.getRegion("L4_" + col)) self.L6aRegions.append(network.getRegion("L6a_" + col)) if L6aParams is not None and "dimensions" in L6aParams: self.dimensions = L6aParams["dimensions"] else: self.dimensions = 2 self.sdrSize = L2Params["sdrSize"] # will be populated during training self.learnedObjects = {}
def testRun(self): """ A simple NetworkAPI example with three regions. /////////////////////////////////////////////////////////////// // // .------------------. // | encoder | // |(RDSEEncoderRegion)|<------ inital input // | | (INPUT.begin) // `-------------------' // | --------------. sp.bottomUpIn // |/ | // .-----------------. | // | sp | | // | (SPRegion) | | // | | | // `-----------------' | // | ^ // .-----------------. | // | tm | | // | (TMRegion) |-----' (tm.bottomUpOut) // | | // `-----------------' // ////////////////////////////////////////////////////////////////// """ """ Creating network instance. """ config = """ {network: [ {addRegion: {name: "encoder", type: "RDSEEncoderRegion", params: {size: 1000, sparsity: 0.2, radius: 0.03, seed: 2019, noise: 0.01}, phase: [1]}}, {addRegion: {name: "sp", type: "SPRegion", params: {columnCount: 1000, globalInhibition: true}, phase: [2]}}, {addRegion: {name: "tm", type: "TMRegion", params: {cellsPerColumn: 8, orColumnOutputs: true}, phase: [2]}}, {addLink: {src: "INPUT.begin", dest: "encoder.values", dim: [1]}}, {addLink: {src: "encoder.encoded", dest: "sp.bottomUpIn", mode: "overwrite"}}, {addLink: {src: "sp.bottomUpOut", dest: "tm.bottomUpIn"}}, {addLink: {src: "tm.bottomUpOut", dest: "sp.bottomUpIn"}} ]}""" net = Network() net.configure(config) net.initialize() # for debugging: print(net.getExecutionMap()) """ Force initial data. """ net.setInputData("begin", np.array([10])) """ Execute encoder once, the loop (sp and tm) 4 times """ net.run(1, [1]) # execute initial entry (phase 1) net.run(4, [2]) # execute loop 4 times (phase 2) # Here is how you access the buffers sp_input_buffer = np.array(net.getRegion('sp').getInputArray('bottomUpIn')) tn_output_buffer = np.array(net.getRegion('tm').getOutputArray('bottomUpOut')) self.assertEqual(sp_input_buffer.size, tn_output_buffer.size)
def _create_network(self, L4Params, L6aParams): """ Constructor. """ network = Network() # Create network network = createL4L6aLocationColumn(network=network, L4Params=L4Params, L6aParams=L6aParams, inverseReadoutResolution=None, baselineCellsPerAxis=6, suffix="") network.initialize() return network
def testCreateL4L6aLocationColumn(self): """ Test 'createL4L6aLocationColumn' by inferring a set of hand crafted objects """ scale = [] orientation = [] # Initialize L6a location region with 5 modules varying scale by sqrt(2) and # 4 different random orientations for each scale for i in range(5): for _ in range(4): angle = np.radians(random.gauss(7.5, 7.5)) orientation.append(random.choice([angle, -angle])) scale.append(10.0 * (math.sqrt(2)**i)) net = Network() createL4L6aLocationColumn(net, L4Params={ "columnCount": NUM_OF_COLUMNS, "cellsPerColumn": CELLS_PER_COLUMN, "activationThreshold": 15, "minThreshold": 15, "initialPermanence": 1.0, "implementation": "ApicalTiebreak", "maxSynapsesPerSegment": -1 }, L6aParams={ "moduleCount": len(scale), "scale": scale, "orientation": orientation, "anchorInputSize": NUM_OF_CELLS, "activationThreshold": 8, "initialPermanence": 1.0, "connectedPermanence": 0.5, "learningThreshold": 8, "sampleSize": 10, "permanenceIncrement": 0.1, "permanenceDecrement": 0.0, "bumpOverlapMethod": "probabilistic" }, inverseReadoutResolution=8) net.initialize() L6a = net.getRegion('L6a') sensor = net.getRegion('sensorInput') motor = net.getRegion('motorInput') # Keeps a list of learned objects learnedRepresentations = defaultdict(list) # Learn Objects self._setLearning(net, True) for objectDescription in OBJECTS: reset = True previousLocation = None L6a.executeCommand("activateRandomLocation") for iFeature, feature in enumerate(objectDescription["features"]): # Move the sensor to the center of the object locationOnObject = np.array([ feature["top"] + feature["height"] / 2., feature["left"] + feature["width"] / 2. ]) # Calculate displacement from previous location if previousLocation is not None: motor.executeCommand( 'addDataToQueue', list(locationOnObject - previousLocation)) else: motor.executeCommand('addDataToQueue', [0, 0]) previousLocation = locationOnObject # Sense feature at location sensor.executeCommand('addDataToQueue', FEATURE_ACTIVE_COLUMNS[feature["name"]], reset, 0) net.run(1) reset = False # Save learned representations representation = L6a.getOutputArray("sensoryAssociatedCells") representation = np.array(representation).nonzero()[0] learnedRepresentations[(objectDescription["name"], iFeature)] = representation # Infer objects self._setLearning(net, False) for objectDescription in OBJECTS: reset = True previousLocation = None inferred = False features = objectDescription["features"] touchSequence = list(range(len(features))) random.shuffle(touchSequence) for iFeature in touchSequence: feature = features[iFeature] # Move the sensor to the center of the object locationOnObject = np.array([ feature["top"] + feature["height"] / 2., feature["left"] + feature["width"] / 2. ]) # Calculate displacement from previous location if previousLocation is not None: motor.executeCommand('addDataToQueue', locationOnObject - previousLocation) else: motor.executeCommand('addDataToQueue', [0, 0]) previousLocation = locationOnObject # Sense feature at location sensor.executeCommand('addDataToQueue', FEATURE_ACTIVE_COLUMNS[feature["name"]], reset, 0) net.run(1) reset = False representation = L6a.getOutputArray("sensoryAssociatedCells") representation = np.array(representation).nonzero()[0] target_representations = set( learnedRepresentations[(objectDescription["name"], iFeature)]) inferred = (set(representation) <= target_representations) if inferred: break self.assertTrue(inferred)
def _createNetwork(inverseReadoutResolution, anchorInputSize, dualPhase=False): """ Create a simple network connecting sensor and motor inputs to the location region. Use :meth:`RawSensor.addDataToQueue` to add sensor input and growth candidates. Use :meth:`RawValues.addDataToQueue` to add motor input. :: +----------+ [ sensor* ] --> | | --> [ activeCells ] [ candidates* ] --> | location | --> [ learnableCells ] [ motor ] --> | | --> [ sensoryAssociatedCells ] +----------+ :param inverseReadoutResolution: Specifies the diameter of the circle of phases in the rhombus encoded by a bump. :type inverseReadoutResolution: int :type anchorInputSize: int :param anchorInputSize: The number of input bits in the anchor input. .. note:: (*) This function will only add the 'sensor' and 'candidates' regions when 'anchorInputSize' is greater than zero. This is useful if you would like to compute locations ignoring sensor input .. seealso:: - :py:func:`htmresearch.frameworks.location.path_integration_union_narrowing.createRatModuleFromReadoutResolution` """ net = Network() # Create simple region to pass motor commands as displacement vectors (dx, dy) net.addRegion("motor", "py.RawValues", json.dumps({"outputWidth": 2})) if anchorInputSize > 0: # Create simple region to pass growth candidates net.addRegion("candidates", "py.RawSensor", json.dumps({"outputWidth": anchorInputSize})) # Create simple region to pass sensor input net.addRegion("sensor", "py.RawSensor", json.dumps({"outputWidth": anchorInputSize})) # Initialize region with 5 modules varying scale by sqrt(2) and 4 different # random orientations for each scale scale = [] orientation = [] for i in range(5): for _ in range(4): angle = np.radians(random.gauss(7.5, 7.5)) orientation.append(random.choice([angle, -angle])) scale.append(10.0 * (math.sqrt(2)**i)) # Create location region params = computeRatModuleParametersFromReadoutResolution( inverseReadoutResolution) params.update({ "moduleCount": len(scale), "scale": scale, "orientation": orientation, "anchorInputSize": anchorInputSize, "activationThreshold": 8, "initialPermanence": 1.0, "connectedPermanence": 0.5, "learningThreshold": 8, "sampleSize": 10, "permanenceIncrement": 0.1, "permanenceDecrement": 0.0, "dualPhase": dualPhase, "bumpOverlapMethod": "probabilistic" }) net.addRegion("location", "py.GridCellLocationRegion", json.dumps(params)) if anchorInputSize > 0: # Link sensor net.link("sensor", "location", "UniformLink", "", srcOutput="dataOut", destInput="anchorInput") net.link("sensor", "location", "UniformLink", "", srcOutput="resetOut", destInput="resetIn") net.link("candidates", "location", "UniformLink", "", srcOutput="dataOut", destInput="anchorGrowthCandidates") # Link motor input net.link("motor", "location", "UniformLink", "", srcOutput="dataOut", destInput="displacement") # Initialize network objects net.initialize() return net
def main(parameters=default_parameters, argv=None, verbose=True): if verbose: import pprint print("Parameters:") pprint.pprint(parameters, indent=4) print("") # Read the input file. records = [] with open(_INPUT_FILE_PATH, "r") as fin: reader = csv.reader(fin) headers = next(reader) next(reader) next(reader) for record in reader: records.append(record) net = Network() # Make the Encoders. These will convert input data into binary representations. dateEncoderRegion = net.addRegion( 'dateEncoder', 'DateEncoderRegion', str( dict(timeOfDay_width=parameters["enc"]["time"]["timeOfDay"][0], timeOfDay_radius=parameters["enc"]["time"]["timeOfDay"][1], weekend_width=parameters["enc"]["time"]["weekend"]))) valueEncoderRegion = net.addRegion( 'valueEncoder', 'RDSEEncoderRegion', str( dict(size=parameters["enc"]["value"]["size"], sparsity=parameters["enc"]["value"]["sparsity"], resolution=parameters["enc"]["value"]["resolution"]))) # Make the HTM. SpatialPooler & TemporalMemory & associated tools. spParams = parameters["sp"] spRegion = net.addRegion( 'sp', 'SPRegion', str( dict( columnCount=spParams['columnCount'], potentialPct=spParams["potentialPct"], potentialRadius=0, # 0 is auto assign as inputWith globalInhibition=True, localAreaDensity=spParams["localAreaDensity"], synPermInactiveDec=spParams["synPermInactiveDec"], synPermActiveInc=spParams["synPermActiveInc"], synPermConnected=spParams["synPermConnected"], boostStrength=spParams["boostStrength"], wrapAround=True))) tmParams = parameters["tm"] tmRegion = net.addRegion( 'tm', 'TMRegion', str( dict(columnCount=spParams['columnCount'], cellsPerColumn=tmParams["cellsPerColumn"], activationThreshold=tmParams["activationThreshold"], initialPermanence=tmParams["initialPerm"], connectedPermanence=spParams["synPermConnected"], minThreshold=tmParams["minThreshold"], maxNewSynapseCount=tmParams["newSynapseCount"], permanenceIncrement=tmParams["permanenceInc"], permanenceDecrement=tmParams["permanenceDec"], predictedSegmentDecrement=0.0, maxSegmentsPerCell=tmParams["maxSegmentsPerCell"], maxSynapsesPerSegment=tmParams["maxSynapsesPerSegment"]))) net.link('dateEncoder', 'sp', '', '', 'encoded', 'bottomUpIn') net.link('valueEncoder', 'sp', '', '', 'encoded', 'bottomUpIn') net.link('sp', 'tm', '', '', 'bottomUpOut', 'bottomUpIn') net.initialize() # Iterate through every datum in the dataset, record the inputs & outputs. inputs = [] anomaly = [] for count, record in enumerate(records): # Convert date string into Python date object. dateString = datetime.datetime.strptime(record[0], "%m/%d/%y %H:%M") # Convert data value string into float. consumption = float(record[1]) inputs.append(consumption) # Call the encoders to create bit representations for each value. These are SDR objects. dateEncoderRegion.setParameterInt64('sensedTime', int(dateString.timestamp())) valueEncoderRegion.setParameterReal64('sensedValue', consumption) net.run(1) anomaly.append(np.array(tmRegion.getOutputArray("anomaly"))[0]) try: import matplotlib.pyplot as plt except: print("WARNING: failed to import matplotlib, plots cannot be shown.") return plt.title("Anomaly Score") plt.xlabel("Time") plt.ylabel("Power Consumption") inputs = np.array(inputs) / max(inputs) plt.plot( np.arange(len(inputs)), inputs, 'red', np.arange(len(inputs)), anomaly, 'blue', ) plt.legend(labels=('Input', 'Anomaly Score')) plt.show() return