From b7e7e315ad71f24c20ed40b3938825802ec24341 Mon Sep 17 00:00:00 2001 From: Matthew Taylor Date: Fri, 9 Jun 2017 16:23:42 -0700 Subject: [PATCH 1/2] Bunch of doc fixes and cleanup --- docs/README.md | 8 +- docs/source/_static/anomaly-equation-1.gif | Bin 0 -> 1321 bytes docs/source/_static/anomaly-equation-2.gif | Bin 0 -> 1000 bytes docs/source/_static/anomaly-equation-3.gif | Bin 0 -> 845 bytes docs/source/_static/anomaly-equation-4.gif | Bin 0 -> 1180 bytes docs/source/_static/anomaly-equation-5.gif | Bin 0 -> 1647 bytes docs/source/_static/network-api-video.jpg | Bin 0 -> 17884 bytes .../_static/swarming-in-docker-video.jpg | Bin 0 -> 16192 bytes docs/source/api/algorithms/encoders.rst | 2 +- docs/source/api/data/field-meta.rst | 13 ---- docs/source/api/data/index.rst | 11 ++- docs/source/api/{opf => data}/stream-def.rst | 0 docs/source/api/network/sensors.rst | 2 +- docs/source/api/opf/description-api.rst | 2 + docs/source/api/opf/description-template.rst | 1 - .../default-config.rst | 0 docs/source/api/support/index.rst | 2 + docs/source/guides/anomaly-detection.md | 10 +-- docs/source/guides/network.md | 2 +- docs/source/guides/opf.md | 9 ++- docs/source/guides/swarming/running.md | 2 +- docs/source/quick-start/network.rst | 1 + src/nupic/algorithms/backtracking_tm.py | 10 +-- src/nupic/algorithms/knn_classifier.py | 15 ++-- src/nupic/algorithms/spatial_pooler.py | 2 +- src/nupic/algorithms/temporal_memory.py | 5 +- src/nupic/data/field_meta.py | 8 +- src/nupic/data/record_stream.py | 7 +- src/nupic/data/utils.py | 6 +- .../frameworks/opf/exp_description_api.py | 2 +- src/nupic/frameworks/opf/opf_utils.py | 7 +- src/nupic/regions/record_sensor.py | 17 ++--- src/nupic/support/configuration_custom.py | 69 +++++++++--------- 33 files changed, 110 insertions(+), 103 deletions(-) create mode 100644 docs/source/_static/anomaly-equation-1.gif create mode 100644 docs/source/_static/anomaly-equation-2.gif create mode 100644 docs/source/_static/anomaly-equation-3.gif create mode 100644 docs/source/_static/anomaly-equation-4.gif create mode 100644 docs/source/_static/anomaly-equation-5.gif create mode 100644 docs/source/_static/network-api-video.jpg create mode 100644 docs/source/_static/swarming-in-docker-video.jpg delete mode 100644 docs/source/api/data/field-meta.rst rename docs/source/api/{opf => data}/stream-def.rst (100%) rename docs/source/api/{algorithms => support}/default-config.rst (100%) diff --git a/docs/README.md b/docs/README.md index 3632153d79..908f40bd1e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -85,7 +85,7 @@ nupic │   │   │   └── cluster_params.py [OK] │   │   ├── exceptions.py [OK] │   │   ├── exp_description_api.py [OK] -│   │   │   └── ExperimentDescriptionAPI [TODO] +│   │   │   └── ExperimentDescriptionAPI [OK] │   │   ├── experiment_runner.py [OK] │   │   ├── metrics.py [OK] │   │   ├── model.py [OK] @@ -119,10 +119,10 @@ nupic │   ├── record_sensor_filters │   │   ├── add_noise.py [TODO] │   │   └── modify_fields.py [TODO] -│   ├── sdr_classifier_region.py [TODO] -│   ├── sp_region.py [TODO] +│   ├── sdr_classifier_region.py [OK] +│   ├── sp_region.py [OK] │   ├── spec.py [TODO] -│   ├── tm_region.py [TODO] +│   ├── tm_region.py [OK] │   ├── test_region.py [TODO] │   └─── unimportable_node.py [TODO] ├── serializable.py [TODO] diff --git a/docs/source/_static/anomaly-equation-1.gif b/docs/source/_static/anomaly-equation-1.gif new file mode 100644 index 0000000000000000000000000000000000000000..3781e21fe6dbe4fbba24bba6b91ab887e09909e1 GIT binary patch literal 1321 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 XWvT10zy>R9Ot21X?6Jt65CH%?lw@Iw literal 0 HcmV?d00001 diff --git a/docs/source/_static/anomaly-equation-4.gif b/docs/source/_static/anomaly-equation-4.gif new file mode 100644 index 0000000000000000000000000000000000000000..8b33d50bf3e27271d52e7641598834a5836703a7 GIT binary patch literal 1180 zcmV;N1Y`S0Nk%w1VJ86+0J8u9|Ns90005Ynn23mo?(XhXR8+dUy3EYX+}zx%s;VL) zB1A+)c6N4VW@Zo&5Hd0{A^8LW00000EC2ui04D(w000F35XecZz1X5fvj1Qxj@m$; zsE8Cu>bi*e&LMJq$Kud@k1`H{Z-~>?ZX*Jt&={CvDWH%@TueQQ0(Hv;C|ccaHe?+! z6iCV0;QEGn0kEfVecMrl-JRN~XW}9Y3l;|fE_r({2YMe4a*2>wT9FtGByKp29}Ny2 z7K15cTLMl50s;jFrl@HWP6-JQ00#^Y3Jg~X02A+m!(6FuBr4_ zv+G80b_0lsWHH#xeNIi5jZL(0wE!SbSkMl5xLdzHUx9A?u7unaj2D^!eiI~snHOgXQQrlheR2hX{XyjwMi&J5 z!Bqz|aKJcaU_dJ+4j>DJ5>Bw-2^N}npmzX-#m0E948lek ze(|VZbPky?QZWM{Q49lYI57fSZ@IOSeg}pGQ~;hF&_YbEb$}xUaS+ggkOTNA0hZAK zhNP0lG?}6WBXK2_SO=B~0BD{R^`nA#Dzs7q3CWlunj~2wWNMosAm(s{GUEy6Kp6MS%k49q{I})_NgFUNPl3fvsTO z!0M{Sx@v(sYFt5!WZyBs%TFC7fJ-m9C>N?6`OX5EzjJ-0-@iT}&_^*9uyYCpN<8BU zyA|MamI3nWLvN0B7z4%u|8g9#CT}wQTE#2Cn`1Gs^byUyR^h@xqpsNG1hP50Oeg~R zy4UVm4eRT%Sb!MosG{$={lb?`;W4hp0FN6i4*~`|O+YyeBp$-(YMAcA;tK=d_zj+K8oK2t u4DurFJtQ4K1C@(#41bWE0`UpLQ+UVkxQn1fbUG(*c^|zyFFo`T002Aar0`<^ literal 0 HcmV?d00001 diff --git a/docs/source/_static/anomaly-equation-5.gif b/docs/source/_static/anomaly-equation-5.gif new file mode 100644 index 0000000000000000000000000000000000000000..6439da2b34f5802012d833f2c4da4c40741f5f5e GIT binary patch literal 1647 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 literal 0 HcmV?d00001 diff --git a/docs/source/api/algorithms/encoders.rst b/docs/source/api/algorithms/encoders.rst index 98c4aba742..9f7d05ea64 100644 --- a/docs/source/api/algorithms/encoders.rst +++ b/docs/source/api/algorithms/encoders.rst @@ -36,7 +36,7 @@ Scalar Encoders :members: mapBucketIndexToNonZeroBits :show-inheritance: -.. autoclass:: nupic.encoders.scalarspace.ScalarSpaceEncoder +.. autoclass:: nupic.encoders.scalar_space.ScalarSpaceEncoder :show-inheritance: .. autoclass:: nupic.encoders.delta.DeltaEncoder diff --git a/docs/source/api/data/field-meta.rst b/docs/source/api/data/field-meta.rst deleted file mode 100644 index 4a278284db..0000000000 --- a/docs/source/api/data/field-meta.rst +++ /dev/null @@ -1,13 +0,0 @@ -Field Meta -^^^^^^^^^^ - -.. automodule:: nupic.data.field_meta - -.. autoclass:: nupic.data.field_meta.FieldMetaInfo - :members: - -.. autoclass:: nupic.data.field_meta.FieldMetaType - :members: - -.. autoclass:: nupic.data.field_meta.FieldMetaSpecial - :members: diff --git a/docs/source/api/data/index.rst b/docs/source/api/data/index.rst index 505fe9780e..2be0739e3d 100644 --- a/docs/source/api/data/index.rst +++ b/docs/source/api/data/index.rst @@ -3,7 +3,11 @@ Data Data wrappers and helpers. -.. include:: field-meta.rst +Field Meta +^^^^^^^^^^ + +.. automodule:: nupic.data.field_meta + :members: FileRecordStream ^^^^^^^^^^^^^^^^ @@ -29,6 +33,11 @@ StreamReader .. autoclass:: nupic.data.stream_reader.StreamReader :members: +Stream Definition +^^^^^^^^^^^^^^^^^ + +See an example at :doc:`stream-def`. + Utilities ^^^^^^^^^ diff --git a/docs/source/api/opf/stream-def.rst b/docs/source/api/data/stream-def.rst similarity index 100% rename from docs/source/api/opf/stream-def.rst rename to docs/source/api/data/stream-def.rst diff --git a/docs/source/api/network/sensors.rst b/docs/source/api/network/sensors.rst index 7cd2f18217..5daa39d593 100644 --- a/docs/source/api/network/sensors.rst +++ b/docs/source/api/network/sensors.rst @@ -11,6 +11,6 @@ PluggableEncoderSensor RecordSensor ^^^^^^^^^^^^ -.. autoclass:: nupic.regions.RecordSensor.RecordSensor +.. autoclass:: nupic.regions.record_sensor.RecordSensor :members: :show-inheritance: diff --git a/docs/source/api/opf/description-api.rst b/docs/source/api/opf/description-api.rst index 54a3fd8f63..1b9a965c6a 100644 --- a/docs/source/api/opf/description-api.rst +++ b/docs/source/api/opf/description-api.rst @@ -3,6 +3,8 @@ Description API .. automodule:: nupic.frameworks.opf.exp_description_api +See :doc:`description-template` for more details. + .. autoclass:: nupic.frameworks.opf.exp_description_api.DescriptionIface :members: diff --git a/docs/source/api/opf/description-template.rst b/docs/source/api/opf/description-template.rst index a994fba430..d94fd257ad 100644 --- a/docs/source/api/opf/description-template.rst +++ b/docs/source/api/opf/description-template.rst @@ -2,4 +2,3 @@ OPF Description Template ======================== .. literalinclude:: ../../../../src/nupic/swarming/exp_generator/descriptionTemplate.tpl - :language: python diff --git a/docs/source/api/algorithms/default-config.rst b/docs/source/api/support/default-config.rst similarity index 100% rename from docs/source/api/algorithms/default-config.rst rename to docs/source/api/support/default-config.rst diff --git a/docs/source/api/support/index.rst b/docs/source/api/support/index.rst index 6b7971652f..4d020f8baa 100644 --- a/docs/source/api/support/index.rst +++ b/docs/source/api/support/index.rst @@ -7,6 +7,8 @@ Support Configuration Base ^^^^^^^^^^^^^^^^^^ +See :doc:`default-config` for details about default values. + .. automodule:: nupic.support.configuration_base :members: diff --git a/docs/source/guides/anomaly-detection.md b/docs/source/guides/anomaly-detection.md index 4e390f903f..f8e55807bf 100644 --- a/docs/source/guides/anomaly-detection.md +++ b/docs/source/guides/anomaly-detection.md @@ -18,11 +18,11 @@ A TemporalAnomaly model calculates the anomaly score based on the correctness of The algorithm for the anomaly score is as follows: -![equation](http://latex.codecogs.com/gif.latex?anomalyScore%3D%5Cfrac%7B%5Clvert%20A_t-%28P_%7Bt-1%7D%5Cbigcap%20A_t%29%5Crvert%20%7D%7B%5Clvert%20A_t%5Crvert%20%7D) +![equation](../_static/anomaly-equation-1.gif) -![equation](http://latex.codecogs.com/gif.latex?P_%7Bt-1%7D%3D%5Ctext%7BPredicted%20columns%20at%20time%20t%7D) +![equation](../_static/anomaly-equation-2.gif) -![equation](http://latex.codecogs.com/gif.latex?A_%7Bt%7D%3D%5Ctext%7BActive%20columns%20at%20time%20t%7D) +![equation](../_static/anomaly-equation-3.gif) __Note__: Here, a "predicted column" is a column with a non-zero confidence value. This is not exactly the same as having a cell in the predicted state. For more information, refer the "predicted cells vs. confidences" section below. @@ -63,11 +63,11 @@ Since NontemporalAnomaly models have no temporal memory, the anomaly score is ba To compute the nontemporal anomaly score, we first compute the "match" score for each winning column after inhibition -![equation](http://latex.codecogs.com/gif.latex?match_%7Bcol_%7Bk%7D%7D%20%3D%20overlap_%7Bcol_%7Bi%7D%7D*dutyCycle_%7Bcol_%7Bi%7D%7D) +![equation](../_static/anomaly-equation-4.gif) Then, to get the anomaly score (how unusual the data is), we take the inverse of the total matches -![equation](http://latex.codecogs.com/gif.latex?anomalyScore%3D%28%5Csum%20_%7Bcol_%7Bi%7D%5Cepsilon%20winningCols%7Dmatch_%7Bcol_%7Bi%7D%7D+1%29%5E%7B-1%7D) +![equation](../_static/anomaly-equation-5.gif) The addition of 1 is to avoid divide by 0 errors. diff --git a/docs/source/guides/network.md b/docs/source/guides/network.md index 26b6d2e2be..f52476c162 100644 --- a/docs/source/guides/network.md +++ b/docs/source/guides/network.md @@ -3,7 +3,7 @@ * [Network API Documentation](../api/network/) * [Network API Quick Start](../quick-start/network.html) -[![Thumbnail of Network API video](http://img.youtube.com/vi/g9yS9zFt3dM/hqdefault.jpg)](https://www.youtube.com/watch?v=g9yS9zFt3dM) +[![Thumbnail of Network API video](../_static/network-api-video.jpg)](https://www.youtube.com/watch?v=g9yS9zFt3dM) ## Introduction diff --git a/docs/source/guides/opf.md b/docs/source/guides/opf.md index d152522bf0..a3f77ab590 100644 --- a/docs/source/guides/opf.md +++ b/docs/source/guides/opf.md @@ -32,7 +32,8 @@ of database) Each of these 3 components is in a separate set of modules. Metrics and writing output are optional when running models. -![Data flow in the OPF](../../_static/opf-figure1.png) +![Data flow in the OPF](../_static/opf-figure1.png) + > Figure 1: Data flow in the OPF ## What doesn’t the OPF do? @@ -104,7 +105,7 @@ It also provides the following functionality, common to all models: ### Model Input -![Records are input to models in the form of dictionary-like objects, where the keys are field names and the values are the raw field values.](../../_static/opf-figure2.png) +![Records are input to models in the form of dictionary-like objects, where the keys are field names and the values are the raw field values.](../_static/opf-figure2.png) > Figure 2: Records are input to models in the form of dictionary-like objects, where the keys are field names and the values are the raw field values. @@ -167,7 +168,7 @@ In this example, we can see that the “_prediction_” inference element is ass This association is used to compute metrics and to determine which parts of the input to write to output. For example, to compute error, the value of “_prediction_” will be compared to the value of SensorInput.dataRow, and the value of “_classification_” will be compared to value of SensorInput.category -![Inference elements](../../_static/opf-figure3.png) +![Inference elements](../_static/opf-figure3.png) > Figure 3: Inference Elements @@ -206,7 +207,7 @@ This shifting applies to both csv output and metrics calculation. Each inference Below is an example of how this shifting occurs to compute errors: -![Shifting](../../_static/opf-figure4.png) +![Shifting](../_static/opf-figure4.png) > Figure 4: Shifting diff --git a/docs/source/guides/swarming/running.md b/docs/source/guides/swarming/running.md index e4daa8ce82..6445036439 100644 --- a/docs/source/guides/swarming/running.md +++ b/docs/source/guides/swarming/running.md @@ -288,7 +288,7 @@ NuPIC includes a Dockerfile for use with [Docker](http://docker.io/), as well as [TL;DR] Watch the [video](https://youtu.be/BtkGn22KSrQ). -[![Swarming in NuPIC video thumbnail](http://img.youtube.com/vi/BtkGn22KSrQ/hqdefault.jpg)](https://youtu.be/BtkGn22KSrQ) +[![Swarming in NuPIC video thumbnail](../../_static/swarming-in-docker-video.jpg)](https://youtu.be/BtkGn22KSrQ) #### Before you begin diff --git a/docs/source/quick-start/network.rst b/docs/source/quick-start/network.rst index 953d22b79d..cdbdc2cbf6 100644 --- a/docs/source/quick-start/network.rst +++ b/docs/source/quick-start/network.rst @@ -211,4 +211,5 @@ which should look something like this: 1-step: 45.6100006104 (96.41%) 5-step: 0.0 (0.1883%) 1-step: 43.4000015259 (3.969%) 5-step: 0.0 (0.1883%) 1-step: 43.4000015259 (4.125%) 5-step: 0.0 (0.1883%) + **Congratulations! You've got HTM predictions for a scalar data stream!** diff --git a/src/nupic/algorithms/backtracking_tm.py b/src/nupic/algorithms/backtracking_tm.py index 03d5dffd22..6fd3c63f2c 100644 --- a/src/nupic/algorithms/backtracking_tm.py +++ b/src/nupic/algorithms/backtracking_tm.py @@ -639,7 +639,7 @@ def getStats(self): - ``curExtra``: the number of bits in the predicted output that are not in the next input - ``predictionScoreTotal``: the sum of every prediction score to date - - ``predictionScoreAvg``: ``predictionScoreTotal / nPredictions `` + - ``predictionScoreAvg``: ``predictionScoreTotal / nPredictions`` - ``pctMissingTotal``: the total number of bits that were missed over all predictions - ``pctMissingAvg``: ``pctMissingTotal / nPredictions`` @@ -2503,10 +2503,10 @@ def trimSegments(self, minPermanence=None, minNumSyns=None): minPermanence and deletes any segments that have less than minNumSyns synapses remaining. - :param minPermanence Any syn whose permanence is 0 or < ``minPermanence`` - will be deleted. If None is passed in, then ``self.connectedPerm`` is - used. - :param minNumSyns Any segment with less than ``minNumSyns`` synapses + :param minPermanence: (float) Any syn whose permanence is 0 or < + ``minPermanence`` will be deleted. If None is passed in, then + ``self.connectedPerm`` is used. + :param minNumSyns: (int) Any segment with less than ``minNumSyns`` synapses remaining in it will be deleted. If None is passed in, then ``self.activationThreshold`` is used. :returns: (tuple) ``numSegsRemoved``, ``numSynsRemoved`` diff --git a/src/nupic/algorithms/knn_classifier.py b/src/nupic/algorithms/knn_classifier.py index 41d198bac7..7cc387e551 100755 --- a/src/nupic/algorithms/knn_classifier.py +++ b/src/nupic/algorithms/knn_classifier.py @@ -609,15 +609,20 @@ def learn(self, inputPattern, inputCategory, partitionId=None, isSparse=0, def getOverlaps(self, inputPattern): - """Return the degree of overlap between an input pattern and each category - stored in the classifier. The overlap is computed by compuing: + """ + Return the degree of overlap between an input pattern and each category + stored in the classifier. The overlap is computed by computing: + + .. code-block:: python + logical_and(inputPattern != 0, trainingPattern != 0).sum() :param inputPattern: pattern to check overlap of - :returns: (overlaps, categories) Two numpy arrays of the same length. - - overlaps: an integer overlap amount for each category - - categories: category index for each element of overlaps + :returns: (overlaps, categories) Two numpy arrays of the same length, where: + + * overlaps: an integer overlap amount for each category + * categories: category index for each element of overlaps """ assert self.useSparseMemory, "Not implemented yet for dense storage" diff --git a/src/nupic/algorithms/spatial_pooler.py b/src/nupic/algorithms/spatial_pooler.py index 3e261902fe..cd394c7dc5 100644 --- a/src/nupic/algorithms/spatial_pooler.py +++ b/src/nupic/algorithms/spatial_pooler.py @@ -116,7 +116,7 @@ class SpatialPooler(object): Format is (height, width, depth, ...), where each value represents the size of the dimension. For a topology of one dimension with 2000 columns use 2000, or (2000,). For a three dimensional topology of 32x64x16 use - (32, 64, 16). Default ```(64, 64)`. + (32, 64, 16). Default ``(64, 64)``. :param potentialRadius: (int) This parameter determines the extent of the input that each column can diff --git a/src/nupic/algorithms/temporal_memory.py b/src/nupic/algorithms/temporal_memory.py index b90244b0e0..3ed352f108 100644 --- a/src/nupic/algorithms/temporal_memory.py +++ b/src/nupic/algorithms/temporal_memory.py @@ -412,11 +412,10 @@ def createSegment(self, cell): some extra bookkeeping. Unit tests should call this method, and not :meth:`~nupic.algorithms.connections.Connections.createSegment`. - :param cell: (int) - Index of cell to create a segment on. + :param cell: (int) Index of cell to create a segment on. :returns: (:class:`~nupic.algorithms.connections.Segment`) The created - segment. + segment. """ return self._createSegment( self.connections, self.lastUsedIterationForSegment, cell, self.iteration, diff --git a/src/nupic/data/field_meta.py b/src/nupic/data/field_meta.py index b134158036..ac87e3b45b 100644 --- a/src/nupic/data/field_meta.py +++ b/src/nupic/data/field_meta.py @@ -78,11 +78,11 @@ def __init__(self, @staticmethod def createFromFileFieldElement(fieldInfoTuple): """ - Creates a :class:`.fieldmeta.FieldMetaInfo` instance from a tuple containing + Creates a :class:`.field_meta.FieldMetaInfo` instance from a tuple containing ``name``, ``type``, and ``special``. :param fieldInfoTuple: Must contain ``name``, ``type``, and ``special`` - :return: :class:`~.fieldmeta.FieldMetaInfo` instance + :return: (:class:`~.field_meta.FieldMetaInfo`) instance """ return FieldMetaInfo._make(fieldInfoTuple) @@ -91,7 +91,7 @@ def createFromFileFieldElement(fieldInfoTuple): def createListFromFileFieldList(cls, fields): """ Creates a FieldMetaInfo list from the a list of tuples. Basically runs - :meth:`~.fieldmeta.FieldMetaInfo.createFromFileFieldElement` on each tuple. + :meth:`~.field_meta.FieldMetaInfo.createFromFileFieldElement` on each tuple. *Example:* @@ -109,7 +109,7 @@ def createListFromFileFieldList(cls, fields): :param fields: a sequence of field attribute tuples conforming to the format of ``name``, ``type``, and ``special`` - :return: A list of :class:`~.fieldmeta.FieldMetaInfo` elements corresponding + :return: A list of :class:`~.field_meta.FieldMetaInfo` elements corresponding to the given 'fields' list. """ return [cls.createFromFileFieldElement(f) for f in fields] diff --git a/src/nupic/data/record_stream.py b/src/nupic/data/record_stream.py index 8c065ca6af..3afe66f505 100644 --- a/src/nupic/data/record_stream.py +++ b/src/nupic/data/record_stream.py @@ -55,8 +55,8 @@ def __init__(self, fields, aggregationPeriod=None): """ :param fields: non-empty sequence of nupic.data.fieldmeta.FieldMetaInfo objects corresponding to fields in input rows. - :param dict aggregationPeriod: aggregation period of the record stream as a - dict containing 'months' and 'seconds'. The months is always an integer + :param aggregationPeriod: (dict) aggregation period of the record stream + containing 'months' and 'seconds'. The months is always an integer and seconds is a floating point. Only one is allowed to be non-zero at a time. If there is no aggregation associated with the stream, pass None. Typically, a raw file or hbase stream will NOT have any aggregation info, @@ -444,7 +444,8 @@ def getFields(self): """ :returns: (list) of :class:`nupic.data.fieldmeta.FieldMetaInfo` objects for each field in the stream. Might be None, if that information is provided - externally (through stream def, for example). + externally (through the `Stream Definition `_, + for example). """ diff --git a/src/nupic/data/utils.py b/src/nupic/data/utils.py index e405d74e10..acf975ba9f 100644 --- a/src/nupic/data/utils.py +++ b/src/nupic/data/utils.py @@ -73,7 +73,8 @@ def serializeTimestamp(t): Turns a datetime object into a string. :param t: (datetime.datetime) - :return: (string) in default format (see :const:`DATETIME_FORMATS`[0]) + :return: (string) in default format (see + :const:`~nupic.data.utils.DATETIME_FORMATS` [0]) """ return t.strftime(DATETIME_FORMATS[0]) @@ -84,7 +85,8 @@ def serializeTimestampNoMS(t): Turns a datetime object into a string ignoring milliseconds. :param t: (datetime.datetime) - :return: (string) in default format (see :const:`DATETIME_FORMATS`[2]) + :return: (string) in default format (see + :const:`~nupic.data.utils.DATETIME_FORMATS` [2]) """ return t.strftime(DATETIME_FORMATS[2]) diff --git a/src/nupic/frameworks/opf/exp_description_api.py b/src/nupic/frameworks/opf/exp_description_api.py index 2474ebfa69..5d680f3b46 100644 --- a/src/nupic/frameworks/opf/exp_description_api.py +++ b/src/nupic/frameworks/opf/exp_description_api.py @@ -89,7 +89,7 @@ def __init__(self, modelConfig, control): def getModelDescription(self): """ :returns: the model creation parameters based on the settings in the config - dictionary. + dictionary. """ diff --git a/src/nupic/frameworks/opf/opf_utils.py b/src/nupic/frameworks/opf/opf_utils.py index 24dcb8462b..ba4795f14e 100644 --- a/src/nupic/frameworks/opf/opf_utils.py +++ b/src/nupic/frameworks/opf/opf_utils.py @@ -135,9 +135,10 @@ def getTemporalDelay(inferenceElement, key=None): @staticmethod def getMaxDelay(inferences): """ - :param inferences: (dict) where the keys are :class:`.InferenceElement`s - :return: (int) the maximum delay for the :class:`.InferenceElement`s in - the inference dictionary + :param inferences: (dict) where the keys are :class:`.InferenceElement` + objects. + :return: (int) the maximum delay for the :class:`.InferenceElement` objects + in the inference dictionary. """ maxDelay = 0 for inferenceElement, inference in inferences.iteritems(): diff --git a/src/nupic/regions/record_sensor.py b/src/nupic/regions/record_sensor.py index d2ff4c742b..98a6763efa 100644 --- a/src/nupic/regions/record_sensor.py +++ b/src/nupic/regions/record_sensor.py @@ -310,21 +310,20 @@ def getNextRecord(self): def applyFilters(self, data): - """Apply pre-encoding filters. - These filters may modify or add data - If a filter needs another record (e.g. a delta filter) - it will request another record by returning False and the current record - will be skipped (but will still be given to all filters) + """ + Apply pre-encoding filters. These filters may modify or add data. If a + filter needs another record (e.g. a delta filter) it will request another + record by returning False and the current record will be skipped (but will + still be given to all filters). We have to be very careful about resets. A filter may add a reset, but other filters should not see the added reset, each filter sees the original reset value, and we keep track of whether any filter adds a reset. - @param data: The data that will be processed by the filter. - @type data: dict - @return: a tuple with the data processed by the filter and a boolean to - know whether or not the filter needs mode data. + :param data: (dict) The data that will be processed by the filter. + :returns: (tuple) with the data processed by the filter and a boolean to + know whether or not the filter needs mode data. """ if self.verbosity > 0: diff --git a/src/nupic/support/configuration_custom.py b/src/nupic/support/configuration_custom.py index e6238a9901..e23653fe9c 100644 --- a/src/nupic/support/configuration_custom.py +++ b/src/nupic/support/configuration_custom.py @@ -45,50 +45,47 @@ def _getLogger(): class Configuration(ConfigurationBase): - """ This class extends the ConfigurationBase implementation with the ability - to read and write custom, persistent parameters. The custom settings will be - stored in the nupic-custom.xml file. - - If the environment variable 'NTA_CONF_PATH' is defined, then the configuration - files are expected to be in the NTA_CONF_PATH search path, which is a ':' - separated list of directories (on Windows the seperator is a ';'). - If NTA_CONF_PATH is not defined, then it is assumed to be NTA/conf/default - (typically ~/nupic/current/conf/default). + """ + This class extends the + :class:`nupic.support.configuration_base.ConfigurationBase` implementation + with the ability to read and write custom, persistent parameters. The custom + settings will be stored in the ``nupic-custom.xml`` file. + + If the environment variable ``NTA_CONF_PATH`` is defined, then the + configuration files are expected to be in the ``NTA_CONF_PATH`` search path, + which is a ``:`` separated list of directories (on Windows the separator is a + ``;``). If ``NTA_CONF_PATH`` is not defined, then it is assumed to be + ``$NTA/conf/default`` (typically ``~/nupic/current/conf/default``). """ @classmethod def getCustomDict(cls): - """ Return a dict containing all custom configuration properties - - Parameters: - ---------------------------------------------------------------- - retval: dict containing all custom configuration properties. + """ + returns: (dict) containing all custom configuration properties. """ return _CustomConfigurationFileWrapper.getCustomDict() @classmethod def setCustomProperty(cls, propertyName, value): - """ Set a single custom setting and persist it to the custom - configuration store. + """ + Set a single custom setting and persist it to the custom configuration + store. - Parameters: - ---------------------------------------------------------------- - propertyName: string containing the name of the property to get - value: value to set the property to + :param propertyName: (string) containing the name of the property to get + :param value: (object) value to set the property to """ cls.setCustomProperties({propertyName : value}) @classmethod def setCustomProperties(cls, properties): - """ Set multiple custom properties and persist them to the custom - configuration store. + """ + Set multiple custom properties and persist them to the custom configuration + store. - Parameters: - ---------------------------------------------------------------- - properties: a dict of property name/value pairs to set + :param properties: (dict) of property name/value pairs to set """ _getLogger().info("Setting custom configuration properties=%r; caller=%r", properties, traceback.format_stack()) @@ -101,8 +98,9 @@ def setCustomProperties(cls, properties): @classmethod def clear(cls): - """ Clear all configuration properties from in-memory cache, but do NOT - alter the custom configuration file. Used in unit-testing. + """ + Clear all configuration properties from in-memory cache, but do NOT alter + the custom configuration file. Used in unit-testing. """ # Clear the in-memory settings cache, forcing reload upon subsequent "get" # request. @@ -114,8 +112,9 @@ def clear(cls): @classmethod def resetCustomConfig(cls): - """ Clear all custom configuration settings and delete the persistent - custom configuration store. + """ + Clear all custom configuration settings and delete the persistent custom + configuration store. """ _getLogger().info("Resetting all custom configuration properties; " "caller=%r", traceback.format_stack()) @@ -131,12 +130,12 @@ def resetCustomConfig(cls): @classmethod def loadCustomConfig(cls): - """ Loads custom configuration settings from their persistent storage. - DO NOT CALL THIS: It's typically not necessary to call this method - directly - see NOTE below. - - NOTE: this method exists *solely* for the benefit of prepare_conf.py, which - needs to load configuration files selectively. + """ + Loads custom configuration settings from their persistent storage. + + .. warning :: DO NOT CALL THIS: It's typically not necessary to call this + method directly. This method exists *solely* for the benefit of + ``prepare_conf.py``, which needs to load configuration files selectively. """ cls.readConfigFile(_CustomConfigurationFileWrapper.customFileName) From 71032a5b08cc843b8425e176ddd39ccfd63b2ff0 Mon Sep 17 00:00:00 2001 From: Matthew Taylor Date: Mon, 12 Jun 2017 10:43:11 -0700 Subject: [PATCH 2/2] OPF Guide cleanup and link fixes --- docs/source/guides/opf.md | 103 +++++++++++----------- src/nupic/data/inference_shifter.py | 6 +- src/nupic/frameworks/opf/model_factory.py | 2 +- 3 files changed, 56 insertions(+), 55 deletions(-) diff --git a/docs/source/guides/opf.md b/docs/source/guides/opf.md index a3f77ab590..c5bc750c19 100644 --- a/docs/source/guides/opf.md +++ b/docs/source/guides/opf.md @@ -19,7 +19,7 @@ Here are some examples of applications using the OPF interface: [__Metrics__](../api/opf/metrics.html) take input values and predictions and output scalar representations of the quality of the predictions. Different metrics are suitable for different problems. -__Clients__ take input data and feed it through encoders, models, and metrics and store or report the resulting predictions or metric results. +[__Clients__](../api/opf/clients.html) take input data and feed it through encoders, models, and metrics and store or report the resulting predictions or metric results. ## What does the OPF do? @@ -38,68 +38,65 @@ Each of these 3 components is in a separate set of modules. Metrics and writing ## What doesn’t the OPF do? -- The OPF does not create models. It is up to the client code to figure out how many models to run, and to instantiate the correct types of models +- The OPF does not create models. It is up to the client code to figure out how many models to run, and to instantiate the correct types of models. - The OPF does not run models automatically. All the models in the OPF operate under a “push” model. The client is responsible for getting records from some data source, feeding records into the model, and handling the output of models. ## Models ### The Model Interface -The OPF defines the abstract "Model" interface for the implementation of any online learning model. Implementers typically subclass the [base class](../api/opf/models.html#model) provided. All models must implement the following methods: +The OPF defines the abstract "Model" interface for the implementation of any online learning model. Implementers typically subclass the [base class](../api/opf/models.html#nupic.frameworks.opf.model.Model) provided. All models must implement the following methods: -- **\_\_init\_\_(modelDescription, inferenceType)** +- **[`__init__(inferenceType)`](../api/opf/models.html#nupic.frameworks.opf.model.Model)** - Constructor for the model. Must take a modelDescription dictionary, which contains all the parameters necessary to instantiate the model, and an InferenceType value (see below). *A model’s \_\_init\_\_() method should always call the \_\_init\_\_() method of the superclass.* + Constructor for the model. Must take an [`InferenceType`](../api/opf/utils.html#nupic.frameworks.opf.opf_utils.InferenceType) value (see below). *A model’s ``__init__()`` method should always call the `__init__()` method of the superclass.* -- **run(inputRecord)** +- **[`run(inputRecord)`](../api/opf/models.html#nupic.frameworks.opf.model.Model.run)** - The main function for the model that does all the computation required for a new input record. Because the OPF only deals with online streaming models, each record is fed to the model one at a time -Returns: A populated ModelResult object (see below) + The main function for the model that does all the computation required for a new input record. Because the OPF only deals with online streaming models, each record is fed to the model one at a time. Returns: A populated ModelResult object (see below) -- **getFieldInfo()** +- **[`getFieldInfo()`](../api/opf/models.html#nupic.frameworks.opf.model.Model.getFieldInfo)** Returns a list of metadata about each of the translated fields (see below about translation). Each entry in the list is a FieldMetaInfo object, which contains information about the field, such as name and data type Returns: A list of FieldMetaInfo objects -- **finishLearning()** +- **[`finishLearning()`](../api/opf/models.html#nupic.frameworks.opf.model.Model.finishLearning)** This is a signal from the client code that the model may be placed in a permanent "finished learning" mode where it will not be able to learn from subsequent input records. This allows the model to perform optimizations and clean up any learning-related state Returns: Nothing -- **resetSequenceStates()** +- **[`resetSequenceStates()`](../api/opf/models.html#nupic.frameworks.opf.model.Model.resetSequenceStates)** Signals the model that a logical sequence has finished. The model should not treat the subsequent input record as subsequent to the previous record. Returns: Nothing -- **mapInputRecord()** - not used - -- **getRuntimeStats()** – [can be a no-op] +- **[`getRuntimeStats()`](../api/opf/models.html#nupic.frameworks.opf.model.Model.getRuntimeStats)** – [can be a no-op] Get runtime statistics specific to this model. Examples include “number of records seen” or “average cell overlap” Returns: A dictionary where the keys are the statistic names, and the values are the statistic values -- **\_getLogger()** – [used by parent class] +- **`_getLogger()`** – [used by parent class] Returns: The logging object for this class. This is used so that that the operations in the superclass use the same logger object. It also provides the following functionality, common to all models: -- **enableLearning()/disableLearning()** +- **[`enableLearning()`](../api/opf/models.html#nupic.frameworks.opf.model.Model.enableLearning) / [`disableLearning()`](../api/opf/models.html#nupic.frameworks.opf.model.Model.disableLearning)** Set’s the learning flag for the model. This can be queried internally and externally using the isLearningEnabled() method -- **enableInference(inferenceArgs=None)/disableInference()** +- **[`enableInference(inferenceArgs=None)`](../api/opf/models.html#nupic.frameworks.opf.model.Model.enableInference) / [`disableInference()`](../api/opf/models.html#nupic.frameworks.opf.model.Model.disableInference)** Enables/Disables inference output for this model. Enabling inference takes an optional argument inferenceArgs, which is a dictionary with extra parameters that affect how inference is performed. For instance, an anomaly detection model may have a boolean parameter “doPrediction”, which toggles whether or not a prediction is computed in addition to the anomaly score. The inference state of a model can be queried internally and externally using the isInferenceEnabled() method. The inference arguments can be queried using the getInferenceArgs() method. -- **save(saveModelDir)** +- **[`save(saveModelDir)`](../api/opf/models.html#nupic.frameworks.opf.model.Model.saveModelDir)** Save the model state via pickle and saves the resulting object in the saveModelDir directory. -- **\_serializeExtraData(extaDataDir)/\_deSerializeExtraData(extraDataDir)** +- **`_serializeExtraData(extaDataDir)` / `_deSerializeExtraData(extraDataDir)`** If there is state that cannot be pickled and needs to be saved separately, this can be done by overriding these methods (implemented as no-ops by default). @@ -115,9 +112,9 @@ Certain field types need to be converted into primitive input types. For example #### Encoding Additionally, for some model types (such as the CLA model), the translated inputs are quantized (put into buckets) and converted into binary vector representation. This process is called **_encoding_** and is handled by [encoders](Encoders) (specific encoders for different data types exist). Most models may not need to encode the input (or, more likely, they will just need to quantize the input). -### Model Output: The ModelResult Object +### Model Output: The [`ModelResult`](../api/opf/results.html#nupic.frameworks.opf.opf_utils.ModelResult) Object -The ModelResult object is the main data container in the OPF. When a record is fed to a model, it instantiates a new ModelResult instance, which contains model input and inferences, and is shuttled around to the various OPF modules. Below is a description of each of the ModelResult attributes. They default to **None** when the ModelResult is instantiated, and must be populated by the Model object. +The [`ModelResult`](../api/opf/results.html#nupic.frameworks.opf.opf_utils.ModelResult) object is the main data container in the OPF. When a record is fed to a model, it instantiates a new [`ModelResult`](../api/opf/results.html#nupic.frameworks.opf.opf_utils.ModelResult) instance, which contains model input and inferences, and is shuttled around to the various OPF modules. Below is a description of each of the ModelResult attributes. They default to **None** when the ModelResult is instantiated, and must be populated by the Model object. - **rawInput**: This is the exact record that is fed into the model. It is a dictionary-like object where the keys are the input field names, and the values are input values of the fields. All the input values maintain their original types. - **sensorInput**: The translated input record, as well as auxiliary information about the input (See below) @@ -137,9 +134,9 @@ binary numpy arrays, one for each field in dataRow. ### Inference Elements -The concept of InferenceElements is a key part of the OPF. A model's inference may have multiple parts to it. For example, a model may output both a prediction and an anomaly score. Models output their set of inferences as a dictionary that is keyed by the enumerated type InferenceElement. Each entry in an inference dictionary is considered a separate inference element, and is handled independently by the OPF. +The concept of [`InferenceElement`](../api/opf/utils.html#nupic.frameworks.opf.opf_utils.InferenceElement)s is a key part of the OPF. A model's inference may have multiple parts to it. For example, a model may output both a prediction and an anomaly score. Models output their set of inferences as a dictionary that is keyed by the enumerated type [`InferenceElement`](../api/opf/utils.html#nupic.frameworks.opf.opf_utils.InferenceElement). Each entry in an inference dictionary is considered a separate inference element, and is handled independently by the OPF. -Data structures related to inference elements are located in [**opf_utils.py**](https://github.com/numenta/nupic/blob/master/nupic/frameworks/opf/opf_utils.py). +Data structures related to inference elements are located in [*Inference Utilities*](../api/opf/utils.html#inference-utilities). #### Inference Data Types @@ -164,9 +161,9 @@ In order to compute metrics and write output, the OPF needs to know which input > Snippet 1: Mapping inferences to input -In this example, we can see that the “_prediction_” inference element is associated with SensorInput.dataRow, and the “_classification_” inference element is associated with SensorInput.category. +In this example, we can see that the “_prediction_” inference element is associated with [`SensorInput`](../api/opf/utils.html#nupic.frameworks.opf.opf_utils.SensorInput)`.dataRow`, and the “_classification_” inference element is associated with [`SensorInput`](../api/opf/utils.html#nupic.frameworks.opf.opf_utils.SensorInput)`.category`. -This association is used to compute metrics and to determine which parts of the input to write to output. For example, to compute error, the value of “_prediction_” will be compared to the value of SensorInput.dataRow, and the value of “_classification_” will be compared to value of SensorInput.category +This association is used to compute metrics and to determine which parts of the input to write to output. For example, to compute error, the value of “_prediction_” will be compared to the value of [`SensorInput`](../api/opf/utils.html#nupic.frameworks.opf.opf_utils.SensorInput)`.dataRow`, and the value of “_classification_” will be compared to value of [`SensorInput`](../api/opf/utils.html#nupic.frameworks.opf.opf_utils.SensorInput)`.category`. ![Inference elements](../_static/opf-figure3.png) @@ -211,52 +208,56 @@ Below is an example of how this shifting occurs to compute errors: > Figure 4: Shifting -## Metrics +You can use the [`InferenceShifter`](../api/opf/results.html#inferenceshifter) to shift inferences: + +```python +from nupic.data.inference_shifter import InferenceShifter as shifter + +shiftedModelResult = shifter.shift(modelResult) +``` -The 2nd responsibility of the OPF is to compute metrics on a model's output. Typically, this is some form of error metric, but in truth it can be any kind of score computed from the information in the input record and the output inferences. Metric calculations are handled by the PredictionMetricManager, which is instantiated with a series of MetricSpec objects (see below). The MetricsManager also handles shifting all the inferences appropriately before they are fed into their respective metrics modules +## [Metrics](../api/opf/metrics.html) + +The 2nd responsibility of the OPF is to compute metrics on a model's output. Typically, this is some form of error metric, but in truth it can be any kind of score computed from the information in the input record and the output inferences. Metric calculations are handled by the [Prediction Metric Manager](../api/opf/metrics.html#module-nupic.frameworks.opf.prediction_metrics_manager), which is instantiated with a series of [`MetricSpec`](../api/opf/metrics.html#nupic.frameworks.opf.metrics.MetricSpec) objects (see below). The [`MetricsManager`](../api/opf/metrics.html#nupic.frameworks.opf.prediction_metrics_manager.MetricsManager) also handles shifting all the inferences appropriately before they are fed into their respective metrics modules ### Metric Specs -A metric calculation is specified by creating a MetricSpec object. This is a container object that contains 4 fields: +A metric calculation is specified by creating a [`MetricSpec`](../api/opf/metrics.html#nupic.frameworks.opf.metrics.MetricSpec) object. This is a container object that contains 4 fields: -- inferenceElement -- metric -- field (optional) -- params (optional) +- `inferenceElement` +- `metric` +- `field` (optional) +- `params` (optional) Here is an example MetricSpec: - MetricSpec( inferenceElement=InferenceElement.multiStepBest, - metric="aae", - field="foo", - params = {"window" : 200 } ) +```python +MetricSpec( inferenceElement=InferenceElement.multiStepBest, + metric="aae", + field="foo", + params = {"window" : 200 } ) +``` -This means that we are calculating the average absolute error ("aae") on the multiStepBest inference element, for the entry that corresponds to the field "foo", and with an optional parameter "window" set to 200. +This means that we are calculating the average absolute error ("aae") on the `multiStepBest` inference element, for the entry that corresponds to the field `foo`, and with an optional parameter `window` set to 200. -### MetricLabels +### Metric Labels Metrics need to be able to be uniquely identified, so that the experiment can indicate which metric should be optimized and which should be written to output. To this end, metric specs can return a "metric label", which is a "human readable" (barely) string that contains all the information to uniquely identify the metric. The metric label for the above metric spec would be: - "multiStepBest:aae:window=200:field=foo" + multiStepBest:aae:window=200:field=foo -### Metrics Calculation Modules (metrics.py) +### Metrics Calculation Modules -The modules that actually calculate metrics are located in metrics.py. They all inherit the abstact base class Metric, and they must define the following methods. +The modules that actually calculate metrics are located in [*Available Metrics*](../api/opf/metrics.html#available-metrics). They all inherit the abstract base class [`MetricsIface`](../api/opf/metrics.html#nupic.frameworks.opf.metrics.MetricsIface), and they must define the following methods. -- **addInstance( prediction, groundTruth, record)**: This is the method where a new inference-groundTruth pair is passed to the metric. Additionally, the raw input record is +- **[`addInstance(prediction, groundTruth, record)`](../api/opf/metrics.html#nupic.frameworks.opf.metrics.MetricsIface.addInstance)**: This is the method where a new inference-groundTruth pair is passed to the metric. Additionally, the raw input record is also passed to the metric calculator. The module is responsible for calculating the metric and storing the relevant information here. -- **getMetric()** +- **[`getMetric()`](../api/opf/metrics.html#nupic.frameworks.opf.metrics.MetricsIface.getMetric)** - Returns a dictionary with the metric value and any auxillary information. The metric's value is stored under the key 'value' (confusing, right?) - - Ex. { 'value': 10.3, 'numIterations': 1003} + - Ex. `{ 'value': 10.3, 'numIterations': 1003}` ## Output -Types: Different inference value types are handled differently. The OPF distinguishes between 3 types: lists, dicts, and other. Lists are assumed to be associated with the model's getFieldInfo() output. An individual element is always output as a string, no matter it's actual type. Dicts are the most general, and separate columns are created for each key. Each entry in a dictionary is output as a string, no matter its type. - -#### Outputting Inferences -- type inference on inference values -- writing to a file (re: column creation) -- writing to a db -- Types +Types: Different inference value types are handled differently. The OPF distinguishes between 3 types: lists, dicts, and other. Lists are assumed to be associated with the model's [`getFieldInfo`](../api/opf/models.html#nupic.frameworks.opf.model.Model.getFieldInfo) output. An individual element is always output as a string, no matter it's actual type. Dicts are the most general, and separate columns are created for each key. Each entry in a dictionary is output as a string, no matter its type. diff --git a/src/nupic/data/inference_shifter.py b/src/nupic/data/inference_shifter.py index 6c3c5e893e..1f0642b4c4 100644 --- a/src/nupic/data/inference_shifter.py +++ b/src/nupic/data/inference_shifter.py @@ -29,7 +29,7 @@ class InferenceShifter(object): """ - Shifts time for :class:`~.nupic.frameworks.opf.opfutils.ModelResult` objects. + Shifts time for :class:`~.nupic.frameworks.opf.opf_utils.ModelResult` objects. This is useful for plotting results with the predictions at the same time step as the input data. """ @@ -45,9 +45,9 @@ def shift(self, modelResult): iteration was learn-only, then we would not have a T(i) prediction in our FIFO and would not be able to emit a meaningful input/prediction pair. - :param modelResult: A :class:`~.nupic.frameworks.opf.opfutils.ModelResult` + :param modelResult: A :class:`~.nupic.frameworks.opf.opf_utils.ModelResult` instance to shift. - :return: A :class:`~.nupic.frameworks.opf.opfutils.ModelResult` instance that + :return: A :class:`~.nupic.frameworks.opf.opf_utils.ModelResult` instance that has been shifted """ inferencesToWrite = {} diff --git a/src/nupic/frameworks/opf/model_factory.py b/src/nupic/frameworks/opf/model_factory.py index 469d5dc1a9..4074bc8972 100644 --- a/src/nupic/frameworks/opf/model_factory.py +++ b/src/nupic/frameworks/opf/model_factory.py @@ -59,7 +59,7 @@ def create(modelConfig, logLevel=logging.ERROR): :param modelConfig: (dict) A dictionary describing the current model, - `described here <../../docs/quick-start/example-model-params.rst>`_. + `described here <../../quick-start/example-model-params.html>`_. :param logLevel: (int) The level of logging output that should be generated