-
Notifications
You must be signed in to change notification settings - Fork 0
/
da.go
196 lines (160 loc) · 6.15 KB
/
da.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
// Copyright (c) 2019, The Emergent Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package pbwm
import (
"log"
"github.com/schapirolab/leabra-sleep/deep"
"github.com/schapirolab/leabra-sleep/leabra"
"github.com/goki/ki/kit"
)
// DaSrcLayer is the basic type of layer that sends dopamine to other layers.
// Uses a list of layer names to send to -- not using Prjn infrastructure
// as it is global broadcast modulator -- individual neurons
// can use it in their own special way.
type DaSrcLayer struct {
ModLayer
SendTo []string `desc:"list of layers to send dopamine to"`
}
var KiT_DaSrcLayer = kit.Types.AddType(&DaSrcLayer{}, deep.LayerProps)
// SendToCheck is called during Build to ensure that SendTo layers are valid
func (ly *DaSrcLayer) SendToCheck() error {
var lasterr error
for _, lnm := range ly.SendTo {
ly, err := ly.Network.LayerByNameTry(lnm)
if err != nil {
log.Printf("DaSrcLayer %s SendToCheck: %v\n", ly.Name(), err)
lasterr = err
}
}
return lasterr
}
// Build constructs the layer state, including calling Build on the projections.
func (ly *DaSrcLayer) Build() error {
err := ly.ModLayer.Build()
if err != nil {
return err
}
err = ly.SendToCheck()
return err
}
// SendDA sends dopamine to SendTo list of layers
func (ly *DaSrcLayer) SendDA(da float32) {
for _, lnm := range ly.SendTo {
ml := ly.Network.LayerByName(lnm).(PBWMLayer).AsMod()
ml.DA = da
}
}
// AddSendTo adds given layer name to list of those to send DA to
func (ly *DaSrcLayer) AddSendTo(laynm string) {
ly.SendTo = append(ly.SendTo, laynm)
}
// SendToAllBut adds all layers in network except those in list to the SendTo
// list of layers to send to -- this layer is automatically excluded as well.
func (ly *DaSrcLayer) SendToAllBut(excl []string) {
exmap := make(map[string]struct{})
exmap[ly.Nm] = struct{}{}
for _, ex := range excl {
exmap[ex] = struct{}{}
}
ly.SendTo = nil
nl := ly.Network.NLayers()
for li := 0; li < nl; li++ {
aly := ly.Network.Layer(li)
nm := aly.Name()
if _, on := exmap[nm]; on {
continue
}
ly.SendTo = append(ly.SendTo, nm)
}
}
//////////////////////////////////////////////////////////////////////////////////////
// ClampDaLayer
// ClampDaLayer is an Input layer that just sends its activity as the dopamine signal
type ClampDaLayer struct {
DaSrcLayer
}
var KiT_ClampDaLayer = kit.Types.AddType(&ClampDaLayer{}, deep.LayerProps)
// SendMods is called at end of Cycle to send modulator signals (DA, etc)
// which will then be active for the next cycle of processing
func (ly *ClampDaLayer) SendMods(ltime *leabra.Time) {
act := ly.Neurons[0].Act
ly.DA = act
ly.SendDA(act)
}
//////////////////////////////////////////////////////////////////////////////////////
// DaMod
// Params for effects of dopamine (Da) based modulation, typically adding
// a Da-based term to the Ge excitatory synaptic input.
// Plus-phase = learning effects relative to minus-phase "performance" dopamine effects
type DaModParams struct {
On bool `desc:"whether to use dopamine modulation"`
ModGain bool `viewif:"On" desc:"modulate gain instead of Ge excitatory synaptic input"`
Minus float32 `viewif:"On" desc:"how much to multiply Da in the minus phase to add to Ge input -- use negative values for NoGo/indirect pathway/D2 type neurons"`
Plus float32 `viewif:"On" desc:"how much to multiply Da in the plus phase to add to Ge input -- use negative values for NoGo/indirect pathway/D2 type neurons"`
NegGain float32 `viewif:"On&&ModGain" desc:"for negative dopamine, how much to change the default gain value as a function of dopamine: gain = gain * (1 + da * NegNain) -- da is multiplied by minus or plus depending on phase"`
PosGain float32 `viewif:"On&&ModGain" desc:"for positive dopamine, how much to change the default gain value as a function of dopamine: gain = gain * (1 + da * PosGain) -- da is multiplied by minus or plus depending on phase"`
}
func (dm *DaModParams) Defaults() {
dm.Minus = 0
dm.Plus = 0.01
dm.NegGain = 0.1
dm.PosGain = 0.1
}
// GeModOn returns true if modulating Ge
func (dm *DaModParams) GeModOn() bool {
return dm.On && !dm.ModGain
}
// GainModOn returns true if modulating Gain
func (dm *DaModParams) GainModOn() bool {
return dm.On && dm.ModGain
}
// Ge returns da-modulated ge value
func (dm *DaModParams) Ge(da, ge float32, plusPhase bool) float32 {
if plusPhase {
return dm.Plus * da * ge
} else {
return dm.Minus * da * ge
}
}
// Gain returns da-modulated gain value
func (dm *DaModParams) Gain(da, gain float32, plusPhase bool) float32 {
if plusPhase {
da *= dm.Plus
} else {
da *= dm.Minus
}
if da < 0 {
return gain * (1 + da*dm.NegGain)
} else {
return gain * (1 + da*dm.PosGain)
}
}
//////////////////////////////////////////////////////////////////////
// Enums
// DaReceptors for D1R and D2R dopamine receptors
type DaReceptors int
//go:generate stringer -type=DaReceptors
var KiT_DaReceptors = kit.Enums.AddEnum(DaReceptorsN, kit.NotBitFlag, nil)
func (ev DaReceptors) MarshalJSON() ([]byte, error) { return kit.EnumMarshalJSON(ev) }
func (ev *DaReceptors) UnmarshalJSON(b []byte) error { return kit.EnumUnmarshalJSON(ev, b) }
const (
// D1R primarily expresses Dopamine D1 Receptors -- dopamine is excitatory and bursts of dopamine lead to increases in synaptic weight, while dips lead to decreases -- direct pathway in dorsal striatum
D1R DaReceptors = iota
// D2R primarily expresses Dopamine D2 Receptors -- dopamine is inhibitory and bursts of dopamine lead to decreases in synaptic weight, while dips lead to increases -- indirect pathway in dorsal striatum
D2R
DaReceptorsN
)
// Valences for Appetitive and Aversive valence coding
type Valences int
//go:generate stringer -type=Valences
var KiT_Valences = kit.Enums.AddEnum(ValencesN, kit.NotBitFlag, nil)
func (ev Valences) MarshalJSON() ([]byte, error) { return kit.EnumMarshalJSON(ev) }
func (ev *Valences) UnmarshalJSON(b []byte) error { return kit.EnumUnmarshalJSON(ev, b) }
const (
// Appetititve is a positive valence US (food, water, etc)
Appetitive Valences = iota
// Aversive is a negative valence US (shock, threat etc)
Aversive
ValencesN
)