Example #1
0
//Returns number of columns
func (ssp *SpParams) NumColumns() int {
	return utils.ProdInt(ssp.ColumnDimensions)
}
Example #2
0
//Creates a new spatial pooler
func NewSpatialPooler(spParams SpParams) *SpatialPooler {
	sp := SpatialPooler{}
	//Validate inputs
	sp.numColumns = utils.ProdInt(spParams.ColumnDimensions)
	sp.numInputs = utils.ProdInt(spParams.InputDimensions)

	if sp.numColumns < 1 {
		panic("Must have at least 1 column")
	}
	if sp.numInputs < 1 {
		panic("must have at least 1 input")
	}
	if spParams.NumActiveColumnsPerInhArea < 1 && (spParams.LocalAreaDensity < 1) && (spParams.LocalAreaDensity >= 0.5) {
		panic("Num active colums invalid")
	}

	sp.InputDimensions = spParams.InputDimensions
	sp.ColumnDimensions = spParams.ColumnDimensions
	sp.PotentialRadius = int(mathutil.Min(spParams.PotentialRadius, sp.numInputs))
	sp.PotentialPct = spParams.PotentialPct
	sp.GlobalInhibition = spParams.GlobalInhibition
	sp.LocalAreaDensity = spParams.LocalAreaDensity
	sp.NumActiveColumnsPerInhArea = spParams.NumActiveColumnsPerInhArea
	sp.StimulusThreshold = spParams.StimulusThreshold
	sp.SynPermInactiveDec = spParams.SynPermInactiveDec
	sp.SynPermActiveInc = spParams.SynPermActiveInc
	sp.SynPermBelowStimulusInc = spParams.SynPermConnected / 10.0
	sp.SynPermConnected = spParams.SynPermConnected
	sp.MinPctOverlapDutyCycles = spParams.MinPctOverlapDutyCycle
	sp.MinPctActiveDutyCycles = spParams.MinPctActiveDutyCycle
	sp.DutyCyclePeriod = spParams.DutyCyclePeriod
	sp.MaxBoost = spParams.MaxBoost
	sp.Seed = spParams.Seed
	sp.SpVerbosity = spParams.SpVerbosity

	// Extra parameter settings
	sp.SynPermMin = 0
	sp.SynPermMax = 1
	sp.SynPermTrimThreshold = sp.SynPermActiveInc / 2.0
	if sp.SynPermTrimThreshold >= sp.SynPermConnected {
		panic("Syn perm threshold >= syn connected.")
	}
	sp.UpdatePeriod = 50
	sp.InitConnectedPct = 0.5

	/*
			# Internal state
		    version = 1.0
		    iterationNum = 0
		    iterationLearnNum = 0
	*/

	/*
			 Store the set of all inputs that are within each column's potential pool.
		     'potentialPools' is a matrix, whose rows represent cortical columns, and
		     whose columns represent the input bits. if potentialPools[i][j] == 1,
		     then input bit 'j' is in column 'i's potential pool. A column can only be
		     connected to inputs in its potential pool. The indices refer to a
		     falttenned version of both the inputs and columns. Namely, irrespective
		     of the topology of the inputs and columns, they are treated as being a
		     one dimensional array. Since a column is typically connected to only a
		     subset of the inputs, many of the entries in the matrix are 0. Therefore
		     the the potentialPool matrix is stored using the SparseBinaryMatrix
		     class, to reduce memory footprint and compuation time of algorithms that
		     require iterating over the data strcuture.
	*/
	sp.potentialPools = NewDenseBinaryMatrix(sp.numColumns, sp.numInputs)

	/*
			 Initialize the permanences for each column. Similar to the
		     'potentialPools', the permances are stored in a matrix whose rows
		     represent the cortial columns, and whose columns represent the input
		     bits. if permanences[i][j] = 0.2, then the synapse connecting
		     cortical column 'i' to input bit 'j' has a permanence of 0.2. Here we
		     also use the SparseMatrix class to reduce the memory footprint and
		     computation time of algorithms that require iterating over the data
		     structure. This permanence matrix is only allowed to have non-zero
		     elements where the potential pool is non-zero.
	*/
	//Assumes 70% sparsity
	elms := make(map[int]float64, int(float64(sp.numColumns*sp.numInputs)*0.3))
	sp.permanences = matrix.MakeSparseMatrix(elms, sp.numColumns, sp.numInputs)

	/*
			 Initialize a tiny random tie breaker. This is used to determine winning
		     columns where the overlaps are identical.
	*/

	sp.tieBreaker = make([]float64, sp.numColumns)
	for i := 0; i < len(sp.tieBreaker); i++ {
		sp.tieBreaker[i] = 0.01 * rand.Float64()
	}

	/*
			 'connectedSynapses' is a similar matrix to 'permanences'
		     (rows represent cortial columns, columns represent input bits) whose
		     entries represent whether the cortial column is connected to the input
		     bit, i.e. its permanence value is greater than 'synPermConnected'. While
		     this information is readily available from the 'permanence' matrix,
		     it is stored separately for efficiency purposes.
	*/
	sp.connectedSynapses = NewDenseBinaryMatrix(sp.numColumns, sp.numInputs)

	/*
			 Stores the number of connected synapses for each column. This is simply
		     a sum of each row of 'ConnectedSynapses'. again, while this
		     information is readily available from 'ConnectedSynapses', it is
		     stored separately for efficiency purposes.
	*/
	sp.connectedCounts = make([]int, sp.numColumns)

	/*
			 Initialize the set of permanence values for each columns. Ensure that
		     each column is connected to enough input bits to allow it to be
		     activated
	*/

	for i := 0; i < sp.numColumns; i++ {
		potential := sp.mapPotential(i, true)
		sp.potentialPools.ReplaceRow(i, potential)
		perm := sp.initPermanence(potential, sp.InitConnectedPct)
		sp.updatePermanencesForColumn(perm, i, true)
	}

	sp.overlapDutyCycles = make([]float64, sp.numColumns)
	sp.activeDutyCycles = make([]float64, sp.numColumns)
	sp.minOverlapDutyCycles = make([]float64, sp.numColumns)
	sp.minActiveDutyCycles = make([]float64, sp.numColumns)
	sp.boostFactors = make([]float64, sp.numColumns)
	for i := 0; i < len(sp.boostFactors); i++ {
		sp.boostFactors[i] = 1.0
	}

	/*
			The inhibition radius determines the size of a column's local
		    neighborhood. of a column. A cortical column must overcome the overlap
		    score of columns in his neighborhood in order to become actives. This
		    radius is updated every learning round. It grows and shrinks with the
		    average number of connected synapses per column.
	*/
	sp.inhibitionRadius = 0
	sp.updateInhibitionRadius(sp.avgConnectedSpanForColumnND, sp.avgColumnsPerInput)

	if sp.spVerbosity > 0 {
		sp.printParameters()
	}

	return &sp
}
Example #3
0
//Returns number of inputs
func (ssp *SpParams) NumInputs() int {
	return utils.ProdInt(ssp.InputDimensions)
}
Example #4
0
func TestAvgConnectedSpanForColumnND(t *testing.T) {
	sp := SpatialPooler{}
	sp.InputDimensions = []int{4, 4, 2, 5}
	sp.numInputs = utils.ProdInt(sp.InputDimensions)
	sp.numColumns = 5
	sp.ColumnDimensions = []int{0, 1, 2, 3, 4}

	sp.connectedSynapses = NewDenseBinaryMatrix(sp.numColumns, sp.numInputs)

	connected := make([]bool, sp.numInputs)
	connected[(1*40)+(0*10)+(1*5)+(0*1)] = true
	connected[(1*40)+(0*10)+(1*5)+(1*1)] = true
	connected[(3*40)+(2*10)+(1*5)+(0*1)] = true
	connected[(3*40)+(0*10)+(1*5)+(0*1)] = true
	connected[(1*40)+(0*10)+(1*5)+(3*1)] = true
	connected[(2*40)+(2*10)+(1*5)+(0*1)] = true

	//# span: 3 3 1 4, avg = 11/4
	sp.connectedSynapses.ReplaceRow(0, connected)

	connected2 := make([]bool, sp.numInputs)
	connected2[(2*40)+(0*10)+(1*5)+(0*1)] = true
	connected2[(2*40)+(0*10)+(0*5)+(0*1)] = true
	connected2[(3*40)+(0*10)+(0*5)+(0*1)] = true
	connected2[(3*40)+(0*10)+(1*5)+(0*1)] = true
	//spn: 2 1 2 1, avg = 6/4
	sp.connectedSynapses.ReplaceRow(1, connected2)

	connected3 := make([]bool, sp.numInputs)
	connected3[(0*40)+(0*10)+(1*5)+(4*1)] = true
	connected3[(0*40)+(0*10)+(0*5)+(3*1)] = true
	connected3[(0*40)+(0*10)+(0*5)+(1*1)] = true
	connected3[(1*40)+(0*10)+(0*5)+(2*1)] = true
	connected3[(0*40)+(0*10)+(1*5)+(1*1)] = true
	connected3[(3*40)+(3*10)+(1*5)+(1*1)] = true
	// span: 4 4 2 4, avg = 14/4
	sp.connectedSynapses.ReplaceRow(2, connected3)

	connected4 := make([]bool, sp.numInputs)
	connected4[(3*40)+(3*10)+(1*5)+(4*1)] = true
	connected4[(0*40)+(0*10)+(0*5)+(0*1)] = true

	// span: 4 4 2 5, avg = 15/4
	sp.connectedSynapses.ReplaceRow(3, connected4)

	connected5 := make([]bool, sp.numInputs)
	//# span: false false false false, avg = false
	sp.connectedSynapses.ReplaceRow(4, connected5)

	//t.Logf("width: %v", sp.connectedSynapses.Width)

	trueAvgConnectedSpan := []float64{11.0 / 4.0, 6.0 / 4.0, 14.0 / 4.0, 15.0 / 4.0, 0.0}

	for i, tspan := range trueAvgConnectedSpan {
		connectedSpan := sp.avgConnectedSpanForColumnND(i)
		if connectedSpan != tspan {
			t.Errorf("Connected span was: %v expected: %v", connectedSpan, tspan)
		}
	}

}