(HTM)nupic空间沉积池实现解读

(HTM)层次时序记忆-空间沉积池实现解读

如果你对HTM感兴趣,我建立了一个群,我们共同学习交流。515743445。

阅读本文前建议先阅读HTM白皮书(需要了解sp和tm的工作步骤),以及论文The HTM Spatial Pooler-A Neocortical Algorithm for Online Sparse Distributed Coding

本文研究src/nupic/algorithms/spatial_pooler.py的代码实现

我们以Complete-algo-example.py为实例对其进行研究。该范例的数据来自gymdata.csv。这是一个关于不同时间consumption数据的文件。其日期部分使用DateEncoder转换为SDR,其consumption部分使用RandomDistributedScalarEncoder转换为SDR。合并后输入sp。该范例的参数存放在model.yaml中。需要注意,该文件中SDRClassifierFactory.create()可能由于配置问题存在错误,我们直接使用python实现的SDRClassifier。另外其使用的tm与opf中使用的是不同的版本,导致结果不同。

 

(HTM)nupic空间沉积池实现解读_第1张图片

SpatialPooler主要包括两个方法。init方法接收入参,构造sp。compute方法接收一个sdr,并计算激活的列。(这里的列指圆柱区域)

 

Sp的一些重要入参包括:

InputDimensions=(946,),一维,输入sdr的大小。默认(32,32)是二维的。

ColumnDimensions=(2048,),一维,输出sdr的大小,默认(64,64)是二维的。

PotentialRadius=16.指每一个列,可以建立前馈输入的范围(半径)。其实际效果是,每一个圆柱的潜在输入,在其与输入sdr的对应输入位的一定范围内。

PotentialPct=0.85 潜在突触范围内,85%是潜在输入。

GlobalInhibition=1使用全局抑制

lacalAreaDensity=-1.0 抑制范围内活跃列的密度,不启用

numActiveColumnsPerInhArea=40,使用该方式控制活跃列数量为40

stimulusThreshold=0, 列激活的,有输入的最小连通突触数

synPermInactiveDec=0.005, 活跃列中,连接到非有效输入的突触的连通值减小量

synPermActiveInc=0.04, 活跃列中,连接到有效输入的突触的连通值增加量

synPermConnected=0.10, 连通阈值

minPctOverlapDutyCycle=0.001,

dutyCyclePeriod=1000, 计算抑制半径的周期

boostStrength=3.0,默认0

seed=1956,

spVerbosity=0,

wrapAround=True

 

Sp的内部变量包括:

self._numInputs=946 输入向量大小

self._numColumns=2048 列的数量

self._columnDimensions = 列的尺寸(各维度)。本例等价2048

self._inputDimensions = 输入的尺寸(各维度)。本例等价946

self._potentialRadius = 946 潜在半径

self._potentialPct = 0.85 列在输入(潜在突触范围内)上的连通百分比限制

self._globalInhibition = 1 启用全局抑制

self._numActiveColumnsPerInhArea = 40 每个抑制区域的活跃列数量限制

self._localAreaDensity = localAreaDensity 活跃列密度限制

self._stimulusThreshold = 0 列的连通位数下限

self._synPermInactiveDec = synPermInactiveDec 活跃列的非输入的减益

self._synPermActiveInc = synPermActiveInc 活跃列的输入的增益

self._synPermBelowStimulusInc = synPermConnected / 10.0 不活跃列的连通值增加量

self._synPermConnected = 0.1 突触连通阈值,同时也是基准值

self._minPctOverlapDutyCycles = 0.001 激活程度的最低占空比。低于它的列被认为是不活跃的。

self._dutyCyclePeriod = 1000 周期。每次计算一次占空比并进行学习。

self._boostStrength = 3.0 boosting的参数

self._spVerbosity = spVerbosity

self._wrapAround = wrapAround

self._synPermMin = 0.0

self._synPermMax = 1.0

self._synPermTrimThreshold = synPermActiveInc / 2.0

self._overlaps = numpy.zeros(self._numColumns, dtype=realDType)

self._boostedOverlaps = numpy.zeros(self._numColumns, dtype=realDType)

 

Init():

  1. 创建_overlaps,大小2048,dtype=float32。覆盖值数组,一个列的激活程度。
  2. 创建_boostedOverlaps,大小2048,dtype=float32。它是促进后的列的激活程度。
  3. 创建潜在连接池_potentialPools,它的size是(2048,946),它是2048大小的数组,每一个元素含有946位。潜在突触区域矩阵。它的每一列是一个圆柱区域,对于一列来说,如果某一行为1,则该行对应的输入是其潜在突触区域,是其存在连接可能的。
  4. 创建_permanences 2048*946. 突触连通值。稀疏矩阵实现。
  5. 创建_connectedSynapses 2048*946指示突触是否连通.由permanences得到,以阈值synPermConnected=0.1为界。
  6. _connectedCounts。对_connectedSynapses连通的突触计数。
  7. _mapPotential 给定一个列的下标。得到其潜在输入。首先列数和输入尺寸不是相同的。且一个列对应一个范围的输入,我们计算其输入中心。得到其中心后由potentialRadius潜在半径计算范围得到该列的输入。然后选中其职责范围内85%的输入。设置potential为1.这样初始时,仅有0.85的输入。更新到_potentialPools。
  8. 根据potential初始化_permanences连通值。在synPermConnected的基准上进行随机初始化。然后依据阈值synPermConnected更新_connectedSynapses的连通状态。最后记录连通总数到_connectedCounts。
  9. 初始化工作完成。
  10. Sp的核心内部变量是取1/0的潜在连接池potentialPools,指示某位是否与输入连接。突触连通值permanences。取1/0的连通池connectedSynapses,指示是否达到阈值连通了。初始时有0.85的时连通的。
  11. 创建_overlapDutyCycles,_activeDutyCycles,_minOverlapDutyCycles,他们的大小都是2048.
  12. 更新抑制半径_inhibitionRadius.全局抑制时抑制半径就是2048

 

Sp.Compute():

1.    calculateOverlap()计算每个柱状区域,其连通的前馈输入,输入是1的位的个数。具体计算方式为调用_connectedSynapses.rightVecSumAtNZ_fast,入参inputvector.使用overlap数组记录2048个数,connectedSynapses拿到inputvector后,计算每一个column激活的前馈输入的数量,写入overlap,overlap我们称之为激活程度。

2.    overlap*boostfactors记录到boostedOverlaps。将连通的,且有前馈输入的突触数量overlap乘以促进因子boostfactor,该因子初始化是1,后续一直没有激活的柱状区域的因子会被提高。

3.    抑制过程。boostedOverlaps作为参数,由_inhibitColumns计算。在所有2048个列中选择激活程度最高的40个列。得到activeColumns。抑制过程中,关键参数_inhibitionRadius抑制半径,会依据激活的柱状区域的数量而增大或缩小。首先计算抑制区域,为(直径+1)为底,ColumnDimensions的维度,即柱状区域和输入输出sdr的维度为指数乘方。即由半径算面积。然后计算密度density,为入参numActiveColumnsPerInhArea要求的40激活列,除以抑制区域,即所有区域的2048.本例采用全局抑制,调用_inhibitColumnsGlobal,由密度还原得到激活列数numActive=40.对overlaps进行排列,得到激活程度最高的前40个列的下标。并且激活程度要大于stimulusThreshold(默认值为0).

4.    以上已经得到了sp的输出activeColumns。将sp的输出activeArray根据下标activeColumns置一即可。可以由activeColumnIndices = np.nonzero(activeColumns)[0]得到激活列在原始column列表中下标。如图所示的”sp output activeColumnIndices“。下面是学习过程。

(HTM)nupic空间沉积池实现解读_第2张图片

5.    _adaptSynapses。这一步是修改连通值。入参inputVector,activeColumns(这里是之前inhibitColumnsGlobal方法返回的下标)。更新_permanences,对于活跃的列(不活跃的列不变,如果这个列被激活,我们认为它识别了一种模式,那么我们让它更加专注于这种模式),获得其潜在连通池,对其所有的连通值_permanences,如果该位有输入则增大synPermActiveInc,如果没有则减小synPermInactiveDec。_connectedSynapses和_connectedCounts同步更新。在这个过程中,注意每一个列最小连通数要符合要求。这样做的后果,是使得每一个列,在其潜在输入范围内,倾向于模拟其输入。从全局看,这样做的后果是,每一个列,在其潜在输入范围内,为其输入寻找共有模式。

6.    _updateDutyCycles更新占空比。即对于所有的列,计算到目前位置它的激活程度的和。和其激活的总次数。再除以周期数。

7.    _bumpUpWeakColumns。增加不活跃的列的连通值。如果一个列的激活程度过低,即小于minOverlapDutyCycles最低占空比,它的连通值会被增加连通阈值的1/10。即所谓对输入的覆盖情况不是很好。

8.    _updateBoostFactors 由激活次数的占空比,依据一个公式,修改列的促进因子。目的是为了达到D图的效果。

9.    _updateInhibitionRadius 更新抑制半径。全局抑制不变。

10.  _updateMinDutyCycles() 更新最小连通程度占空比。设置为当前最大的连通程度的1/1000

11.  综上,首先计算覆盖情况,乘以促进因子,然后在全局范围内进行抑制,取前40.最后进行学习,修改连通值。然后有两种独立的促进机制帮助一个列学习如何连接。一是overlap占空比过低,即对于输入的覆盖情况不是很好。这种情况提升其所有突触的连通值。二是激活次数过低,提升其促进因子。Sp_tutorial.py对sp进行了一些测试。

12.  over

你可能感兴趣的