-
Notifications
You must be signed in to change notification settings - Fork 1
/
ProfessorFNeuralNet.bas
293 lines (272 loc) · 7.77 KB
/
ProfessorFNeuralNet.bas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
Attribute VB_Name = "mNeuralNet"
'
' ProfessorF (pf) Neural Network Excel Library
'
' Copyright (c) Nick V. Flor, 2014-2017, All rights reserved
'
' This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 International License.
' CC BY-SA, If you use this code for research, you must cite me in your paper references
' To view a copy of the license visit: http://creativecommons.org/licenses/by-sa/4.0/legalcode
' To view a summary of the license visit: http://creativecommons.org/licenses/by-sa/4.0/
'
' This material is based partly upon work supported by the National Science Foundation (NSF)
' under ECCS - 1231046 and - SNM 1635334 . Any opinions, findings, and conclusions or recommendations
' expressed in this material are those of the author and do not necessarily reflect the views of the NSF.
'
' Based on the algorithms in the Explorations in PDP Book (McClelland & Rumelhart, 1988)
'
Option Explicit
Dim nunits As Long
Dim netinput() As Double
Dim activation() As Double
Dim err(), delta() As Double
Dim weight(), wed(), dweight() As Double
Dim first_weight_to() As Double
Dim last_weight_to() As Double
Dim ninputs, nhidden, noutputs As Long
Dim istartinput, iendinput, istarthidden, iendhidden, istartoutput, iendoutput, lastunit As Long
Dim istarttrain, iendtrain As Long
Dim wstrain As Worksheet
Dim trainrow As Long
Dim lrate, momentum As Double
Sub nnInit()
Attribute nnInit.VB_ProcData.VB_Invoke_Func = "i\n14"
Dim i, j As Long
'
' Determine # of units
' Add 2 for input layer & hidden layer biases
'
ninputs = CLng(Range("ninputs"))
nhidden = CLng(Range("nhidden"))
noutputs = CLng(Range("noutputs"))
nunits = ninputs + nhidden + noutputs + 2
'
' To facilitate porting to other languages, we'll use 0 as a base
'
ReDim activation(0 To nunits - 1)
ReDim delta(0 To nunits - 1)
ReDim netinput(0 To nunits - 1)
ReDim weight(0 To nunits - 1, 0 To nunits - 1)
ReDim dweight(0 To nunits - 1, 0 To nunits - 1)
ReDim wed(0 To nunits - 1, 0 To nunits - 1)
ReDim first_weight_to(0 To nunits - 1)
ReDim last_weight_to(0 To nunits - 1)
ReDim err(0 To nunits - 1)
'
' Initialize all unit connections
'
istartinput = 0
iendinput = ninputs
istarthidden = iendinput + 1
iendhidden = istarthidden + nhidden
istartoutput = iendhidden + 1
iendoutput = istartoutput + noutputs - 1
lastunit = nunits - 1
For i = istartinput To iendinput ' inputs have no connections
first_weight_to(i) = -1
last_weight_to(i) = -1
Next
For i = istarthidden To iendhidden
first_weight_to(i) = istartinput
last_weight_to(i) = iendinput
Next
For i = istartoutput To iendoutput
first_weight_to(i) = istarthidden
last_weight_to(i) = iendhidden
Next
'
' Initialize weights
'
For i = istartoutput To iendoutput
For j = istarthidden To iendhidden
weight(i, j) = Math.Rnd
Next
Next
For i = istarthidden To iendhidden
For j = istartinput To iendinput
weight(i, j) = Math.Rnd
Next
Next
'
' Initalize weight delta matrix
'
For i = istartinput To iendoutput
For j = istartinput To iendoutput
wed(i, j) = 0
Next
Next
'
' Initalize learning weight & momentum
'
lrate = CDbl(Range("lrate"))
momentum = CDbl(Range("momentum"))
'
' initialize training indices
'
Set wstrain = Sheets("training")
istarttrain = 1
iendtrain = wstrain.Cells(Rows.Count, 1).End(xlUp).Row
End Sub
Function logistic(net As Double) As Double
logistic = 1 / (1 + Math.Exp(-net))
End Function
Sub change_weights()
Dim i, j As Long
' sum_linked_weds?
For i = istarthidden To iendoutput
For j = first_weight_to(i) To last_weight_to(i)
dweight(i, j) = lrate * wed(i, j) + momentum * dweight(i, j)
weight(i, j) = weight(i, j) + dweight(i, j)
wed(i, j) = 0
Next
Next
End Sub
Sub compute_wed()
Dim i, j As Long
' WARNING: where do weds get zeroed out?
For i = istarthidden To iendoutput
For j = first_weight_to(i) To last_weight_to(i)
wed(i, j) = wed(i, j) + delta(i) * activation(j)
Next
Next
End Sub
Sub compute_error()
Dim tr As Double
Dim i, j, traincol As Long
'
' Clear out all error for hidden and output units
'
For i = istarthidden To iendoutput
err(i) = 0
Next
'
' Compute errors for output units
'
For i = istartoutput To iendoutput
traincol = ninputs + (i - istartoutput + 1) ' + noutputs
tr = wstrain.Cells(trainrow, traincol)
err(i) = tr - activation(i)
Next
'
' compute errors for all hidden to output
'
For i = iendoutput To istarthidden Step -1
'
' Remember, delta is different for back propagation
'
delta(i) = err(i) * activation(i) * (1 - activation(i))
'
' propagate down
'
For j = first_weight_to(i) To last_weight_to(i)
err(j) = err(j) + delta(i) * weight(i, j)
Next
Next
End Sub
Sub compute_output()
Dim i, j As Long
For i = istarthidden To iendoutput
netinput(i) = 0
For j = first_weight_to(i) To last_weight_to(i)
netinput(i) = netinput(i) + weight(i, j) * activation(j) ' weight to i from j
Next
activation(i) = logistic(netinput(i))
Next
End Sub
Sub nnLoadWeights()
Dim i, j As Long
Dim ws As Worksheet
Set ws = Worksheets("weights")
For i = istartinput To iendoutput
For j = istartinput To iendoutput
weight(i, j) = ws.Cells(i + 1, j + 1)
Next
Next
End Sub
Sub nnDumpWeights()
Attribute nnDumpWeights.VB_ProcData.VB_Invoke_Func = "w\n14"
Dim i, j As Long
Dim ws As Worksheet
Set ws = Worksheets("weights")
For i = istartinput To iendoutput
For j = istartinput To iendoutput
ws.Cells(i + 1, j + 1) = weight(i, j)
Next
Next
End Sub
Sub nnDumpActivations()
Attribute nnDumpActivations.VB_ProcData.VB_Invoke_Func = "a\n14"
Dim i, j As Long
Dim ws As Worksheet
Set ws = Worksheets("activations")
For i = istartoutput To iendoutput
ws.Cells(1, (i - istartoutput + 1)) = activation(i)
Next
For i = istarthidden To iendhidden
ws.Cells(2, (i - istarthidden + 1)) = activation(i)
Next
For i = istartinput To iendinput
ws.Cells(3, (i - istartinput + 1)) = activation(i)
Next
End Sub
Sub nnDumpNets()
Attribute nnDumpNets.VB_ProcData.VB_Invoke_Func = "n\n14"
Dim i, j As Long
Dim ws As Worksheet
Set ws = Worksheets("nets")
For i = istartoutput To iendoutput
ws.Cells(1, (i - istartoutput + 1)) = netinput(i)
Next
For i = istarthidden To iendhidden
ws.Cells(2, (i - istarthidden + 1)) = netinput(i)
Next
For i = istartinput To iendinput
ws.Cells(3, (i - istartinput + 1)) = netinput(i)
Next
End Sub
Sub nnLoad(r As Long)
Dim i As Long
For i = istartinput To iendinput 'istartinput must ALWAYS be 0
If (i = istartinput) Then
activation(i) = 1 ' bias is always 1
Else
activation(i) = wstrain.Cells(r, i)
End If
Next
End Sub
Sub show_outputs()
Dim i, tcol As Long
For i = istartoutput To iendoutput
tcol = ninputs + noutputs + 1
wstrain.Cells(trainrow, (tcol + i - istartoutput)) = activation(i)
Next
End Sub
Sub nnTrain()
Attribute nnTrain.VB_ProcData.VB_Invoke_Func = "r\n14"
Dim i, epochs As Long
'For r = istarttrain To iendtrain
epochs = CLng(Range("epoch"))
For i = 1 To epochs
lrate = CDbl(Range("lrate"))
momentum = CDbl(Range("momentum"))
For trainrow = istarttrain To iendtrain
nnLoad (trainrow)
compute_output
compute_error ' training
compute_wed ' weight deltas
change_weights ' actually changes the weights
show_outputs
DoEvents
Next
Application.StatusBar = CStr(i) + "/" + CStr(epochs)
Next
End Sub
Sub nnRun()
Dim i, epochs As Long
For trainrow = istarttrain To iendtrain
nnLoad (trainrow)
compute_output
show_outputs
DoEvents
Next
End Sub