small racing game im working on
Diffstat (limited to 'lib/neural_network.gd')
| -rw-r--r-- | lib/neural_network.gd | 127 |
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 |