Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Imagination #3

Open
wants to merge 64 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
2c27f30
use a new threshold for input cell activation during imagination
carver Mar 28, 2011
9ee17f7
execute a step of imagination, when running htm.imagineNext
carver Mar 28, 2011
0fcff95
test temporal recognition, using imagination (incomplete)
carver Mar 28, 2011
4bd381b
fix shift so that it's moving the right direction
carver Mar 28, 2011
b40a13e
Merge branch 'master' into HEAD
carver Mar 28, 2011
cb39a73
Merge branch 'refs/heads/master' of local repository into HEAD
carver Mar 28, 2011
8e2198e
only imagine the immediate next step
carver Mar 28, 2011
afe1ce7
Merge branch 'refs/heads/master' of local repository into HEAD
carver Mar 28, 2011
8e84b71
bugfix when looking to see if any columns cells are predicting
carver Mar 28, 2011
3f3746f
Merge branch 'refs/heads/master' of local repository into HEAD
carver Mar 28, 2011
448106d
show previous input and imagined activation in separate images
carver Mar 28, 2011
8c2c299
Merge branch 'refs/heads/master' of local repository into HEAD
carver Mar 28, 2011
477b0c7
Merge branch 'refs/heads/master' of local repository into HEAD
carver Mar 29, 2011
db0766a
show better information about columns during temporal recognition
carver Mar 29, 2011
fd0786c
merge from master
carver Mar 29, 2011
74d3c49
predict next step more accurately during imagination
carver Mar 29, 2011
26ea558
Merge branch 'refs/heads/master' of local repository into HEAD
carver Mar 29, 2011
4deb690
merge cleanup
carver Mar 29, 2011
67e041c
cache the predictingNext value to let it be set manually or calculated
carver Mar 29, 2011
aa65cbc
fix stuck cell state cache
carver Mar 29, 2011
6c37fd5
hide more image generation in recognition_temporal.py
carver Mar 29, 2011
f9bbc9e
Merge branch 'refs/heads/master' of local repository into HEAD
carver Mar 29, 2011
58fe38a
add clarifying comments
carver Mar 29, 2011
2656b10
ignore local config file
carver Mar 29, 2011
40aab33
refactor imagination/stimulation in HTM
carver Mar 29, 2011
930ef9f
convenience function to show input activation vs column stimulation
carver Mar 29, 2011
d07c253
Merge branch 'refs/heads/master' of local repository into HEAD
carver Mar 29, 2011
bfc2811
name/comment clarify
carver Mar 31, 2011
df8612d
last imagination run would have been more effective if the cutoff were
carver Mar 31, 2011
630fe92
try higher compression, fails test
carver Mar 31, 2011
52c9f9b
Merge branch 'master' into HEAD
carver Mar 31, 2011
46ed5eb
bugfix: input display would crash when htm was compressed
carver Mar 31, 2011
932c6ab
show red when input is not expected in display, or almost black if it
carver Mar 31, 2011
f5d4924
another input vs htm size bugfix
carver Mar 31, 2011
15deb9e
test smaller network to debug temporal pooler
carver Mar 31, 2011
35664c9
Merge branch 'refs/heads/master' of C:/Users/Jason/Documents/Coding/e…
carver Mar 31, 2011
7329e2d
Merge branch 'refs/heads/master' of C:/Users/Jason/Documents/Coding/e…
carver Mar 31, 2011
ba6e442
Merge branch 'refs/heads/master' of C:/Users/Jason/Documents/Coding/e…
carver Mar 31, 2011
5d61f03
continue learning while showing output, for step-through debugging
carver Mar 31, 2011
fee012e
Merge branch 'refs/heads/master' of C:/Users/Jason/Documents/Coding/e…
carver Mar 31, 2011
df52303
Merge branch 'refs/heads/master' of C:/Users/Jason/Documents/Coding/e…
carver Mar 31, 2011
bfaf9e6
Merge branch 'refs/heads/master' of C:/Users/Jason/Documents/Coding/e…
carver Mar 31, 2011
3391358
Merge branch 'refs/heads/master' of C:/Users/Jason/Documents/Coding/e…
carver Mar 31, 2011
9a2d937
Merge branch 'refs/heads/master' of C:/Users/Jason/Documents/Coding/e…
carver Mar 31, 2011
6b584e9
Merge branch 'refs/heads/master' of C:/Users/Jason/Documents/Coding/e…
carver Mar 31, 2011
1245750
Merge branch 'refs/heads/master' of C:/Users/Jason/Documents/Coding/e…
carver Mar 31, 2011
e68897b
fix many of the segment threshold updates in imagination branch
carver Mar 31, 2011
3d782a5
Merge branch 'refs/heads/master' of C:/Users/Jason/Documents/Coding/e…
carver Mar 31, 2011
36641e6
patch up final segment threshold holdover
carver Mar 31, 2011
9ef55ab
Merge branch 'refs/heads/master' of C:/Users/Jason/Documents/Coding/e…
carver Mar 31, 2011
f8abf85
merge new timing standard into branch
carver Mar 31, 2011
d6271d6
refactor out imagebuilder from htm_main
carver Mar 31, 2011
32d1f37
protect against empty set when rounding out synapses
carver Apr 1, 2011
30f5c1e
show more info in temporal recognition, plus a /0 bugfix
carver Apr 1, 2011
5496ad7
don't filter by near synapses when choosing the learning cell
carver Apr 1, 2011
af38bd8
shorter htm_main until it runs more efficiently
carver Apr 1, 2011
809ee39
Merge branch 'master' of C:/Users/Jason/Documents/Coding/eclipse-work…
carver Apr 1, 2011
704b321
Merge commit 'af38bd' into imagination
carver Apr 1, 2011
6ad13fd
automate looking for how many cells are lit up (finding a pattern?)
carver Apr 1, 2011
cbb7f48
fix sparsity to work normally on larger ones and degrade gracefully on
carver Apr 1, 2011
ced8906
successfully test temporal pooler & imagination on tiny 2x2 example
carver Apr 1, 2011
c4181e6
prefer segments that were learning when returning to temporal phase 1
carver Apr 1, 2011
e70a5e1
stimulate input according to permanence, when imagining
carver Apr 1, 2011
f93c4c6
htm lost pattern on one major cycle, so cycle twice to ingrain it,
carver Apr 1, 2011
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 39 additions & 19 deletions src/carver/htm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,15 @@
EXTENSION_NEXT_STEP_PENALTY = config.getboolean('extensions', 'next_step_penalty')

class HTM(object):

dimensions = 2 #hard-coded for now

def __init__(self, cellsPerColumn=None):
self.inhibitionRadius = config.getint('init', 'inhibitionRadius')

impliedSparsity = float(config.getint('constants','desiredLocalActivity'))/(self.inhibitionRadius**self.dimensions)
self.impliedSparsity = min(impliedSparsity, 1.0)

if cellsPerColumn:
self.cellsPerColumn = cellsPerColumn
else:
Expand Down Expand Up @@ -97,36 +104,35 @@ def inputLength(self):
return len(self._inputCells[0])

def imagineNext(self):
'project down estimates for next time step to the input cells'
'project down estimates for next time step to the input cells, and step through'
self._imagineStimulate(self.columns)
return self._imagineOverride(self._inputCells)

self._imagineOverride(self._inputCells)
self.__executeOne(False)

@classmethod
def _imagineStimulate(cls, columns):
'testable step one of imagineNext'
def stimulateFromColumns(cls, columns, columnFilter):
for col in columns:
if col.predicting:
down_scale = len(col.synapsesConnected)
activityPerSynapse = float(1) / down_scale
if columnFilter(col):
permanences = map(lambda syn: syn.permanence, col.synapsesConnected)
down_scale = float(sum(permanences))

for synapse in col.synapsesConnected:
synapse.input.stimulate(activityPerSynapse)
synapse.input.stimulate(synapse.permanence / down_scale)

@classmethod
def _imagineStimulate(cls, columns):
'testable step one of imagineNext'
cls.stimulateFromColumns(columns, lambda col: col.predictingNext)

@classmethod
def _imagineOverride(cls, inputCells):
'testable step two of imagineNext'

#flatten cell matrix
allInputs = []
cls.normalize_input_stimulation(inputCells)

for row in inputCells:
for cell in row:
allInputs.append(cell)

maxStim = max(map(lambda inCell: inCell.stimulation, allInputs))
if maxStim:
for inCell in allInputs:
inCell.stimulation /= maxStim
inCell.override()
cell.override()

def executeOnce(self, data, learning=True, postTick=None):
'''
Expand Down Expand Up @@ -248,8 +254,22 @@ def average_receptive_field_size(self):
radii = []
for c in self.columns:
for syn in c.synapsesConnected:
radii.append(((c.x-syn.input.x)**2 + (c.y-syn.input.y)**2)**0.5)
radius = ((c.x-syn.input.x)**2 + (c.y-syn.input.y)**2)**0.5
if radius!=0:
radii.append(radius)
return sum(radii)/len(radii)

@classmethod
def _max_input_stimulation(cls, inputCells):
return max(cell.stimulation for row in inputCells for cell in row)

@classmethod
def normalize_input_stimulation(cls, inputCells):
maxStim = cls._max_input_stimulation(inputCells)
if maxStim:
for row in inputCells:
for cell in row:
cell.stimulation /= maxStim

class UpdateSegments(DictDefault):

Expand Down
21 changes: 18 additions & 3 deletions src/carver/htm/cell.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,15 +144,25 @@ def __ne__(self, other):
return not (self == other)

def findSegmentWasActive(self, nextStep=True):
'prefer distal, return hits from segments connected to other cells that were active'
'''
prefer distal (comes for free, all cells have only distal segments)
prefer segments where learning cell triggered
return hits from segments connected to other cells that were active
'''
if nextStep:
segments = self.segmentsNear
else:
segments = self.segments

activeSeg = None

for seg in segments:
if seg.wasActive:
return seg
activeSeg = seg
if seg.wasActiveFromLearningCells:
return seg

return activeSeg

def bestMatchingSegment(self, nextStep):
'''
Expand All @@ -167,7 +177,12 @@ def bestMatchingSegment(self, nextStep):
'''
bestSegment = None
bestSegmentSynapseCount = MIN_THRESHOLD-1
for seg in filter(lambda seg: seg.nextStep == nextStep, self.segments):

segments = self.segments
if nextStep:
segments = self.segmentsNear

for seg in segments:
synapseCount = len(seg.old_firing_synapses(requireConnection=False))
if synapseCount > bestSegmentSynapseCount:
bestSegmentSynapseCount = synapseCount
Expand Down
20 changes: 18 additions & 2 deletions src/carver/htm/column.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,16 +127,20 @@ def neighbor_duty_cycle_max(self):
'''
return max((c.dutyCycleActive for c in self.neighbors))

def __adjustKthNeighborForSparsity(self, numNeighbors):
return max(int(self.htm.impliedSparsity*numNeighbors), 1)

def kth_neighbor(self, k):
'''

Numenta docs: Given the list of columns, return the kth highest overlap value
'''
allNeighbors = sorted(self.neighbors, reverse=True, key=lambda col: col.overlap)
index = min(k-1,len(allNeighbors)-1)
sparserK = self.__adjustKthNeighborForSparsity(len(allNeighbors))
index = min(k-1, sparserK-1)
return allNeighbors[index]

@property
@property
def predicting(self):
for cell in self.cells:
if cell.predicting:
Expand All @@ -151,6 +155,18 @@ def predictedNext(self):
return True
return False

@property
def predictingNext(self):
'''
is this column expected to get excited next?
@requires: cells' active state is already set
'''
for cell in self.cells:
for seg in cell.segmentsNear:
if seg.active:
return True
return False

def __hash__(self):
return self.x * self.y * hash(self.htm)

Expand Down
12 changes: 9 additions & 3 deletions src/carver/htm/input.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

@author: Jason Carver
'''
from carver.htm.synapse import SYNAPSES_PER_SEGMENT
from carver.htm.segment import FRACTION_SEGMENT_ACTIVATION_THRESHOLD

class InputCell(object):
'''
Expand Down Expand Up @@ -49,8 +51,12 @@ def stimulate(self, amount):

def override(self):
self.overrideInput = True
#TODO move magic number 0.8 into .properties file, or make htm understand float
self.stimulationPast = 1 if self.stimulation > 0.8 else 0
self.resetStimulation()

if self.stimulation >= FRACTION_SEGMENT_ACTIVATION_THRESHOLD:
self.stimulationPast = 1
else:
self.stimulationPast = 0

self.resetStimulation()


94 changes: 81 additions & 13 deletions src/carver/htm/io/image_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
'''

from PIL import Image
from carver.htm import HTM
from carver.htm.synapse import SYNAPSES_PER_SEGMENT
from carver.htm.segment import FRACTION_SEGMENT_ACTIVATION_THRESHOLD
from carver.htm.ui.excite_history import ExciteHistory

class ImageBuilder(object):
'''
Expand Down Expand Up @@ -35,37 +39,101 @@ def setData(self, data):
def show(self):
return self.img.show()

class ColumnDisplay(object):
def __init__(self, htm):
width = len(htm._column_grid)
length = len(htm._column_grid[0])
self.imageBuilder = ImageBuilder((width, length), self.colStateColor)
self.imageBuilder.setData(htm.columns)
class HTMDisplayBase(object):

def show(self):
return self.imageBuilder.show()

@classmethod
def showNow(cls, htm):
cls(htm).show()

class ActivityOverTimeDisplay(HTMDisplayBase):
def __init__(self, columnStates):
img = ImageBuilder([len(columnStates[0]), len(columnStates)], self.stateToRGB)
img.setData2D(columnStates)
img.rotate90()
self.imageBuilder = img

def show(self):
print """*************** Graph History **************
Y-Axis: All cells in the network, with the 4 cells per column grouped together
X-Axis: Time
Colors:
\tblack: no activity
\tgray: predicting
\twhite: active
"""
HTMDisplayBase.show(self)

@classmethod
def stateToRGB(cls, state):
if state == ExciteHistory.ACTIVE:
return (255, 255, 255)
elif state == ExciteHistory.PREDICTING:
return (127, 127, 127)
elif state == ExciteHistory.INACTIVE:
return (0, 0, 0)
else:
return (255, 0, 0) #unknown cell/column state

class ColumnDisplay(HTMDisplayBase):
def __init__(self, htm):
width = len(htm._column_grid)
length = len(htm._column_grid[0])
self.imageBuilder = ImageBuilder((width, length), self.colStateColor)
self.imageBuilder.setData(htm.columns)

@classmethod
def colStateColor(cls, column):
if column.active:
if column.active and column.predictedNext: #correct
return (0,255,0)
elif column.active: #false negative
return (255,0,0)
elif column.predictedNext: #false positive
return (180,0,180) #purple
else:
return (0,0,0)

class InputReflectionOverlayDisplay(HTMDisplayBase):
'show the input cells, and the column activation pushed back onto the input space'
def __init__(self, htm):
self.imageBuilder = ImageBuilder((htm.inputWidth, htm.inputLength), self.inputOverlay)

HTM.stimulateFromColumns(htm.columns, lambda col: col.active)
HTM.normalize_input_stimulation(htm._inputCells)

data = [(cell, cell.stimulation) for row in htm._inputCells for cell in row]

for row in htm._inputCells:
for cell in row:
cell.resetStimulation()

self.imageBuilder.setData(data)

@classmethod
def inputOverlay(cls, cellInfo):
(cell, percentStimulated) = cellInfo

triggered = percentStimulated >= FRACTION_SEGMENT_ACTIVATION_THRESHOLD

if cell.wasActive and triggered: #correct
return (0,int(percentStimulated*255),0)
elif cell.wasActive: #false negative
return (255-int(percentStimulated*255),0,0)
elif triggered: #false positive
return (int(percentStimulated*180),0,int(percentStimulated*180)) #purple
else:
gray = int(percentStimulated*255)
return (gray,gray,gray)


class InputCellsDisplay(object):
class InputCellsDisplay(HTMDisplayBase):
def __init__(self, htm):
self.imageBuilder = ImageBuilder((htm.width, htm.length), self.cellActiveBW)
self.imageBuilder = ImageBuilder((htm.inputWidth, htm.inputLength), self.cellActiveBW)
data = [cell for row in htm._inputCells for cell in row]
self.imageBuilder.setData(data)

def show(self):
return self.imageBuilder.show()

@classmethod
def cellActiveBW(cls, cell):
'A black and white representation of whether a cell is active'
Expand Down
21 changes: 17 additions & 4 deletions src/carver/htm/segment.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,18 @@ def old_firing_synapses(self, requireConnection=True):
'''
return filter(lambda synapse: synapse.was_firing(requireConnection=requireConnection),
self.synapses)

@classmethod
def _is_firing_filter(cls, requireConnection=True):
return lambda synapse: synapse.is_firing(requireConnection=requireConnection)

def synapses_firing(self, requireConnection=True):
'''
@param requireConnection: only include synapse if the synapse is connected
@return an iterable of firing synapses
'''
return filter(self._is_firing_filter(requireConnection),
self.synapses)

def increase_permanences(self, byAmount):
'increase permanence on all synapses'
Expand All @@ -72,7 +84,7 @@ def active(self):
Timing note: a synapse is considered active if the cell it came from
was active in the previous step
'''
filterFunc = lambda synapse: synapse.is_firing(requireConnection=True)
filterFunc = self._is_firing_filter(requireConnection=True)
return self._areSynapsesAboveThreshold(filterFunc)

@property
Expand Down Expand Up @@ -121,6 +133,7 @@ def round_out_synapses(self, htm):
missingSynapses = MAX_NEW_SYNAPSES - len(synapses)
if missingSynapses > 0:
lastLearningCells = filter(lambda cell: cell.wasLearning, htm.cells)
for _ in xrange(missingSynapses):
cell = random.choice(lastLearningCells)
self.create_synapse(cell)
if len(lastLearningCells):
for _ in xrange(missingSynapses):
cell = random.choice(lastLearningCells)
self.create_synapse(cell)
4 changes: 2 additions & 2 deletions src/carver/htm/synapse.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def was_firing(self, requireConnection=True):
if False: return True even if synapse is not connected
'''
return self.input.wasActive and (self.connected or not requireConnection)

def is_firing(self, requireConnection=True):
'''
Is the input firing?
Expand All @@ -54,7 +54,7 @@ def firing_at(self, timeDelta, requireConnection=True):
else:
raise NotImplementedError

def wasInputLearning(self):
def wasInputLearning(self):
if not hasattr(input, 'learning'):
return False
else:
Expand Down
Loading