From 43732d156fc8eb921ae324cdd59266cb77f55da6 Mon Sep 17 00:00:00 2001 From: mirimatcode Date: Fri, 20 Mar 2026 18:59:08 +0100 Subject: [PATCH] reinizio a metterci mano per completarlo 2 --- AGENTS.md | 153 +++++++++++++++++++++++++++++++++++++++ classificatore_singolo.c | 2 +- codice_ricordo | Bin 0 -> 21616 bytes codice_ricordo.c | 33 +++++++-- percettroni.h | 105 +++++++++++++++++++++------ 5 files changed, 262 insertions(+), 31 deletions(-) create mode 100644 AGENTS.md create mode 100755 codice_ricordo diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..231fcdf --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,153 @@ +# AGENTS.md - Agentic Coding Guidelines + +## Project Overview +C-based neural network implementation from scratch for image classification on CIFAR-10 and MNIST datasets. + +## Build Commands + +### Compilation +```bash +# Main classifier (MNIST) - compiles the single-classifier training program +gcc -o classificatore_singolo_mnist classificatore_singolo.c -lm + +# XOR test/demo - simple test to verify neural network works +gcc -o codice_ricordo codice_ricordo.c -lm + +# Visualizer (requires Allegro library) +gcc -o visualizzatore visualizzatore.c -lalleg -lm + +# Older multi-layer implementation +gcc -o rete_neurale rete_neurale.c -lm +``` + +### Running Tests +```bash +# Run XOR validation test (quick sanity check for neural network) +./codice_ricordo + +# Run full training loop with existing compiled binary +./classificatore_singolo_mnist + +# Automated training with pauses (prevents overheating) +./addestratore.sh +``` + +### Running a Single Test +```bash +# Compile and run XOR test (single test case) +gcc -o codice_ricordo codice_ricordo.c -lm && ./codice_ricordo + +# Compile and run classifier with specific category +gcc -o classificatore_singolo_mnist classificatore_singolo.c -lm && ./classificatore_singolo_mnist +``` + +## Code Style Guidelines + +### Language +- Use **Italian** for comments and variable names (maintain consistency) +- Use **English** for struct/type definitions and technical terms + +### Formatting +- Indent with 4 spaces (no tabs) +- Opening braces on same line: `if (cond) {` +- Always use braces for control structures, even single lines +- Line length: ~80-100 characters preferred +- One space after keywords (if, for, while, return) +- No space between function name and opening parenthesis +- Blank line between functions + +### Naming Conventions +- Functions: `snake_case` (e.g., `inizializza_rete_neurale`) +- Structs: `PascalCase` (e.g., `ReteNeurale`) +- Constants: `UPPER_SNAKE_CASE` (e.g., `EPOCHE`) +- Global variables: file scope preferred +- Types: use `typedef` for structs + +### Types +- Use `byte` (typedef for `unsigned char`) for values 0-255 +- Use `double` for all floating-point calculations +- Prefer explicit types over implicit conversions +- Use `size_t` for sizes and indices where appropriate + +### Imports +- Standard library headers first (``, ``, ``, ``) +- Project headers after (use `"quotes"`) +- No include guards needed for header-only library +- Group related includes together + +### Memory Management +- Always check `malloc` return values +- Free memory in reverse allocation order +- Use `perror()` for error messages before exiting +- Avoid memory leaks in loops + +### Error Handling +- Check file operations with `if (!file)` pattern +- Return `NULL` on failure for functions returning pointers +- Exit with `EXIT_FAILURE` on unrecoverable errors +- Validate function inputs at entry points + +### Key Constants (from percettroni.h) +- `LRE = 0.1` (learning rate - was 1.414, now 0.1) +- `soglia_sigmoide = 0.5` (sigmoid threshold for binary classification) +- `file_pesi = "rete_pesi.bin"` (model weights file) + +### Dataset Configuration +In `percettroni.h`, uncomment the desired dataset section: +- XOR: `#include "xor_manager.h"` (for testing - currently active) +- MNIST: Uncomment mnist includes and set file paths +- CIFAR-10: Uncomment cifar-10 includes and file paths + +## Testing +No formal test framework. Use these approaches: +1. `codice_ricordo.c` - XOR validation (4 inputs, quick convergence test) +2. Visual inspection of weight outputs via `stampa_pesi_rete()` +3. Monitor epoch error rates in training output +4. Check for memory leaks with valgrind: `valgrind --leak-check=full ./codice_ricordo` + +## Project Structure +- `percettroni.h` - Core neural network (header-only library with implementations) +- `classificatore_singolo.c` - Single-category classifier main program +- `codice_ricordo.c` - XOR test/demo +- `xor_manager.h` - XOR dataset for testing +- `mnist/mnist_manager.h` - MNIST dataset loader +- `cifar-10/cifar10_manager.h` - CIFAR-10 dataset loader +- `rete_pesi.bin` - Saved model weights +- `addestratore.sh` - Training automation script + +## Neural Network Architecture +- Activation: sigmoid function +- Training: backpropagation with gradient descent +- Configurable: layer count and perceptrons per layer +- Learning rate: controlled via `LRE` constant (default 0.1) +- Binary threshold: 0.5 for classification decisions + +## Development Workflow + +### Adding a New Dataset +1. Create manager header (e.g., `custom_manager.h`) +2. Define `N_INPUTS` constant for input size +3. Implement `get_dataset()` returning `Dataset*` +4. Update `percettroni.h` includes and file paths + +### Debugging Tips +- Call `stampa_pesi_rete(rete)` to inspect weights +- Reference `codice_ricordo.c` for minimal working example +- Verify dataset loading before training loop +- Check epoch timing to monitor training progress + +### File I/O +- Weights saved as binary in `rete_pesi.bin` +- Use `salvaReteNeurale()` and `caricaReteNeurale()` for persistence +- Dataset files must match expected binary format + +## Performance Notes +- Training is CPU-intensive (minutes per epoch expected) +- Use `addestratore.sh` with sleep intervals to prevent overheating +- Memory allocated dynamically based on network architecture +- No GPU acceleration - pure CPU implementation + +## Language Reference +Technical terms (English): activation function, gradient descent, sigmoid, neural network, backpropagation + +Italian terms: pesi (weights), bias, livello (layer), percettrone (perceptron), addestramento (training), epoca (epoch), errore (error), classificazione (label/classification), previsione (prediction), istanza (instance) diff --git a/classificatore_singolo.c b/classificatore_singolo.c index 77c0d68..03147a5 100644 --- a/classificatore_singolo.c +++ b/classificatore_singolo.c @@ -63,7 +63,7 @@ void main() double **gradienti = elabora_gradienti(rete_neurale, gradiente_errore, sigmoidi); - aggiorna_pesi(&rete_neurale, sigmoidi, gradienti, set.istanze[indice_set]); + aggiorna_pesi(rete_neurale, sigmoidi, gradienti, set.istanze[indice_set]); } diff --git a/codice_ricordo b/codice_ricordo new file mode 100755 index 0000000000000000000000000000000000000000..44b9f84678ecdc86faa8c3734da068838ff81b59 GIT binary patch literal 21616 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 literal 0 HcmV?d00001 diff --git a/codice_ricordo.c b/codice_ricordo.c index 247720c..176b0d3 100644 --- a/codice_ricordo.c +++ b/codice_ricordo.c @@ -1,17 +1,34 @@ #include "percettroni.h" -#define EPOCHE 10 +#define EPOCHE 100000 void main() { - ReteNeurale rete = inizializza_rete_neurale(3, 8, 2); - stampa_pesi_rete(rete); + ReteNeurale rete = inizializza_rete_neurale(2, 2, 2); + //stampa_pesi_rete(rete); - Dataset *xor; - xor = crea_dataset_xor(); + Dataset xor = *crea_dataset_xor(); + + //for(int i = 0; i < xor->size; i++) { + // printf("%d\n", xor->istanze[i].classificazione); + //} + + //double **sigmoidi; + + /* for(int epoca = 0; epoca < EPOCHE; epoca++) { + for(int indice_istanza = 0; indice_istanza < xor->size; indice_istanza++) { + sigmoidi = elabora_sigmoidi(rete, xor->istanze[indice_istanza]); + } + } */ for(int epoca = 0; epoca < EPOCHE; epoca++) { - for(int indice_istanza = 0; indice_istanza < xor->size; indice_istanza++) { - elabora_sigmoidi(rete, xor->istanze[indice_istanza]); - } + printf("\nEPOCA %d\n", epoca); + if (addestra(&rete, xor)) + break; } + + //0:0 -> 0 + /* sigmoidi = elabora_sigmoidi(rete, xor->istanze[0]); + + int previsto = previsione(sigmoidi[rete.size -1][0]); + printf("La previsione per la prima istanza: %d\n", previsto); */ } \ No newline at end of file diff --git a/percettroni.h b/percettroni.h index f98e84c..6094387 100644 --- a/percettroni.h +++ b/percettroni.h @@ -5,27 +5,26 @@ char *file_pesi = "rete_pesi.bin"; -//#include "mnist/mnist_manager.h" +// #include "mnist/mnist_manager.h" /* char *file_immagini = "mnist/t10k-images.idx3-ubyte"; char *file_label = "mnist/t10k-labels.idx1-ubyte"; */ -//char *file_immagini = "mnist/train-images.idx3-ubyte"; -//char *file_label = "mnist/train-labels.idx1-ubyte"; +// char *file_immagini = "mnist/train-images.idx3-ubyte"; +// char *file_label = "mnist/train-labels.idx1-ubyte"; - -//#include "cifar-10/cifar10_manager.h"; -//char *file_immagini = "cifar-10/data_batch_1.bin"; -// char *file_immagini = "cifar-10/data_batch_2.bin"; -// char *file_immagini = "cifar-10/data_batch_3.bin"; -// char *file_immagini = "cifar-10/data_batch_4.bin"; -// char *file_immagini = "cifar-10/data_batch_5.bin"; -//char *file_immagini = "cifar-10/test_batch.bin"; +// #include "cifar-10/cifar10_manager.h"; +// char *file_immagini = "cifar-10/data_batch_1.bin"; +// char *file_immagini = "cifar-10/data_batch_2.bin"; +// char *file_immagini = "cifar-10/data_batch_3.bin"; +// char *file_immagini = "cifar-10/data_batch_4.bin"; +// char *file_immagini = "cifar-10/data_batch_5.bin"; +// char *file_immagini = "cifar-10/test_batch.bin"; #include "xor_manager.h" // Siccome il char è un byte che rappresenta il valore tra 0 e 255. Per evitare confusioni definisco il tipo "byte" come in Java typedef unsigned char byte; -double LRE = 1.414; +double LRE = 0.5; double soglia_sigmoide = 0.5; typedef struct @@ -61,7 +60,7 @@ double **elabora_gradienti(ReteNeurale, double, double **); void discesa_gradiente(ReteNeurale, double **, double **); double calcola_gradiente_disceso(ReteNeurale, int, int, double **); -void aggiorna_pesi(ReteNeurale*, double**, double**, Istanza); +void aggiorna_pesi(ReteNeurale *, double **, double **, Istanza); void correggi_pesi_percettrone_double(Percettrone *, int, double **, double); void correggi_pesi_percettrone_byte(Percettrone *, Istanza, double, int); @@ -146,6 +145,7 @@ ReteNeurale inizializza_rete_neurale(int numero_layers, int numero_percettroni_i ################# PREVISIONI ################################ */ +// Da eseguire a mano 2 double **elabora_gradienti(ReteNeurale rete_neurale, double gradiente_errore, double **sigmoidi) { double **gradienti = (double **)malloc(sizeof(double *) * rete_neurale.size); @@ -164,6 +164,7 @@ double **elabora_gradienti(ReteNeurale rete_neurale, double gradiente_errore, do return gradienti; } +// Invocata da elabora_sigmoidi() double sigmoide(Percettrone p, double *valori) { double sommatoria = 0.0; @@ -174,32 +175,48 @@ double sigmoide(Percettrone p, double *valori) } sommatoria += p.bias; + + //Sigmoide double risultato = 1.0 / (1.0 + exp(-sommatoria)); + //ReLU + //double risultato = sommatoria > 0 ? sommatoria : 0.0f; + // printf(" sommatoria %f -> %f\n",sommatoria, risultato); return risultato; } +// Invocata da elabora_gradienti() double derivata_sigmoide(double valore) { - return (valore * (1.0 - valore)); + //Sigmoide + double derivata = valore * (1.0 - valore); + //ReLU + //double derivata = valore > 0 ? 1.0f : 0.0f; + + return derivata; } int previsione(double valore) { + //Sigmoide if (valore >= soglia_sigmoide) return 1; else return 0; + + //ReLU + //return valore > 0 ? 1 : 0; } +// Invocata da elabora_gradienti() void discesa_gradiente(ReteNeurale rete, double **sigmoidi, double **gradienti) { for (int indice_layer = rete.size - 2; indice_layer >= 0; indice_layer--) { for (int indice_percettrone = 0; indice_percettrone < rete.layers[indice_layer].size; indice_percettrone++) { - double derivata_attivazione = sigmoidi[indice_layer][indice_percettrone] * (1.0 - sigmoidi[indice_layer][indice_percettrone]); + double derivata_attivazione = derivata_sigmoide(sigmoidi[indice_layer][indice_percettrone]); double gradiente_disceso = calcola_gradiente_disceso(rete, indice_layer + 1, indice_percettrone, gradienti); gradienti[indice_layer][indice_percettrone] = gradiente_disceso * derivata_attivazione; @@ -207,17 +224,19 @@ void discesa_gradiente(ReteNeurale rete, double **sigmoidi, double **gradienti) } } +// Invocata da discesa_gradienti() double calcola_gradiente_disceso(ReteNeurale rete, int livello, int indice_peso, double **gradienti) { double sommatoria = 0.0; for (int indice_percettrone = 0; indice_percettrone < rete.layers[livello].size; indice_percettrone++) { - sommatoria += (gradienti[livello][indice_peso] * rete.layers[livello].percettroni[indice_percettrone].pesi[indice_peso]); + sommatoria += (gradienti[livello][indice_percettrone] * rete.layers[livello].percettroni[indice_percettrone].pesi[indice_peso]); } return sommatoria; } +// Da eseguire a mano 1 double **elabora_sigmoidi(ReteNeurale rete, Istanza istanza) { double **sigmoidi = (double **)malloc(sizeof(double *) * rete.size); @@ -300,13 +319,52 @@ void correggi_pesi_percettrone_byte(Percettrone *p, Istanza input, double gradie // Determino il gradiente del peso double gradiente_peso = gradiente_percettrone * (double)input.dati[indice_peso]; - // Modifico il peso Qui si impalla perchè per qualche ragione arriva size elevatissimo + // Modifico il peso p->pesi[indice_peso] += (gradiente_peso * LRE); } p->bias += (gradiente_percettrone * LRE); } +/* + ################### ADDESTRAMENTO ######################### +*/ +//Elabora un'epoca. Restituisce 1 se ha dato il 100% di previsioni corrette +byte addestra(ReteNeurale *rete_neurale, Dataset set) +{ + int corrette = 0; + double errore_totale = 0.0; + + //Per ogni istanza del dataset + for (int indice_set = 0; indice_set < set.size; indice_set++) + { + double **sigmoidi = elabora_sigmoidi(*rete_neurale, set.istanze[indice_set]); + + byte output_corretto = set.istanze[indice_set].classificazione; + int previsto = previsione(sigmoidi[rete_neurale->size - 1][0]); + printf("\tPrevisto: %d, corretto: %d\n", previsto, output_corretto); + if (previsto == output_corretto) { + corrette++; + } + else { + // Derivata funzione di perdita + double gradiente_errore = (output_corretto - sigmoidi[rete_neurale->size - 1][0]); + errore_totale += pow(gradiente_errore, 2); + + double **gradienti = elabora_gradienti(*rete_neurale, gradiente_errore, sigmoidi); + + aggiorna_pesi(rete_neurale, sigmoidi, gradienti, set.istanze[indice_set]); + } + } + + printf("Errore: %f, risposte corrette: %d%\n", errore_totale, (corrette * 100) / set.size); + + if(corrette == set.size) + return 1; + else + return 0; +} + /* ################# IMPORT EXPORT ################################ */ @@ -399,16 +457,19 @@ ReteNeurale *caricaReteNeurale(const char *filename) return rete; } - /* ################ STAMPE ############################ */ -void stampa_pesi_rete(ReteNeurale rete) { - for(int indice_layer = 0; indice_layer < rete.size; indice_layer++) { +void stampa_pesi_rete(ReteNeurale rete) +{ + for (int indice_layer = 0; indice_layer < rete.size; indice_layer++) + { printf("\nLivello %d", indice_layer); - for(int indice_percettrone = 0; indice_percettrone < rete.layers[indice_layer].size; indice_percettrone++) { + for (int indice_percettrone = 0; indice_percettrone < rete.layers[indice_layer].size; indice_percettrone++) + { printf("\n\tPercettrone %d", indice_percettrone); - for(int indice_peso = 0; indice_peso < rete.layers[indice_layer].percettroni[indice_percettrone].size; indice_peso++) { + for (int indice_peso = 0; indice_peso < rete.layers[indice_layer].percettroni[indice_percettrone].size; indice_peso++) + { printf("\n\t\tPeso %d: %f", indice_peso, rete.layers[indice_layer].percettroni[indice_percettrone].pesi[indice_peso]); } }