small racing game im working on
Diffstat (limited to 'lib/neural_network.gd')
-rw-r--r--lib/neural_network.gd127
1 files changed, 127 insertions, 0 deletions
diff --git a/lib/neural_network.gd b/lib/neural_network.gd
new file mode 100644
index 0000000..70c49f6
--- /dev/null
+++ b/lib/neural_network.gd
@@ -0,0 +1,127 @@
+## Neural network
+##
+## It is a basic neural network with three layers (input, hidden and output).
+## The network is randomly initialized, it is possible to train it by passing it
+## the expected result for some input.
+class_name NeuralNetwork
+
+var input_nodes: int
+var hidden_nodes: int
+var output_nodes: int
+
+var weights_input_hidden: Matrix
+var weights_hidden_output: Matrix
+
+var bias_hidden: Matrix
+var bias_output: Matrix
+
+var learning_rate: float
+
+var activation_function: Callable
+var activation_dfunction: Callable
+
+
+func _init(_input_nodes: int,_hidden_nodes: int,_output_nodes: int):
+ input_nodes = _input_nodes;
+ hidden_nodes = _hidden_nodes;
+ output_nodes = _output_nodes;
+
+ weights_input_hidden = Matrix.rand(Matrix.new(hidden_nodes, input_nodes))
+ weights_hidden_output = Matrix.rand(Matrix.new(output_nodes, hidden_nodes));
+
+ bias_hidden = Matrix.rand(Matrix.new(hidden_nodes, 1));
+ bias_output = Matrix.rand(Matrix.new(output_nodes, 1));
+
+ set_learning_rate()
+ set_activation_function()
+
+
+func set_learning_rate(_learning_rate: float = 0.1) -> void:
+ learning_rate = _learning_rate
+
+
+func set_activation_function(callback: Callable = Callable(Activation, "sigmoid"), dcallback: Callable = Callable(Activation, "dsigmoid")) -> void:
+ activation_function = callback
+ activation_dfunction = dcallback
+
+
+func predict(input_array: Array[float]) -> Array[float]:
+ var inputs := Matrix.from_array(input_array)
+
+ var hidden := Matrix.product(weights_input_hidden, inputs)
+ hidden = Matrix.add(hidden, bias_hidden)
+ hidden = Matrix.map(hidden, activation_function)
+
+ var output = Matrix.product(weights_hidden_output, hidden)
+ output = Matrix.add(output, bias_output)
+ output = Matrix.map(output, activation_function)
+
+ return Matrix.to_array(output)
+
+
+func train(input_array: Array[float], target_array: Array[float]):
+ var inputs := Matrix.from_array(input_array)
+ var targets := Matrix.from_array(target_array)
+
+ var hidden := Matrix.product(weights_input_hidden, inputs);
+ hidden = Matrix.add(hidden, bias_hidden)
+ hidden = Matrix.map(hidden, activation_function)
+
+ var outputs := Matrix.product(weights_hidden_output, hidden)
+ outputs = Matrix.add(outputs, bias_output)
+ outputs = Matrix.map(outputs, activation_function)
+
+ var output_errors = Matrix.subtract(targets, outputs)
+
+ var gradients = Matrix.map(outputs, activation_dfunction)
+ gradients = Matrix.multiply(gradients, output_errors)
+ gradients = Matrix.scalar(gradients, learning_rate)
+
+ var hidden_t = Matrix.transpose(hidden)
+ var weight_ho_deltas = Matrix.product(gradients, hidden_t)
+
+ weights_hidden_output = Matrix.add(weights_hidden_output, weight_ho_deltas)
+ bias_output = Matrix.add(bias_output, gradients)
+
+ var weights_hidden_output_t = Matrix.transpose(weights_hidden_output)
+ var hidden_errors = Matrix.product(weights_hidden_output_t, output_errors)
+
+ var hidden_gradient = Matrix.map(hidden, activation_dfunction)
+ hidden_gradient = Matrix.multiply(hidden_gradient, hidden_errors)
+ hidden_gradient = Matrix.scalar(hidden_gradient, learning_rate)
+
+ var inputs_t = Matrix.transpose(inputs)
+ var weight_ih_deltas = Matrix.product(hidden_gradient, inputs_t)
+
+ weights_input_hidden = Matrix.add(weights_input_hidden, weight_ih_deltas)
+
+ bias_hidden = Matrix.add(bias_hidden, hidden_gradient)
+
+
+static func reproduce(a: NeuralNetwork, b: NeuralNetwork) -> NeuralNetwork:
+ var result = NeuralNetwork.new(a.input_nodes, a.hidden_nodes, a.output_nodes)
+
+ result.weights_input_hidden = Matrix.random(a.weights_input_hidden, b.weights_input_hidden)
+ result.weights_hidden_output = Matrix.random(a.weights_hidden_output, b.weights_hidden_output)
+ result.bias_hidden = Matrix.random(a.bias_hidden, b.bias_hidden)
+ result.bias_output = Matrix.random(a.bias_output, b.bias_output)
+
+ return result
+
+
+static func mutate(nn: NeuralNetwork, callback: Callable) -> NeuralNetwork:
+ var result = NeuralNetwork.new(nn.input_nodes, nn.hidden_nodes, nn.output_nodes)
+ result.weights_input_hidden = Matrix.map(nn.weights_input_hidden, callback)
+ result.weights_hidden_output = Matrix.map(nn.weights_hidden_output, callback)
+ result.bias_hidden = Matrix.map(nn.bias_hidden, callback)
+ result.bias_output = Matrix.map(nn.bias_output, callback)
+ return result
+
+
+static func copy(nn : NeuralNetwork) -> NeuralNetwork:
+ var result = NeuralNetwork.new(nn.input_nodes, nn.hidden_nodes, nn.output_nodes)
+ result.weights_input_hidden = Matrix.copy(nn.weights_input_hidden)
+ result.weights_hidden_output = Matrix.copy(nn.weights_hidden_output)
+ result.bias_hidden = Matrix.copy(nn.bias_hidden)
+ result.bias_output = Matrix.copy(nn.bias_output)
+ return result