-
Notifications
You must be signed in to change notification settings - Fork 7
/
pool.go
337 lines (280 loc) · 11.9 KB
/
pool.go
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
// Code generated by "goal build"; DO NOT EDIT.
//line pool.goal:1
// Copyright (c) 2019, The Emergent Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package axon
import (
"cogentcore.org/core/base/atomicx"
"cogentcore.org/core/math32"
"github.com/emer/axon/v2/fsfffb"
"log"
"sync/atomic"
)
//gosl:start
//gosl:import "github.com/emer/axon/v2/fsfffb"
// PoolIntVars are int32 pool variables, for computing fsfffb inhibition etc.
// Note that we use int32 instead of uint32 so that overflow errors can be detected.
// See [PoolVars] for float32 variables.
type PoolIntVars int32 //enums:enum
const (
// PoolNeurSt is the starting layer-wise index within the list
// of neurons in this pool.
// Add layer starting neuron index (NeurSt) to get index into global
// network neurons list.
PoolNeurSt PoolIntVars = iota
// PoolNeurEd is the ending (exclusive) layer-wise index within the list
// of neurons in this pool.
// Add layer starting neuron index (NeurSt) to get index into global
// network neurons list.
PoolNeurEd
// PoolLayerIdx is the layer index for this pool.
PoolLayerIdx
// PoolIsLayer is true (> 0) if this pool represents the entire layer,
// which is always the first pool in the list of pools for a layer.
PoolIsLayer
// Clamped if true (!=0), this layer is hard-clamped and should
// use GeExts exclusively for PV.
Clamped
// PoolGated is true (> 0) if this pool gated (for [MatrixLayer], [BGThalLayer])
PoolGated
// FFsRawInt is the int32 atomic add compatible integration of [fsfffb.FFsRaw].
FFsRawInt
// FBsRawInt is the int32 atomic add compatible integration of [fsfffb.FBsRaw].
FBsRawInt
// GeExtRawInt is the int32 atomic add compatible integration of [fsfffb.GeExtRaw].
GeExtRawInt
// PoolIntAvgMaxStart is the starting point for int32 AvgMax variables.
// Use AvgMaxIntVarIndex to get the relevant variable index.
// There are only values for Cycle phase, for the different variables.
PoolIntAvgMaxStart
)
// AvgMax are Avg and Max
type AvgMax int32 //enums:enum
const (
Avg AvgMax = iota
Max
)
// AvgMaxPhases are the different Phases over which AvgMax values are tracked.
type AvgMaxPhases int32 //enums:enum -trim-prefix AM
const (
// Cycle is the current cycle, which is the source for the rest.
AMCycle AvgMaxPhases = iota
// Minus is at the end of the minus phase.
AMMinus
// Plus is at the end of the plus phase.
AMPlus
// Prev is at the end of the previous plus phase.
AMPrev
)
// AvgMaxVars are the different Neuron variables for which [AvgMaxPhases]
// is computed.
type AvgMaxVars int32 //enums:enum -trim-prefix AM
const (
// CaP is the primary variable for tracking overall pool activity
// over a recent timescale, integrated at roughly 40 msec time constant.
AMCaP AvgMaxVars = iota
// CaD is a slower moving activation signal, capable of reflecting
// activity over the entire trial.
AMCaD
// CaPMax is the maximum CaP over the trial of processing.
AMCaPMax
// Act is the computed rate-code equivalent of current spike rate.
AMAct
// GeInt is the integrated running-average value of excitatory conductance.
AMGeInt
// GiInt is the integrated running-average value of inhibitory conductance.
AMGiInt
// AvgDif is the integrated AvgDif between ActPct - TrgAvg.
// Only the Plus phase is used.
AMAvgDif
)
const (
// poolFloatAvgMaxStart is the starting index for AvgMax float32 variables.
poolFloatAvgMaxStart = fsfffb.InhibVarsN
PoolVarsN = poolFloatAvgMaxStart + fsfffb.InhibVars(int32(AvgMaxVarsN)*int32(AvgMaxN)*int32(AvgMaxPhasesN))
PoolIntVarsTot = PoolIntAvgMaxStart + PoolIntVars(int32(AvgMaxVarsN)*int32(AvgMaxN))
)
// avgMaxToNeuron is the mapping from AvgMaxVars to neuron vars.
var avgMaxToNeuron = [AMAvgDif]NeuronVars{CaP, CaD, CaPMax, Act, GeInt, GiInt}
// AvgMaxVarIndex returns the variable index for accessing
// [Pools] AvgMax float32 variables.
func AvgMaxVarIndex(vr AvgMaxVars, phase AvgMaxPhases, am AvgMax) uint32 {
return uint32(poolFloatAvgMaxStart) + uint32(vr)*uint32(AvgMaxN)*uint32(AvgMaxPhasesN) + uint32(phase)*uint32(AvgMaxN) + uint32(am)
}
// AvgMaxIntVarIndex returns the variable index for accessing
// [Pools] AvgMax int32 variables. Avg = Sum actually.
// There are only values for the Cycle phase level.
func AvgMaxIntVarIndex(vr AvgMaxVars, am AvgMax) uint32 {
return uint32(PoolIntAvgMaxStart) + uint32(vr)*uint32(AvgMaxN) + uint32(am)
}
// PoolAvgMax returns an AvgMax value for given variable, phase,
// and Avg or Max, for given pool index and data index.
func PoolAvgMax(vr AvgMaxVars, phase AvgMaxPhases, am AvgMax, pi, di uint32) float32 {
return Pools.Value(int(pi), int(di), int(AvgMaxVarIndex(vr, phase, am)))
}
// PoolNNeurons returns the number of neurons in the given pool.
// pi = global pool index.
func PoolNNeurons(pi uint32) int32 {
return PoolsInt.Value(int(pi), int(0), int(PoolNeurEd)) - PoolsInt.Value(int(pi), int(0), int(PoolNeurSt))
}
// PoolAvgMaxInit initializes the AvgMax Int accumulators for Cycle vals
// for update start. always left init'd so generally unnecessary.
// pi = global pool index.
func PoolAvgMaxInit(pi, di uint32) {
for vr := range AMAvgDif {
PoolsInt.Set(0, int(pi), int(di), int(AvgMaxIntVarIndex(vr, Avg)))
PoolsInt.Set(0, int(pi), int(di), int(AvgMaxIntVarIndex(vr, Max)))
}
}
// PoolAvgMaxZero initializes all the AvgMax values to zero.
// pi = global pool index.
func PoolAvgMaxZero(pi, di uint32) {
PoolAvgMaxInit(pi, di)
for vr := range AMAvgDif {
for ph := range AvgMaxPhasesN {
Pools.Set(0.0, int(pi), int(di), int(AvgMaxVarIndex(vr, ph, Avg)))
Pools.Set(0.0, int(pi), int(di), int(AvgMaxVarIndex(vr, ph, Max)))
}
}
}
// PoolAvgMaxUpdateVar updates the AvgMax value based on given value.
// pi = global pool index.
func PoolAvgMaxUpdateVar(vr AvgMaxVars, pi, di uint32, val float32) {
n := float32(PoolNNeurons(pi))
floatToInt := float32(uint32(1) << 20)
floatToSum := floatToInt / n
vis := AvgMaxIntVarIndex(vr, Avg)
vim := AvgMaxIntVarIndex(vr, Max)
atomic.AddInt32(PoolsInt.ValuePtr(int(pi), int(di), int(vis)), int32(val*floatToSum))
atomicx.MaxInt32(PoolsInt.ValuePtr(int(pi), int(di), int(vim)), int32(val*floatToInt))
}
// PoolAvgMaxUpdate updates the AvgMax values based on current neuron values.
// pi = global pool index.
func PoolAvgMaxUpdate(pi, di, ni uint32) {
PoolAvgMaxUpdateVar(AMCaP, pi, di, math32.Abs(Neurons.Value(int(ni), int(di), int(avgMaxToNeuron[AMCaP]))))
PoolAvgMaxUpdateVar(AMCaD, pi, di, math32.Abs(Neurons.Value(int(ni), int(di), int(avgMaxToNeuron[AMCaD]))))
PoolAvgMaxUpdateVar(AMCaPMax, pi, di, math32.Abs(Neurons.Value(int(ni), int(di), int(avgMaxToNeuron[AMCaPMax]))))
PoolAvgMaxUpdateVar(AMAct, pi, di, math32.Abs(Neurons.Value(int(ni), int(di), int(avgMaxToNeuron[AMAct]))))
PoolAvgMaxUpdateVar(AMGeInt, pi, di, math32.Abs(Neurons.Value(int(ni), int(di), int(avgMaxToNeuron[AMGeInt]))))
PoolAvgMaxUpdateVar(AMGiInt, pi, di, math32.Abs(Neurons.Value(int(ni), int(di), int(avgMaxToNeuron[AMGiInt]))))
}
// PoolAvgMaxCalcVar does Calc on Cycle level, and re-inits, for given Var
func PoolAvgMaxCalcVar(vr AvgMaxVars, pi, di uint32) {
floatFromInt := float32(1.0) / float32(uint32(1)<<20)
vis := AvgMaxIntVarIndex(vr, Avg)
sum := PoolsInt.Value(int(pi), int(di), int(vis))
if sum < 0 {
//gosl:end
log.Println("PoolAvgMaxCalc overflow in Sum", "pi:", pi, "di:", di, "sum:", sum)
//gosl:start
sum = int32(uint32(1) << 20)
}
Pools.Set(float32(sum)*floatFromInt, int(pi), int(di), int(AvgMaxVarIndex(vr, AMCycle, Avg)))
PoolsInt.Set(0, int(pi), int(di), int(vis))
vim := AvgMaxIntVarIndex(vr, Max)
mx := PoolsInt.Value(int(pi), int(di), int(vim))
if mx < 0 {
//gosl:end
log.Println("PoolAvgMaxCalc overflow in Max", "pi:", pi, "di:", di, "max:", mx)
//gosl:start
mx = int32(uint32(1) << 20)
}
PoolsInt.Set(0, int(pi), int(di), int(vim))
Pools.Set(float32(mx)*floatFromInt, int(pi), int(di), int(AvgMaxVarIndex(vr, AMCycle, Max)))
}
// PoolAvgMaxCalc does Calc on Cycle level, and re-inits
func PoolAvgMaxCalc(pi, di uint32) {
for vr := range AMAvgDif { // don't do AvgDif
PoolAvgMaxCalcVar(vr, pi, di)
}
}
// PoolAvgDifInit initializes the AvgMax AvgDif Int accumulators for Cycle vals
// for update start. always left init'd so generally unnecessary.
// pi = global pool index.
func PoolAvgDifInit(pi, di uint32) {
PoolsInt.Set(0, int(pi), int(di), int(AvgMaxIntVarIndex(AMAvgDif, Avg)))
PoolsInt.Set(0, int(pi), int(di), int(AvgMaxIntVarIndex(AMAvgDif, Max)))
}
// PoolAvgDifUpdate updates the AvgMax values for AvgDif Var.
// pi = global pool index.
func PoolAvgDifUpdate(pi, di uint32, avdif float32) {
PoolAvgMaxUpdateVar(AMAvgDif, pi, di, avdif)
}
// PoolAvgDifCalc does Calc on Cycle level, and re-inits
func PoolAvgDifCalc(pi, di uint32) {
PoolAvgMaxCalcVar(AMAvgDif, pi, di)
}
// PoolCycleToMinus grabs current Cycle values into the Minus phase values,
// and Plus values into Prev.
func PoolCycleToMinus(pi, di uint32) {
for vr := range AMAvgDif { // don't do AvgDif
Pools.Set(Pools.Value(int(pi), int(di), int(AvgMaxVarIndex(vr, AMCycle, Avg))), int(pi), int(di), int(AvgMaxVarIndex(vr, AMMinus, Avg)))
Pools.Set(Pools.Value(int(pi), int(di), int(AvgMaxVarIndex(vr, AMCycle, Max))), int(pi), int(di), int(AvgMaxVarIndex(vr, AMMinus, Max)))
Pools.Set(Pools.Value(int(pi), int(di), int(AvgMaxVarIndex(vr, AMPlus, Avg))), int(pi), int(di), int(AvgMaxVarIndex(vr, AMPrev, Avg)))
Pools.Set(Pools.Value(int(pi), int(di), int(AvgMaxVarIndex(vr, AMPlus, Max))), int(pi), int(di), int(AvgMaxVarIndex(vr, AMPrev, Max)))
}
}
// PoolCycleToPlus grabs current Cycle values into the Plus phase values.
func PoolCycleToPlus(pi, di uint32) {
for vr := range AMAvgDif { // don't do AvgDif
Pools.Set(Pools.Value(int(pi), int(di), int(AvgMaxVarIndex(vr, AMCycle, Avg))), int(pi), int(di), int(AvgMaxVarIndex(vr, AMPlus, Avg)))
Pools.Set(Pools.Value(int(pi), int(di), int(AvgMaxVarIndex(vr, AMCycle, Max))), int(pi), int(di), int(AvgMaxVarIndex(vr, AMPlus, Max)))
}
}
// PoolInit is callled during InitActs
func PoolInit(pi, di uint32) {
PoolInhibInit(pi, di)
PoolsInt.Set(0, int(pi), int(di), int(PoolGated))
PoolAvgMaxZero(pi, di)
}
// PoolPoolGi computes the total inhibitory conductance for the pool.
func PoolPoolGi(ctx *Context, pi, di uint32) {
if PoolsInt.Value(int(pi), int(di), int(PoolIsLayer)) > 0 {
return
}
li := PoolsInt.Value(int(pi), int(di), int(PoolLayerIdx))
PoolAvgMaxCalc(pi, di)
PoolInhibIntToRaw(pi, di)
ly := GetLayers(uint32(li))
giMult := LayerStates.Value(int(li), int(di), int(LayerGiMult))
lyIsOn := (ly.Inhib.Layer.On == 1)
lpi := ly.PoolIndex(uint32(0))
ly.SubPoolGiFromSpikes(ctx, lpi, pi, di, lyIsOn, giMult)
}
//gosl:end
// IndexToAvgMaxVar returns the AvgMaxVar indexes from overall Pool variable index.
func IndexToAvgMaxVar(vi uint32) (vr AvgMaxVars, phase AvgMaxPhases, am AvgMax) {
vi -= uint32(poolFloatAvgMaxStart)
vr = AvgMaxVars(vi / (uint32(AvgMaxN) * uint32(AvgMaxPhasesN)))
rmdr := vi % (uint32(AvgMaxN) * uint32(AvgMaxPhasesN))
phase = AvgMaxPhases(rmdr / uint32(AvgMaxN))
am = AvgMax(rmdr % uint32(AvgMaxN))
return
}
func PoolVarName(vi uint32) string {
if vi < uint32(fsfffb.InhibVarsN) {
return fsfffb.InhibVars(vi).String()
}
vr, phase, am := IndexToAvgMaxVar(vi)
return vr.String() + "_" + phase.String() + "_" + am.String()
}
// IndexToAvgMaxIntVar returns the AvgMaxVar indexes from overall PoolInt variable index.
func IndexToAvgMaxIntVar(vi uint32) (vr AvgMaxVars, am AvgMax) {
vi -= uint32(PoolIntAvgMaxStart)
vr = AvgMaxVars(vi / uint32(AvgMaxN))
am = AvgMax(vi % uint32(AvgMaxN))
return
}
func PoolIntVarName(vi uint32) string {
if vi < uint32(PoolIntAvgMaxStart) {
return PoolIntVars(vi).String()
}
vr, am := IndexToAvgMaxIntVar(vi)
return vr.String() + "_" + am.String()
}
// TestValues returns a map of CaD.Avg, which provides an
// integrated summary of pool activity for testing
func PoolTestValues(pi, di uint32, layKey string, vals map[string]float32) {
vals[layKey+" CaD Avg"] = PoolAvgMax(AMCaD, AMCycle, Avg, pi, di)
}