-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2617 from vitaly-krugl/move-model-selection-to-nupic
Add cluster params selection module from numenta-apps htmegine
- Loading branch information
Showing
5 changed files
with
333 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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/ | ||
# ---------------------------------------------------------------------- |
97 changes: 97 additions & 0 deletions
97
...ks/opf/common_models/anomaly_params_random_encoder/best_single_metric_anomaly_params.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
130
src/nupic/frameworks/opf/common_models/cluster_params.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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/ | ||
# ---------------------------------------------------------------------- |
66 changes: 66 additions & 0 deletions
66
tests/unit/nupic/frameworks/opf/common_models/cluster_params_test.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() | ||
|