Files
kicking-high/proto2/tests/nn.gd

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()