Skip to content

Commit

Permalink
Merge pull request #2617 from vitaly-krugl/move-model-selection-to-nupic
Browse files Browse the repository at this point in the history
Add cluster params selection module from numenta-apps htmegine
  • Loading branch information
vitaly-krugl committed Sep 30, 2015
2 parents c710feb + 997d4ca commit 37ac787
Show file tree
Hide file tree
Showing 5 changed files with 333 additions and 0 deletions.
20 changes: 20 additions & 0 deletions src/nupic/frameworks/opf/common_models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# ----------------------------------------------------------------------
# Numenta Platform for Intelligent Computing (NuPIC)
# Copyright (C) 2015, Numenta, Inc. Unless you have purchased from
# Numenta, Inc. a separate commercial license for this software code, the
# following terms and conditions apply:
#
# 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.
#
# http://numenta.org/licenses/
# ----------------------------------------------------------------------
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
{
"inferenceArgs": {
"predictionSteps": [1],
"predictedField": "c1",
"inputPredictedField": "auto"
},
"modelConfig": {
"aggregationInfo": {
"seconds": 0,
"fields": [],
"months": 0,
"days": 0,
"years": 0,
"hours": 0,
"microseconds": 0,
"weeks": 0,
"minutes": 0,
"milliseconds": 0
},
"model": "CLA",
"version": 1,
"predictAheadTime": null,
"modelParams": {
"sensorParams": {
"verbosity": 0,
"encoders": {
"c0_dayOfWeek": null,
"c0_timeOfDay": {
"type": "DateEncoder",
"timeOfDay": [21, 9.4912233474773693],
"fieldname": "c0",
"name": "c0"
},
"c1": {
"name": "c1",
"fieldname": "c1",
"numBuckets": 114.0,
"seed": 42,
"type": "RandomDistributedScalarEncoder"
},
"c0_weekend": null
},
"sensorAutoReset": null
},
"spParams": {
"spatialImp": "cpp",
"columnCount": 2048,
"synPermInactiveDec": 0.0005,
"inputWidth": 0,
"spVerbosity": 0,
"synPermActiveInc": 0.0015,
"synPermConnected": 0.10000000000000001,
"numActiveColumnsPerInhArea": 40,
"seed": 1956,
"potentialPct": 0.8,
"globalInhibition": 1,
"maxBoost": 1.0
},
"trainSPNetOnlyIfRequested": false,
"clParams": {
"alpha": 0.035828933612157998,
"regionName": "CLAClassifierRegion",
"steps": "1",
"clVerbosity": 0
},
"tpParams": {
"columnCount": 2048,
"activationThreshold": 13,
"pamLength": 3,
"cellsPerColumn": 32,
"permanenceInc": 0.10000000000000001,
"minThreshold": 10,
"verbosity": 0,
"maxSynapsesPerSegment": 32,
"outputType": "normal",
"globalDecay": 0.0,
"initialPerm": 0.20999999999999999,
"permanenceDec": 0.10000000000000001,
"seed": 1960,
"maxAge": 0,
"newSynapseCount": 20,
"maxSegmentsPerCell": 128,
"temporalImp": "cpp",
"inputWidth": 2048
},
"anomalyParams": {
"anomalyCacheRecords": null,
"autoDetectThreshold": null,
"autoDetectWaitRecords": 5030
},
"spEnable": true,
"inferenceType": "TemporalAnomaly",
"tpEnable": true,
"clEnable": false
}
}
}
130 changes: 130 additions & 0 deletions src/nupic/frameworks/opf/common_models/cluster_params.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# ----------------------------------------------------------------------
# Numenta Platform for Intelligent Computing (NuPIC)
# Copyright (C) 2015, Numenta, Inc. Unless you have purchased from
# Numenta, Inc. a separate commercial license for this software code, the
# following terms and conditions apply:
#
# 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.
#
# http://numenta.org/licenses/
# ----------------------------------------------------------------------

import json
import numpy as np
import os
from pkg_resources import resource_stream



def getScalarMetricWithTimeOfDayAnomalyParams(metricData,
minVal=None,
maxVal=None,
minResolution=None):
"""
Return a dict that can be used to create an anomaly model via OPF's
ModelFactory.
:param metricData: numpy array of metric data. Used to calculate minVal
and maxVal if either is unspecified
:param minVal: minimum value of metric. Used to set up encoders. If None
will be derived from metricData.
:param maxVal: maximum value of metric. Used to set up input encoders. If
None will be derived from metricData
:param minResolution: minimum resolution of metric. Used to set up
encoders. If None, will use default value of 0.001.
:returns: a dict containing "modelConfig" and "inferenceArgs" top-level
properties. The value of the "modelConfig" property is for passing to
the OPF `ModelFactory.create()` method as the `modelConfig` parameter. The
"inferenceArgs" property is for passing to the resulting model's
`enableInference()` method as the inferenceArgs parameter. NOTE: the
timestamp field corresponds to input "c0"; the predicted field corresponds
to input "c1".
:rtype: dict
Example:
from nupic.frameworks.opf.modelfactory import ModelFactory
from nupic.frameworks.opf.common_models.cluster_params import (
getScalarMetricWithTimeOfDayAnomalyParams)
params = getScalarMetricWithTimeOfDayAnomalyParams(
metricData=[0],
minVal=0.0,
maxVal=100.0)
model = ModelFactory.create(modelConfig=params["modelConfig"])
model.enableLearning()
model.enableInference(params["inferenceArgs"])
"""
# Default values
if minResolution is None:
minResolution = 0.001

# Compute min and/or max from the data if not specified
if minVal is None or maxVal is None:
compMinVal, compMaxVal = _rangeGen(metricData)
if minVal is None:
minVal = compMinVal
if maxVal is None:
maxVal = compMaxVal

# Handle the corner case where the incoming min and max are the same
if minVal == maxVal:
maxVal = minVal + 1

# Load model parameters and update encoder params
paramFileRelativePath = os.path.join(
"anomaly_params_random_encoder",
"best_single_metric_anomaly_params.json")

with resource_stream(__name__, paramFileRelativePath) as infile:
paramSet = json.load(infile)

_fixupRandomEncoderParams(paramSet, minVal, maxVal, minResolution)

return paramSet



def _rangeGen(data, std=1):
"""
Return reasonable min/max values to use given the data.
"""
dataStd = np.std(data)
if dataStd == 0:
dataStd = 1
minval = np.min(data) - std * dataStd
maxval = np.max(data) + std * dataStd
return minval, maxval



def _fixupRandomEncoderParams(params, minVal, maxVal, minResolution):
"""
Given model params, figure out the correct parameters for the
RandomDistributed encoder. Modifies params in place.
"""
encodersDict = (
params["modelConfig"]["modelParams"]["sensorParams"]["encoders"]
)

for encoder in encodersDict.itervalues():
if encoder is not None:
if encoder["type"] == "RandomDistributedScalarEncoder":
resolution = max(minResolution,
(maxVal - minVal) / encoder.pop("numBuckets")
)
encodersDict["c1"]["resolution"] = resolution
20 changes: 20 additions & 0 deletions tests/unit/nupic/frameworks/opf/common_models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# ----------------------------------------------------------------------
# Numenta Platform for Intelligent Computing (NuPIC)
# Copyright (C) 2015, Numenta, Inc. Unless you have purchased from
# Numenta, Inc. a separate commercial license for this software code, the
# following terms and conditions apply:
#
# 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.
#
# http://numenta.org/licenses/
# ----------------------------------------------------------------------
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#!/usr/bin/env python
# ----------------------------------------------------------------------
# Numenta Platform for Intelligent Computing (NuPIC)
# Copyright (C) 2015, Numenta, Inc. Unless you have purchased from
# Numenta, Inc. a separate commercial license for this software code, the
# following terms and conditions apply:
#
# 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.
#
# http://numenta.org/licenses/
# ----------------------------------------------------------------------

"""Unit tests for model selection via cluster params."""

import unittest
from nupic.support.unittesthelpers.testcasebase import TestCaseBase
from nupic.frameworks.opf.modelfactory import ModelFactory
from nupic.frameworks.opf.clamodel import CLAModel
from nupic.frameworks.opf.common_models.cluster_params import (
getScalarMetricWithTimeOfDayAnomalyParams)



class ClusterParamsTest(TestCaseBase):


def testModelParams(self):
"""
Test that clusterParams loads returns a valid dict that can be instantiated
as a CLAModel.
"""
params = getScalarMetricWithTimeOfDayAnomalyParams([0],
minVal=23.42,
maxVal=23.420001)

encodersDict= (
params['modelConfig']['modelParams']['sensorParams']['encoders'])

model = ModelFactory.create(modelConfig=params['modelConfig'])
self.assertIsInstance(model,
CLAModel,
"JSON returned cannot be used to create a model")

# Ensure we have a time of day field
self.assertIsNotNone(encodersDict['c0_timeOfDay'])

# Ensure resolution doesn't get too low
if encodersDict['c1']['type'] == 'RandomDistributedScalarEncoder':
self.assertGreaterEqual(encodersDict['c1']['resolution'], 0.001,
"Resolution is too low")



if __name__ == '__main__':
unittest.main()

0 comments on commit 37ac787

Please sign in to comment.