extends Node class_name MLP @export var weights: Array[Array] = [] @export var biases: Array[Array] = [] @export var learning_rate: float = 0.01 func _init(sizes: Array = [3,2]) -> void: randomize() weights = [] biases = [] for i in range(sizes.size() - 1): weights.append([]) biases.append([]) for _j in range(sizes[i]): weights[i].append([]) for _k in range(sizes[i + 1]): weights[i][_j].append(randf() * 2 - 1) biases[i].append(randf() * 2 - 1) # Feedforward: compute the output of the MLP for a given input. func feedforward(input: Array) -> Array: var a = input for i in range(weights.size()): var dp = dot_product(a, weights[i]) for j in range(a.size()): a[j] = sigmoid(dp[j] + + biases[i][j]) return a # Backpropagation: update the weights and biases based on the input and target output. func backpropagate(input: Array, target: Array) -> void: var nabla_b: Array = [] var nabla_w: Array = [] # Feedforward var activation:Array[float] = input var activations: Array[Array] = [input] # List to store all the activations, layer by layer var zs: Array[Array] = [] # List to store all the z vectors, layer by layer var z: int = 0 var sp: float = 0.0 var delta: Array = [] for i in range(weights.size()): var dp = dot_product(activation, weights[i]) var zs_i:Array[float] = [] var activations_i: Array[float] = [] for j in range(dp.size()): z = dp[j] + biases[i][j] zs_i.append(z) activations_i.append(sigmoid(z)) activation = activations_i zs.append(zs_i) activations.append(activations_i) # Backward pass sp = sigmoid_prime(zs[zs.size() - 1]) for cd in cost_derivative(activations[activations.size() - 1], target): delta.append(cd * sp) nabla_b.append(delta) nabla_w.append(dot_product(delta, activations[activations.size() - 2].transpose())) for l in range(2, weights.size() + 1): z = zs[zs.size() - l] sp = sigmoid_prime(z) delta = [] for dp in dot_product(weights[weights.size() - l + 1].transpose(), delta): delta.append(dp * sp) nabla_b.append(delta) nabla_w.append(dot_product(delta, activations[activations.size() - l - 1].transpose())) # Update weights and biases for i in range(weights.size()): weights[i] -= learning_rate * nabla_w[nabla_w.size() - i - 1] biases[i] -= learning_rate * nabla_b[nabla_b.size() - i - 1] func sigmoid(x: float) -> float: return 1.0 / (1.0 + exp(-x)) func sigmoid_prime(x: float) -> float: return sigmoid(x) * (1 - sigmoid(x)) func cost_derivative(output_activations: Array, y: Array) -> Array: var output: Array = [] for i in range(0, output_activations.size()): output[i] = output_activations[i] - y[i] return output func dot_product(a: Array, b: Array) -> Array: var result: Array = [] for i in range(a.size()): var sum: float = 0.0 for j in range(a[i].size()): sum += a[i][j] * b[j] result.append(sum) return result # Called when the node enters the scene tree for the first time. func _ready(): pass # Replace with function body. # Called every frame. 'delta' is the elapsed time since the previous frame. func _process(delta): pass