diff --git a/axon/rubicon-net.go b/axon/rubicon-net.go
index 38c98bd0..1d15d6e7 100644
--- a/axon/rubicon-net.go
+++ b/axon/rubicon-net.go
@@ -488,7 +488,7 @@ func (nt *Network) ConnectToSC1to1(send, recv *Layer) *Path {
// from Global Drive.Drives.
// Uses a PopCode representation based on LayerParams.Act.PopCode, distributed over
// given numbers of neurons in the X and Y dimensions, per drive pool.
-func (nt *Network) AddDrivesLayer(ctx *Context, nNeurY, nNeurX int) *Layer {
+func (nt *Network) AddDrivesLayer(nNeurY, nNeurX int) *Layer {
nix := nt.NetIxs()
drv := nt.AddLayer4D("Drives", DrivesLayer, 1, int(nix.RubiconNPosUSs), nNeurY, nNeurX)
return drv
@@ -499,8 +499,8 @@ func (nt *Network) AddDrivesLayer(ctx *Context, nNeurY, nNeurX int) *Layer {
// Uses a PopCode representation based on LayerParams.Act.PopCode, distributed over
// given numbers of neurons in the X and Y dimensions, per drive pool.
// Adds Pulvinar predictive layers for Drives.
-func (nt *Network) AddDrivesPulvLayer(ctx *Context, nNeurY, nNeurX int, space float32) (drv, drvP *Layer) {
- drv = nt.AddDrivesLayer(ctx, nNeurY, nNeurX)
+func (nt *Network) AddDrivesPulvLayer(nNeurY, nNeurX int, space float32) (drv, drvP *Layer) {
+ drv = nt.AddDrivesLayer(nNeurY, nNeurX)
drvP = nt.AddPulvForLayer(drv, space)
drvP.AddDefaultParams(func(ly *LayerParams) {
ly.Inhib.ActAvg.Nominal = 0.01
@@ -534,12 +534,12 @@ func (nt *Network) AddUrgencyLayer(nNeurY, nNeurX int) *Layer {
// valences -- this is what the dopamine value ends up conding (pos - neg).
// Layers are organized in depth per type: USs in one column, PVs in the next,
// with Drives in the back; urgency behind that.
-func (nt *Network) AddRubiconPulvLayers(ctx *Context, nYneur, popY, popX int, space float32) (drives, drivesP, urgency, usPos, usNeg, cost, costFinal, usPosP, usNegP, costP, pvPos, pvNeg, pvPosP, pvNegP *Layer) {
+func (nt *Network) AddRubiconPulvLayers(nYneur, popY, popX int, space float32) (drives, drivesP, urgency, usPos, usNeg, cost, costFinal, usPosP, usNegP, costP, pvPos, pvNeg, pvPosP, pvNegP *Layer) {
rel := relpos.Behind
usPos, usNeg, cost, costFinal, usPosP, usNegP, costP = nt.AddUSPulvLayers(popY, popX, rel, space)
pvPos, pvNeg, pvPosP, pvNegP = nt.AddPVPulvLayers(popY, popX, rel, space)
- drives, drivesP = nt.AddDrivesPulvLayer(ctx, popY, popX, space)
+ drives, drivesP = nt.AddDrivesPulvLayer(popY, popX, space)
urgency = nt.AddUrgencyLayer(popY, popX)
pvPos.PlaceRightOf(usPos, space)
@@ -551,7 +551,7 @@ func (nt *Network) AddRubiconPulvLayers(ctx *Context, nYneur, popY, popX int, sp
// AddOFCpos adds orbital frontal cortex positive US-coding layers,
// for given number of pos US pools (first is novelty / curiosity pool),
// with given number of units per pool.
-func (nt *Network) AddOFCpos(ctx *Context, nUSs, nY, ofcY, ofcX int, space float32) (ofc, ofcCT, ofcPT, ofcPTp, ofcMD *Layer) {
+func (nt *Network) AddOFCpos(nUSs, nY, ofcY, ofcX int, space float32) (ofc, ofcCT, ofcPT, ofcPTp, ofcMD *Layer) {
ofc, ofcCT, ofcPT, ofcPTp, ofcMD = nt.AddPFC4D("OFCpos", "MD", 1, nUSs, ofcY, ofcX, true, true, space)
ofc.AddDefaultParams(func(ly *LayerParams) { ly.Inhib.Pool.Gi = 1 })
ofcPT.AddDefaultParams(func(ly *LayerParams) { ly.Inhib.ActAvg.Nominal = 0.02 })
@@ -569,7 +569,7 @@ func (nt *Network) AddOFCpos(ctx *Context, nUSs, nY, ofcY, ofcX int, space float
// AddOFCneg adds orbital frontal cortex negative US-coding layers,
// for given number of neg US pools with given number of units per pool.
-func (nt *Network) AddOFCneg(ctx *Context, nUSs, ofcY, ofcX int, space float32) (ofc, ofcCT, ofcPT, ofcPTp, ofcMD *Layer) {
+func (nt *Network) AddOFCneg(nUSs, ofcY, ofcX int, space float32) (ofc, ofcCT, ofcPT, ofcPTp, ofcMD *Layer) {
ofc, ofcCT, ofcPT, ofcPTp, ofcMD = nt.AddPFC4D("OFCneg", "MD", 1, nUSs, ofcY, ofcX, true, true, space)
ofc.AddDefaultParams(func(ly *LayerParams) { ly.Inhib.Pool.Gi = 1 })
@@ -587,7 +587,7 @@ func (nt *Network) AddOFCneg(ctx *Context, nUSs, ofcY, ofcX int, space float32)
// AddACCost adds anterior cingulate cost coding layers,
// for given number of cost pools (typically 2: time, effort),
// with given number of units per pool.
-func (nt *Network) AddACCost(ctx *Context, nCosts, accY, accX int, space float32) (acc, accCT, accPT, accPTp, accMD *Layer) {
+func (nt *Network) AddACCost(nCosts, accY, accX int, space float32) (acc, accCT, accPT, accPTp, accMD *Layer) {
acc, accCT, accPT, accPTp, accMD = nt.AddPFC4D("ACCcost", "MD", 1, nCosts, accY, accX, true, true, space)
acc.AddDefaultParams(func(ly *LayerParams) { ly.Inhib.Layer.On.SetBool(false) }) // no match
@@ -625,7 +625,7 @@ func (nt *Network) AddACCost(ctx *Context, nCosts, accY, accX int, space float32
// Makes all appropriate interconnections and sets default parameters.
// Needs CS -> BLA, OFC connections to be made.
// Returns layers most likely to be used for remaining connections and positions.
-func (nt *Network) AddRubiconOFCus(ctx *Context, nYneur, popY, popX, bgY, bgX, ofcY, ofcX int, space float32) (vSgpi, vSmtxGo, vSmtxNo, vSpatchD1, vSpatchD2, urgency, usPos, pvPos, usNeg, usNegP, pvNeg, pvNegP, blaPosAcq, blaPosExt, blaNegAcq, blaNegExt, blaNov, ofcPos, ofcPosCT, ofcPosPT, ofcPosPTp, ilPos, ilPosCT, ilPosPT, ilPosPTp, ilPosMD, ofcNeg, ofcNegCT, ofcNegPT, ofcNegPTp, accCost, accCostCT, accCostPT, accCostPTp, accCostMD, ilNeg, ilNegCT, ilNegPT, ilNegPTp, ilNegMD, sc *Layer) {
+func (nt *Network) AddRubiconOFCus(nYneur, popY, popX, bgY, bgX, ofcY, ofcX int, space float32) (vSgpi, vSmtxGo, vSmtxNo, vSpatchD1, vSpatchD2, urgency, usPos, pvPos, usNeg, usNegP, pvNeg, pvNegP, blaPosAcq, blaPosExt, blaNegAcq, blaNegExt, blaNov, ofcPos, ofcPosCT, ofcPosPT, ofcPosPTp, ilPos, ilPosCT, ilPosPT, ilPosPTp, ilPosMD, ofcNeg, ofcNegCT, ofcNegPT, ofcNegPTp, accCost, accCostCT, accCostPT, accCostPTp, accCostMD, ilNeg, ilNegCT, ilNegPT, ilNegPTp, ilNegMD, sc *Layer) {
nUSpos := int(nt.Rubicon.NPosUSs)
nUSneg := int(nt.Rubicon.NNegUSs)
nCosts := int(nt.Rubicon.NCosts)
@@ -634,7 +634,7 @@ func (nt *Network) AddRubiconOFCus(ctx *Context, nYneur, popY, popX, bgY, bgX, o
_ = lhb
_ = ldt
- drives, drivesP, urgency, usPos, usNeg, cost, costFinal, usPosP, usNegP, costP, pvPos, pvNeg, pvPosP, pvNegP := nt.AddRubiconPulvLayers(ctx, nYneur, popY, popX, space)
+ drives, drivesP, urgency, usPos, usNeg, cost, costFinal, usPosP, usNegP, costP, pvPos, pvNeg, pvPosP, pvNegP := nt.AddRubiconPulvLayers(nYneur, popY, popX, space)
_ = urgency
vSmtxGo, vSmtxNo, vSgpePr, vSgpeAk, vSstn, vSgpi := nt.AddVBG("", 1, nUSpos, bgY, bgX, bgY, bgX, space)
@@ -650,10 +650,10 @@ func (nt *Network) AddRubiconOFCus(ctx *Context, nYneur, popY, popX, bgY, bgX, o
blaPosAcq, blaPosExt, blaNegAcq, blaNegExt, cemPos, cemNeg, blaNov := nt.AddAmygdala("", true, ofcY, ofcX, space)
_, _, _, _, _ = blaNegAcq, blaNegExt, cemPos, cemNeg, blaNov
- ofcPos, ofcPosCT, ofcPosPT, ofcPosPTp, ofcPosMD := nt.AddOFCpos(ctx, nUSpos, nYneur, ofcY, ofcX, space)
+ ofcPos, ofcPosCT, ofcPosPT, ofcPosPTp, ofcPosMD := nt.AddOFCpos(nUSpos, nYneur, ofcY, ofcX, space)
_ = ofcPosPT
- ofcNeg, ofcNegCT, ofcNegPT, ofcNegPTp, ofcNegMD := nt.AddOFCneg(ctx, nUSneg, ofcY, ofcX, space)
+ ofcNeg, ofcNegCT, ofcNegPT, ofcNegPTp, ofcNegMD := nt.AddOFCneg(nUSneg, ofcY, ofcX, space)
_ = ofcNegPT
ilPos, ilPosCT, ilPosPT, ilPosPTp, ilPosMD = nt.AddPFC2D("ILpos", "MD", ofcY, ofcX, true, true, space)
@@ -665,7 +665,7 @@ func (nt *Network) AddRubiconOFCus(ctx *Context, nYneur, popY, popX, bgY, bgX, o
ilPosPT.AddDefaultParams(func(ly *LayerParams) { ly.Acts.Dend.ModACh.SetBool(true) })
ilNegPT.AddDefaultParams(func(ly *LayerParams) { ly.Acts.Dend.ModACh.SetBool(true) })
- accCost, accCostCT, accCostPT, accCostPTp, accCostMD = nt.AddACCost(ctx, nCosts, ofcY, ofcX, space)
+ accCost, accCostCT, accCostPT, accCostPTp, accCostMD = nt.AddACCost(nCosts, ofcY, ofcX, space)
_ = accCostPT
p1to1 := paths.NewPoolOneToOne()
@@ -1005,12 +1005,12 @@ func (nt *Network) AddRubiconOFCus(ctx *Context, nYneur, popY, popX, bgY, bgX, o
// Makes all appropriate interconnections and sets default parameters.
// Needs CS -> BLA, OFC connections to be made.
// Returns layers most likely to be used for remaining connections and positions.
-func (nt *Network) AddRubicon(ctx *Context, nYneur, popY, popX, bgY, bgX, pfcY, pfcX int, space float32) (vSgpi, vSmtxGo, vSmtxNo, urgency, pvPos, blaPosAcq, blaPosExt, blaNegAcq, blaNegExt, blaNov, ofcPos, ofcPosCT, ofcPosPT, ofcPosPTp, ilPos, ilPosCT, ilPosPT, ilPosPTp, ofcNeg, ofcNegCT, ofcNegPT, ofcNegPTp, ilNeg, ilNegCT, ilNegPT, ilNegPTp, accCost, plUtil, sc *Layer) {
+func (nt *Network) AddRubicon(nYneur, popY, popX, bgY, bgX, pfcY, pfcX int, space float32) (vSgpi, vSmtxGo, vSmtxNo, urgency, pvPos, blaPosAcq, blaPosExt, blaNegAcq, blaNegExt, blaNov, ofcPos, ofcPosCT, ofcPosPT, ofcPosPTp, ilPos, ilPosCT, ilPosPT, ilPosPTp, ofcNeg, ofcNegCT, ofcNegPT, ofcNegPTp, ilNeg, ilNegCT, ilNegPT, ilNegPTp, accCost, plUtil, sc *Layer) {
full := paths.NewFull()
var pt *Path
- vSgpi, vSmtxGo, vSmtxNo, vSpatchD1, vSpatchD2, urgency, usPos, pvPos, usNeg, usNegP, pvNeg, pvNegP, blaPosAcq, blaPosExt, blaNegAcq, blaNegExt, blaNov, ofcPos, ofcPosCT, ofcPosPT, ofcPosPTp, ilPos, ilPosCT, ilPosPT, ilPosPTp, ilPosMD, ofcNeg, ofcNegCT, ofcNegPT, ofcNegPTp, accCost, accCostCT, accCostPT, accCostPTp, accCostMD, ilNeg, ilNegCT, ilNegPT, ilNegPTp, ilNegMD, sc := nt.AddRubiconOFCus(ctx, nYneur, popY, popX, bgY, bgX, pfcY, pfcX, space)
+ vSgpi, vSmtxGo, vSmtxNo, vSpatchD1, vSpatchD2, urgency, usPos, pvPos, usNeg, usNegP, pvNeg, pvNegP, blaPosAcq, blaPosExt, blaNegAcq, blaNegExt, blaNov, ofcPos, ofcPosCT, ofcPosPT, ofcPosPTp, ilPos, ilPosCT, ilPosPT, ilPosPTp, ilPosMD, ofcNeg, ofcNegCT, ofcNegPT, ofcNegPTp, accCost, accCostCT, accCostPT, accCostPTp, accCostMD, ilNeg, ilNegCT, ilNegPT, ilNegPTp, ilNegMD, sc := nt.AddRubiconOFCus(nYneur, popY, popX, bgY, bgX, pfcY, pfcX, space)
_, _, _, _, _, _, _ = usPos, usNeg, usNegP, pvNeg, pvNegP, ilPosCT, ilNegMD
_, _, _ = accCost, accCostCT, accCostPTp
_, _ = blaNegAcq, blaNegExt
diff --git a/examples/deep-fsa/deep-fsa.go b/examples/deep-fsa/deep-fsa.go
index 3a055bec..8dd1a013 100644
--- a/examples/deep-fsa/deep-fsa.go
+++ b/examples/deep-fsa/deep-fsa.go
@@ -699,7 +699,8 @@ func (ss *Sim) ConfigGUI() {
ss.GUI.CycleUpdateInterval = 10
nv := ss.GUI.AddNetView("Network")
- nv.Options.MaxRecs = 300
+ nv.Options.MaxRecs = 2 * ss.Config.Run.Cycles
+ nv.Options.Raster.Max = ss.Config.Run.Cycles
nv.SetNet(ss.Net)
ss.TrainUpdate.Config(nv, axon.Theta, ss.StatCounters)
ss.TestUpdate.Config(nv, axon.Theta, ss.StatCounters)
diff --git a/examples/deep-move/deep-move.go b/examples/deep-move/deep-move.go
index b3207ae2..b3c57e6d 100644
--- a/examples/deep-move/deep-move.go
+++ b/examples/deep-move/deep-move.go
@@ -658,7 +658,8 @@ func (ss *Sim) ConfigGUI() {
ss.GUI.CycleUpdateInterval = 10
nv := ss.GUI.AddNetView("Network")
- nv.Options.MaxRecs = 300
+ nv.Options.MaxRecs = 2 * ss.Config.Run.Cycles
+ nv.Options.Raster.Max = ss.Config.Run.Cycles
nv.SetNet(ss.Net)
ss.TrainUpdate.Config(nv, axon.Theta, ss.StatCounters)
ss.TestUpdate.Config(nv, axon.Theta, ss.StatCounters)
diff --git a/examples/deep-music/deep-music.go b/examples/deep-music/deep-music.go
index bd6ab45e..1dfe59e1 100644
--- a/examples/deep-music/deep-music.go
+++ b/examples/deep-music/deep-music.go
@@ -658,7 +658,8 @@ func (ss *Sim) ConfigGUI() {
ss.GUI.CycleUpdateInterval = 10
nv := ss.GUI.AddNetView("Network")
- nv.Options.MaxRecs = 300
+ nv.Options.MaxRecs = 2 * ss.Config.Run.Cycles
+ nv.Options.Raster.Max = ss.Config.Run.Cycles
nv.SetNet(ss.Net)
ss.TrainUpdate.Config(nv, axon.Theta, ss.StatCounters)
ss.TestUpdate.Config(nv, axon.Theta, ss.StatCounters)
diff --git a/examples/inhib/inhib.go b/examples/inhib/inhib.go
index 608fd91b..dc2716e0 100644
--- a/examples/inhib/inhib.go
+++ b/examples/inhib/inhib.go
@@ -548,7 +548,8 @@ func (ss *Sim) ConfigGUI() {
ss.GUI.CycleUpdateInterval = 10
nv := ss.GUI.AddNetView("Network")
- nv.Options.MaxRecs = 300
+ nv.Options.MaxRecs = 2 * ss.Config.Run.Cycles
+ nv.Options.Raster.Max = ss.Config.Run.Cycles
nv.SetNet(ss.Net)
ss.NetUpdate.Config(nv, axon.Cycle, ss.StatCounters)
ss.GUI.OnStop = func(mode, level enums.Enum) {
diff --git a/examples/mpi/mpi.go b/examples/mpi/mpi.go
index 76b4441d..6c9d4ff0 100644
--- a/examples/mpi/mpi.go
+++ b/examples/mpi/mpi.go
@@ -341,7 +341,7 @@ func (ss *Sim) ConfigLoops() {
})
if ss.Config.GUI {
- axon.LooperUpdateNetView(ls, Cycle, Trial, ss.NetViewUpdater, ss.StatCounters)
+ axon.LooperUpdateNetView(ls, Cycle, Trial, ss.NetViewUpdater)
ls.Stacks[Train].OnInit.Add("GUI-Init", func() { ss.GUI.UpdateWindow() })
ls.Stacks[Test].OnInit.Add("GUI-Init", func() { ss.GUI.UpdateWindow() })
@@ -692,7 +692,8 @@ func (ss *Sim) ConfigGUI() {
ss.GUI.CycleUpdateInterval = 10
nv := ss.GUI.AddNetView("Network")
- nv.Options.MaxRecs = 300
+ nv.Options.MaxRecs = 2 * ss.Config.Run.Cycles
+ nv.Options.Raster.Max = ss.Config.Run.Cycles
nv.SetNet(ss.Net)
ss.TrainUpdate.Config(nv, axon.Theta, ss.StatCounters)
ss.TestUpdate.Config(nv, axon.Theta, ss.StatCounters)
diff --git a/examples/neuron/neuron.go b/examples/neuron/neuron.go
index 86cbda42..c53ef035 100644
--- a/examples/neuron/neuron.go
+++ b/examples/neuron/neuron.go
@@ -433,7 +433,8 @@ func (ss *Sim) ConfigGUI() {
ss.GUI.CycleUpdateInterval = 10
nv := ss.GUI.AddNetView("Network")
- nv.Options.MaxRecs = 300
+ nv.Options.MaxRecs = 2 * ss.Config.Run.Cycles
+ nv.Options.Raster.Max = ss.Config.Run.Cycles
nv.SetNet(ss.Net)
ss.NetUpdate.Config(nv, axon.Cycle, ss.StatCounters)
ss.GUI.OnStop = func(mode, level enums.Enum) {
diff --git a/examples/objrec/objrec.go b/examples/objrec/objrec.go
index d8e1d8ed..e83c4a4c 100644
--- a/examples/objrec/objrec.go
+++ b/examples/objrec/objrec.go
@@ -678,7 +678,8 @@ func (ss *Sim) ConfigGUI() {
ss.GUI.CycleUpdateInterval = 10
nv := ss.GUI.AddNetView("Network")
- nv.Options.MaxRecs = 300
+ nv.Options.MaxRecs = 2 * ss.Config.Run.Cycles
+ nv.Options.Raster.Max = ss.Config.Run.Cycles
nv.SetNet(ss.Net)
ss.TrainUpdate.Config(nv, axon.Theta, ss.StatCounters)
ss.TestUpdate.Config(nv, axon.Theta, ss.StatCounters)
diff --git a/examples/pcore-ds/pcore-ds.go b/examples/pcore-ds/pcore-ds.go
index b0052d8f..4bfe43a7 100644
--- a/examples/pcore-ds/pcore-ds.go
+++ b/examples/pcore-ds/pcore-ds.go
@@ -202,9 +202,9 @@ func (ss *Sim) ConfigEnv() {
}
func (ss *Sim) ConfigRubicon(trn *MotorSeqEnv) {
- pv := &ss.Net.Rubicon
- pv.SetNUSs(2, 1)
- pv.Urgency.U50 = 20 // 20 def
+ rp := &ss.Net.Rubicon
+ rp.SetNUSs(2, 1)
+ rp.Urgency.U50 = 20 // 20 def
}
func (ss *Sim) ConfigNet(net *axon.Network) {
@@ -479,9 +479,9 @@ func (ss *Sim) ApplyInputs(mode Modes) {
// ApplyRubicon applies Rubicon reward inputs
func (ss *Sim) ApplyRubicon(ev *MotorSeqEnv, mode Modes, inRew bool, di uint32) {
- pv := &ss.Net.Rubicon
- pv.EffortUrgencyUpdate(di, 1)
- pv.Urgency.Reset(di)
+ rp := &ss.Net.Rubicon
+ rp.EffortUrgencyUpdate(di, 1)
+ rp.Urgency.Reset(di)
if inRew {
axon.GlobalScalars.Set(1, int(axon.GvACh), int(di))
@@ -493,13 +493,13 @@ func (ss *Sim) ApplyRubicon(ev *MotorSeqEnv, mode Modes, inRew bool, di uint32)
}
func (ss *Sim) SetRew(rew float32, di uint32) {
- pv := &ss.Net.Rubicon
+ rp := &ss.Net.Rubicon
axon.GlobalSetRew(di, rew, true)
axon.GlobalScalars.Set(rew, int(axon.GvDA), int(di)) // no reward prediction error
if rew > 0 {
- pv.SetUS(di, axon.Positive, 0, 1)
+ rp.SetUS(di, axon.Positive, 0, 1)
} else if rew < 0 {
- pv.SetUS(di, axon.Negative, 0, 1)
+ rp.SetUS(di, axon.Negative, 0, 1)
}
}
@@ -682,7 +682,6 @@ func (ss *Sim) RunStats(mode Modes, level Levels, phase StatsPhase) {
if phase == Step && ss.GUI.Tabs != nil {
nm := mode.String() + "/" + level.String() + " Plot"
ss.GUI.Tabs.GoUpdatePlot(nm)
- ss.GUI.Tabs.GoUpdatePlot("Train/TrialAll Plot")
}
}
@@ -872,7 +871,8 @@ func (ss *Sim) ConfigGUI() {
ss.GUI.CycleUpdateInterval = 10
nv := ss.GUI.AddNetView("Network")
- nv.Options.MaxRecs = 300
+ nv.Options.MaxRecs = 2 * ss.Config.Run.Cycles
+ nv.Options.Raster.Max = ss.Config.Run.Cycles
nv.SetNet(ss.Net)
ss.TrainUpdate.Config(nv, axon.Theta, ss.StatCounters)
ss.TestUpdate.Config(nv, axon.Theta, ss.StatCounters)
diff --git a/examples/pcore-vs/pcore-vs.go b/examples/pcore-vs/pcore-vs.go
index 632643bc..02e24588 100644
--- a/examples/pcore-vs/pcore-vs.go
+++ b/examples/pcore-vs/pcore-vs.go
@@ -197,9 +197,9 @@ func (ss *Sim) ConfigEnv() {
}
func (ss *Sim) ConfigRubicon(trn *GoNoEnv) {
- pv := &ss.Net.Rubicon
- pv.SetNUSs(2, 1)
- pv.Urgency.U50 = 20 // 20 def
+ rp := &ss.Net.Rubicon
+ rp.SetNUSs(2, 1)
+ rp.Urgency.U50 = 20 // 20 def
}
func (ss *Sim) ConfigNet(net *axon.Network) {
@@ -410,10 +410,10 @@ func (ss *Sim) ApplyInputs(mode Modes, trial, theta int) {
// ApplyRubicon applies Rubicon reward inputs
func (ss *Sim) ApplyRubicon(ev *GoNoEnv, mode Modes, trial int, di uint32) {
- pv := &ss.Net.Rubicon
- pv.EffortUrgencyUpdate(di, 1)
+ rp := &ss.Net.Rubicon
+ rp.EffortUrgencyUpdate(di, 1)
if mode == Test {
- pv.Urgency.Reset(di)
+ rp.Urgency.Reset(di)
}
switch trial {
@@ -437,13 +437,13 @@ func (ss *Sim) GatedRew(ev *GoNoEnv, di uint32) {
}
func (ss *Sim) SetRew(rew float32, di uint32) {
- pv := &ss.Net.Rubicon
+ rp := &ss.Net.Rubicon
axon.GlobalSetRew(di, rew, true)
axon.GlobalScalars.Set(rew, int(axon.GvDA), int(di)) // no reward prediction error
if rew > 0 {
- pv.SetUS(di, axon.Positive, 0, 1)
+ rp.SetUS(di, axon.Positive, 0, 1)
} else if rew < 0 {
- pv.SetUS(di, axon.Negative, 0, 1)
+ rp.SetUS(di, axon.Negative, 0, 1)
}
}
@@ -713,7 +713,8 @@ func (ss *Sim) ConfigGUI() {
ss.GUI.CycleUpdateInterval = 10
nv := ss.GUI.AddNetView("Network")
- nv.Options.MaxRecs = 300
+ nv.Options.MaxRecs = 2 * ss.Config.Run.Cycles
+ nv.Options.Raster.Max = ss.Config.Run.Cycles
nv.SetNet(ss.Net)
ss.TrainUpdate.Config(nv, axon.Theta, ss.StatCounters)
ss.TestUpdate.Config(nv, axon.Theta, ss.StatCounters)
diff --git a/examples/pfcmaint/pfcmaint_env.go b/examples/pfcmaint/pfcmaint-env.go
similarity index 100%
rename from examples/pfcmaint/pfcmaint_env.go
rename to examples/pfcmaint/pfcmaint-env.go
diff --git a/examples/pfcmaint/pfcmaint.go b/examples/pfcmaint/pfcmaint.go
index 943442bf..9eb0308c 100644
--- a/examples/pfcmaint/pfcmaint.go
+++ b/examples/pfcmaint/pfcmaint.go
@@ -222,8 +222,8 @@ func (ss *Sim) ConfigNet(net *axon.Network) {
}
func (ss *Sim) ConfigRubicon() {
- pv := &ss.Net.Rubicon
- pv.SetNUSs(1, 1)
+ rp := &ss.Net.Rubicon
+ rp.SetNUSs(1, 1)
}
func (ss *Sim) ApplyParams() {
@@ -348,8 +348,8 @@ func (ss *Sim) ApplyInputs(mode Modes, trial, theta int) {
// ApplyRubicon applies Rubicon reward inputs
func (ss *Sim) ApplyRubicon(ev *PFCMaintEnv, mode Modes, trial int, di uint32) {
- pv := &ss.Net.Rubicon
- pv.NewState(di, &ss.Net.Rand) // first before anything else is updated
+ rp := &ss.Net.Rubicon
+ rp.NewState(di, &ss.Net.Rand) // first before anything else is updated
if ev.Trial.Cur == 0 { // reset maint on rew -- trial counter wraps around to 0
axon.GlobalSetRew(di, 1, true)
}
@@ -567,7 +567,8 @@ func (ss *Sim) ConfigGUI() {
ss.GUI.CycleUpdateInterval = 10
nv := ss.GUI.AddNetView("Network")
- nv.Options.MaxRecs = 300
+ nv.Options.MaxRecs = 2 * ss.Config.Run.Cycles
+ nv.Options.Raster.Max = ss.Config.Run.Cycles
nv.SetNet(ss.Net)
ss.TrainUpdate.Config(nv, axon.Theta, ss.StatCounters)
ss.TestUpdate.Config(nv, axon.Theta, ss.StatCounters)
diff --git a/examples/pvlv/cond/blocks_all.go b/examples/pvlv/cond/blocks-all.go
similarity index 100%
rename from examples/pvlv/cond/blocks_all.go
rename to examples/pvlv/cond/blocks-all.go
diff --git a/examples/pvlv/cond/conds_all.go b/examples/pvlv/cond/conds-all.go
similarity index 100%
rename from examples/pvlv/cond/conds_all.go
rename to examples/pvlv/cond/conds-all.go
diff --git a/examples/pvlv/cond/env.go b/examples/pvlv/cond/env.go
index 2e82f1a4..a9c2a1e8 100644
--- a/examples/pvlv/cond/env.go
+++ b/examples/pvlv/cond/env.go
@@ -11,7 +11,6 @@ import (
"cogentcore.org/core/tensor"
"github.com/emer/emergent/v2/env"
- "github.com/emer/emergent/v2/etime"
)
// CondEnv provides a flexible implementation of standard Pavlovian
@@ -86,29 +85,24 @@ func (ev *CondEnv) Config(rmax int, rnm string) {
ev.RunName = rnm
ev.Run.Max = rmax
ev.NYReps = 4
- ev.Run.Scale = etime.Run
- ev.Condition.Scale = etime.Condition
- ev.Block.Scale = etime.Block
- ev.Sequence.Scale = etime.Sequence
- ev.Tick.Scale = etime.Tick
-
ev.CurStates = make(map[string]*tensor.Float32)
stsh := []int{StimShape[0], StimShape[1], ev.NYReps, 1}
- ev.CurStates["CS"] = tensor.NewFloat32(stsh)
+ ev.CurStates["CS"] = tensor.NewFloat32(stsh...)
ctsh := []int{ContextShape[0], ContextShape[1], ev.NYReps, 1}
- ev.CurStates["ContextIn"] = tensor.NewFloat32(ctsh)
+ ev.CurStates["ContextIn"] = tensor.NewFloat32(ctsh...)
ustsh := make([]int, 4)
copy(ustsh, USTimeShape)
ustsh[2] = ev.NYReps
- ev.CurStates["USTimeIn"] = tensor.NewFloat32(ustsh)
- ev.CurStates["Time"] = tensor.NewFloat32([]int{1, MaxTime, ev.NYReps, 1})
+ ev.CurStates["USTimeIn"] = tensor.NewFloat32(ustsh...)
+ ev.CurStates["Time"] = tensor.NewFloat32(1, MaxTime, ev.NYReps, 1)
ussh := []int{USShape[0], USShape[1], ev.NYReps, 1}
- ev.CurStates["USpos"] = tensor.NewFloat32(ussh)
- ev.CurStates["USneg"] = tensor.NewFloat32(ussh)
+ ev.CurStates["USpos"] = tensor.NewFloat32(ussh...)
+ ev.CurStates["USneg"] = tensor.NewFloat32(ussh...)
}
-func (ev *CondEnv) Label() string { return ev.Name }
+func (ev *CondEnv) Label() string { return ev.Name }
+func (ev *CondEnv) String() string { return ev.SequenceName }
// Init sets current run index and max
func (ev *CondEnv) Init(ridx int) {
@@ -142,7 +136,7 @@ func (ev *CondEnv) InitCond() {
ev.Tick.Max = trl.NTicks
}
-func (ev *CondEnv) State(element string) tensor.Tensor {
+func (ev *CondEnv) State(element string) tensor.Values {
return ev.CurStates[element]
}
@@ -168,7 +162,7 @@ func (ev *CondEnv) Step() bool {
return true
}
-func (ev *CondEnv) Action(_ string, _ tensor.Tensor) {
+func (ev *CondEnv) Action(_ string, _ tensor.Values) {
// nop
}
diff --git a/examples/pvlv/cond/inputs.go b/examples/pvlv/cond/inputs.go
index d56936c3..7fc85405 100644
--- a/examples/pvlv/cond/inputs.go
+++ b/examples/pvlv/cond/inputs.go
@@ -95,7 +95,7 @@ func SetStim(tsr *tensor.Float32, nyrep int, stm string) int {
xy = append(xy, 0)
for y := 0; y < nyrep; y++ {
xy[2] = y
- tsr.Set(xy, 1)
+ tsr.Set(1, xy...)
}
return stidx
}
@@ -120,7 +120,7 @@ func SetContext(tsr *tensor.Float32, nyrep int, ctx string) int {
xy = append(xy, 0)
for y := 0; y < nyrep; y++ {
xy[2] = y
- tsr.Set(xy, 1)
+ tsr.Set(1, xy...)
}
return ctidx
}
@@ -150,7 +150,7 @@ func SetUSTime(tsr *tensor.Float32, nyrep, stidx, tick, start, end int) bool {
}
for y := 0; y < nyrep; y++ {
idx[2] = y
- tsr.Set(idx, 1)
+ tsr.Set(1, idx...)
}
return true
}
@@ -163,7 +163,7 @@ func SetTime(tsr *tensor.Float32, nyrep int, tick int) {
idx := []int{0, tick, 0, 0}
for y := 0; y < nyrep; y++ {
idx[2] = y
- tsr.Set(idx, 1)
+ tsr.Set(1, idx...)
}
}
@@ -172,6 +172,6 @@ func SetUS(tsr *tensor.Float32, nyrep int, pv int, mag float32) {
idx := []int{0, pv, 0, 0}
for y := 0; y < nyrep; y++ {
idx[2] = y
- tsr.Set(idx, mag)
+ tsr.Set(mag, idx...)
}
}
diff --git a/examples/pvlv/cond/runs_all.go b/examples/pvlv/cond/runs-all.go
similarity index 100%
rename from examples/pvlv/cond/runs_all.go
rename to examples/pvlv/cond/runs-all.go
diff --git a/examples/pvlv/config.go b/examples/pvlv/config.go
index 46653279..2ba6ed0c 100644
--- a/examples/pvlv/config.go
+++ b/examples/pvlv/config.go
@@ -4,21 +4,20 @@
package main
-// EnvConfig has config params for environment
-// note: only adding fields for key Env params that matter for both Network and Env
-// other params are set via the Env map data mechanism.
+// EnvConfig has config params for environment.
type EnvConfig struct {
- // env parameters -- can set any field/subfield on Env struct, using standard TOML formatting
+ // Env parameters: can set any field/subfield on Env struct,
+ // using standard TOML formatting.
Env map[string]any
- // environment run name
+ // RunName is the environment overall run config.
RunName string `default:"PosAcq_A100B50"`
- // override the default number of blocks to run conditions with NBlocks
+ // SetNBlocks overrides the default number of blocks to run conditions with NBlocks.
SetNBlocks bool
- // number of blocks to run if SetNBlocks is true
+ // NBlocks is number of blocks to run if SetNBlocks is true.
NBlocks int
}
@@ -31,97 +30,112 @@ func (ec *EnvConfig) ShouldDisplay(field string) bool {
}
}
-// ParamConfig has config parameters related to sim params
+// ParamConfig has config parameters related to sim params.
type ParamConfig struct {
- // Rubicon parameters -- can set any field/subfield on Net.Rubicon params, using standard TOML formatting
+ // Rubicon parameters: can set any field/subfield on Net.Rubicon params,
+ // using standard TOML formatting.
Rubicon map[string]any
- // network parameters
- Network map[string]any
-
- // Extra Param Sheet name(s) to use (space separated if multiple) -- must be valid name as listed in compiled-in params or loaded params
+ // Sheet is the extra params sheet name(s) to use (space separated
+ // if multiple). Must be valid name as listed in compiled-in params
+ // or loaded params.
Sheet string
- // extra tag to add to file names and logs saved from this run
+ // Tag is an extra tag to add to file names and logs saved from this run.
Tag string
- // user note -- describe the run params etc -- like a git commit message for the run
+ // Note is additional info to describe the run params etc,
+ // like a git commit message for the run.
Note string
- // Name of the JSON file to input saved parameters from.
- File string `nest:"+"`
-
- // Save a snapshot of all current param and config settings in a directory named params_ (or _good if Good is true), then quit -- useful for comparing to later changes and seeing multiple views of current params
+ // SaveAll will save a snapshot of all current param and config settings
+ // in a directory named params_ (or _good if Good is true),
+ // then quit. Useful for comparing to later changes and seeing multiple
+ // views of current params.
SaveAll bool `nest:"+"`
- // for SaveAll, save to params_good for a known good params state. This can be done prior to making a new release after all tests are passing -- add results to git to provide a full diff record of all params over time.
+ // Good is for SaveAll, save to params_good for a known good params state.
+ // This can be done prior to making a new release after all tests are passing.
+ // Add results to git to provide a full diff record of all params over level.
Good bool `nest:"+"`
}
-// RunConfig has config parameters related to running the sim
+// RunConfig has config parameters related to running the sim.
type RunConfig struct {
- // use the GPU for computation -- only for testing in this model -- not faster
+ // GPU uses the GPU for computation: not faster in this case.
GPU bool `default:"false"`
- // number of parallel threads for CPU computation -- 0 = use default
+ // NThreads is the number of parallel threads for CPU computation;
+ // 0 = use default.
NThreads int `default:"0"`
- // number of cycles per Theta phase (trial) -- either 200 or 300 (latter needed for motor actions)
- ThetaCycles int `default:"300"`
-
- // starting run number -- determines the random seed -- runs counts from there -- can do all runs in parallel by launching separate jobs with each run, runs = 1
+ // Run is the _starting_ run number, which determines the random seed.
+ // NRuns counts up from there. Can do all runs in parallel by launching
+ // separate jobs with each starting Run, NRuns = 1.
Run int `default:"0"`
- // total number of runs to do when running Train
- NRuns int `default:"1" min:"1"`
+ // Runs is the total number of runs to do when running Train, starting from Run.
+ Runs int `default:"25" min:"1"`
+
+ // Cycles is the total number of cycles per trial: at least 200.
+ Cycles int `default:"200"`
+
+ // PlusCycles is the total number of plus-phase cycles per trial. For Cycles=300, use 100.
+ PlusCycles int `default:"50"`
}
-// LogConfig has config parameters related to logging data
+// LogConfig has config parameters related to logging data.
type LogConfig struct {
- // stats to aggregate at higher levels
- AggStats []string `default:"['DA','RewPred']"`
-
- // if true, save final weights after each run
+ // SaveWeights will save final weights after each run.
SaveWeights bool
- // if true, save block log to file, as .blk.tsv typically
- Block bool `default:"true" nest:"+"`
+ // Train has the list of Train mode levels to save log files for.
+ Train []string `default:"['Run', 'Epoch']" nest:"+"`
- // if true, save condition log to file, as .cnd.tsv typically
- Cond bool `default:"true" nest:"+"`
-
- // if true, save trial log to file, as .trl.tsv typically
- Trial bool `default:"false" nest:"+"`
-
- // if true, save network activation etc data from testing trials, for later viewing in netview
- NetData bool
+ // Testing activates testing mode: records detailed data for Go CI tests
+ // (not the same as running test mode on network, via Looper).
+ Testing bool
}
-// Config is a standard Sim config -- use as a starting point.
+// Config has the overall Sim configuration options.
type Config struct {
- // specify include files here, and after configuration, it contains list of include files added
+ // Name is the short name of the sim.
+ Name string `display:"-" default:"PVLV"`
+
+ // Title is the longer title of the sim.
+ Title string `display:"-" default:"Primary Value, Learned Value"`
+
+ // URL is a link to the online README or other documentation for this sim.
+ URL string `display:"-" default:"https://github.com/emer/axon/blob/main/examples/pvlv/README.md"`
+
+ // Doc is brief documentation of the sim.
+ Doc string `display:"-" default:"Simulates the primary value, learned value model of classical conditioning and phasic dopamine in the amygdala, ventral striatum and associated areas."`
+
+ // Includes has a list of additional config files to include.
+ // After configuration, it contains list of include files added.
Includes []string
- // open the GUI -- does not automatically run -- if false, then runs automatically and quits
+ // GUI means open the GUI. Otherwise it runs automatically and quits,
+ // saving results to log files.
GUI bool `default:"true"`
- // log debugging information
+ // Debug reports debugging information.
Debug bool
- // environment configuration options
+ // Env has environment configuration options.
Env EnvConfig `display:"add-fields"`
- // parameter related configuration options
+ // Params has parameter related configuration options.
Params ParamConfig `display:"add-fields"`
- // sim running related configuration options
+ // Run has sim running related configuration options.
Run RunConfig `display:"add-fields"`
- // data logging related configuration options
+ // Log has data logging related configuration options.
Log LogConfig `display:"add-fields"`
}
diff --git a/examples/pvlv/effort_plot.go b/examples/pvlv/effort-plot.go
similarity index 99%
rename from examples/pvlv/effort_plot.go
rename to examples/pvlv/effort-plot.go
index 7ed2a04f..dc95bfcd 100644
--- a/examples/pvlv/effort_plot.go
+++ b/examples/pvlv/effort-plot.go
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:build not
+
// effort_plot plots the Rubicon effort cost equations.
package main
diff --git a/examples/pvlv/params.go b/examples/pvlv/params.go
index 18a59189..23878374 100644
--- a/examples/pvlv/params.go
+++ b/examples/pvlv/params.go
@@ -4,142 +4,145 @@
package main
-import (
- "github.com/emer/emergent/v2/params"
-)
+import "github.com/emer/axon/v2/axon"
-// ParamSets is the default set of parameters -- Base is always applied,
-// and others can be optionally selected to apply on top of that
-var ParamSets = params.Sets{
+// LayerParams sets the minimal non-default params.
+// Base is always applied, and others can be optionally selected to apply on top of that.
+var LayerParams = axon.LayerSheets{
"Base": {
{Sel: ".InputLayer", Doc: "",
- Params: params.Params{
- ly.Acts.Decay.Act = "1.0",
- ly.Acts.Decay.Glong = "1.0",
+ Set: func(ly *axon.LayerParams) {
+ ly.Acts.Decay.Act = 1.0
+ ly.Acts.Decay.Glong = 1.0
}},
{Sel: "#CS", Doc: "expect act",
- Params: params.Params{
- ly.Inhib.ActAvg.Nominal = "0.05", // 1 / css
+ Set: func(ly *axon.LayerParams) {
+ ly.Inhib.ActAvg.Nominal = 0.05 // 1 / css
}},
{Sel: "#ContextIn", Doc: "expect act",
- Params: params.Params{
- ly.Inhib.ActAvg.Nominal = "0.025", // 1 / css
+ Set: func(ly *axon.LayerParams) {
+ ly.Inhib.ActAvg.Nominal = 0.025 // 1 / css
}},
{Sel: ".VSPatchLayer", Doc: "",
- Params: params.Params{
- ly.Inhib.Pool.Gi = "0.5", // 0.5 needed for differentiation
- ly.Inhib.Layer.Gi = "0.5",
- ly.Learn.NeuroMod.DipGain = "1", // boa requires balanced..
- ly.Learn.TrgAvgAct.GiBaseInit = "0", // 0.5 def; 0 faster
- ly.Learn.RLRate.SigmoidMin = "0.05", // 0.05 def
- ly.Learn.NeuroMod.AChLRateMod = "0",
+ Set: func(ly *axon.LayerParams) {
+ ly.Inhib.Pool.Gi = 0.5 // 0.5 needed for differentiation
+ ly.Inhib.Layer.Gi = 0.5
+ ly.Learn.NeuroMod.DipGain = 1 // boa requires balanced..
+ ly.Learn.TrgAvgAct.GiBaseInit = 0 // 0.5 def; 0 faster
+ ly.Learn.RLRate.SigmoidMin = 0.05 // 0.05 def
+ ly.Learn.NeuroMod.AChLRateMod = 0
}},
{Sel: ".VTALayer", Doc: "",
- Params: params.Params{
- ly.VTA.CeMGain = "0.5", // 0.75 def -- controls size of CS burst
- ly.VTA.LHbGain = "1.25", // 1.25 def -- controls size of PV DA
- ly.VTA.AChThr = "0.5", // prevents non-CS-onset CS DA
+ Set: func(ly *axon.LayerParams) {
+ ly.VTA.CeMGain = 0.5 // 0.75 def -- controls size of CS burst
+ ly.VTA.LHbGain = 1.25 // 1.25 def -- controls size of PV DA
+ ly.VTA.AChThr = 0.5 // prevents non-CS-onset CS DA
}},
{Sel: ".MatrixLayer", Doc: "all mtx",
- Params: params.Params{
- ly.Acts.Kir.Gbar = "2", // 10 > 5 > 2 -- key for pause
- ly.Learn.RLRate.On = "true", // only used for non-rew trials -- key
- ly.Learn.RLRate.Diff = "false",
+ Set: func(ly *axon.LayerParams) {
+ ly.Acts.Kir.Gbar = 2 // 10 > 5 > 2 -- key for pause
+ ly.Learn.RLRate.On.SetBool(true) // only used for non-rew trials -- key
+ ly.Learn.RLRate.Diff.SetBool(false)
}},
{Sel: "#BLAposExtD2", Doc: "",
- Params: params.Params{
- ly.Inhib.Layer.Gi = "1.8", // 1.8 puts just under water
- ly.Inhib.Pool.Gi = "1.0",
- ly.Learn.NeuroMod.DAModGain = "0", // critical to be 0 -- otherwise prevents CS onset activity!
+ Set: func(ly *axon.LayerParams) {
+ ly.Inhib.Layer.Gi = 1.8 // 1.8 puts just under water
+ ly.Inhib.Pool.Gi = 1.0
+ ly.Learn.NeuroMod.DAModGain = 0 // critical to be 0 -- otherwise prevents CS onset activity!
}},
{Sel: ".PTMaintLayer", Doc: "time integration params",
- Params: params.Params{
- ly.Acts.Dend.ModGain = "1.5",
- // ly.Inhib.Layer.Gi = "3.0",
- // ly.Inhib.Pool.Gi = "3.6",
+ Set: func(ly *axon.LayerParams) {
+ ly.Acts.Dend.ModGain = 1.5
+ // ly.Inhib.Layer.Gi = 3.0
+ // ly.Inhib.Pool.Gi = 3.6
}},
{Sel: "#OFCposPT", Doc: "",
- Params: params.Params{
- ly.Acts.SMaint.Gbar = "0.4",
+ Set: func(ly *axon.LayerParams) {
+ ly.Acts.SMaint.Gbar = 0.4
}},
{Sel: ".PTPredLayer", Doc: "",
- Params: params.Params{
- ly.CT.GeGain = "0.1", // 0.05 orig; stronger ptp
+ Set: func(ly *axon.LayerParams) {
+ ly.CT.GeGain = 0.1 // 0.05 orig; stronger ptp
}},
{Sel: ".LDTLayer", Doc: "",
- Params: params.Params{
- ly.LDT.MaintInhib = "0.8", // 0.8 def; AChThr = 0.5 typically
+ Set: func(ly *axon.LayerParams) {
+ ly.LDT.MaintInhib = 0.8 // 0.8 def; AChThr = 0.5 typically
}},
{Sel: "#OFCposPTp", Doc: "",
- Params: params.Params{
- ly.Inhib.Pool.Gi = "1",
- ly.Inhib.ActAvg.Nominal = "0.025", // 0.1 -- affects how strongly BLA is driven -- key param
+ Set: func(ly *axon.LayerParams) {
+ ly.Inhib.Pool.Gi = 1
+ ly.Inhib.ActAvg.Nominal = 0.025 // 0.1 -- affects how strongly BLA is driven -- key param
}},
// {Sel: "#OFCposPT", Doc: "",
- // Params: params.Params{
- // ly.Acts.SMaint.Gbar = "0.4", // 0.2 def fine
+ // Set: func(ly *axon.LayerParams) {
+ // ly.Acts.SMaint.Gbar = 0.4 // 0.2 def fine
// }},
{Sel: "#SC", Doc: "",
- Params: params.Params{
- ly.Acts.KNa.Slow.Max = "0.5", // .5 needed to shut off
+ Set: func(ly *axon.LayerParams) {
+ ly.Acts.KNa.Slow.Max = 0.5 // .5 needed to shut off
}},
{Sel: "#CostP", Doc: "",
- Params: params.Params{
- ly.Pulv.DriveScale = "0.2", // 0.1 def
+ Set: func(ly *axon.LayerParams) {
+ ly.Pulv.DriveScale = 0.2 // 0.1 def
}},
- //////////////////////////////////////////////////
- // current experimental settings
+ },
+}
+
+// PathParams sets the minimal non-default params.
+// Base is always applied, and others can be optionally selected to apply on top of that.
+var PathParams = axon.PathSheets{
+ "Base": {
{Sel: ".VSMatrixPath", Doc: "",
- Params: params.Params{
- pt.Learn.Trace.LearnThr = "0.1", // prevents learning below this thr: preserves low act
+ Set: func(pt *axon.PathParams) {
+ pt.Learn.Trace.LearnThr = 0.1 // prevents learning below this thr: preserves low act
}},
{Sel: ".SuperToThal", Doc: "",
- Params: params.Params{
- pt.PathScale.Abs = "4.0", // 4 > 2 for gating sooner
+ Set: func(pt *axon.PathParams) {
+ pt.PathScale.Abs = 4.0 // 4 > 2 for gating sooner
}},
{Sel: ".BLAExtPath", Doc: "",
- Params: params.Params{
- pt.Learn.LRate.Base = "0.05", // 0.05 is fine -- maybe a bit fast
- pt.BLA.NegDeltaLRate = "1",
- pt.PathScale.Abs = "4",
+ Set: func(pt *axon.PathParams) {
+ pt.Learn.LRate.Base = 0.05 // 0.05 is fine -- maybe a bit fast
+ pt.BLA.NegDeltaLRate = 1
+ pt.PathScale.Abs = 4
}},
// {Sel: ".BLANovelInhib", Doc: "",
- // Params: params.Params{
- // pt.PathScale.Abs = "0.2",
+ // Set: func(pt *axon.PathParams) {
+ // pt.PathScale.Abs = 0.2
// }},
{Sel: ".GPiToBGThal", Doc: "inhibition from GPi to MD",
- Params: params.Params{
- pt.PathScale.Abs = "3", // 3 best -- 4 prevents some gating, 2 can sometimes leak
+ Set: func(pt *axon.PathParams) {
+ pt.PathScale.Abs = 3 // 3 best -- 4 prevents some gating, 2 can sometimes leak
}},
{Sel: ".PTpToBLAExt", Doc: "modulatory so only active with -da, drives extinction learning based on maintained goal rep",
- Params: params.Params{
- pt.PathScale.Abs = "1", // todo: expt
+ Set: func(pt *axon.PathParams) {
+ pt.PathScale.Abs = 1 // todo: expt
}},
{Sel: "#BLAposAcqD1ToOFCpos", Doc: "strong, high variance",
- Params: params.Params{
- pt.PathScale.Abs = "2", // key param for OFC focusing on current cs -- expt
+ Set: func(pt *axon.PathParams) {
+ pt.PathScale.Abs = 2 // key param for OFC focusing on current cs -- expt
}},
{Sel: ".CSToBLApos", Doc: "",
- Params: params.Params{
- pt.Learn.LRate.Base = "0.05",
+ Set: func(pt *axon.PathParams) {
+ pt.Learn.LRate.Base = 0.05
}},
{Sel: ".BLAAcqToGo", Doc: "",
- Params: params.Params{
- pt.PathScale.Abs = "4", // 4 def
+ Set: func(pt *axon.PathParams) {
+ pt.PathScale.Abs = 4 // 4 def
}},
{Sel: ".BLAExtToAcq", Doc: "fixed inhibitory",
- Params: params.Params{
- pt.PathScale.Abs = "1.0", // key param for efficacy of inhibition
+ Set: func(pt *axon.PathParams) {
+ pt.PathScale.Abs = 1.0 // key param for efficacy of inhibition
}},
{Sel: ".VSPatchPath", Doc: "",
- Params: params.Params{
- pt.PathScale.Abs = "3",
- pt.Learn.Trace.LearnThr = "0",
- pt.Learn.LRate.Base = "0.02", // 0.02 for vspatch -- essential to drive long enough extinction
+ Set: func(pt *axon.PathParams) {
+ pt.PathScale.Abs = 3
+ pt.Learn.Trace.LearnThr = 0
+ pt.Learn.LRate.Base = 0.02 // 0.02 for vspatch -- essential to drive long enough extinction
}},
// {Sel: ".ToPTp", Doc: "",
- // Params: params.Params{
- // pt.PathScale.Abs = "2",
+ // Set: func(pt *axon.PathParams) {
+ // pt.PathScale.Abs = 2
// }},
},
}
diff --git a/examples/pvlv/pvlv.go b/examples/pvlv/pvlv.go
index 7554ccd0..1918865a 100644
--- a/examples/pvlv/pvlv.go
+++ b/examples/pvlv/pvlv.go
@@ -1,62 +1,72 @@
-// Copyright (c) 2023, The Emergent Authors. All rights reserved.
+// Copyright (c) 2024, 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.
-/*
-pvlv: simulates the primary value, learned value model of classical conditioning and phasic dopamine
-in the amygdala, ventral striatum and associated areas.
-*/
+// pvlv simulates the primary value, learned value model of classical
+// conditioning and phasic dopamine the amygdala, ventral striatum
+// and associated areas.
package main
-//go:generate core generate -add-types
+//go:generate core generate -add-types -add-funcs
import (
"fmt"
"log"
- "os"
- "reflect"
- "strings"
"cogentcore.org/core/base/mpi"
+ "cogentcore.org/core/base/num"
"cogentcore.org/core/base/randx"
"cogentcore.org/core/base/reflectx"
+ "cogentcore.org/core/cli"
"cogentcore.org/core/core"
- "cogentcore.org/core/events"
+ "cogentcore.org/core/enums"
"cogentcore.org/core/icons"
"cogentcore.org/core/math32"
- "cogentcore.org/core/math32/minmax"
- "cogentcore.org/core/plot/plotcore"
- "cogentcore.org/core/tensor/stats/split"
- "cogentcore.org/core/tensor/stats/stats"
- "cogentcore.org/core/tensor/table"
+ "cogentcore.org/core/tensor/tensorfs"
"cogentcore.org/core/tree"
"github.com/emer/axon/v2/axon"
"github.com/emer/axon/v2/examples/pvlv/cond"
- "github.com/emer/emergent/v2/econfig"
"github.com/emer/emergent/v2/egui"
- "github.com/emer/emergent/v2/elog"
- "github.com/emer/emergent/v2/emer"
"github.com/emer/emergent/v2/env"
- "github.com/emer/emergent/v2/estats"
- "github.com/emer/emergent/v2/etime"
"github.com/emer/emergent/v2/looper"
- "github.com/emer/emergent/v2/netview"
- "github.com/emer/emergent/v2/params"
"github.com/emer/emergent/v2/paths"
)
func main() {
- sim := &Sim{}
- sim.New()
- sim.ConfigAll()
- if sim.Config.GUI {
- sim.RunGUI()
- } else {
- sim.RunNoGUI()
- }
+ cfg := &Config{}
+ cli.SetFromDefaults(cfg)
+ opts := cli.DefaultOptions(cfg.Name, cfg.Title)
+ opts.DefaultFiles = append(opts.DefaultFiles, "config.toml")
+ cli.Run(opts, cfg, RunSim)
}
-// see params.go for network params, config.go for Config
+// Modes are the looping modes (Stacks) for running and statistics.
+type Modes int32 //enums:enum
+const (
+ Train Modes = iota
+ Test
+)
+
+// Levels are the looping levels for running and statistics.
+type Levels int32 //enums:enum
+const (
+ Cycle Levels = iota
+ Trial
+ Sequence
+ Block
+ Condition
+ Run
+)
+
+// StatsPhase is the phase of stats processing for given mode, level.
+// Accumulated values are reset at Start, added each Step.
+type StatsPhase int32 //enums:enum
+const (
+ Start StatsPhase = iota
+ Step
+)
+
+// see params.go for params
// Sim encapsulates the entire simulation model, and we define all the
// functionality as methods on this struct. This structure keeps all relevant
@@ -66,93 +76,104 @@ func main() {
type Sim struct {
// simulation configuration parameters -- set by .toml config file and / or args
- Config Config `new-window:"+"`
+ Config *Config `new-window:"+"`
- // the network -- click to view / edit parameters for layers, paths, etc
+ // Net is the network: click to view / edit parameters for layers, paths, etc.
Net *axon.Network `new-window:"+" display:"no-inline"`
- // all parameter management
- Params emer.NetParams `display:"add-fields"`
+ // Params manages network parameter setting.
+ Params axon.Params
+
+ // Loops are the the control loops for running the sim, in different Modes
+ // across stacks of Levels.
+ Loops *looper.Stacks `new-window:"+" display:"no-inline"`
- // contains looper control loops for running sim
- Loops *looper.Manager `new-window:"+" display:"no-inline"`
+ // Envs provides mode-string based storage of environments.
+ Envs env.Envs `new-window:"+" display:"no-inline"`
- // contains computed statistic values
- Stats estats.Stats `new-window:"+"`
+ // TrainUpdate has Train mode netview update parameters.
+ TrainUpdate axon.NetViewUpdate `display:"inline"`
- // Contains all the logs and information about the logs.'
- Logs elog.Logs `new-window:"+"`
+ // Root is the root tensorfs directory, where all stats and other misc sim data goes.
+ Root *tensorfs.Node `display:"-"`
- // Environments
- Envs env.Envs `new-window:"+" display:"no-inline"`
+ // Stats has the stats directory within Root.
+ Stats *tensorfs.Node `display:"-"`
- // axon timing parameters and state
- Context axon.Context `new-window:"+"`
+ // Current has the current stats values within Stats.
+ Current *tensorfs.Node `display:"-"`
- // netview update parameters
- ViewUpdate netview.ViewUpdate `display:"add-fields"`
+ // StatFuncs are statistics functions called at given mode and level,
+ // to perform all stats computations. phase = Start does init at start of given level,
+ // and all intialization / configuration (called during Init too).
+ StatFuncs []func(mode Modes, level Levels, phase StatsPhase) `display:"-"`
- // manages all the gui elements
+ // GUI manages all the GUI elements
GUI egui.GUI `display:"-"`
- // a list of random seeds to use for each run
+ // RandSeeds is a list of random seeds to use for each run.
RandSeeds randx.Seeds `display:"-"`
}
-// New creates new blank elements and initializes defaults
-func (ss *Sim) New() {
- ss.Net = axon.NewNetwork("PVLV")
- econfig.Config(&ss.Config, "config.toml")
- ss.Params.Config(ParamSets, ss.Config.Params.Sheet, ss.Config.Params.Tag, ss.Net)
- ss.Stats.Init()
- ss.RandSeeds.Init(100) // max 100 runs
- ss.InitRandSeed(0)
- ss.Context.Defaults()
- ss.Context.ThetaCycles = int32(ss.Config.Run.ThetaCycles)
+// RunSim runs the simulation with given configuration.
+func RunSim(cfg *Config) error {
+ sim := &Sim{}
+ sim.Config = cfg
+ sim.Run()
+ return nil
}
-////////////////////////////////////////////////////////////////////////////////////////////
-// Configs
-
-// ConfigAll configures all the elements using the standard functions
-func (ss *Sim) ConfigAll() {
+func (ss *Sim) Run() {
+ ss.Root, _ = tensorfs.NewDir("Root")
+ tensorfs.CurRoot = ss.Root
+ ss.Net = axon.NewNetwork(ss.Config.Name)
+ ss.Params.Config(LayerParams, PathParams, ss.Config.Params.Sheet, ss.Config.Params.Tag)
+ ss.RandSeeds.Init(100) // max 100 runs
+ ss.InitRandSeed(0)
+ if ss.Config.Run.GPU {
+ axon.GPUInit()
+ axon.UseGPU = true
+ }
ss.ConfigEnv()
ss.ConfigNet(ss.Net)
- ss.ConfigLogs()
ss.ConfigLoops()
+ ss.ConfigStats()
+ // if ss.Config.Run.GPU {
+ // fmt.Println(axon.GPUSystem.Vars().StringDoc())
+ // }
if ss.Config.Params.SaveAll {
ss.Config.Params.SaveAll = false
- ss.Net.SaveParamsSnapshot(&ss.Params.Params, &ss.Config, ss.Config.Params.Good)
- os.Exit(0)
+ ss.Net.SaveParamsSnapshot(&ss.Config, ss.Config.Params.Good)
+ return
+ }
+ if ss.Config.GUI {
+ ss.RunGUI()
+ } else {
+ ss.RunNoGUI()
}
}
func (ss *Sim) ConfigEnv() {
- // Can be called multiple times -- don't re-create
var trn *cond.CondEnv
if len(ss.Envs) == 0 {
trn = &cond.CondEnv{}
} else {
- trn = ss.Envs.ByMode(etime.Train).(*cond.CondEnv)
+ trn = ss.Envs.ByMode(Train).(*cond.CondEnv)
}
-
- // note: names must be standard here!
- trn.Name = etime.Train.String()
+ trn.Name = Train.String()
if ss.Config.Env.Env != nil {
- params.ApplyMap(trn, ss.Config.Env.Env, ss.Config.Debug)
+ reflectx.SetFieldsFromMap(trn, ss.Config.Env.Env)
}
- trn.Config(ss.Config.Run.NRuns, ss.Config.Env.RunName)
+ trn.Config(ss.Config.Run.Runs, ss.Config.Env.RunName)
trn.Init(0)
ss.ConfigRubicon()
-
- // note: names must be in place when adding
ss.Envs.Add(trn)
}
func (ss *Sim) ConfigRubicon() {
rp := &ss.Net.Rubicon
- rp.SetNUSs(&ss.Context, cond.NUSs, 1) // 1=neg
+ rp.SetNUSs(cond.NUSs, 1) // 1=neg
rp.Defaults()
rp.USs.PVposGain = 2
rp.USs.PVnegGain = 1
@@ -163,17 +184,16 @@ func (ss *Sim) ConfigRubicon() {
rp.Urgency.U50 = 50 // no pressure during regular trials
if ss.Config.Params.Rubicon != nil {
- params.ApplyMap(rp, ss.Config.Params.Rubicon, ss.Config.Debug)
+ reflectx.SetFieldsFromMap(rp, ss.Config.Params.Rubicon)
}
rp.Update()
}
func (ss *Sim) ConfigNet(net *axon.Network) {
- ctx := &ss.Context
- net.SetMaxData(ctx, 1)
+ net.SetMaxData(1)
net.SetRandSeed(ss.RandSeeds[0]) // init new separate random seed, using run = 0
- ev := ss.Envs.ByMode(etime.Train).(*cond.CondEnv)
+ ev := ss.Envs.ByMode(Train).(*cond.CondEnv)
ny := ev.NYReps
nuBgY := 5
@@ -193,7 +213,7 @@ func (ss *Sim) ConfigNet(net *axon.Network) {
stim := ev.CurStates["CS"]
ctxt := ev.CurStates["ContextIn"]
- vSgpi, vSmtxGo, vSmtxNo, vSpatchD1, vSpatchD2, urgency, usPos, pvPos, usNeg, usNegP, pvNeg, pvNegP, blaPosAcq, blaPosExt, blaNegAcq, blaNegExt, blaNov, ofcPos, ofcPosCT, ofcPosPTp, ofcPosPT, ilPos, ilPosCT, ilPosPT, ilPosPTp, ilPosMD, ofcNeg, ofcNegCT, ofcNegPT, ofcNegPTp, accCost, accCostCT, accCostPT, accCostPTp, accCostMD, ilNeg, ilNegCT, ilNegPT, ilNegPTp, ilNegMD, sc := net.AddRubiconOFCus(&ss.Context, ny, popY, popX, nuBgY, nuBgX, nuCtxY, nuCtxX, space)
+ vSgpi, vSmtxGo, vSmtxNo, vSpatchD1, vSpatchD2, urgency, usPos, pvPos, usNeg, usNegP, pvNeg, pvNegP, blaPosAcq, blaPosExt, blaNegAcq, blaNegExt, blaNov, ofcPos, ofcPosCT, ofcPosPTp, ofcPosPT, ilPos, ilPosCT, ilPosPT, ilPosPTp, ilPosMD, ofcNeg, ofcNegCT, ofcNegPT, ofcNegPTp, accCost, accCostCT, accCostPT, accCostPTp, accCostMD, ilNeg, ilNegCT, ilNegPT, ilNegPTp, ilNegMD, sc := net.AddRubiconOFCus(ny, popY, popX, nuBgY, nuBgX, nuCtxY, nuCtxX, space)
// note: list all above so can copy / paste and validate correct return values
_, _, _, _, _, _ = vSgpi, vSmtxGo, vSmtxNo, vSpatchD1, vSpatchD2, urgency
_, _, _, _, _, _ = usPos, pvPos, usNeg, usNegP, pvNeg, pvNegP
@@ -210,8 +230,7 @@ func (ss *Sim) ConfigNet(net *axon.Network) {
ctxIn := net.AddLayer4D("ContextIn", axon.InputLayer, ctxt.DimSize(0), ctxt.DimSize(1), ctxt.DimSize(2), ctxt.DimSize(3))
- ///////////////////////////////////////////
- // CS -> BLA, OFC
+ //////// CS -> BLA, OFC
net.ConnectToSC1to1(cs, sc)
@@ -230,8 +249,7 @@ func (ss *Sim) ConfigNet(net *axon.Network) {
net.ConnectToPFCBack(cs, csP, ofcPos, ofcPosCT, ofcPosPT, ofcPosPTp, full, "CSToPFC")
net.ConnectToPFCBack(cs, csP, ofcNeg, ofcNegCT, ofcNegPT, ofcNegPTp, full, "CSToPFC")
- ///////////////////////////////////////////
- // OFC predicts time, effort, urgency
+ //////// OFC predicts time, effort, urgency
// todo: a more dynamic US rep is needed to drive predictions in OFC
@@ -242,46 +260,38 @@ func (ss *Sim) ConfigNet(net *axon.Network) {
net.ConnectToPFCBack(time, timeP, accCost, accCostCT, accCostPT, accCostPTp, full, "TimeToPFC")
net.ConnectToPFCBack(time, timeP, ilNeg, ilNegCT, ilNegPT, ilNegPTp, full, "TimeToPFC")
- ////////////////////////////////////////////////
- // position
+ //////// position
time.PlaceRightOf(pvPos, space*2)
cs.PlaceRightOf(time, space)
ctxIn.PlaceRightOf(cs, space)
- net.Build(ctx)
+ net.Build()
net.Defaults()
net.SetNThreads(ss.Config.Run.NThreads)
ss.ApplyParams()
- net.InitWeights(ctx)
+ net.InitWeights()
}
func (ss *Sim) ApplyParams() {
- ss.Params.SetAll() // first hard-coded defaults
- if ss.Config.Params.Network != nil {
- ss.Params.SetNetworkMap(ss.Net, ss.Config.Params.Network)
- }
+ ss.Params.ApplyAll(ss.Net)
}
-////////////////////////////////////////////////////////////////////////////////
-// Init, utils
+//////// Init, utils
// Init restarts the run, and initializes everything, including network weights
// and resets the epoch log table
func (ss *Sim) Init() {
- if ss.Config.GUI {
- ss.Stats.SetString("RunName", ss.Params.RunName(0)) // in case user interactively changes tag
- }
ss.Loops.ResetCounters()
+ ss.SetRunName()
ss.InitRandSeed(0)
- // ss.ConfigEnv() // re-config env just in case a different set of patterns was
- // selected or patterns have been modified etc
+ // ss.ConfigEnv() // always do -- otherwise env params not reset after run
ss.GUI.StopNow = false
ss.ApplyParams()
- ss.Net.GPU.SyncParamsToGPU()
+ ss.StatsInit()
ss.NewRun()
- ss.ViewUpdate.RecordSyns()
- ss.ViewUpdate.Update()
+ ss.TrainUpdate.RecordSyns()
+ ss.TrainUpdate.Update(Train, Trial)
}
// InitRandSeed initializes the random seed based on current training run number
@@ -290,138 +300,142 @@ func (ss *Sim) InitRandSeed(run int) {
ss.RandSeeds.Set(run, &ss.Net.Rand)
}
-// ConfigLoops configures the control loops: Training, Testing
-func (ss *Sim) ConfigLoops() {
- man := looper.NewManager()
-
- nCycles := ss.Config.Run.ThetaCycles
- man.AddStack(etime.Train).
- AddTime(etime.Run, ss.Config.Run.NRuns).
- AddTime(etime.Condition, 1). // all these counters will be set from env
- AddTime(etime.Block, 50).
- AddTime(etime.Sequence, 8).
- AddTime(etime.Trial, 5).
- AddTime(etime.Cycle, nCycles)
-
- axon.LooperStdPhases(man, &ss.Context, ss.Net, nCycles-50, nCycles-1) // plus phase timing
- axon.LooperSimCycleAndLearn(man, ss.Net, &ss.Context, &ss.ViewUpdate) // std algo code
-
- for m, _ := range man.Stacks {
- stack := man.Stacks[m]
- stack.Loops[etime.Trial].OnStart.Add("ApplyInputs", func() {
- ss.ApplyInputs()
- })
- }
-
- man.GetLoop(etime.Train, etime.Run).OnStart.Add("NewRun", ss.NewRun)
+// CurrentMode returns the current Train / Test mode from Context.
+func (ss *Sim) CurrentMode() Modes {
+ ctx := ss.Net.Context()
+ var md Modes
+ md.SetInt64(int64(ctx.Mode))
+ return md
+}
- /////////////////////////////////////////////
- // Logging
+// NetViewUpdater returns the NetViewUpdate for given mode.
+func (ss *Sim) NetViewUpdater(mode enums.Enum) *axon.NetViewUpdate {
+ return &ss.TrainUpdate
+}
- man.AddOnEndToAll("Log", ss.Log)
- axon.LooperResetLogBelow(man, &ss.Logs, etime.Sequence)
- man.GetLoop(etime.Train, etime.Block).OnStart.Add("ResetLogTrial", func() {
- ss.Logs.ResetLog(etime.Train, etime.Trial)
- })
- man.GetLoop(etime.Train, etime.Sequence).OnStart.Add("ResetDebugTrial", func() {
- ss.Logs.ResetLog(etime.Debug, etime.Trial)
+// ConfigLoops configures the control loops: Training, Testing
+func (ss *Sim) ConfigLoops() {
+ ls := looper.NewStacks()
+
+ cycles := ss.Config.Run.Cycles
+ plusPhase := ss.Config.Run.PlusCycles
+
+ // Note: actual max counters set by env
+ ls.AddStack(Train, Trial).
+ AddLevel(Run, ss.Config.Run.Runs).
+ AddLevel(Condition, 1).
+ AddLevel(Block, 50).
+ AddLevel(Sequence, 8).
+ AddLevel(Trial, 5).
+ AddLevel(Cycle, cycles)
+
+ axon.LooperStandard(ls, ss.Net, ss.NetViewUpdater, 50, cycles-plusPhase, cycles-1, Cycle, Trial, Train)
+ ls.Stacks[Train].OnInit.Add("Init", func() { ss.Init() })
+ ls.AddOnStartToLoop(Trial, "ApplyInputs", func(mode enums.Enum) {
+ ss.ApplyInputs(mode.(Modes))
})
- ////////////////////////////////////////////
- // GUI
+ ls.Loop(Train, Run).OnStart.Add("NewRun", ss.NewRun)
+
+ ls.AddOnStartToAll("StatsStart", ss.StatsStart)
+ ls.AddOnEndToAll("StatsStep", ss.StatsStep)
if ss.Config.GUI {
- axon.LooperUpdateNetView(man, &ss.ViewUpdate, ss.Net, ss.NetViewCounters)
- axon.LooperUpdatePlots(man, &ss.GUI)
+ axon.LooperUpdateNetView(ls, Cycle, Trial, ss.NetViewUpdater)
+
+ ls.Stacks[Train].OnInit.Add("GUI-Init", func() { ss.GUI.UpdateWindow() })
}
if ss.Config.Debug {
- mpi.Println(man.DocString())
+ mpi.Println(ls.DocString())
}
- ss.Loops = man
+ ss.Loops = ls
}
// UpdateLoopMax gets the latest loop counter Max values from env
func (ss *Sim) UpdateLoopMax() {
- ev := ss.Envs.ByMode(etime.Train).(*cond.CondEnv)
- trn := ss.Loops.Stacks[etime.Train]
- trn.Loops[etime.Condition].Counter.Max = ev.Condition.Max
- trn.Loops[etime.Block].Counter.Max = ev.Block.Max
- trn.Loops[etime.Sequence].Counter.Max = ev.Sequence.Max
- trn.Loops[etime.Trial].Counter.Max = ev.Tick.Max
+ ev := ss.Envs.ByMode(Train).(*cond.CondEnv)
+ trn := ss.Loops.Stacks[Train]
+ trn.Loops[Condition].Counter.Max = ev.Condition.Max
+ trn.Loops[Block].Counter.Max = ev.Block.Max
+ trn.Loops[Sequence].Counter.Max = ev.Sequence.Max
+ trn.Loops[Trial].Counter.Max = ev.Tick.Max
if ss.Config.Env.SetNBlocks {
- trn.Loops[etime.Block].Counter.Max = ss.Config.Env.NBlocks
+ trn.Loops[Block].Counter.Max = ss.Config.Env.NBlocks
}
}
-// ApplyInputs applies input patterns from given environment.
-// It is good practice to have this be a separate method with appropriate
-// args so that it can be used for various different contexts
-// (training, testing, etc).
-func (ss *Sim) ApplyInputs() {
- ctx := &ss.Context
+// ApplyInputs applies input patterns from given environment for given mode.
+// Any other start-of-trial logic can also be put here.
+func (ss *Sim) ApplyInputs(mode Modes) {
net := ss.Net
- ev := ss.Envs.ByMode(ctx.Mode).(*cond.CondEnv)
+ ss.Net.InitExt()
+ curModeDir := ss.Current.RecycleDir(mode.String())
+ ev := ss.Envs.ByMode(mode).(*cond.CondEnv)
ev.Step()
ss.UpdateLoopMax()
- net.InitExt(ctx)
lays := net.LayersByType(axon.InputLayer, axon.TargetLayer)
for _, lnm := range lays {
ly := ss.Net.LayerByName(lnm)
pats := ev.State(ly.Name)
- if !reflectx.AnyIsNil(pats) {
- ly.ApplyExt(ctx, 0, pats)
+ if pats != nil {
+ ly.ApplyExt(0, pats)
}
switch lnm {
case "CS":
- ly.Pool(0, 0).Inhib.Clamped.SetBool(ev.CurTick.CSOn)
+ lpi := ly.Params.PoolIndex(0)
+ axon.PoolsInt.Set(num.FromBool[int32](ev.CurTick.CSOn), int(lpi), 0, int(axon.Clamped))
}
}
- ss.ApplyRubicon(ctx, &ev.CurTick)
- net.ApplyExts(ctx) // now required for GPU mode
+ curModeDir.StringValue("TrialName", 1).SetString1D(ev.String(), 0)
+ curModeDir.StringValue("SeqType", 1).SetString1D(ev.SequenceType, 0)
+ curModeDir.StringValue("Cond", 1).SetString1D(ev.CondName, 0)
+ curModeDir.StringValue("TickType", 1).SetString1D(fmt.Sprintf("%02d_%s", ev.Tick.Prev, ev.CurTick.Type.String()), 0)
+
+ ss.ApplyRubicon(ev, mode, &ev.CurTick)
+ net.ApplyExts()
}
-// ApplyRubicon applies current Rubicon values to Context.Rubicon,
-// from given trial data.
-func (ss *Sim) ApplyRubicon(ctx *axon.Context, seq *cond.Sequence) {
+// ApplyRubicon applies Rubicon reward inputs.
+func (ss *Sim) ApplyRubicon(ev *cond.CondEnv, mode Modes, seq *cond.Sequence) {
rp := &ss.Net.Rubicon
- di := uint32(0) // not doing NData here -- otherwise loop over
- ev := ss.Envs.ByMode(etime.Train).(*cond.CondEnv)
- rp.NewState(ctx, di, &ss.Net.Rand) // first before anything else is updated
- rp.SetGoalMaintFromLayer(ctx, di, ss.Net, "ILposPT", 0.3)
- rp.DecodePVEsts(ctx, di, ss.Net)
+ di := uint32(0) // not doing NData here -- otherwise loop over
+ rp.NewState(di, &ss.Net.Rand) // first before anything else is updated
+ rp.SetGoalMaintFromLayer(di, ss.Net, "ILposPT", 0.3)
+ rp.DecodePVEsts(di, ss.Net)
dist := math32.Abs(float32(3 - ev.Tick.Cur))
- rp.SetGoalDistEst(ctx, di, dist)
- rp.EffortUrgencyUpdate(ctx, di, 1)
+ rp.SetGoalDistEst(di, dist)
+ rp.EffortUrgencyUpdate(di, 1)
if seq.USOn {
if seq.Valence == cond.Pos {
- rp.SetUS(ctx, di, axon.Positive, seq.US, seq.USMag)
+ rp.SetUS(di, axon.Positive, seq.US, seq.USMag)
} else {
- rp.SetUS(ctx, di, axon.Negative, seq.US, seq.USMag) // adds to neg us
+ rp.SetUS(di, axon.Negative, seq.US, seq.USMag) // adds to neg us
}
}
drvs := make([]float32, cond.NUSs)
drvs[seq.US] = 1
- rp.SetDrives(ctx, di, 1, drvs...)
- rp.Step(ctx, di, &ss.Net.Rand)
+ rp.SetDrives(di, 1, drvs...)
+ rp.Step(di, &ss.Net.Rand)
}
// InitEnvRun intializes a new environment run, as when the RunName is changed
// or at NewRun()
func (ss *Sim) InitEnvRun() {
- ev := ss.Envs.ByMode(etime.Train).(*cond.CondEnv)
+ ev := ss.Envs.ByMode(Train).(*cond.CondEnv)
ev.RunName = ss.Config.Env.RunName
ev.Init(0)
ss.LoadCondWeights(ev.CurRun.Weights) // only if nonempty
- ss.Loops.ResetCountersBelow(etime.Train, etime.Sequence)
- ss.Logs.ResetLog(etime.Train, etime.Trial)
- ss.Logs.ResetLog(etime.Train, etime.Sequence)
+ // todo:
+ // ss.Loops.ResetCountersBelow(Train, Sequence)
+ // ss.Logs.ResetLog(Train, Trial)
+ // ss.Logs.ResetLog(Train, Sequence)
}
// LoadRunWeights loads weights specified in current run, if any
func (ss *Sim) LoadRunWeights() {
- ev := ss.Envs.ByMode(etime.Train).(*cond.CondEnv)
+ ev := ss.Envs.ByMode(Train).(*cond.CondEnv)
ss.LoadCondWeights(ev.CurRun.Weights) // only if nonempty
}
@@ -439,7 +453,7 @@ func (ss *Sim) LoadCondWeights(cond string) {
// SaveCondWeights saves weights based on current condition, in wts/cond.wts.gz
func (ss *Sim) SaveCondWeights() {
- ev := ss.Envs.ByMode(etime.Train).(*cond.CondEnv)
+ ev := ss.Envs.ByMode(Train).(*cond.CondEnv)
cnm, _ := ev.CurRun.Cond(ev.Condition.Cur)
if cnm == "" {
return
@@ -453,329 +467,256 @@ func (ss *Sim) SaveCondWeights() {
}
}
-// NewRun intializes a new run of the model, using the TrainEnv.Run counter
-// for the new run value
+// NewRun intializes a new Run level of the model.
func (ss *Sim) NewRun() {
- ctx := &ss.Context
- ss.InitRandSeed(ss.Loops.GetLoop(etime.Train, etime.Run).Counter.Cur)
+ ctx := ss.Net.Context()
+ ss.InitRandSeed(ss.Loops.Loop(Train, Run).Counter.Cur)
ss.InitEnvRun()
ctx.Reset()
- ctx.Mode = etime.Train
- ss.Net.InitWeights(ctx)
+ ss.Net.InitWeights()
ss.LoadRunWeights()
- ss.StatsInit()
- ss.StatCounters()
- ss.Logs.ResetLog(etime.Train, etime.Condition)
- ss.Logs.ResetLog(etime.Train, etime.Block)
ss.UpdateLoopMax()
}
-////////////////////////////////////////////////////////////////////////////////////////////
-// Stats
+//////// Stats
-// StatsInit initializes all the statistics.
-// called at start of new run
-func (ss *Sim) StatsInit() {
- ss.Stats.SetString("Debug", "") // special debug notes per trial
- ss.Stats.SetString("Cond", "")
- ss.Stats.SetString("TrialName", "")
- ss.Stats.SetString("SeqType", "")
- ss.Stats.SetString("TickType", "")
-}
-
-// StatCounters saves current counters to Stats, so they are available for logging etc
-// Also saves a string rep of them for ViewUpdate.Text
-func (ss *Sim) StatCounters() {
- ctx := &ss.Context
- mode := ctx.Mode
- ss.Loops.Stacks[mode].CountersToStats(&ss.Stats)
- ss.Stats.SetInt("Cycle", int(ctx.Cycle))
- ev := ss.Envs.ByMode(ctx.Mode).(*cond.CondEnv)
- ss.Stats.SetString("TrialName", ev.SequenceName)
- ss.Stats.SetString("SeqType", ev.SequenceType)
- trl := ss.Stats.Int("Trial")
- ss.Stats.SetString("TickType", fmt.Sprintf("%02d_%s", trl, ev.CurTick.Type.String()))
- ss.Stats.SetString("Cond", ev.CondName)
-}
-
-func (ss *Sim) NetViewCounters(tm etime.Times) {
- if ss.ViewUpdate.View == nil {
+// AddStat adds a stat compute function.
+func (ss *Sim) AddStat(f func(mode Modes, level Levels, phase StatsPhase)) {
+ ss.StatFuncs = append(ss.StatFuncs, f)
+}
+
+// StatsStart is called by Looper at the start of given level, for each iteration.
+// It needs to call RunStats Start at the next level down.
+// e.g., each Epoch is the start of the full set of Trial Steps.
+func (ss *Sim) StatsStart(lmd, ltm enums.Enum) {
+ mode := lmd.(Modes)
+ level := ltm.(Levels)
+ if level <= Trial {
return
}
- ss.StatCounters()
- ss.ViewUpdate.Text = ss.Stats.Print([]string{"Run", "Condition", "Block", "Sequence", "Trial", "SeqType", "TrialName", "TickType", "Cycle", "Time", "HasRew", "Gated", "GiveUp"})
-}
-
-// TrialStats computes the tick-level statistics.
-// Aggregation is done directly from log data.
-func (ss *Sim) TrialStats() {
- ctx := &ss.Context
- diu := uint32(0)
- ss.Stats.SetFloat32("HasRew", axon.GlobalScalars[axon.GvHasRew), diu]
- ss.Stats.SetFloat32("Gated", axon.GlobalScalars[axon.GvVSMatrixJustGated), diu]
- ss.Stats.SetFloat32("Time", axon.GlobalScalars[axon.GvTime), diu]
- ss.Stats.SetFloat32("GiveUp", axon.GlobalScalars[axon.GvGiveUp), diu]
- ss.Stats.SetFloat32("SC", ss.Net.LayerByName("SC").Pool(0, 0).AvgMax.CaD.Cycle.Max)
-}
-
-//////////////////////////////////////////////////////////////////////////////
-// Logging
-
-func (ss *Sim) ConfigLogs() {
- ss.Stats.SetString("RunName", ss.Params.RunName(0)) // used for naming logs, stats, etc
-
- ss.Logs.AddCounterItems(etime.Run, etime.Condition, etime.Block, etime.Sequence, etime.Trial, etime.Cycle)
- ss.Logs.AddStatStringItem(etime.AllModes, etime.AllTimes, "Cond")
- ss.Logs.AddStatStringItem(etime.AllModes, etime.AllTimes, "RunName")
- ss.Logs.AddStatStringItem(etime.AllModes, etime.Trial, "TrialName")
- ss.Logs.AddStatStringItem(etime.AllModes, etime.Trial, "SeqType")
- ss.Logs.AddStatStringItem(etime.AllModes, etime.Trial, "TickType")
-
- // ss.Logs.AddPerTrlMSec("PerTrlMSec", etime.Run, etime.Epoch, etime.Trial)
-
- axon.LogAddGlobals(&ss.Logs, &ss.Context, etime.Train, etime.Run, etime.Condition, etime.Block, etime.Sequence, etime.Trial)
-
- plots := ss.ConfigLogItems()
-
- // layers := ss.Net.LayersByType(axon.SuperLayer, axon.CTLayer, axon.TargetLayer)
- // axon.LogAddDiagnosticItems(&ss.Logs, layers, etime.Train, etime.Block, etime.Trial)
- // axon.LogInputLayer(&ss.Logs, ss.Net, etime.Train)
-
- ss.Logs.PlotItems("DA", "RewPred")
-
- ss.Logs.CreateTables()
- ss.Logs.SetContext(&ss.Stats, ss.Net)
- // don't plot certain combinations we don't use
- ss.Logs.NoPlot(etime.Train, etime.Epoch, etime.Cycle)
- // note: Analyze not plotted by default
- ss.Logs.SetMeta(etime.Train, etime.Run, "LegendCol", "RunName")
- ss.Logs.SetMeta(etime.Train, etime.Trial, "LegendCol", "Sequence")
-
- // plot selected agg data at higher levels
- times := []etime.Times{etime.Block, etime.Condition, etime.Run}
- for _, tm := range times {
- ss.Logs.SetMeta(etime.Train, tm, "DA:On", "-")
- ss.Logs.SetMeta(etime.Train, tm, "VSPatch:On", "-")
- for _, pl := range plots {
- ss.Logs.SetMeta(etime.Train, tm, pl+":On", "+")
- }
+ ss.RunStats(mode, level-1, Start)
+}
+
+// StatsStep is called by Looper at each step of iteration,
+// where it accumulates the stat results.
+func (ss *Sim) StatsStep(lmd, ltm enums.Enum) {
+ mode := lmd.(Modes)
+ level := ltm.(Levels)
+ if level < Trial {
+ return
}
+ ss.RunStats(mode, level, Step)
+ tensorfs.DirTable(axon.StatsNode(ss.Stats, mode, level), nil).WriteToLog()
}
-func (ss *Sim) ConfigLogItems() []string {
- ss.Logs.AddStatAggItem("SC", etime.Run, etime.Condition, etime.Block, etime.Sequence, etime.Trial)
-
- var plots []string
-
- points := []string{"CS", "US"}
- for ci := 0; ci < 2; ci++ { // conditions
- ci := ci
- for _, pt := range points {
- for _, st := range ss.Config.Log.AggStats {
- itmName := fmt.Sprintf("C%d_%s_%s", ci, pt, st)
- plots = append(plots, itmName)
- statName := fmt.Sprintf("%s_%s", pt, st)
- ss.Logs.AddItem(&elog.Item{
- Name: itmName,
- Type: reflect.Float64,
- // FixMin: true,
- // FixMax: true,
- Range: minmax.F32{Max: 1},
- Write: elog.WriteMap{
- etime.Scope(etime.AllModes, etime.Block): func(ctx *elog.Context) {
- ctx.SetFloat64(ctx.Stats.FloatDi(statName, ci))
- }, etime.Scope(etime.AllModes, etime.Condition): func(ctx *elog.Context) {
- ix := ctx.LastNRows(ctx.Mode, etime.Block, 5) // cached
- ctx.SetFloat64(stats.MeanColumn(ix, ctx.Item.Name)[0])
- }, etime.Scope(etime.Train, etime.Run): func(ctx *elog.Context) {
- ctx.SetAgg(ctx.Mode, etime.Condition, stats.Mean)
- }}})
- }
- }
+// RunStats runs the StatFuncs for given mode, level and phase.
+func (ss *Sim) RunStats(mode Modes, level Levels, phase StatsPhase) {
+ for _, sf := range ss.StatFuncs {
+ sf(mode, level, phase)
+ }
+ if phase == Step && ss.GUI.Tabs != nil {
+ nm := mode.String() + "/" + level.String() + " Plot"
+ ss.GUI.Tabs.GoUpdatePlot(nm)
}
+}
- // Add a special debug message -- use of etime.Debug triggers
- // inclusion
- ss.Logs.AddStatStringItem(etime.Debug, etime.Trial, "Debug")
+// SetRunName sets the overall run name, used for naming output logs and weight files
+// based on params extra sheets and tag, and starting run number (for distributed runs).
+func (ss *Sim) SetRunName() string {
+ runName := ss.Params.RunName(ss.Config.Run.Run)
+ ss.Current.StringValue("RunName", 1).SetString1D(runName, 0)
+ return runName
+}
- return plots
+// RunName returns the overall run name, used for naming output logs and weight files
+// based on params extra sheets and tag, and starting run number (for distributed runs).
+func (ss *Sim) RunName() string {
+ return ss.Current.StringValue("RunName", 1).String1D(0)
}
-// Log is the main logging function, handles special things for different scopes
-func (ss *Sim) Log(mode etime.Modes, time etime.Times) {
- if mode != etime.Analyze && mode != etime.Debug {
- ss.Context.Mode = mode // Also set specifically in a Loop callback.
+// StatsInit initializes all the stats by calling Start across all modes and levels.
+func (ss *Sim) StatsInit() {
+ for md, st := range ss.Loops.Stacks {
+ mode := md.(Modes)
+ for _, lev := range st.Order {
+ level := lev.(Levels)
+ if level == Cycle {
+ continue
+ }
+ ss.RunStats(mode, level, Start)
+ }
}
- dt := ss.Logs.Table(mode, time)
- if dt == nil {
- return
+ if ss.GUI.Tabs != nil {
+ _, idx := ss.GUI.Tabs.CurrentTab()
+ ss.GUI.Tabs.PlotTensorFS(axon.StatsNode(ss.Stats, Train, Sequence))
+ ss.GUI.Tabs.PlotTensorFS(axon.StatsNode(ss.Stats, Train, Block))
+ ss.GUI.Tabs.PlotTensorFS(axon.StatsNode(ss.Stats, Train, Run))
+ ss.GUI.Tabs.PlotTensorFS(axon.StatsNode(ss.Stats, Train, Trial))
+ ss.GUI.Tabs.SelectTabIndex(idx)
}
- row := dt.Rows
+}
- switch {
- case time == etime.Cycle:
- return
- case mode == etime.Train && time == etime.Trial:
- ss.TrialStats()
- ss.StatCounters()
- if ss.Config.GUI {
- ss.Logs.Log(etime.Debug, etime.Trial)
- ss.GUI.UpdateTableView(etime.Debug, etime.Trial)
- }
- case time == etime.Block:
- ss.BlockStats()
- }
+// ConfigStats handles configures functions to do all stats computation
+// in the tensorfs system.
+func (ss *Sim) ConfigStats() {
+ net := ss.Net
+ ss.Stats, _ = ss.Root.Mkdir("Stats")
+ ss.Current, _ = ss.Stats.Mkdir("Current")
- ss.Logs.LogRow(mode, time, row) // also logs to file, etc
-}
+ ss.SetRunName()
-func (ss *Sim) BlockStats() {
- stnm := "BlockByType"
+ // note: Trial level is not recorded, only the sequence
- ix := ss.Logs.IndexView(etime.Train, etime.Trial)
- spl := split.GroupBy(ix, "SeqType", "TickType")
- for _, ts := range ix.Table.ColumnNames {
- if ts == "SeqType" || ts == "TrialName" || ts == "TickType" {
- continue
- }
- split.AggColumn(spl, ts, stats.Mean)
+ // last arg(s) are levels to exclude
+ counterFunc := axon.StatLoopCounters(ss.Stats, ss.Current, ss.Loops, net, Trial, Cycle)
+ ss.AddStat(func(mode Modes, level Levels, phase StatsPhase) {
+ counterFunc(mode, level, phase == Start)
+ })
+ // todo: add Cond
+ runNameFunc := axon.StatRunName(ss.Stats, ss.Current, ss.Loops, net, Trial, Cycle)
+ ss.AddStat(func(mode Modes, level Levels, phase StatsPhase) {
+ runNameFunc(mode, level, phase == Start)
+ })
+ // todo: add SeqType, TickType
+ trialNameFunc := axon.StatTrialName(ss.Stats, ss.Current, ss.Loops, net, Trial)
+ ss.AddStat(func(mode Modes, level Levels, phase StatsPhase) {
+ trialNameFunc(mode, level, phase == Start)
+ })
+ perTrlFunc := axon.StatPerTrialMSec(ss.Stats, Train, Trial)
+ ss.AddStat(func(mode Modes, level Levels, phase StatsPhase) {
+ perTrlFunc(mode, level, phase == Start)
+ })
+
+ // trialStats := []string{"Action", "Target", "Correct"}
+ // ss.AddStat(func(mode Modes, level Levels, phase StatsPhase) {
+ // if level != Trial {
+ // return
+ // }
+ // for si, name := range trialStats {
+ // modeDir := ss.Stats.RecycleDir(mode.String())
+ // curModeDir := ss.Current.RecycleDir(mode.String())
+ // levelDir := modeDir.RecycleDir(level.String())
+ // di := 0 //
+ // tsr := levelDir.Float64(name)
+ // if phase == Start {
+ // tsr.SetNumRows(0)
+ // plot.SetFirstStylerTo(tsr, func(s *plot.Style) {
+ // s.Range.SetMin(0).SetMax(1)
+ // if si >= 2 && si <= 5 {
+ // s.On = true
+ // }
+ // })
+ // continue
+ // }
+ // ev := ss.Envs.ByModeDi(mode, di).(*MotorSeqEnv)
+ // var stat float32
+ // switch name {
+ // case "Action":
+ // stat = float32(ev.CurAction)
+ // case "Target":
+ // stat = float32(ev.Target)
+ // case "Correct":
+ // stat = num.FromBool[float32](ev.Correct)
+ // }
+ // curModeDir.Float32(name, 1).SetFloat1D(float64(stat), di)
+ // tsr.AppendRowFloat(float64(stat))
+ // }
+ // })
+ //
+ // seqStats := []string{"NCorrect", "Rew", "RewPred", "RPE", "RewEpc"}
+ // ss.AddStat(func(mode Modes, level Levels, phase StatsPhase) {
+ // if level <= Trial {
+ // return
+ // }
+ // for _, name := range seqStats {
+ // modeDir := ss.Stats.RecycleDir(mode.String())
+ // curModeDir := ss.Current.RecycleDir(mode.String())
+ // levelDir := modeDir.RecycleDir(level.String())
+ // subDir := modeDir.RecycleDir((level - 1).String()) // note: will fail for Cycle
+ // tsr := levelDir.Float64(name)
+ // ndata := int(ss.Net.Context().NData)
+ // var stat float64
+ // if phase == Start {
+ // tsr.SetNumRows(0)
+ // plot.SetFirstStylerTo(tsr, func(s *plot.Style) {
+ // s.Range.SetMin(0).SetMax(1)
+ // s.On = true
+ // })
+ // continue
+ // }
+ // switch level {
+ // case Trial:
+ // curModeDir.Float32(name, ndata).SetFloat1D(float64(stat), di)
+ // tsr.AppendRowFloat(float64(stat))
+ // default:
+ // stat = stats.StatMean.Call(subDir.Value(name)).Float1D(0)
+ // tsr.AppendRowFloat(stat)
+ // }
+ // }
+ // })
+}
+
+// StatCounters returns counters string to show at bottom of netview.
+func (ss *Sim) StatCounters(mode, level enums.Enum) string {
+ counters := ss.Loops.Stacks[mode].CountersString()
+ vu := ss.NetViewUpdater(mode)
+ if vu == nil || vu.View == nil {
+ return counters
}
- dt := spl.AggsToTable(table.ColumnNameOnly)
- for ri := 0; ri < dt.Rows; ri++ {
- tt := dt.StringValue("SeqType", ri)
- trl := int(dt.Float("Trial", ri))
- dt.SetString("SeqType", ri, fmt.Sprintf("%s_%d", tt, trl))
+ di := vu.View.Di
+ counters += fmt.Sprintf(" Di: %d", di)
+ curModeDir := ss.Current.RecycleDir(mode.String())
+ if curModeDir.Node("TrialName") == nil {
+ return counters
}
- dt.SetMetaData("DA:On", "+")
- dt.SetMetaData("RewPred:On", "+")
- dt.SetMetaData("DA:FixMin", "+")
- dt.SetMetaData("DA:Min", "-1")
- dt.SetMetaData("DA:FixMax", "-")
- dt.SetMetaData("DA:Max", "1")
- dt.SetMetaData("XAxisRot", "45")
- ss.Logs.MiscTables[stnm] = dt
-
- // grab selected stats at CS and US for higher level aggregation,
- nrows := dt.Rows
- curSeq := ""
- seq := -1
- for ri := 0; ri < nrows; ri++ {
- st := dt.StringValue("SeqType", ri)
- ui := strings.LastIndex(st, "_")
- st = st[:ui]
- if curSeq != st {
- seq++
- curSeq = st
- ss.Stats.SetStringDi("SeqType", seq, curSeq)
- }
- tt := dt.StringValue("TickType", ri)
- if strings.Contains(tt, "_CS") {
- for _, st := range ss.Config.Log.AggStats {
- ss.Stats.SetFloatDi("CS_"+st, seq, dt.Float(st, ri))
- }
- }
- if strings.Contains(tt, "_US") {
- for _, st := range ss.Config.Log.AggStats {
- ss.Stats.SetFloatDi("US_"+st, seq, dt.Float(st, ri))
- }
- }
+ strNames := []string{"Cond", "TrialName", "SeqType", "TickType"}
+ for _, name := range strNames {
+ counters += fmt.Sprintf(" %s: %s", name, curModeDir.StringValue(name).String1D(di))
}
-
- if ss.Config.GUI {
- plt := ss.GUI.Plots[etime.ScopeKey(stnm)]
- plt.SetTable(dt)
- plt.GoUpdatePlot()
+ statNames := []string{"DA", "RewPred"}
+ if level == Cycle || curModeDir.Node(statNames[0]) == nil {
+ return counters
+ }
+ for _, name := range statNames {
+ counters += fmt.Sprintf(" %s: %.4g", name, curModeDir.Value(name).Float1D(di))
}
+ return counters
}
-////////////////////////////////////////////////////////////////////////////////////////////
-// GUI
+//////// GUI
// ConfigGUI configures the Cogent Core GUI interface for this simulation.
func (ss *Sim) ConfigGUI() {
- title := "Axon PVLV"
- ss.GUI.MakeBody(ss, "pvlv", title, `This is the PVLV test model in Axon, in the Rubicon framework. See emergent on GitHub.
`)
+ ss.GUI.MakeBody(ss, ss.Config.Name, ss.Config.Title, ss.Config.Doc)
+ ss.GUI.FS = ss.Root
+ ss.GUI.DataRoot = "Root"
ss.GUI.CycleUpdateInterval = 10
nv := ss.GUI.AddNetView("Network")
- nv.Options.MaxRecs = 400
- nv.Options.Raster.Max = ss.Config.Run.ThetaCycles
+ nv.Options.MaxRecs = 2 * ss.Config.Run.Cycles
+ nv.Options.Raster.Max = ss.Config.Run.Cycles
nv.Options.LayerNameSize = 0.02
nv.SetNet(ss.Net)
- ss.ViewUpdate.Config(nv, etime.Phase, etime.Phase)
- ss.GUI.ViewUpdate = &ss.ViewUpdate
+ ss.TrainUpdate.Config(nv, axon.Theta, ss.StatCounters)
+ ss.GUI.OnStop = func(mode, level enums.Enum) {
+ vu := ss.NetViewUpdater(mode)
+ vu.UpdateWhenStopped(mode, level)
+ }
nv.SceneXYZ().Camera.Pose.Pos.Set(0, 1.4, 2.6)
nv.SceneXYZ().Camera.LookAt(math32.Vec3(0, 0, 0), math32.Vec3(0, 1, 0))
- ss.GUI.AddPlots(title, &ss.Logs)
-
- ss.GUI.AddTableView(&ss.Logs, etime.Debug, etime.Trial)
-
- stnm := "BlockByType"
- dt := ss.Logs.MiscTable(stnm)
- bcp, _ := ss.GUI.Tabs.NewTab(stnm + " Plot")
- plt := plotcore.NewSubPlot(bcp)
- ss.GUI.Plots[etime.ScopeKey(stnm)] = plt
- plt.Options.Title = stnm
- plt.Options.XAxis = "SeqType"
- plt.SetTable(dt)
-
+ ss.GUI.UpdateFiles()
+ ss.StatsInit()
ss.GUI.FinalizeGUI(false)
- if ss.Config.Run.GPU {
- // vgpu.Debug = ss.Config.Debug
- ss.Net.ConfigGPUnoGUI(&ss.Context) // must happen after gui or no gui
- core.TheApp.AddQuitCleanFunc(func() {
- ss.Net.GPU.Destroy()
- })
- }
}
func (ss *Sim) MakeToolbar(p *tree.Plan) {
- tree.Add(p, func(w *core.Chooser) {
- w.SetStrings(cond.RunNames...)
- w.SetCurrentValue(ss.Config.Env.RunName)
- w.OnChange(func(e events.Event) {
- ss.Config.Env.RunName = w.CurrentItem.Value.(string)
- ss.InitEnvRun()
- })
- })
-
- ss.GUI.AddToolbarItem(p, egui.ToolbarItem{Label: "Init", Icon: icons.Update,
- Tooltip: "Initialize everything including network weights, and start over. Also applies current params.",
- Active: egui.ActiveStopped,
- Func: func() {
- ss.Init()
- ss.GUI.UpdateWindow()
- },
- })
-
- ss.GUI.AddLooperCtrl(p, ss.Loops, []etime.Modes{etime.Train})
-
- tree.Add(p, func(w *core.Separator) {})
- ss.GUI.AddToolbarItem(p, egui.ToolbarItem{Label: "Save Wts", Icon: icons.Save,
- Tooltip: "Save weights for the current condition name.",
- Active: egui.ActiveStopped,
- Func: func() {
- ss.SaveCondWeights()
- // ss.GUI.UpdateWindow()
- },
- })
+ ss.GUI.AddLooperCtrl(p, ss.Loops)
- ////////////////////////////////////////////////
- tree.Add(p, func(w *core.Separator) {})
- ss.GUI.AddToolbarItem(p, egui.ToolbarItem{Label: "Reset RunLog",
- Icon: icons.Reset,
- Tooltip: "Reset the accumulated log of all Runs, which are tagged with the ParamSet used",
- Active: egui.ActiveAlways,
- Func: func() {
- ss.Logs.ResetLog(etime.Train, etime.Run)
- ss.GUI.UpdatePlot(etime.Train, etime.Run)
- },
- })
- ////////////////////////////////////////////////
tree.Add(p, func(w *core.Separator) {})
- ss.GUI.AddToolbarItem(p, egui.ToolbarItem{Label: "New Seed",
+ ss.GUI.AddToolbarItem(p, egui.ToolbarItem{
+ Label: "New seed",
Icon: icons.Add,
Tooltip: "Generate a new initial random seed to get different results. By default, Init re-establishes the same initial seed every time.",
Active: egui.ActiveAlways,
@@ -783,20 +724,13 @@ func (ss *Sim) MakeToolbar(p *tree.Plan) {
ss.RandSeeds.NewSeeds()
},
})
- ss.GUI.AddToolbarItem(p, egui.ToolbarItem{Label: "Plot Drive & Effort",
- Icon: icons.PlayArrow,
- Tooltip: "Opens a new window to plot Rubicon Drive and Effort dynamics.",
- Active: egui.ActiveAlways,
- Func: func() {
- go DriveEffortGUI()
- },
- })
- ss.GUI.AddToolbarItem(p, egui.ToolbarItem{Label: "README",
+ ss.GUI.AddToolbarItem(p, egui.ToolbarItem{
+ Label: "README",
Icon: icons.FileMarkdown,
Tooltip: "Opens your browser on the README file that contains instructions for how to run this model.",
Active: egui.ActiveAlways,
Func: func() {
- core.TheApp.OpenURL("https://github.com/emer/axon/blob/main/examples/pvlv/README.md")
+ core.TheApp.OpenURL(ss.Config.URL)
},
})
}
@@ -808,43 +742,25 @@ func (ss *Sim) RunGUI() {
}
func (ss *Sim) RunNoGUI() {
+ ss.Init()
+
if ss.Config.Params.Note != "" {
mpi.Printf("Note: %s\n", ss.Config.Params.Note)
}
if ss.Config.Log.SaveWeights {
mpi.Printf("Saving final weights per run\n")
}
- runName := ss.Params.RunName(ss.Config.Run.Run)
- ss.Stats.SetString("RunName", runName) // used for naming logs, stats, etc
- netName := ss.Net.Name
-
- elog.SetLogFile(&ss.Logs, ss.Config.Log.Block, etime.Train, etime.Block, "blk", netName, runName)
- elog.SetLogFile(&ss.Logs, ss.Config.Log.Cond, etime.Train, etime.Condition, "cnd", netName, runName)
- elog.SetLogFile(&ss.Logs, ss.Config.Log.Trial, etime.Test, etime.Trial, "trl", netName, runName)
-
- netdata := ss.Config.Log.NetData
- if netdata {
- mpi.Printf("Saving NetView data from testing\n")
- ss.GUI.InitNetData(ss.Net, 200)
- }
- ss.Init()
-
- mpi.Printf("Running %d Runs starting at %d\n", ss.Config.Run.NRuns, ss.Config.Run.Run)
- ss.Loops.GetLoop(etime.Train, etime.Run).Counter.SetCurMaxPlusN(ss.Config.Run.Run, ss.Config.Run.NRuns)
-
- if ss.Config.Run.GPU {
- ss.Net.ConfigGPUnoGUI(&ss.Context)
- }
- mpi.Printf("Set NThreads to: %d\n", ss.Net.NThreads)
-
- ss.Loops.Run(etime.Train)
+ runName := ss.SetRunName()
+ netName := ss.Net.Name
+ cfg := &ss.Config.Log
+ axon.OpenLogFiles(ss.Loops, ss.Stats, netName, runName, [][]string{cfg.Train})
- ss.Logs.CloseLogFiles()
+ mpi.Printf("Running %d Runs starting at %d\n", ss.Config.Run.Runs, ss.Config.Run.Run)
+ ss.Loops.Loop(Train, Run).Counter.SetCurMaxPlusN(ss.Config.Run.Run, ss.Config.Run.Runs)
- if netdata {
- ss.GUI.SaveNetData(ss.Stats.String("RunName"))
- }
+ ss.Loops.Run(Train)
- ss.Net.GPU.Destroy() // safe even if no GPU
+ axon.CloseLogFiles(ss.Loops, ss.Stats, Cycle)
+ axon.GPURelease()
}
diff --git a/examples/pvlv/typegen.go b/examples/pvlv/typegen.go
index 854cf2ee..d6744e5d 100644
--- a/examples/pvlv/typegen.go
+++ b/examples/pvlv/typegen.go
@@ -1,4 +1,4 @@
-// Code generated by "core generate -add-types"; DO NOT EDIT.
+// Code generated by "core generate -add-types -add-funcs"; DO NOT EDIT.
package main
@@ -6,16 +6,24 @@ import (
"cogentcore.org/core/types"
)
-var _ = types.AddType(&types.Type{Name: "main.EnvConfig", IDName: "env-config", Doc: "EnvConfig has config params for environment\nnote: only adding fields for key Env params that matter for both Network and Env\nother params are set via the Env map data mechanism.", Fields: []types.Field{{Name: "Env", Doc: "env parameters -- can set any field/subfield on Env struct, using standard TOML formatting"}, {Name: "RunName", Doc: "environment run name"}, {Name: "SetNBlocks", Doc: "override the default number of blocks to run conditions with NBlocks"}, {Name: "NBlocks", Doc: "number of blocks to run if SetNBlocks is true"}}})
+var _ = types.AddType(&types.Type{Name: "main.EnvConfig", IDName: "env-config", Doc: "EnvConfig has config params for environment.", Fields: []types.Field{{Name: "Env", Doc: "Env parameters: can set any field/subfield on Env struct,\nusing standard TOML formatting."}, {Name: "RunName", Doc: "RunName is the environment overall run config."}, {Name: "SetNBlocks", Doc: "SetNBlocks overrides the default number of blocks to run conditions with NBlocks."}, {Name: "NBlocks", Doc: "NBlocks is number of blocks to run if SetNBlocks is true."}}})
-var _ = types.AddType(&types.Type{Name: "main.ParamConfig", IDName: "param-config", Doc: "ParamConfig has config parameters related to sim params", Fields: []types.Field{{Name: "Rubicon", Doc: "Rubicon parameters -- can set any field/subfield on Net.Rubicon params, using standard TOML formatting"}, {Name: "Network", Doc: "network parameters"}, {Name: "Sheet", Doc: "Extra Param Sheet name(s) to use (space separated if multiple) -- must be valid name as listed in compiled-in params or loaded params"}, {Name: "Tag", Doc: "extra tag to add to file names and logs saved from this run"}, {Name: "Note", Doc: "user note -- describe the run params etc -- like a git commit message for the run"}, {Name: "File", Doc: "Name of the JSON file to input saved parameters from."}, {Name: "SaveAll", Doc: "Save a snapshot of all current param and config settings in a directory named params_ (or _good if Good is true), then quit -- useful for comparing to later changes and seeing multiple views of current params"}, {Name: "Good", Doc: "for SaveAll, save to params_good for a known good params state. This can be done prior to making a new release after all tests are passing -- add results to git to provide a full diff record of all params over time."}}})
+var _ = types.AddType(&types.Type{Name: "main.ParamConfig", IDName: "param-config", Doc: "ParamConfig has config parameters related to sim params.", Fields: []types.Field{{Name: "Rubicon", Doc: "Rubicon parameters: can set any field/subfield on Net.Rubicon params,\nusing standard TOML formatting."}, {Name: "Sheet", Doc: "Sheet is the extra params sheet name(s) to use (space separated\nif multiple). Must be valid name as listed in compiled-in params\nor loaded params."}, {Name: "Tag", Doc: "Tag is an extra tag to add to file names and logs saved from this run."}, {Name: "Note", Doc: "Note is additional info to describe the run params etc,\nlike a git commit message for the run."}, {Name: "SaveAll", Doc: "SaveAll will save a snapshot of all current param and config settings\nin a directory named params_ (or _good if Good is true),\nthen quit. Useful for comparing to later changes and seeing multiple\nviews of current params."}, {Name: "Good", Doc: "Good is for SaveAll, save to params_good for a known good params state.\nThis can be done prior to making a new release after all tests are passing.\nAdd results to git to provide a full diff record of all params over level."}}})
-var _ = types.AddType(&types.Type{Name: "main.RunConfig", IDName: "run-config", Doc: "RunConfig has config parameters related to running the sim", Fields: []types.Field{{Name: "GPU", Doc: "use the GPU for computation -- only for testing in this model -- not faster"}, {Name: "NThreads", Doc: "number of parallel threads for CPU computation -- 0 = use default"}, {Name: "ThetaCycles", Doc: "number of cycles per Theta phase (trial) -- either 200 or 300 (latter needed for motor actions)"}, {Name: "Run", Doc: "starting run number -- determines the random seed -- runs counts from there -- can do all runs in parallel by launching separate jobs with each run, runs = 1"}, {Name: "NRuns", Doc: "total number of runs to do when running Train"}}})
+var _ = types.AddType(&types.Type{Name: "main.RunConfig", IDName: "run-config", Doc: "RunConfig has config parameters related to running the sim.", Fields: []types.Field{{Name: "GPU", Doc: "GPU uses the GPU for computation: not faster in this case."}, {Name: "NThreads", Doc: "NThreads is the number of parallel threads for CPU computation;\n0 = use default."}, {Name: "Run", Doc: "Run is the _starting_ run number, which determines the random seed.\nNRuns counts up from there. Can do all runs in parallel by launching\nseparate jobs with each starting Run, NRuns = 1."}, {Name: "Runs", Doc: "Runs is the total number of runs to do when running Train, starting from Run."}, {Name: "Cycles", Doc: "Cycles is the total number of cycles per trial: at least 200."}, {Name: "PlusCycles", Doc: "PlusCycles is the total number of plus-phase cycles per trial. For Cycles=300, use 100."}}})
-var _ = types.AddType(&types.Type{Name: "main.LogConfig", IDName: "log-config", Doc: "LogConfig has config parameters related to logging data", Fields: []types.Field{{Name: "AggStats", Doc: "stats to aggregate at higher levels"}, {Name: "SaveWeights", Doc: "if true, save final weights after each run"}, {Name: "Block", Doc: "if true, save block log to file, as .blk.tsv typically"}, {Name: "Cond", Doc: "if true, save condition log to file, as .cnd.tsv typically"}, {Name: "Trial", Doc: "if true, save trial log to file, as .trl.tsv typically"}, {Name: "NetData", Doc: "if true, save network activation etc data from testing trials, for later viewing in netview"}}})
+var _ = types.AddType(&types.Type{Name: "main.LogConfig", IDName: "log-config", Doc: "LogConfig has config parameters related to logging data.", Fields: []types.Field{{Name: "SaveWeights", Doc: "SaveWeights will save final weights after each run."}, {Name: "Train", Doc: "Train has the list of Train mode levels to save log files for."}, {Name: "Testing", Doc: "Testing activates testing mode: records detailed data for Go CI tests\n(not the same as running test mode on network, via Looper)."}}})
-var _ = types.AddType(&types.Type{Name: "main.Config", IDName: "config", Doc: "Config is a standard Sim config -- use as a starting point.", Fields: []types.Field{{Name: "Includes", Doc: "specify include files here, and after configuration, it contains list of include files added"}, {Name: "GUI", Doc: "open the GUI -- does not automatically run -- if false, then runs automatically and quits"}, {Name: "Debug", Doc: "log debugging information"}, {Name: "Env", Doc: "environment configuration options"}, {Name: "Params", Doc: "parameter related configuration options"}, {Name: "Run", Doc: "sim running related configuration options"}, {Name: "Log", Doc: "data logging related configuration options"}}})
+var _ = types.AddType(&types.Type{Name: "main.Config", IDName: "config", Doc: "Config has the overall Sim configuration options.", Fields: []types.Field{{Name: "Name", Doc: "Name is the short name of the sim."}, {Name: "Title", Doc: "Title is the longer title of the sim."}, {Name: "URL", Doc: "URL is a link to the online README or other documentation for this sim."}, {Name: "Doc", Doc: "Doc is brief documentation of the sim."}, {Name: "Includes", Doc: "Includes has a list of additional config files to include.\nAfter configuration, it contains list of include files added."}, {Name: "GUI", Doc: "GUI means open the GUI. Otherwise it runs automatically and quits,\nsaving results to log files."}, {Name: "Debug", Doc: "Debug reports debugging information."}, {Name: "Env", Doc: "Env has environment configuration options."}, {Name: "Params", Doc: "Params has parameter related configuration options."}, {Name: "Run", Doc: "Run has sim running related configuration options."}, {Name: "Log", Doc: "Log has data logging related configuration options."}}})
-var _ = types.AddType(&types.Type{Name: "main.DrEffPlot", IDName: "dr-eff-plot", Doc: "DrEffPlot holds the params, table, etc", Methods: []types.Method{{Name: "EffortPlot", Doc: "EffortPlot plots the equation as a function of effort / time", Directives: []types.Directive{{Tool: "types", Directive: "add"}}}, {Name: "UrgencyPlot", Doc: "UrgencyPlot plots the equation as a function of effort / time", Directives: []types.Directive{{Tool: "types", Directive: "add"}}}, {Name: "TimeRun", Doc: "TimeRun runs the equation over time.", Directives: []types.Directive{{Tool: "types", Directive: "add"}}}}, Fields: []types.Field{{Name: "Context", Doc: "context just for plotting"}, {Name: "Rubicon", Doc: "Rubicon params"}, {Name: "TimeSteps", Doc: "total number of time steps to simulate"}, {Name: "USTime", Doc: "range for number of time steps between US receipt"}, {Name: "Effort", Doc: "range for random effort per step"}, {Name: "Table", Doc: "table for plot"}, {Name: "Plot", Doc: "the plot"}, {Name: "TimeTable", Doc: "table for plot"}, {Name: "TimePlot", Doc: "the plot"}, {Name: "Rand", Doc: "random number generator"}}})
+var _ = types.AddType(&types.Type{Name: "main.Modes", IDName: "modes", Doc: "Modes are the looping modes (Stacks) for running and statistics."})
-var _ = types.AddType(&types.Type{Name: "main.Sim", IDName: "sim", Doc: "Sim encapsulates the entire simulation model, and we define all the\nfunctionality as methods on this struct. This structure keeps all relevant\nstate information organized and available without having to pass everything around\nas arguments to methods, and provides the core GUI interface (note the view tags\nfor the fields which provide hints to how things should be displayed).", Fields: []types.Field{{Name: "Config", Doc: "simulation configuration parameters -- set by .toml config file and / or args"}, {Name: "Net", Doc: "the network -- click to view / edit parameters for layers, paths, etc"}, {Name: "Params", Doc: "all parameter management"}, {Name: "Loops", Doc: "contains looper control loops for running sim"}, {Name: "Stats", Doc: "contains computed statistic values"}, {Name: "Logs", Doc: "Contains all the logs and information about the logs.'"}, {Name: "Envs", Doc: "Environments"}, {Name: "Context", Doc: "axon timing parameters and state"}, {Name: "ViewUpdate", Doc: "netview update parameters"}, {Name: "GUI", Doc: "manages all the gui elements"}, {Name: "RandSeeds", Doc: "a list of random seeds to use for each run"}}})
+var _ = types.AddType(&types.Type{Name: "main.Levels", IDName: "levels", Doc: "Levels are the looping levels for running and statistics."})
+
+var _ = types.AddType(&types.Type{Name: "main.StatsPhase", IDName: "stats-phase", Doc: "StatsPhase is the phase of stats processing for given mode, level.\nAccumulated values are reset at Start, added each Step."})
+
+var _ = types.AddType(&types.Type{Name: "main.Sim", IDName: "sim", Doc: "Sim encapsulates the entire simulation model, and we define all the\nfunctionality as methods on this struct. This structure keeps all relevant\nstate information organized and available without having to pass everything around\nas arguments to methods, and provides the core GUI interface (note the view tags\nfor the fields which provide hints to how things should be displayed).", Fields: []types.Field{{Name: "Config", Doc: "simulation configuration parameters -- set by .toml config file and / or args"}, {Name: "Net", Doc: "Net is the network: click to view / edit parameters for layers, paths, etc."}, {Name: "Params", Doc: "Params manages network parameter setting."}, {Name: "Loops", Doc: "Loops are the the control loops for running the sim, in different Modes\nacross stacks of Levels."}, {Name: "Envs", Doc: "Envs provides mode-string based storage of environments."}, {Name: "TrainUpdate", Doc: "TrainUpdate has Train mode netview update parameters."}, {Name: "Root", Doc: "Root is the root tensorfs directory, where all stats and other misc sim data goes."}, {Name: "Stats", Doc: "Stats has the stats directory within Root."}, {Name: "Current", Doc: "Current has the current stats values within Stats."}, {Name: "StatFuncs", Doc: "StatFuncs are statistics functions called at given mode and level,\nto perform all stats computations. phase = Start does init at start of given level,\nand all intialization / configuration (called during Init too)."}, {Name: "GUI", Doc: "GUI manages all the GUI elements"}, {Name: "RandSeeds", Doc: "RandSeeds is a list of random seeds to use for each run."}}})
+
+var _ = types.AddFunc(&types.Func{Name: "main.main"})
+
+var _ = types.AddFunc(&types.Func{Name: "main.RunSim", Doc: "RunSim runs the simulation with given configuration.", Args: []string{"cfg"}, Returns: []string{"error"}})
diff --git a/examples/ra25/ra25.go b/examples/ra25/ra25.go
index 3c19f824..5f2781d2 100644
--- a/examples/ra25/ra25.go
+++ b/examples/ra25/ra25.go
@@ -845,7 +845,8 @@ func (ss *Sim) ConfigGUI() {
ss.GUI.CycleUpdateInterval = 10
nv := ss.GUI.AddNetView("Network")
- nv.Options.MaxRecs = 300
+ nv.Options.MaxRecs = 2 * ss.Config.Run.Cycles
+ nv.Options.Raster.Max = ss.Config.Run.Cycles
nv.SetNet(ss.Net)
ss.TrainUpdate.Config(nv, axon.Theta, ss.StatCounters)
ss.TestUpdate.Config(nv, axon.Theta, ss.StatCounters)
diff --git a/examples/ra25x/ra25x.go b/examples/ra25x/ra25x.go
index f6618267..a9c3e119 100644
--- a/examples/ra25x/ra25x.go
+++ b/examples/ra25x/ra25x.go
@@ -712,7 +712,8 @@ func (ss *Sim) ConfigGUI() {
ss.GUI.CycleUpdateInterval = 10
nv := ss.GUI.AddNetView("Network")
- nv.Options.MaxRecs = 300
+ nv.Options.MaxRecs = 2 * ss.Config.Run.Cycles
+ nv.Options.Raster.Max = ss.Config.Run.Cycles
nv.SetNet(ss.Net)
ss.TrainUpdate.Config(nv, axon.Theta, ss.StatCounters)
ss.TestUpdate.Config(nv, axon.Theta, ss.StatCounters)
diff --git a/examples/rl/rl.go b/examples/rl/rl.go
index fec5ee2d..051b8fa6 100644
--- a/examples/rl/rl.go
+++ b/examples/rl/rl.go
@@ -547,7 +547,8 @@ func (ss *Sim) ConfigGUI() {
ss.GUI.CycleUpdateInterval = 10
nv := ss.GUI.AddNetView("Network")
- nv.Options.MaxRecs = 300
+ nv.Options.MaxRecs = 2 * ss.Config.Run.Cycles
+ nv.Options.Raster.Max = ss.Config.Run.Cycles
nv.SetNet(ss.Net)
ss.TrainUpdate.Config(nv, axon.Theta, ss.StatCounters)
ss.GUI.OnStop = func(mode, level enums.Enum) {
diff --git a/examples/vspatch/vspatch.go b/examples/vspatch/vspatch.go
index b63e064c..3be6c2fd 100644
--- a/examples/vspatch/vspatch.go
+++ b/examples/vspatch/vspatch.go
@@ -671,7 +671,8 @@ func (ss *Sim) ConfigGUI() {
ss.GUI.CycleUpdateInterval = 10
nv := ss.GUI.AddNetView("Network")
- nv.Options.MaxRecs = 300
+ nv.Options.MaxRecs = 2 * ss.Config.Run.Cycles
+ nv.Options.Raster.Max = ss.Config.Run.Cycles
nv.SetNet(ss.Net)
ss.TrainUpdate.Config(nv, axon.Theta, ss.StatCounters)
ss.TestUpdate.Config(nv, axon.Theta, ss.StatCounters)