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
|
const const {
double FireThreshold = 0.015; // [V], fasimu
double Tau_Voltage = 0.05; // [s], fasimu
double RefractoryPeriod = 0.001; // [s], fasimu
double Tau_Dopamine = 0.005; // [s], fasimu
double TauEligibility = 0.2; // [s], fasimu
double Tau_LTP = 0.014; // [s], fasimu
double Tau_LTD = 0.034; // [s], fasimu
double Delta_LTP = 1; // [V]
double Delta_LTD = 1; // [V]
double DeltaET_LTP = 0.000103; // christina 2008 (poster)
double DeltaET_LTD = 0.000055; // christina 2008 (poster)
double Tau_MomEst = 0.01; // [s]
double Tau_SlowMomEst = 20; // [s]
double TargetFreq = 10; // [Hz]
double RandomFreq = 3.15; // [Hz] (per neuron); is the break even
// point (rand freq = neuron freq) w/o IP
double RandomSpikeWeight = 0.01; // [V]
double MaxWeight = 0.004; // [V]
int TrainerNumSymbols = 2;
double TrainerInput = 0.008; // [V]
double TrainerInputWindow = 0.05; // [ms]
double TrainerInputFreq = 40; // [Hz]
double TrainerWinAdv = 0.1;
double TrainerReward = 50; // reduced to half as Tau_ET will be increased
double TrainerPunish = 0;
double TrainerReadoutDelay = 0.25;
double TrainerReadoutRandDelay = 0.05;
double TrainerReadoutWindow = 0.05;
double TrainerReadoutFreq = 40; // [Hz]
double TrainerInterTrialDelay = 0.75;
double TrainerInterTrialRandDelay = 0.5;
double TrainerInitialDelay = 50;
int FanIn = 100;
int FanOut = 100;
int NumExcitatory = 800;
double LambdaIP1 = 0.00005; // achieves steady state after ~50s
}
discrete GlobalMsg {
TrainerT NextTrainer;
}
continuous Global {
double Dopamine = 0.0;
TrainerT Trainer = TrainerT();
double Performance = 1.0 / TrainerNumSymbols;
uint16_t LastInput = 2;
uint16_t LastOutput = 2;
bool ResetSpikeCounter = true;
Dopamine' = Dopamine * exp(-dt / Tau_Dopamine);
on GlobalMsg {
Trainer' = NextTrainer;
Performance' = NextTrainer.performance;
LastInput' = NextTrainer.input;
LastOutput' = NextTrainer.output;
ResetSpikeCounter' = NextTrainer.resetCounter;
}
emit GlobalMsg {
default true;
after Trainer'.delay;
Dopamine' = Dopamine + Trainer.reward;
NextTrainer' = Trainer.update(pc, indices, queues, t);
}
}
continuous Neuron {
double Voltage = 0.0;
double LTDTrace = 0.0;
double RefractoryLeft = 0.0;
double SpikeRate = 0.0;
double Moment1 = TargetFreq;
double SlowMoment1 = TargetFreq;
double IPCoeff1 = 0.0;
double SumWeight = 0.0; // set by convert_topology
double TargetSumWeight = 0.0; // set by convert_topology
Time LastSpike = 0.0;
uint16_t SpikeCounter = 0;
RNG::seed_t RandomSeed = 0; // initialized seperately during bootstrap
bool RandomEnabled = false; // an incoming randspike turns this to true,
// on outgoing to false again -> only
// incoming randspikes generate new ones
Voltage' = Voltage * exp(-dt / Tau_Voltage);
LTDTrace' = LTDTrace * exp(-dt / Tau_LTD);
RefractoryLeft' = fmax(0.0, RefractoryLeft - dt);
Moment1' = Moment1 * exp(-dt / Tau_MomEst);
SpikeCounter' = ResetSpikeCounter ? 0 : SpikeCounter;
on SpikeArrival {
SumWeight' = SumWeight + DeltaWeight;
Voltage' = Voltage + Weight;
}
on RandomSpike {
Voltage' = Voltage + RandomSpikeWeight + FireThreshold
* (context.template getptr<Neuron>()() > NumExcitatory);
RandomEnabled' = context.template getptr<Neuron>()() < NumExcitatory;
}
emit Spike {
default true;
if Voltage' > FireThreshold + _CP(IPCoeff1);
if RefractoryLeft' == 0.0;
LTDTrace' = Delta_LTD;
RefractoryLeft' = RefractoryPeriod * (context.template getptr<Neuron>()() < NumExcitatory);
Voltage' = 0;
LastSpike' = t;
SpikeRate' = 1 / (t() - LastSpike());
Moment1' = Moment1 + SpikeRate' * (1 - exp(- (t() - LastSpike()) / Tau_MomEst));
SlowMoment1' = SlowMoment1 * exp(- (t() - LastSpike()) / Tau_SlowMomEst)
+ SpikeRate' * (1 - exp(- (t() - LastSpike()) / Tau_SlowMomEst));
IPCoeff1' = (context.template getptr<Neuron>()() < NumExcitatory)
? fmax(-FireThreshold, IPCoeff1 - (t() - LastSpike()) * LambdaIP1 * (TargetFreq - SpikeRate'))
: IPCoeff1;
SpikeCounter' = ResetSpikeCounter ? 0 : SpikeCounter + 1;
}
emit RandomSpike {
default false;
if RandomEnabled' == true;
after RNG::expo(RandomSeed, 1.0 / RandomFreq);
RandomEnabled' = false;
RandomSeed' = RNG::next(RandomSeed);
}
}
continuous Synapse {
double Weight = 0.0; // set by convert_topology
double DeltaWeight = 0;
double TmpDeltaWeight = 0;
double EligibilityTrace = 0.0;
double LTPTrace = 0.0;
TmpDeltaWeight' = (Weight >= 0 && Weight <= MaxWeight
&& (context.template getptr<Neuron>()() < NumExcitatory))
? TmpDeltaWeight
+ EligibilityTrace * Dopamine
* Tau_Dopamine * TauEligibility
/ (Tau_Dopamine + TauEligibility)
* (1.0 - exp( (-(Tau_Dopamine + TauEligibility))
/ (Tau_Dopamine * TauEligibility)
* dt))
: 0;
// HACK: we compare begin of time interval to evolve with time of the last
// outgoing spike; if equal, this is the first time that synapse if
// evolved since that spike and we can add LTDTrace
EligibilityTrace' = EligibilityTrace * exp(-dt / TauEligibility)
+ (LastSpike == t) * DeltaET_LTP * LTPTrace';
LTPTrace' = LTPTrace * exp(-dt / Tau_LTP);
on Spike {
LTPTrace' = LTPTrace + Delta_LTP;
EligibilityTrace' = EligibilityTrace - DeltaET_LTD * LTDTrace;
}
emit SpikeArrival {
default true; // unconditionally emit SA event (it is more like
// a pseudo event)
Weight' = (Weight >= 0 && Weight <= MaxWeight
&& (context.template getptr<Neuron>()() < NumExcitatory))
? fmin(MaxWeight, fmax(0,
(Weight + TmpDeltaWeight)
/ (SumWeight + TmpDeltaWeight)
* TargetSumWeight))
: Weight;
DeltaWeight' = Weight' - Weight;
TmpDeltaWeight' = 0;
}
}
|