Hierarchical Temporal Memory Implementation in Golang
This is a direct port of the spatial & temporal poolers, temporal memory, and encoders as they currently exist in Numenta's Nupic Project. This project was done as a learning exercise, no effort has been made to optimize this implementation and it was not designed for production use.
The Nupic project basically demonstrates the CLA, a single stage of the cortical hierarchy. Eventually this same code can be extended to form a full HTM hierarchy. https://github.com/numenta/nupic
##Changes From Numentas Implementation
- Temporal pooler ephemeral state is stored in strongly typed struct rather than a hashmap. t-1 vars have "last" appended to their names.
- Temporal pooler params stored in "params" sub struct
- Binary data structures are used rather than ints
- No C++ dependency everything is written in Go
##Current State of Project
- Temporal and Spatial poolers pass basic tests
- Temporal memory passes basic unit tests
- Basic scaler encoder implemented
##Todo
* Finish temporal unit tests
- Implement a better sparse binary matrix structure with versions optimized for col or row heavy access.
- Implement better binary datastructure
- Refactor to be more idiomatic Go. It is basically a line for line port of the python implementation, it could be refactored to make better use of Go's type system.
- Implement some of the common encoders
##Examples
###Temporal Pooler
package main
import (
"fmt""github.com/zacg/htm""github.com/nupic-community/htmutils"
)
funcmain() {
tps:=htm.NewTemporalPoolerParams()
tps.Verbosity=0tps.NumberOfCols=50tps.CellsPerColumn=2tps.ActivationThreshold=8tps.MinThreshold=10tps.InitialPerm=0.5tps.ConnectedPerm=0.5tps.NewSynapseCount=10tps.PermanenceDec=0.0tps.PermanenceInc=0.1tps.GlobalDecay=0tps.BurnIn=1tps.PamLength=10tps.CollectStats=truetp:=htm.NewTemporalPooler(*tps)
//Mock encoding of ABCDEinputs:=make([][]bool, 5)
inputs[0] =boolRange(0, 9, 50) //bits 0-9 are "on"inputs[1] =boolRange(10, 19, 50) //bits 10-19 are "on"inputs[2] =boolRange(20, 29, 50) //bits 20-29 are "on"inputs[3] =boolRange(30, 39, 50) //bits 30-39 are "on"inputs[4] =boolRange(40, 49, 50) //bits 40-49 are "on"//Learn 5 sequences abovefori:=0; i<10; i++ {
forp:=0; p<5; p++ {
tp.Compute(inputs[p], true, false)
}
tp.Reset()
}
//Predict sequencesfori:=0; i<4; i++ {
tp.Compute(inputs[i], false, true)
p:=tp.DynamicState.InfPredictedStatefmt.Printf("Predicted: %v From input: %v \n", p.NonZeroRows(), utils.OnIndices(inputs[i]))
}
}
//helper method for creating boolean sequencesfuncboolRange(startint, endint, lengthint) []bool {
result:=make([]bool, length)
fori:=start; i<=end; i++ {
result[i] =true
}
returnresult
}
###Spatial Pooler
package main
import (
"fmt""github.com/davecheney/profile""github.com/zacg/htm""github.com/nupic-community/htmutils""math/rand"
)
funcmain() {
ssp:=htm.NewSpParams()
ssp.ColumnDimensions= []int{64, 64}
ssp.InputDimensions= []int{32, 32}
ssp.PotentialRadius=ssp.NumInputs()
ssp.NumActiveColumnsPerInhArea=int(0.02*float64(ssp.NumColumns()))
ssp.GlobalInhibition=truessp.SynPermActiveInc=0.01ssp.SpVerbosity=10sp:=htm.NewSpatialPooler(ssp)
activeArray:=make([]bool, sp.NumColumns())
inputVector:=make([]bool, sp.NumInputs())
foridx, _:=rangeinputVector {
inputVector[idx] =rand.Intn(5) >=2
}
sp.Compute(inputVector, true, activeArray, sp.InhibitColumns)
fmt.Println("Active Indices:", utils.OnIndices(activeArray))
}###Temporal Memory
tmp:=NewTemporalMemoryParams()
tmp.MaxNewSynapseCount=1000tm:=NewTemporalMemory(tmp)###Encoding
//Create new scaler encoderp:=NewScalerEncoderParams(3, 1, 8)
p.Radius=1.5p.Periodic=truep.Verbosity=5e:=NewScalerEncoder(p)
//Encode "1"encoded:=e.Encode(1, false)
//Print resultsfmt.Printfn("1 Encoded as: %v", utils.Bool2Int(encoded))//Create new date encoderp:=NewDateEncoderParams()
p.SeasonWidth=3p.DayOfWeekWidth=1p.WeekendWidth=3p.TimeOfDayWidth=5p.Verbosity=5de:=NewDateEncoder(p)
d:=time.Date(2010, 11, 4, 14, 55, 0, 0, time.UTC)
encoded:=de.Encode(d)
//Print resultsfmt.Printfn("%v Encoded as: %v", d, utils.Bool2Int(encoded))