1 | using System; |
---|
2 | using System.Collections.Generic; |
---|
3 | using System.Collections; |
---|
4 | using System.Linq; |
---|
5 | using System.Text; |
---|
6 | |
---|
7 | namespace BCMToolbox |
---|
8 | { |
---|
9 | |
---|
10 | #region Network |
---|
11 | public class SynchronousBCMNetwork : FixedTraceableNetwork |
---|
12 | { |
---|
13 | |
---|
14 | protected Func<double, double> __activation = null; |
---|
15 | protected Func<double, double> __activationDerivative = null; |
---|
16 | protected int __neuronCount = 0; |
---|
17 | protected double __slidingThreshold = 0.0; |
---|
18 | |
---|
19 | double __inertia = 0.8; |
---|
20 | double[] __intermediaryPotentials = null; |
---|
21 | double[,] __potentialsQueues = null; |
---|
22 | double[] __memoryRegression = null; |
---|
23 | |
---|
24 | |
---|
25 | internal SynchronousBCMNetwork(int neuronCount, Func<double, double> newThreshold, Func<double, double> newThresholdDerivative, int newID) |
---|
26 | : base(neuronCount, newID) |
---|
27 | { |
---|
28 | __activation = newThreshold; |
---|
29 | __activationDerivative = newThresholdDerivative; |
---|
30 | __neuronCount = neuronCount; |
---|
31 | __intermediaryPotentials = new double[neuronCount]; |
---|
32 | |
---|
33 | |
---|
34 | |
---|
35 | // setup the memory trace function memoizer |
---|
36 | __memoryRegression = new double[] { 1, 0.90483741803596, 0.818730753077982, 0.740818220681718, 0.670320046035639, 0.606530659712633, 0.548811636094027, 0.49658530379141, 0.449328964117222, 0.406569659740599, 0.367879441171442, 0.33287108369808, 0.301194211912202, 0.272531793034013, 0.246596963941606, 0.22313016014843, 0.201896517994655, 0.182683524052735, 0.165298888221587, 0.149568619222635 }; |
---|
37 | __slidingThreshold = 9.08618386468457; |
---|
38 | //__slidingThreshold = 9; |
---|
39 | |
---|
40 | /* |
---|
41 | int memoryRegressionDepth = 0; |
---|
42 | for (memoryRegressionDepth = 0; memoryRegressionDepth > -100; memoryRegressionDepth--) |
---|
43 | if (memoryFunction(memoryRegressionDepth) < MEMORY_REGRESSION_THRESHOLD) |
---|
44 | break; |
---|
45 | |
---|
46 | __memoryRegression = new double[-memoryRegressionDepth]; |
---|
47 | for (int i = 0; i > memoryRegressionDepth; i--) |
---|
48 | __memoryRegression[-i] = memoryFunction(i); */ |
---|
49 | |
---|
50 | // setup the queues |
---|
51 | __potentialsQueues = new double[__neuronCount, __memoryRegression.Length]; |
---|
52 | } |
---|
53 | |
---|
54 | public override string Identification |
---|
55 | { |
---|
56 | get |
---|
57 | { |
---|
58 | return String.Format("Vanilla BCM #{0}", this.UID); |
---|
59 | } |
---|
60 | } |
---|
61 | |
---|
62 | |
---|
63 | |
---|
64 | |
---|
65 | |
---|
66 | public double Inertia |
---|
67 | { |
---|
68 | get |
---|
69 | { |
---|
70 | return __inertia; |
---|
71 | } |
---|
72 | |
---|
73 | set |
---|
74 | { |
---|
75 | __inertia = value; |
---|
76 | } |
---|
77 | } |
---|
78 | |
---|
79 | |
---|
80 | |
---|
81 | |
---|
82 | #region Applying inputs and propagation |
---|
83 | |
---|
84 | |
---|
85 | public override void ApplyInputs(double[] newInputs) |
---|
86 | { |
---|
87 | lock (SyncRoot) |
---|
88 | { |
---|
89 | if (newInputs == null) |
---|
90 | throw new ArgumentNullException(); |
---|
91 | |
---|
92 | if (newInputs.Length != __neuronCount) |
---|
93 | throw new ArgumentException("Invalid input size. Expected: ", __neuronCount.ToString()); |
---|
94 | |
---|
95 | for (int i = 0; i < __neuronCount; i++) |
---|
96 | __potentials[i] += newInputs[i]; |
---|
97 | } |
---|
98 | |
---|
99 | base.ApplyInputs(newInputs); |
---|
100 | } |
---|
101 | |
---|
102 | |
---|
103 | |
---|
104 | public override void Propagate() |
---|
105 | { |
---|
106 | // calculate intermediary potentials |
---|
107 | for (int i = 0; i < __neuronCount; i++) |
---|
108 | { |
---|
109 | __intermediaryPotentials[i] = 0.0; |
---|
110 | for (int j = 0; j < __neuronCount; j++) |
---|
111 | if ((i != j) && !double.IsNaN(__weights[j, i])) |
---|
112 | __intermediaryPotentials[i] += __weights[j, i] * __potentials[j]; |
---|
113 | |
---|
114 | |
---|
115 | |
---|
116 | __intermediaryPotentials[i] = __activation(__intermediaryPotentials[i]); |
---|
117 | System.Diagnostics.Debug.Assert(!double.IsNaN(__intermediaryPotentials[i])); |
---|
118 | System.Diagnostics.Debug.Assert(!double.IsInfinity(__intermediaryPotentials[i])); |
---|
119 | } |
---|
120 | |
---|
121 | lock (SyncRoot) |
---|
122 | { |
---|
123 | // update weights |
---|
124 | int queueIdx = Ticks % __memoryRegression.Length; |
---|
125 | for (int i = 0; i < __neuronCount; i++) |
---|
126 | { |
---|
127 | // determine output threshold |
---|
128 | double outputThreshold = 0.0; |
---|
129 | double last = __intermediaryPotentials[i]; |
---|
130 | for (int j = 0; j < __memoryRegression.Length; j++) |
---|
131 | { |
---|
132 | int idx = queueIdx - 1 - j + __memoryRegression.Length; |
---|
133 | idx %= __memoryRegression.Length; |
---|
134 | |
---|
135 | if (j >= Ticks) // not progressed this far yet |
---|
136 | outputThreshold += last * last * __memoryRegression[j]; |
---|
137 | else |
---|
138 | { |
---|
139 | outputThreshold += __potentialsQueues[i, idx] * __potentialsQueues[i, idx] * __memoryRegression[j]; |
---|
140 | last = __potentialsQueues[i, idx]; |
---|
141 | } |
---|
142 | } |
---|
143 | outputThreshold *= 1 / __slidingThreshold; |
---|
144 | |
---|
145 | /* |
---|
146 | if (i == 50) |
---|
147 | System.Diagnostics.Debug.WriteLine(String.Format("{0} - {1}", __intermediaryPotentials[i], outputThreshold)); */ |
---|
148 | |
---|
149 | // update weights |
---|
150 | for (int j = 0; j < __neuronCount; j++) |
---|
151 | { |
---|
152 | if ((i == j) || double.IsNaN(__weights[j, i])) continue; |
---|
153 | |
---|
154 | double delta = __intermediaryPotentials[i] * (__intermediaryPotentials[i] - outputThreshold); |
---|
155 | |
---|
156 | delta *= __potentials[j]; |
---|
157 | delta *= __activationDerivative(__intermediaryPotentials[i]); // Intrator and Cooper |
---|
158 | /* |
---|
159 | if(0 != outputThreshold) |
---|
160 | delta /= outputThreshold; // Law and Cooper */ |
---|
161 | delta *= __inertia; |
---|
162 | System.Diagnostics.Debug.Assert(!double.IsNaN(delta)); |
---|
163 | System.Diagnostics.Debug.Assert(!double.IsInfinity(delta)); |
---|
164 | __weights[j, i] += delta; |
---|
165 | |
---|
166 | /* |
---|
167 | // additional constraint: connections preserve their exc/inh status |
---|
168 | * NOT A GOOD IDEA - network wide inhibition needs to be implemented as a process which does not influece calculus |
---|
169 | if (__weights[j, i] < 0) |
---|
170 | { |
---|
171 | __weights[j, i] -= delta; |
---|
172 | if (__weights[j, i] > 0) |
---|
173 | __weights[j, i] = -double.Epsilon; |
---|
174 | } |
---|
175 | else |
---|
176 | { |
---|
177 | __weights[j, i] += delta; |
---|
178 | if (__weights[j, i] < 0) |
---|
179 | __weights[j, i] = double.Epsilon; |
---|
180 | } */ |
---|
181 | } |
---|
182 | } |
---|
183 | |
---|
184 | |
---|
185 | // update potentials and queues |
---|
186 | for (int i = 0; i < __neuronCount; i++) |
---|
187 | { |
---|
188 | __potentials[i] = __intermediaryPotentials[i]; |
---|
189 | __potentialsQueues[i, queueIdx] = __potentials[i]; |
---|
190 | } |
---|
191 | |
---|
192 | |
---|
193 | NormalizeWeights(2.0); |
---|
194 | } |
---|
195 | |
---|
196 | base.Propagate(); |
---|
197 | } |
---|
198 | |
---|
199 | #endregion |
---|
200 | |
---|
201 | |
---|
202 | } |
---|
203 | #endregion |
---|
204 | |
---|
205 | #region Factories |
---|
206 | public class BCMFactory |
---|
207 | { |
---|
208 | static int __uid = 0; |
---|
209 | public static TraceableNetwork BuildSyncSigmoidActivationNetwork(int nodesCount) |
---|
210 | { |
---|
211 | return new SynchronousBCMNetwork( |
---|
212 | nodesCount, |
---|
213 | x => 1.0 / (1 + Math.Exp(-x)), // threshold function |
---|
214 | x => { double e = Math.Exp(-x); return e / ((1.0 + e) * (1.0 + e)); }, // derivative of the threshold |
---|
215 | __uid++); // memory regression parameter |
---|
216 | } |
---|
217 | |
---|
218 | public static TraceableNetwork BuildSyncSigmoidActivationNetworkSparse(int nodesCount, Func<int, int, bool> weightExistenceFunction) |
---|
219 | { |
---|
220 | SynchronousBCMNetwork toRet = new SynchronousBCMNetwork( |
---|
221 | nodesCount, |
---|
222 | x => 1.0 / (1 + Math.Exp(-x)), // threshold function |
---|
223 | x => { double e = Math.Exp(-x); return e / ((1.0 + e) * (1.0 + e)); }, // derivative of the threshold |
---|
224 | __uid++); |
---|
225 | |
---|
226 | for (int i = 0; i < nodesCount; i++) |
---|
227 | for (int j = 0; j < nodesCount; j++) |
---|
228 | if (!weightExistenceFunction(i, j)) |
---|
229 | toRet[i, j] = double.NaN; |
---|
230 | |
---|
231 | return toRet; |
---|
232 | } |
---|
233 | |
---|
234 | public static TraceableNetwork Reduce(TraceableNetwork toReduce, Func<int, int, bool> weightExistenceFunction) |
---|
235 | { |
---|
236 | for (int i = 0; i < toReduce.Count; i++) |
---|
237 | for (int j = 0; j < toReduce.Count; j++) |
---|
238 | if (!weightExistenceFunction(i, j)) |
---|
239 | toReduce[i, j] = double.NaN; |
---|
240 | return toReduce; |
---|
241 | } |
---|
242 | |
---|
243 | |
---|
244 | public static TraceableNetwork BuildSyncSigmoidActivationNetwork2(int nodesCount) |
---|
245 | { |
---|
246 | return new SynchronousBCMNetwork( |
---|
247 | nodesCount, |
---|
248 | x => 2.0 / (1 - Math.Exp(-2*x)) - 1.0, // threshold function |
---|
249 | x => { double e = Math.Exp(-2*x); return 4.0* e / ((1 + e) * (1 + e)); }, // derivative of the threshold |
---|
250 | __uid++ |
---|
251 | ); // memory regression parameter |
---|
252 | } |
---|
253 | |
---|
254 | public static TraceableNetwork BuildOja(int nodesCount) |
---|
255 | { |
---|
256 | return new SynchronousOjaNetwork(nodesCount, |
---|
257 | __uid++); |
---|
258 | } |
---|
259 | |
---|
260 | public static TraceableNetwork BuildModel01(int nodesCount) |
---|
261 | { |
---|
262 | return new Model01(nodesCount, |
---|
263 | __uid++); |
---|
264 | } |
---|
265 | |
---|
266 | /* |
---|
267 | public static TraceableNetwork BuildSyncLinearActivationNetwork(int nodesCount, double slidingThreshold) |
---|
268 | { |
---|
269 | return new SynchronousBCMNetwork( |
---|
270 | nodesCount, |
---|
271 | x => x, |
---|
272 | x => 1.0, |
---|
273 | __uid++, |
---|
274 | x => Math.Exp(x / slidingThreshold), |
---|
275 | slidingThreshold); |
---|
276 | } */ |
---|
277 | } |
---|
278 | #endregion |
---|
279 | } |
---|