185 lines
4.6 KiB
GDScript
185 lines
4.6 KiB
GDScript
extends Reference
|
|
class_name NeuralNetwork
|
|
|
|
class Matrix:
|
|
var r
|
|
var c
|
|
var data = []
|
|
func _init(rows, cols):
|
|
r = rows
|
|
c = cols
|
|
data.resize(r * c)
|
|
for i in range(r):
|
|
for j in range(c):
|
|
data[i * c + j] = 0.0
|
|
func _s(row, col, value):
|
|
data[row * c + col] = value
|
|
func _g(row, col):
|
|
return data[row * c + col]
|
|
static func multiply(m1, m2):
|
|
assert(m1.c == m2.r)
|
|
var result = Matrix.new(m1.r, m2.c)
|
|
for i in range(result.r):
|
|
for j in range(result.c):
|
|
var sum = 0.0
|
|
for k in range(m1.c):
|
|
sum += m1.data[i * m1.c + k] * m2.data[k * m2.c + j]
|
|
result.data[i * result.c + j] = sum
|
|
return result
|
|
|
|
func multiply_elementwise(val):
|
|
if val is Matrix:
|
|
for i in range(data.size()):
|
|
data[i] *= val.data[i]
|
|
else:
|
|
for i in range(data.size()):
|
|
data[i] *= val
|
|
func add(val):
|
|
if val is Matrix:
|
|
for i in range(data.size()):
|
|
data[i] += val.data[i]
|
|
else:
|
|
for i in range(data.size()):
|
|
data[i] += val
|
|
func randomize():
|
|
for i in range(data.size()):
|
|
data[i] = floor(randf() * 2.0 - 1.0)
|
|
func transposed():
|
|
var result = Matrix.new(c, r)
|
|
for i in range(r):
|
|
for j in range(c):
|
|
result.data[j * result.c + i] = data[i * c + j]
|
|
return result
|
|
static func transpose(mat):
|
|
var result = Matrix.new(mat.c, mat.r)
|
|
for i in range(mat.r):
|
|
for j in range(mat.c):
|
|
result.data[j * result.c + i] = mat.data[i * mat.c + j]
|
|
return result
|
|
static func from_array(arr):
|
|
var m = Matrix.new(arr.size(), 1)
|
|
for i in range(m.data.size()):
|
|
m.data[i] = arr[i]
|
|
return m
|
|
static func subtract(m1, m2):
|
|
var result = Matrix.new(m1.r, m1.c)
|
|
for e in range(m1.data.size()):
|
|
result.data[e] = m1.data[e] - m2.data[e]
|
|
return result
|
|
func display():
|
|
print("[")
|
|
for i in range(r):
|
|
var mat_row = "\t[ "
|
|
for j in range(c):
|
|
mat_row += str(data[i * c + j])
|
|
if j < c - 1:
|
|
mat_row += " "
|
|
else:
|
|
mat_row += " ]"
|
|
print(mat_row)
|
|
print("]")
|
|
func map(obj, f):
|
|
for e in range(data.size()):
|
|
var val = obj.call(f, data[e])
|
|
data[e] = val
|
|
static func map_s(m, obj, f):
|
|
var result = Matrix.new(m.r, m.c)
|
|
for e in range(m.data.size()):
|
|
var val = obj.call(f, m.data[e])
|
|
result.data[e] = val
|
|
return result
|
|
func to_array():
|
|
return data
|
|
|
|
|
|
var input_nodes
|
|
var hidden_nodes
|
|
var output_nodes
|
|
var weights_ih
|
|
var weights_ho
|
|
var bias_h
|
|
var bias_o
|
|
var learning_rate = 0.1
|
|
# 3Blue1Brown
|
|
func tst(data):
|
|
return 1.0
|
|
func sigmoid(x):
|
|
return 1.0 / (1.0 + exp(-x))
|
|
func dsigmoid(x):
|
|
return x * (1.0 - x)
|
|
func feedforward(inputs_array):
|
|
# Hidden outputs
|
|
var inputs = Matrix.from_array(inputs_array)
|
|
var hidden = Matrix.multiply(weights_ih, inputs)
|
|
hidden.add(bias_h)
|
|
hidden.map(self, "sigmoid")
|
|
|
|
var output = Matrix.multiply(weights_ho, hidden)
|
|
output.add(bias_o)
|
|
output.map(self, "sigmoid")
|
|
|
|
return output.to_array()
|
|
func train(inputs_array, targets_array):
|
|
var inputs = Matrix.from_array(inputs_array)
|
|
var hidden = Matrix.multiply(weights_ih, inputs)
|
|
hidden.add(bias_h)
|
|
hidden.map(self, "sigmoid")
|
|
|
|
var outputs = Matrix.multiply(weights_ho, hidden)
|
|
outputs.add(bias_o)
|
|
outputs.map(self, "sigmoid")
|
|
|
|
var targets = Matrix.from_array(targets_array)
|
|
var output_errors = Matrix.subtract(targets, outputs)
|
|
var gradients = Matrix.map_s(outputs, self, "dsigmoid")
|
|
gradients.multiply_elementwise(output_errors)
|
|
gradients.multiply_elementwise(learning_rate)
|
|
|
|
var hidden_T = Matrix.transpose(hidden)
|
|
var weights_ho_deltas = Matrix.multiply(gradients, hidden_T)
|
|
weights_ho.add(weights_ho_deltas)
|
|
bias_o.add(gradients)
|
|
|
|
var who_t = Matrix.transpose(weights_ho)
|
|
var hidden_errors = Matrix.multiply(who_t, output_errors)
|
|
var hidden_gradients = Matrix.map_s(hidden, self, "dsigmoid")
|
|
hidden_gradients.multiply_elementwise(hidden_errors)
|
|
hidden_gradients.multiply_elementwise(learning_rate)
|
|
var inputs_T = Matrix.transpose(inputs)
|
|
var weights_ih_deltas = Matrix.multiply(hidden_gradients, inputs_T)
|
|
weights_ih.add(weights_ih_deltas)
|
|
bias_h.add(hidden_gradients)
|
|
|
|
|
|
# outputs.display()
|
|
# targets.display()
|
|
# error.display()
|
|
|
|
func _init(numI, numH, numO):
|
|
input_nodes = numI
|
|
hidden_nodes = numH
|
|
output_nodes = numO
|
|
weights_ih = Matrix.new(hidden_nodes, input_nodes)
|
|
weights_ho = Matrix.new(output_nodes, hidden_nodes)
|
|
weights_ih.randomize()
|
|
weights_ho.randomize()
|
|
bias_h = Matrix.new(hidden_nodes, 1)
|
|
bias_h.randomize()
|
|
bias_o = Matrix.new(output_nodes, 1)
|
|
bias_o.randomize()
|
|
|
|
|
|
# var matrix = Matrix.new(3, 2)
|
|
# matrix.randomize()
|
|
# matrix.display()
|
|
# var matrix2 = Matrix.new(2, 3)
|
|
# matrix2.randomize()
|
|
# matrix2.display()
|
|
# var matrix3 = Matrix.multiply(matrix, matrix2)
|
|
# matrix3.display()
|
|
# Matrix.transpose(matrix3).display()
|
|
# matrix3.map(self, "tst")
|
|
# matrix3.display()
|
|
|
|
|