Skip to content

Commit 8b5a633

Browse files
committed
fix some typos and bugs
1 parent edb2c88 commit 8b5a633

2 files changed

Lines changed: 54 additions & 43 deletions

File tree

addons/NeuralNetwork/Classes/Network.gd

Lines changed: 39 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ func feedforward(inputs: Array[float]) -> Matrix:
4646
## Feeding our inputs to the activation matrix
4747
var activation_matrix = Matrix.new(inputs.size(), 1)
4848
for row in range(activation_matrix.no_of_rows):
49-
activation_matrix.set_index(row, 0, inputs[row])
49+
activation_matrix.set_index(row, 0, clamp(inputs[row], -1, 1))
5050
emit_signal("activation_changed", 0, activation_matrix)
5151

5252
## Calculate the next layer's activation array using to the weights and biases
@@ -65,10 +65,10 @@ func feedforward(inputs: Array[float]) -> Matrix:
6565

6666

6767
## Train the neural network using mini-batch stochastic
68-
## gradient descent. The ``training_data`` is a list of tuples
69-
## ``(x, y)`` representing the training inputs and the desired
68+
## gradient descent. The training_data is an Array of Arrays
69+
## [data, expected output] representing the training inputs and the desired
7070
## outputs. The other non-optional parameters are
71-
## self-explanatory. If ``test_data`` is provided then the
71+
## self-explanatory. If test_data is provided then the
7272
## network will be evaluated against the test data after each
7373
## epoch, and partial progress printed out. This is useful for
7474
## tracking progress, but slows things down substantially."""
@@ -79,73 +79,72 @@ func SGD(
7979
eta: float,
8080
test_data: Array[Array] = []
8181
):
82-
var n = len(training_data)
82+
var n = training_data.size()
8383
for j in range(epochs):
8484
training_data.shuffle()
8585
for k in range(0, n, mini_batch_size):
8686
var mini_batch: Array[Array] = training_data.slice(k, k + mini_batch_size)
8787
update_mini_batch(mini_batch, eta)
8888
if test_data:
89-
print("Epoch &s: &s / &s" % [str(j), str(evaluate(test_data)), str(len(test_data))])
89+
print("Epoch %s: %s / %s" % [str(j), str(evaluate(test_data)), str(test_data.size())])
9090
else:
9191
print("Epoch %s complete" % str(j))
9292

93+
if _visualizer:
94+
_visualizer.update_weights(self)
95+
9396

9497
## Update the network's weights and biases by applying
9598
## gradient descent using backpropagation to a single mini batch.
96-
## The ``mini_batch`` is a list of tuples ``(x, y)``, and ``eta``
99+
## The mini_batch is is an Array of Arrays [data, expected output], and eta
97100
## is the learning rate.
98101
func update_mini_batch(mini_batch: Array[Array], eta: float) -> void:
99102
var total_nabla_b: Array[Matrix]
100103
var total_nabla_w: Array[Matrix]
101-
for b: Matrix in biases:
102-
total_nabla_b.append(Matrix.new(b.no_of_rows, b.no_of_columns))
103-
for w: Matrix in weights:
104-
total_nabla_w.append(Matrix.new(w.no_of_rows, w.no_of_columns))
104+
for i: int in biases.size():
105+
total_nabla_b.append(Matrix.new(biases[i].no_of_rows, biases[i].no_of_columns))
106+
total_nabla_w.append(Matrix.new(weights[i].no_of_rows, weights[i].no_of_columns))
105107

106108
for activation_and_results: Array[Matrix] in mini_batch:
107-
## error_array contains [nabla_b, nabla_w]
108109
var error_array = backprop(activation_and_results[0], activation_and_results[1])
109110
var delta_nabla_b: Array[Matrix] = error_array[0]
110111
var delta_nabla_w: Array[Matrix] = error_array[1]
111112

112113
for i: int in total_nabla_b.size():
113-
for dnb: Matrix in delta_nabla_b:
114-
total_nabla_b[i] = total_nabla_b[i].add(dnb)
115-
for i: int in total_nabla_w.size():
116-
for dnw: Matrix in delta_nabla_w:
117-
total_nabla_w[i] = total_nabla_w[i].add(dnw)
114+
total_nabla_b[i] = total_nabla_b[i].add(delta_nabla_b[i])
115+
total_nabla_w[i] = total_nabla_w[i].add(delta_nabla_w[i])
118116

119117
# update weights and biases accordinly
120118
for i: int in weights.size():
121-
for nw: Matrix in total_nabla_w:
122-
weights[i] = nw.multiply_scalar(eta / len(mini_batch)).subtract_from(weights[i])
123-
124-
for i: int in biases.size():
125-
for nb: Matrix in total_nabla_b:
126-
biases[i] = nb.multiply_scalar(eta / len(mini_batch)).subtract_from(biases[i])
119+
weights[i] = total_nabla_w[i].multiply_scalar(eta / mini_batch.size()).subtract_from(weights[i])
120+
biases[i] = total_nabla_b[i].multiply_scalar(eta / mini_batch.size()).subtract_from(biases[i])
127121

128122

129123
## Return an Array [nabla_b, nabla_w] representing the gradient for the cost function C_x.
130124
## nabla_b and nabla_w are layer-by-layer matrices, similar to biases and weights.
131125
func backprop(x: Matrix, y: Matrix):
132126
var nabla_b_array: Array[Matrix]
133127
var nabla_w_array: Array[Matrix]
134-
for b: Matrix in biases:
135-
nabla_b_array.append(Matrix.new(b.no_of_rows, b.no_of_columns))
136-
for w: Matrix in weights:
137-
nabla_w_array.append(Matrix.new(w.no_of_rows, w.no_of_columns))
128+
for i: int in biases.size():
129+
nabla_b_array.append(Matrix.new(biases[i].no_of_rows, biases[i].no_of_columns))
130+
nabla_w_array.append(Matrix.new(weights[i].no_of_rows, weights[i].no_of_columns))
138131

139132
# feedforward
140-
var activation: Matrix = x
133+
var activation_matrix: Matrix = x
141134
var activations: Array[Matrix] = [x] # list to store all the activations, layer by layer
142135
var zs: Array[Matrix] = [] # list to store all the z vectors, layer by layer
143-
for b: Matrix in biases:
144-
for w: Matrix in weights:
145-
var z := w.product_matrix(activation).add(b)
146-
zs.append(z)
147-
activation = z.sigmoid()
148-
activations.append(activation)
136+
## Calculate the next layer's activation array using to the weights and biases
137+
## the next layer holds for the current layer. (and loop through this procedure till
138+
## the final layer's activation array is achieved)
139+
for layer in num_layers - 1:
140+
var bias = biases[layer] # Next layer's bias for this layer.
141+
var weight = weights[layer] # Next layer's weight for this layer.
142+
## Find the activation matrix for the next layer
143+
## N+1 = Sigmoid of {(Weight).(N) + bias}
144+
var z = weight.product_matrix(activation_matrix).add(bias)
145+
zs.append(z)
146+
activation_matrix = z.sigmoid()
147+
activations.append(activation_matrix)
149148

150149
# backward pass
151150
var delta := cost_derivative(activations[-1], y).multiply_corresponding(zs[-1].sigmoid_prime())
@@ -154,7 +153,7 @@ func backprop(x: Matrix, y: Matrix):
154153
for l in range(2, num_layers):
155154
var z := zs[-l]
156155
var sp = z.sigmoid_prime()
157-
delta = weights[-l+1].clone(true).product_matrix(delta).multiply_corresponding(sp)
156+
delta = weights[-l + 1].clone(true).product_matrix(delta).multiply_corresponding(sp)
158157
nabla_b_array[-l] = delta
159158
nabla_w_array[-l] = delta.product_matrix(activations[-l-1].clone(true))
160159
return [nabla_b_array, nabla_w_array]
@@ -163,13 +162,14 @@ func backprop(x: Matrix, y: Matrix):
163162
## Return the number of test inputs for which the neural network outputs the correct result.
164163
## Note that the neural network's output is assumed to be the index of whichever neuron in the
165164
## final layer has the highest activation.
166-
func evaluate(test_data: Array[Array]):
165+
func evaluate(test_data: Array[Array]) -> int:
167166
var test_results: Array[Array] = []
168-
var sum = 0
169-
for sample: Array in test_data:
170-
test_results.append([feedforward(sample[0]).argmax(), sample[1]])
167+
var sum: int = 0
168+
for sample: Array[Matrix] in test_data:
169+
test_results.append([feedforward(sample[0].to_array()).argmax(), sample[1].argmax()])
171170
for result: Array[float] in test_results:
172171
sum += int(result[0] == result[1])
172+
return sum
173173

174174

175175
## Return the vector of partial derivatives

addons/NeuralNetwork/HelperClasses/Matrix.gd

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,14 @@ func clone(transposed := false) -> Matrix:
4141
return matrix
4242

4343

44+
func to_array() -> PackedFloat32Array:
45+
var array := PackedFloat32Array()
46+
for row: int in no_of_rows:
47+
for column: int in no_of_columns:
48+
array.append(get_index(row, column))
49+
return array
50+
51+
4452
func set_index(row: int, col: int, value: float) -> void:
4553
if col > no_of_columns:
4654
printerr("attempting to access column (", col, "), greater than", no_of_columns - 1)
@@ -66,7 +74,7 @@ func print_pretty() -> void:
6674
## Returns a normally-distributed pseudo-random matrix, using Box-Muller transform
6775
## with the specified [param mean] and a standard [param deviation].
6876
## This is also called Gaussian distribution.
69-
func make_rand_matrix(mean: float = 0, deviation: float = 1.0) -> void:
77+
func make_rand_matrix(mean: float = 0, deviation: float = 0.2) -> void:
7078
_random.randomize()
7179
assert(no_of_rows >= 1 or no_of_columns >= 1, "Can not create, 0 or negative size detected")
7280
# rows increase top-down so y
@@ -136,7 +144,11 @@ func add(b) -> Matrix:
136144
if b is Matrix:
137145
assert(
138146
Vector2i(no_of_rows, no_of_columns) == Vector2i(b.no_of_rows, b.no_of_columns),
139-
"Incompatible Matrices, can not add"
147+
str(
148+
"Incompatible Matrices, can not add. Self: ",
149+
Vector2i(no_of_rows, no_of_columns),
150+
", Other: ", Vector2i(b.no_of_rows, b.no_of_columns)
151+
)
140152
)
141153
var matrix := clone()
142154
# this will add two (x, 1) matrices
@@ -157,13 +169,12 @@ func subtract_from(a) -> Matrix:
157169
"Incompatible Matrices, can not add"
158170
)
159171
var matrix := clone()
160-
# this will add two (x, 1) matrices
161172
for row: int in range(no_of_rows):
162173
for col: int in range(no_of_columns):
163174
if a is Matrix:
164175
matrix.set_index(row, col, a.get_index(row, col) - get_index(row, col))
165176
else:
166-
matrix.set_index(row, col, a - get_index(row, col) - a)
177+
matrix.set_index(row, col, a - get_index(row, col))
167178
return matrix
168179

169180

0 commit comments

Comments
 (0)