diff --git a/src/main.zig b/src/main.zig index 66bee12..f8c1b7f 100644 --- a/src/main.zig +++ b/src/main.zig @@ -7,40 +7,63 @@ pub fn main() !void { const allocator = gpa.allocator(); defer _ = gpa.deinit(); - // 1. Inizializza Neurone - var my_neuron = try Neuron.init(allocator, 3); + // 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. Dati di Input - var inputs = try Tensor.init(allocator, &[_]usize{3}); - defer inputs.deinit(); - inputs.data[0] = 1.0; - inputs.data[1] = 0.5; - inputs.data[2] = -2.0; + // 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(); - // 3. Il Target: Vogliamo che il neurone impari a rispondere "4.0" - const target: f32 = 4.0; + // I 4 casi possibili (Training Data) + const training_data = [_][2]f32{ + .{ 0.0, 0.0 }, + .{ 0.0, 1.0 }, + .{ 1.0, 0.0 }, + .{ 1.0, 1.0 }, + }; - // Learning Rate: La velocità di apprendimento (né troppo alta, né troppo bassa) - const lr: f32 = 0.01; + // Le 4 risposte corrette (Labels) + const targets = [_]f32{ 0.0, 0.0, 0.0, 1.0 }; - std.debug.print("--- INIZIO TRAINING ---\n", .{}); - std.debug.print("Target desiderato: {d:.2}\n", .{target}); + const lr: f32 = 0.1; // Learning rate un po' più aggressivo - // 4. Ciclo di Training (Epochs) - var i: usize = 0; - while (i < 100) : (i += 1) { - const loss = my_neuron.train(inputs, target, lr); + std.debug.print("--- INIZIO TRAINING (AND GATE) ---\n", .{}); - // Stampiamo lo stato ogni 10 passaggi - if (i % 10 == 0) { - const current_pred = my_neuron.forward(inputs); - std.debug.print("Epoca {d}: Loss = {d:.6} | Previsione attuale = {d:.4}\n", .{ i, loss, current_pred }); + // 3. Ciclo di Training + var epoch: usize = 0; + while (epoch < 2000) : (epoch += 1) { // 2000 Epoche + var total_error: 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; + } + + // Stampiamo ogni 200 epoche + if (epoch % 200 == 0) { + std.debug.print("Epoca {d}: Errore Medio = {d:.6}\n", .{ epoch, total_error / 4.0 }); } } - std.debug.print("\n--- TRAINING COMPLETATO ---\n", .{}); - std.debug.print("Pesi finali: {any}\n", .{my_neuron.weights.data}); - std.debug.print("Bias finale: {d:.4}\n", .{my_neuron.bias}); - std.debug.print("Risultato finale: {d:.4}\n", .{my_neuron.forward(inputs)}); + 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 }); + } }