Test porta logica XOR con network di neuroni
This commit is contained in:
parent
33941367e4
commit
98f557370f
64
src/main.zig
64
src/main.zig
|
|
@ -1,69 +1,39 @@
|
|||
const std = @import("std");
|
||||
const Neuron = @import("neuron.zig").Neuron;
|
||||
const Tensor = @import("tensor.zig").Tensor;
|
||||
const SimpleNetwork = @import("network.zig").SimpleNetwork;
|
||||
|
||||
pub fn main() !void {
|
||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||
const allocator = gpa.allocator();
|
||||
defer _ = gpa.deinit();
|
||||
var net = SimpleNetwork.init(1234);
|
||||
|
||||
// 1. Inizializziamo il neurone (2 input perché la porta AND ha 2 ingressi)
|
||||
var my_neuron = try Neuron.init(allocator, 2);
|
||||
defer my_neuron.deinit();
|
||||
|
||||
// 2. Prepariamo il Dataset (AND Gate)
|
||||
// Creiamo un tensore riutilizzabile per gli input
|
||||
var input_tensor = try Tensor.init(allocator, &[_]usize{2});
|
||||
defer input_tensor.deinit();
|
||||
|
||||
// I 4 casi possibili (Training Data)
|
||||
const training_data = [_][2]f32{
|
||||
const inputs = [_][2]f32{
|
||||
.{ 0.0, 0.0 },
|
||||
.{ 0.0, 1.0 },
|
||||
.{ 1.0, 0.0 },
|
||||
.{ 1.0, 1.0 },
|
||||
};
|
||||
|
||||
// Le 4 risposte corrette (Labels)
|
||||
const targets = [_]f32{ 0.0, 0.0, 0.0, 1.0 };
|
||||
const targets = [_]f32{ 0.0, 1.0, 1.0, 0.0 };
|
||||
|
||||
const lr: f32 = 0.1; // Learning rate un po' più aggressivo
|
||||
const lr: f32 = 0.5;
|
||||
|
||||
std.debug.print("--- INIZIO TRAINING (AND GATE) ---\n", .{});
|
||||
std.debug.print("--- TRAINING XOR (2 LAYERS) ---\n", .{});
|
||||
|
||||
// 3. Ciclo di Training
|
||||
var epoch: usize = 0;
|
||||
while (epoch < 2000) : (epoch += 1) { // 2000 Epoche
|
||||
var total_error: f32 = 0.0;
|
||||
while (epoch < 10000) : (epoch += 1) {
|
||||
var total_loss: f32 = 0.0;
|
||||
|
||||
// Per ogni epoca, passiamo attraverso TUTTI gli esempi
|
||||
for (training_data, 0..) |data, index| {
|
||||
// Carichiamo i dati nel tensore
|
||||
input_tensor.data[0] = data[0];
|
||||
input_tensor.data[1] = data[1];
|
||||
|
||||
// Train su questo specifico esempio
|
||||
const loss = my_neuron.train(input_tensor, targets[index], lr);
|
||||
total_error += loss;
|
||||
for (inputs, 0..) |inp, i| {
|
||||
total_loss += net.train(inp, targets[i], lr);
|
||||
}
|
||||
|
||||
// Stampiamo ogni 200 epoche
|
||||
if (epoch % 200 == 0) {
|
||||
std.debug.print("Epoca {d}: Errore Medio = {d:.6}\n", .{ epoch, total_error / 4.0 });
|
||||
if (epoch % 1000 == 0) {
|
||||
std.debug.print("Epoca {d}: Loss = {d:.6}\n", .{ epoch, total_loss / 4.0 });
|
||||
}
|
||||
}
|
||||
|
||||
std.debug.print("\n--- TEST FINALE ---\n", .{});
|
||||
|
||||
// Verifichiamo cosa ha imparato
|
||||
for (training_data) |data| {
|
||||
input_tensor.data[0] = data[0];
|
||||
input_tensor.data[1] = data[1];
|
||||
const prediction = my_neuron.forward(input_tensor);
|
||||
|
||||
// Arrotondiamo visivamente per capire se è 0 o 1
|
||||
const result_bool: u8 = if (prediction > 0.5) 1 else 0;
|
||||
|
||||
std.debug.print("Input: {d:.1}, {d:.1} -> Predizione: {d:.4} (Interpretato: {d})\n", .{ data[0], data[1], prediction, result_bool });
|
||||
std.debug.print("\n--- TEST XOR ---\n", .{});
|
||||
for (inputs) |inp| {
|
||||
const out = net.forward(inp);
|
||||
const bit: u8 = if (out > 0.5) 1 else 0;
|
||||
std.debug.print("In: {d:.0},{d:.0} -> Out: {d:.4} -> {d}\n", .{ inp[0], inp[1], out, bit });
|
||||
}
|
||||
}
|
||||
|
|
|
|||
83
src/network.zig
Normal file
83
src/network.zig
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
const std = @import("std");
|
||||
|
||||
pub const SimpleNetwork = struct {
|
||||
w_hidden: [2][2]f32,
|
||||
b_hidden: [2]f32,
|
||||
|
||||
w_output: [2]f32,
|
||||
b_output: f32,
|
||||
|
||||
hidden_outputs: [2]f32,
|
||||
|
||||
pub fn init(seed: u64) SimpleNetwork {
|
||||
var prng = std.Random.DefaultPrng.init(seed);
|
||||
const rand = prng.random();
|
||||
|
||||
var net = SimpleNetwork{
|
||||
.w_hidden = undefined,
|
||||
.b_hidden = undefined,
|
||||
.w_output = undefined,
|
||||
.b_output = 0.0,
|
||||
.hidden_outputs = undefined,
|
||||
};
|
||||
|
||||
for (&net.w_hidden) |*row| {
|
||||
row[0] = rand.float(f32) * 2.0 - 1.0;
|
||||
row[1] = rand.float(f32) * 2.0 - 1.0;
|
||||
}
|
||||
for (&net.b_hidden) |*b| b.* = 0.0;
|
||||
|
||||
for (&net.w_output) |*w| w.* = rand.float(f32) * 2.0 - 1.0;
|
||||
|
||||
return net;
|
||||
}
|
||||
|
||||
fn sigmoid(x: f32) f32 {
|
||||
return 1.0 / (1.0 + std.math.exp(-x));
|
||||
}
|
||||
|
||||
fn sigmoid_derivative(x: f32) f32 {
|
||||
return x * (1.0 - x);
|
||||
}
|
||||
|
||||
pub fn forward(self: *SimpleNetwork, input: [2]f32) f32 {
|
||||
for (0..2) |i| {
|
||||
const sum = (input[0] * self.w_hidden[i][0]) +
|
||||
(input[1] * self.w_hidden[i][1]) +
|
||||
self.b_hidden[i];
|
||||
self.hidden_outputs[i] = sigmoid(sum);
|
||||
}
|
||||
|
||||
const sum_out = (self.hidden_outputs[0] * self.w_output[0]) +
|
||||
(self.hidden_outputs[1] * self.w_output[1]) +
|
||||
self.b_output;
|
||||
|
||||
return sigmoid(sum_out);
|
||||
}
|
||||
|
||||
pub fn train(self: *SimpleNetwork, input: [2]f32, target: f32, lr: f32) f32 {
|
||||
const prediction = self.forward(input);
|
||||
|
||||
const output_error = target - prediction;
|
||||
const output_delta = output_error * sigmoid_derivative(prediction);
|
||||
|
||||
var hidden_deltas: [2]f32 = undefined;
|
||||
for (0..2) |i| {
|
||||
const error_contrib = output_delta * self.w_output[i];
|
||||
hidden_deltas[i] = error_contrib * sigmoid_derivative(self.hidden_outputs[i]);
|
||||
}
|
||||
|
||||
for (0..2) |i| {
|
||||
self.w_output[i] += lr * output_delta * self.hidden_outputs[i];
|
||||
}
|
||||
self.b_output += lr * output_delta;
|
||||
|
||||
for (0..2) |i| {
|
||||
self.w_hidden[i][0] += lr * hidden_deltas[i] * input[0];
|
||||
self.w_hidden[i][1] += lr * hidden_deltas[i] * input[1];
|
||||
self.b_hidden[i] += lr * hidden_deltas[i];
|
||||
}
|
||||
|
||||
return output_error * output_error;
|
||||
}
|
||||
};
|
||||
Loading…
Reference in a new issue