Zac Gross

Code & More

Porting Nupic to Go

| Comments

Recently I ported the core parts of the Nupic project to Go.

Nupic is Numenta’s current open source implementation of Jeff Hawkin’s hierarchical temporal memory(HTM) model. It currently consists of the CLA (cortical learning algorithm) which is a single stage/layer of the HTM implemented in a mix of python and C++.

In an effort to better understand the difference between the current implementation and the whitepaper I decided to try and port the spatial and temporal poolers to Go. Porting line by line gave me the opportunity to understand the design better as well as it’s dependencies: python, numpy, etc…

One of the more difficult parts of this project was interpreting the numpy expressions and translating them into a statically typed language. A few nested numpy expressions can easily end up being 10 of lines of Go.

The result is 2 simple APIs for the spatial and temporal pooler which are go gettable.

1
2
    go get github.com/zacg/htm
    go get github.com/zacg/htm/utils
Spatial Pooler Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
   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 = true
    ssp.SynPermActiveInc = 0.01
    ssp.SpVerbosity = 10
    sp := htm.NewSpatialPooler(ssp)


    activeArray := make([]bool, sp.NumColumns())
    inputVector := make([]bool, sp.NumInputs())

    for idx, _ := range inputVector {
        inputVector[idx] = rand.Intn(5) >= 2
    }

    sp.Compute(inputVector, true, activeArray, sp.InhibitColumns)

    fmt.Println("Active Indices:", utils.OnIndices(activeArray))
Temporal Pooler Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package main

import (
    "fmt"
    "github.com/zacg/htm"
    "github.com/zacg/htm/utils"
)

func main() {
    tps := htm.NewTemporalPoolerParams()
    tps.Verbosity = 0
    tps.NumberOfCols = 50
    tps.CellsPerColumn = 2
    tps.ActivationThreshold = 8
    tps.MinThreshold = 10
    tps.InitialPerm = 0.5
    tps.ConnectedPerm = 0.5
    tps.NewSynapseCount = 10
    tps.PermanenceDec = 0.0
    tps.PermanenceInc = 0.1
    tps.GlobalDecay = 0
    tps.BurnIn = 1
    tps.PamLength = 10
    tps.CollectStats = true
    tp := htm.NewTemporalPooler(*tps)

    //Mock encoding of ABCDE
    inputs := 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"

    //Learning and prediction can be done at the same time

    //Learn 5 sequences above
    for i := 0; i < 10; i++ {
        for p := 0; p < 5; p++ {
            tp.Compute(inputs[p], true, false)
        }
        tp.Reset() //not required
    }

    //Predict sequences
    for i := 0; i < 4; i++ {
        tp.Compute(inputs[i], false, true)
        p := tp.DynamicState.InfPredictedState

        fmt.Printf("Predicted: %v From input: %v \n", p.NonZeroRows(), utils.OnIndices(inputs[i]))
    }

}

//helper method for creating boolean sequences
func boolRange(start int, end int, length int) []bool {
    result := make([]bool, length)
    for i := start; i <= end; i++ {
        result[i] = true
    }
    return result
}

You can grab the code @ https://github.com/zacg/htm

Comments