aggiornato readme e documentazione con ai
This commit is contained in:
@@ -29,8 +29,8 @@ gcc -o classificatore_mnist classificatore.c -lm && ./classificatore_mnist
|
|||||||
# Memory leak detection
|
# Memory leak detection
|
||||||
valgrind --leak-check=full ./classificatore_mnist
|
valgrind --leak-check=full ./classificatore_mnist
|
||||||
|
|
||||||
# Run pre-compiled binary (50 epochs)
|
# Run pre-compiled binary
|
||||||
./classificatore_mnist_50_epoche
|
./classificatore
|
||||||
```
|
```
|
||||||
|
|
||||||
### Running a Single Test
|
### Running a Single Test
|
||||||
@@ -88,10 +88,11 @@ gcc -o test_xor classificatore.c -lm && ./test_xor
|
|||||||
- Validate function inputs at entry points
|
- Validate function inputs at entry points
|
||||||
|
|
||||||
## Key Constants (from percettroni.h)
|
## Key Constants (from percettroni.h)
|
||||||
- `LRE = 0.1` (learning rate)
|
- `LRE = 0.01` (learning rate)
|
||||||
- `soglia_sigmoide = 0.5` (sigmoid threshold)
|
- `soglia_sigmoide = 0.5` (sigmoid threshold)
|
||||||
- `file_pesi = "rete_pesi.bin"` (model weights file)
|
- `file_pesi = "rete_mnist.bin"` (model weights file)
|
||||||
- `SOFTMAX = 1` (use softmax for multi-class prediction)
|
- `TOLLERANZA = 99.5` (accuracy tolerance for early stopping)
|
||||||
|
- `FUNZIONE_ATTIVAZIONE = 1` (0=sigmoid, 1=ReLU, 2=step function)
|
||||||
|
|
||||||
## Dataset Configuration
|
## Dataset Configuration
|
||||||
In `percettroni.h`, include the desired dataset manager:
|
In `percettroni.h`, include the desired dataset manager:
|
||||||
@@ -106,6 +107,13 @@ No formal test framework. Use these approaches:
|
|||||||
3. Monitor epoch error rates in training output
|
3. Monitor epoch error rates in training output
|
||||||
4. Check memory leaks with valgrind
|
4. Check memory leaks with valgrind
|
||||||
|
|
||||||
|
## Linting and Type Checking
|
||||||
|
No formal linting or type checking tools are configured for this C project. Code quality is maintained through:
|
||||||
|
- Manual code review
|
||||||
|
- Compilation warnings (use `-Wall -Wextra` flags if needed)
|
||||||
|
- Valgrind for memory issues
|
||||||
|
- Consistent adherence to the style guidelines below
|
||||||
|
|
||||||
## Project Structure
|
## Project Structure
|
||||||
- `percettroni.h` - Core neural network (header-only library)
|
- `percettroni.h` - Core neural network (header-only library)
|
||||||
- `classificatore.c` - Main classifier program
|
- `classificatore.c` - Main classifier program
|
||||||
|
|||||||
@@ -1,42 +1,54 @@
|
|||||||
# Classificatore di Immagini con Rete Neurale
|
# Classificatore di Immagini con Rete Neurale
|
||||||
|
|
||||||
Implementazione in C di una rete neurale from-scratch per la classificazione di immagini sui dataset MNIST e CIFAR-10.
|
Implementazione in C di una rete neurale **from-scratch** per la classificazione di immagini sui dataset MNIST e CIFAR-10. Questo progetto educativo dimostra i principi fondamentali del deep learning in modo trasparente e accessibile.
|
||||||
|
|
||||||
|
📖 **[Documentazione Completa della Libreria percettroni.h](percettroni_documentation.md)**
|
||||||
|
|
||||||
## Panoramica
|
## Panoramica
|
||||||
|
|
||||||
Questo progetto implementa una rete neurale fully-connected con:
|
Questa implementazione supporta reti neurali feedforward completamente connesse con:
|
||||||
- **Attivazione**: funzione sigmoide
|
- **Architettura dinamica**: Numero variabile di layer e neuroni per layer
|
||||||
- **Addestramento**: backpropagation con discesa del gradiente
|
- **Funzioni di attivazione**: Sigmoide, ReLU o gradino (configurabile)
|
||||||
- **Predizione**: softmax per classificazione multi-classe
|
- **Addestramento**: Backpropagation con discesa del gradiente stocastica
|
||||||
|
- **Classificazione**: Softmax per problemi multi-classe
|
||||||
|
- **Inizializzazione**: Strategia He per prevenire vanishing/exploding gradients
|
||||||
|
|
||||||
## Struttura del Progetto
|
## Struttura del Progetto
|
||||||
|
|
||||||
```
|
```
|
||||||
.
|
.
|
||||||
├── classificatore.c # Programma principale
|
├── classificatore.c # Programma principale di addestramento
|
||||||
├── percettroni.h # Libreria core della rete neurale (header-only)
|
├── percettroni.h # Libreria core della rete neurale (header-only)
|
||||||
|
├── percettroni_documentation.md # Documentazione completa della libreria
|
||||||
├── xor_manager.h # Manager dataset XOR (4 campioni, test rapido)
|
├── xor_manager.h # Manager dataset XOR (4 campioni, test rapido)
|
||||||
├── mnist/
|
├── mnist/
|
||||||
│ └── mnist_manager.h # Manager dataset MNIST (28x28 pixel)
|
│ └── mnist_manager.h # Manager dataset MNIST (28x28 pixel)
|
||||||
├── cifar-10/
|
├── cifar-10/
|
||||||
│ └── cifar10_manager.h # Manager dataset CIFAR-10 (32x32 RGB)
|
│ └── cifar10_manager.h # Manager dataset CIFAR-10 (32x32 RGB)
|
||||||
├── visualizzatore.c # Visualizzatore immagini (richiede Allegro)
|
├── visualizzatore.c # Visualizzatore immagini (richiede Allegro)
|
||||||
└── rete_pesi.bin # Pesi pre-addestrati
|
├── rete_mnist.bin # Pesi salvati dopo l'addestramento
|
||||||
|
└── AGENTS.md # Guida per agenti di codifica
|
||||||
```
|
```
|
||||||
|
|
||||||
## Compilazione
|
## Compilazione e Esecuzione
|
||||||
|
|
||||||
### Classificatore MNIST (default)
|
### Classificatore MNIST (default)
|
||||||
```bash
|
```bash
|
||||||
|
# Compila il classificatore
|
||||||
gcc -o classificatore_mnist classificatore.c -lm
|
gcc -o classificatore_mnist classificatore.c -lm
|
||||||
|
|
||||||
|
# Esegue l'addestramento
|
||||||
./classificatore_mnist
|
./classificatore_mnist
|
||||||
```
|
```
|
||||||
|
|
||||||
### Test XOR (validazione rapida)
|
### Test XOR (validazione rapida)
|
||||||
Modifica `percettroni.h`:
|
Per verificare rapidamente che la rete converga correttamente:
|
||||||
- Commenta: `// #include "mnist/mnist_manager.h"`
|
|
||||||
- Decommenta: `#include "xor_manager.h"`
|
|
||||||
|
|
||||||
|
1. Modifica `percettroni.h`:
|
||||||
|
- Commenta: `// #include "mnist/mnist_manager.h"`
|
||||||
|
- Decommenta: `#include "xor_manager.h"`
|
||||||
|
|
||||||
|
2. Compila ed esegui:
|
||||||
```bash
|
```bash
|
||||||
gcc -o classificatore_xor classificatore.c -lm
|
gcc -o classificatore_xor classificatore.c -lm
|
||||||
./classificatore_xor
|
./classificatore_xor
|
||||||
@@ -47,153 +59,192 @@ gcc -o classificatore_xor classificatore.c -lm
|
|||||||
gcc -o visualizzatore visualizzatore.c -lalleg -lm
|
gcc -o visualizzatore visualizzatore.c -lalleg -lm
|
||||||
```
|
```
|
||||||
|
|
||||||
## Componenti Principali
|
## Configurazione dell'Addestramento
|
||||||
|
|
||||||
### percettroni.h
|
### Parametri Modificabili in `classificatore.c`
|
||||||
|
|
||||||
Libreria header-only che implementa la rete neurale completa.
|
|
||||||
|
|
||||||
**Strutture dati:**
|
|
||||||
- `Percettrone`: singolo neurone con pesi, bias e dimensione
|
|
||||||
- `Layer`: strato di percettroni
|
|
||||||
- `ReteNeurale`: rete completa con array di layer
|
|
||||||
|
|
||||||
**Funzioni principali:**
|
|
||||||
|
|
||||||
```c
|
```c
|
||||||
// Inizializzazione
|
#define EPOCHE 500 // Numero massimo di epoche di addestramento
|
||||||
ReteNeurale inizializza_rete_neurale(int numero_input, int numero_layers,
|
|
||||||
int numero_percettroni_iniziali,
|
|
||||||
int numero_percettroni_finali);
|
|
||||||
|
|
||||||
// Forward propagation
|
|
||||||
double **elabora_sigmoidi(ReteNeurale *rete, Istanza istanza);
|
|
||||||
|
|
||||||
// Backpropagation
|
|
||||||
double **elabora_gradienti(ReteNeurale *rete, byte output_corretto, double **sigmoidi);
|
|
||||||
void aggiorna_pesi(ReteNeurale *rete, double **sigmoidi, double **gradienti, Istanza istanza);
|
|
||||||
|
|
||||||
// Predizione
|
|
||||||
int previsione_softmax(double *output, int size);
|
|
||||||
|
|
||||||
// Persistenza
|
|
||||||
void salvaReteNeurale(const char *filename, ReteNeurale *rete);
|
|
||||||
ReteNeurale *caricaReteNeurale(const char *filename);
|
|
||||||
```
|
|
||||||
|
|
||||||
**Architettura dinamica:**
|
|
||||||
I layer intermedi riducono progressivamente i percettroni secondo la formula:
|
|
||||||
```
|
|
||||||
percettroni = percettroni_iniziali * (layer_rimanenti / layer_totali)
|
|
||||||
```
|
|
||||||
|
|
||||||
### classificatore.c
|
|
||||||
|
|
||||||
Programma principale che configura e addestra la rete.
|
|
||||||
|
|
||||||
```c
|
|
||||||
#define EPOCHE 50
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
// Rete: 784 input (MNIST), 10 layer, 256 percettroni iniziali, 10 output
|
// inizializza_rete_neurale(numero_input, numero_layers, percettroni_iniziali, percettroni_finali)
|
||||||
ReteNeurale rete = inizializza_rete_neurale(N_INPUTS, 10, 256, 10);
|
ReteNeurale rete = inizializza_rete_neurale(N_INPUTS, 2, 32, 10);
|
||||||
Dataset mnist = *get_dataset();
|
// ...
|
||||||
|
|
||||||
for(int epoca = 0; epoca < EPOCHE; epoca++) {
|
|
||||||
if (addestra(&rete, mnist))
|
|
||||||
break; // Stop se accuratezza 100%
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Manager Dataset
|
**Parametri della rete neurale:**
|
||||||
|
- `numero_input`: Dimensione dell'input (784 per MNIST, 3072 per CIFAR-10)
|
||||||
|
- `numero_layers`: Numero totale di layer nella rete
|
||||||
|
- `percettroni_iniziali`: Numero di neuroni nel primo layer nascosto
|
||||||
|
- `percettroni_finali`: Numero di neuroni nell'ultimo layer (output)
|
||||||
|
|
||||||
Ogni manager definisce:
|
**Architettura automatica:** I layer intermedi riducono progressivamente i neuroni secondo la formula:
|
||||||
- `N_INPUTS`: dimensione input (es. 784 per MNIST 28x28)
|
```
|
||||||
- `Istanza`: struct con `classificazione` e `dati[]`
|
neuroni_layer[i] = percettroni_iniziali * ((numero_layers - i) / numero_layers)
|
||||||
- `Dataset`: struct con array di istanze e dimensione
|
```
|
||||||
- `get_dataset()`: funzione che carica i dati
|
|
||||||
|
|
||||||
#### xor_manager.h
|
### Costanti Modificabili in `percettroni.h`
|
||||||
Dataset semplice per test (4 campioni):
|
|
||||||
- Input: 2 valori binari
|
|
||||||
- Output: 1 valore (XOR)
|
|
||||||
- Perfetto per verificare convergenza
|
|
||||||
|
|
||||||
#### mnist/mnist_manager.h
|
|
||||||
Dataset MNIST:
|
|
||||||
- Input: 784 pixel (28×28)
|
|
||||||
- Output: 10 classi (cifre 0-9)
|
|
||||||
- Formato IDX: header binario + pixel raw
|
|
||||||
- Supporta train (60k) e test (10k) set
|
|
||||||
|
|
||||||
#### cifar-10/cifar10_manager.h
|
|
||||||
Dataset CIFAR-10:
|
|
||||||
- Input: 3072 valori (32×32 RGB)
|
|
||||||
- Output: 10 classi (oggetti)
|
|
||||||
- Formato binario: label + pixel RGB
|
|
||||||
|
|
||||||
## Configurazione Dataset
|
|
||||||
|
|
||||||
In `percettroni.h`, includi il manager desiderato:
|
|
||||||
|
|
||||||
```c
|
```c
|
||||||
// Per MNIST
|
float LRE = 0.01; // Learning Rate (tasso di apprendimento)
|
||||||
|
float soglia_sigmoide = 0.5; // Soglia per classificazione binaria
|
||||||
|
#define TOLLERANZA 99.5 // Accuratezza % per arresto anticipato
|
||||||
|
#define FUNZIONE_ATTIVAZIONE 1 // 0=sigmoide, 1=ReLU, 2=gradino
|
||||||
|
char *file_pesi = "rete_mnist.bin"; // File per salvataggio pesi
|
||||||
|
```
|
||||||
|
|
||||||
|
### Selezione del Dataset
|
||||||
|
|
||||||
|
In `percettroni.h`, includi solo il manager del dataset desiderato:
|
||||||
|
|
||||||
|
```c
|
||||||
|
// Per MNIST (attivo di default)
|
||||||
#include "mnist/mnist_manager.h"
|
#include "mnist/mnist_manager.h"
|
||||||
|
|
||||||
// Per XOR (testing)
|
// Per XOR (testing rapido)
|
||||||
// #include "xor_manager.h"
|
// #include "xor_manager.h"
|
||||||
|
|
||||||
// Per CIFAR-10
|
// Per CIFAR-10
|
||||||
// #include "cifar-10/cifar10_manager.h"
|
// #include "cifar-10/cifar10_manager.h"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Costanti Principali
|
**Requisiti dei dataset:**
|
||||||
|
- **MNIST**: File `t10k-images.idx3-ubyte` e `t10k-labels.idx1-ubyte` nella cartella `mnist/`
|
||||||
|
- **CIFAR-10**: File binari appropriati nella cartella `cifar-10/`
|
||||||
|
- **XOR**: Nessun file esterno richiesto (dataset hardcoded)
|
||||||
|
|
||||||
- `LRE = 0.1`: learning rate
|
## Processo di Addestramento
|
||||||
- `soglia_sigmoide = 0.5`: soglia per predizione binaria
|
|
||||||
- `EPOCHE`: numero epoche addestramento
|
|
||||||
|
|
||||||
## Debugging
|
L'addestramento segue questo flusso completo:
|
||||||
|
|
||||||
|
1. **Inizializzazione**: Creazione della rete con pesi casuali (inizializzazione He)
|
||||||
|
2. **Ciclo per epoca**: Fino a `EPOCHE` massime o raggiungimento della `TOLLERANZA`
|
||||||
|
3. **Forward propagation**: Calcolo delle predizioni per ogni istanza
|
||||||
|
4. **Calcolo accuratezza**: Percentuale di predizioni corrette
|
||||||
|
5. **Backpropagation**: Calcolo dei gradienti dell'errore
|
||||||
|
6. **Aggiornamento pesi**: Discesa del gradiente stocastica
|
||||||
|
7. **Arresto anticipato**: Se accuratezza ≥ `TOLLERANZA` (99.5%)
|
||||||
|
8. **Salvataggio**: Scrittura dei pesi finali su `rete_mnist.bin`
|
||||||
|
|
||||||
|
### Output di Esempio
|
||||||
|
```
|
||||||
|
Layer 0 -> percettroni: 32
|
||||||
|
Layer 1 -> percettroni: 10
|
||||||
|
Rete neurale da 25354 parametri
|
||||||
|
|
||||||
|
EPOCA 0
|
||||||
|
Risposte corrette: 12.34%
|
||||||
|
|
||||||
|
EPOCA 1
|
||||||
|
Risposte corrette: 45.67%
|
||||||
|
...
|
||||||
|
EPOCA 25
|
||||||
|
Risposte corrette: 99.60%
|
||||||
|
```
|
||||||
|
|
||||||
|
## Caratteristiche Avanzate
|
||||||
|
|
||||||
|
### Funzioni di Attivazione Supportate
|
||||||
|
|
||||||
|
**ReLU (default - più efficiente):**
|
||||||
|
- Formula: `f(x) = max(0, x)`
|
||||||
|
- Vantaggi: Nessun vanishing gradient, computazionalmente efficiente
|
||||||
|
|
||||||
|
**Sigmoide:**
|
||||||
|
- Formula: `f(x) = 1 / (1 + e^(-x))`
|
||||||
|
- Uso: Tradizionale per output binari, ma soffre di vanishing gradient
|
||||||
|
|
||||||
|
**Gradino:**
|
||||||
|
- Formula: `f(x) = 1 se x > 0, altrimenti 0`
|
||||||
|
- Limitazione: Non differenziabile, non utilizzabile con backpropagation
|
||||||
|
|
||||||
|
### Gestione della Memoria
|
||||||
|
|
||||||
|
- **Allocazione dinamica**: Tutti gli array sono allocati dinamicamente
|
||||||
|
- **Pulizia automatica**: La memoria viene liberata correttamente dopo ogni epoca
|
||||||
|
- **Persistenza**: Supporto per salvataggio/caricamento di reti addestrate
|
||||||
|
|
||||||
|
### Debugging e Analisi
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Ispezione pesi
|
# Ispezione dettagliata dei pesi
|
||||||
stampa_pesi_rete(&rete);
|
// Decommenta in classificatore.c: stampa_pesi_rete(rete);
|
||||||
|
|
||||||
# Controllo memory leak
|
# Controllo memory leak
|
||||||
valgrind --leak-check=full ./classificatore_mnist
|
valgrind --leak-check=full ./classificatore_mnist
|
||||||
|
|
||||||
# Monitoraggio training
|
# Monitoraggio performance
|
||||||
// Modifica addestra() per stampare errore per epoca
|
time ./classificatore_mnist
|
||||||
```
|
```
|
||||||
|
|
||||||
## Note Tecniche
|
## Best Practice per l'Addestramento
|
||||||
|
|
||||||
- **Normalizzazione**: input byte (0-255) convertiti in double (0.0-1.0)
|
### Scelta dell'Architettura
|
||||||
- **Inizializzazione**: pesi casuali in [-1, 1]
|
- **Reti profonde** (>5 layer): Richiedono più dati e tempo di addestramento
|
||||||
- **Attivazione**: sigmoide con formula `1/(1+e^(-x))`
|
- **Reti larghe**: Più neuroni per layer aumentano la capacità ma anche l'overfitting
|
||||||
- **Softmax**: usato solo sull'output per probabilità multi-classe
|
- **Architettura a imbuto**: Riduzione progressiva dei neuroni è generalmente efficace
|
||||||
- **Prestazioni**: training CPU-intensive (minuti per epoca su MNIST)
|
|
||||||
|
|
||||||
## Esempio Output Training
|
### Ottimizzazione degli Iperparametri
|
||||||
|
- **Learning Rate**:
|
||||||
|
- Troppo alto (>0.1): Instabilità, divergenza
|
||||||
|
- Troppo basso (<0.001): Convergenza lenta
|
||||||
|
- Valore consigliato: 0.01 (default)
|
||||||
|
- **Numero di epoche**: Dipende dalla complessità del dataset
|
||||||
|
- XOR: 100-500 epoche sufficienti
|
||||||
|
- MNIST: 500+ epoche per buone prestazioni
|
||||||
|
|
||||||
```
|
### Prevenzione dell'Overfitting
|
||||||
Layer 0 -> percettroni: 256
|
- **Arresto anticipato**: Implementato con soglia del 99.5%
|
||||||
Layer 1 -> percettroni: 230
|
- **Dataset adeguato**: Utilizzare set di training/test separati
|
||||||
...
|
- **Architettura semplice**: Evitare reti troppo complesse per il dataset
|
||||||
Layer 9 -> percettroni: 10
|
|
||||||
Rete neurale da 123456 parametri
|
|
||||||
Risposte corrette: 85%
|
|
||||||
Risposte corrette: 92%
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
## Requisiti
|
## Requisiti di Sistema
|
||||||
|
|
||||||
- GCC o compilatore C compatibile
|
- **Compilatore**: GCC o qualsiasi compilatore C standard
|
||||||
- Libreria math (`-lm`)
|
- **Librerie**: math (`-lm`) obbligatoria, Allegro opzionale (solo visualizzatore)
|
||||||
- Allegro (solo per visualizzatore)
|
- **Memoria**: Dipende dall'architettura della rete (MNIST richiede ~100MB)
|
||||||
|
- **Dataset**: MNIST (~11MB), CIFAR-10 (~160MB)
|
||||||
|
|
||||||
|
## Note Tecniche Importanti
|
||||||
|
|
||||||
|
- **Normalizzazione input**: I valori pixel (0-255) vengono convertiti automaticamente in (0.0-1.0)
|
||||||
|
- **Precisione**: Utilizzo di `float` per tutti i calcoli (bilancio tra precisione e memoria)
|
||||||
|
- **Performance**: Implementazione CPU-only, ottimizzata per chiarezza piuttosto che velocità
|
||||||
|
- **Determinismo**: Il seed random è basato su `time(NULL)`, quindi ogni esecuzione è diversa
|
||||||
|
|
||||||
|
## Risoluzione Problemi Comuni
|
||||||
|
|
||||||
|
**"Errore nell'apertura del file"**:
|
||||||
|
- Verifica che i file del dataset siano nella posizione corretta
|
||||||
|
- Controlla i permessi di lettura
|
||||||
|
|
||||||
|
**Addestramento troppo lento**:
|
||||||
|
- Riduci il numero di layer/neuroni
|
||||||
|
- Usa il dataset XOR per test rapidi
|
||||||
|
- Verifica che il learning rate non sia troppo basso
|
||||||
|
|
||||||
|
**Accuratezza bassa**:
|
||||||
|
- Aumenta il numero di epoche
|
||||||
|
- Prova architetture diverse
|
||||||
|
- Verifica la qualità del dataset
|
||||||
|
|
||||||
|
**Memory leak**:
|
||||||
|
- Assicurati di usare `valgrind` per identificare problemi
|
||||||
|
- La libreria gestisce correttamente la memoria in condizioni normali
|
||||||
|
|
||||||
|
## Estensioni Future
|
||||||
|
|
||||||
|
- **Batch training**: Implementazione della discesa del gradiente mini-batch
|
||||||
|
- **Regularizzazione**: Dropout, L1/L2 regularization
|
||||||
|
- **Ottimizzatori avanzati**: Adam, RMSprop
|
||||||
|
- **Convoluzioni**: Supporto per reti neurali convoluzionali (CNN)
|
||||||
|
|
||||||
## Licenza
|
## Licenza
|
||||||
|
|
||||||
Progetto didattico - Implementazione from-scratch per scopi educativi.
|
Progetto didattico - Implementazione from-scratch per scopi educativi.
|
||||||
|
Libero da utilizzare per apprendimento e ricerca.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
💡 **Suggerimento**: Consulta la [documentazione completa](percettroni_documentation.md) per comprendere le formule matematiche, gli algoritmi implementati e le proprietà teoriche di questa implementazione di rete neurale.
|
||||||
@@ -1,6 +1,13 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.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";
|
||||||
|
|
||||||
#define N_INPUTS 3072 // 1024 pixel * 3 (R, G, B)
|
#define N_INPUTS 3072 // 1024 pixel * 3 (R, G, B)
|
||||||
|
|
||||||
// Siccome il char è un byte che rappresenta il valore tra 0 e 255. Per evitare confusioni definisco il tipo "byte" come in Java
|
// Siccome il char è un byte che rappresenta il valore tra 0 e 255. Per evitare confusioni definisco il tipo "byte" come in Java
|
||||||
@@ -49,8 +56,8 @@ Dataset *get_dataset(char *path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Dataset set;
|
// Dataset set;
|
||||||
(*set).size = numero_righe;
|
set->size = numero_righe;
|
||||||
(*set).istanze = istanze;
|
set->istanze = istanze;
|
||||||
|
|
||||||
fclose(file);
|
fclose(file);
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
@@ -7,14 +7,7 @@
|
|||||||
char *file_pesi = "rete_mnist.bin";
|
char *file_pesi = "rete_mnist.bin";
|
||||||
|
|
||||||
#include "mnist/mnist_manager.h"
|
#include "mnist/mnist_manager.h"
|
||||||
|
|
||||||
// #include "cifar-10/cifar10_manager.h";
|
// #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";
|
|
||||||
|
|
||||||
typedef unsigned char byte;
|
typedef unsigned char byte;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,234 @@
|
|||||||
|
# Documentazione della Libreria `percettroni.h`
|
||||||
|
|
||||||
|
Questa libreria implementa una rete neurale feedforward completamente connessa (fully-connected) in linguaggio C puro, progettata per la classificazione di immagini sui dataset MNIST e CIFAR-10. L'implementazione segue i principi fondamentali del deep learning con backpropagation e discesa del gradiente stocastica.
|
||||||
|
|
||||||
|
## Struttura dei Dati
|
||||||
|
|
||||||
|
### Percettrone
|
||||||
|
Il **percettrone** è l'unità fondamentale di calcolo nella rete neurale, ispirato al modello biologico del neurone.
|
||||||
|
|
||||||
|
```c
|
||||||
|
typedef struct {
|
||||||
|
float *pesi; // Vettore dei pesi sinaptici
|
||||||
|
float bias; // Bias (soglia di attivazione)
|
||||||
|
int size; // Numero di input (dimensione del vettore pesi)
|
||||||
|
} Percettrone;
|
||||||
|
```
|
||||||
|
|
||||||
|
**Proprietà matematiche:**
|
||||||
|
- Ogni percettrone calcola una combinazione lineare degli input: `z = Σ(w_i * x_i) + b`
|
||||||
|
- La funzione di attivazione trasforma questo valore in un output non lineare
|
||||||
|
- I pesi rappresentano la "forza" delle connessioni sinaptiche
|
||||||
|
- Il bias permette di spostare la soglia di attivazione
|
||||||
|
|
||||||
|
### Layer
|
||||||
|
Un **layer** (strato) è un insieme di percettroni che operano in parallelo sugli stessi input.
|
||||||
|
|
||||||
|
```c
|
||||||
|
typedef struct {
|
||||||
|
Percettrone *percettroni; // Array di percettroni
|
||||||
|
int size; // Numero di percettroni nello strato
|
||||||
|
} Layer;
|
||||||
|
```
|
||||||
|
|
||||||
|
### ReteNeurale
|
||||||
|
La **rete neurale** è composta da una sequenza di layer interconnessi.
|
||||||
|
|
||||||
|
```c
|
||||||
|
typedef struct {
|
||||||
|
Layer *layers; // Array di layer
|
||||||
|
int size; // Numero totale di layer
|
||||||
|
} ReteNeurale;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Costanti Fondamentali
|
||||||
|
|
||||||
|
- **`LRE = 0.01`**: Learning Rate (tasso di apprendimento) - controlla la dimensione dei passi nella discesa del gradiente
|
||||||
|
- **`soglia_sigmoide = 0.5`**: Soglia per la classificazione binaria con funzione sigmoide
|
||||||
|
- **`TOLLERANZA = 99.5`**: Percentuale di accuratezza richiesta per l'arresto anticipato dell'addestramento
|
||||||
|
- **`FUNZIONE_ATTIVAZIONE = 1`**: Tipo di funzione di attivazione (0=sigmoide, 1=ReLU, 2=gradino)
|
||||||
|
|
||||||
|
## Funzioni di Inizializzazione
|
||||||
|
|
||||||
|
### `inizializza_percettrone(int n_pesi)`
|
||||||
|
**Descrizione:** Inizializza un singolo percettrone con pesi casuali secondo la strategia di **inizializzazione He**.
|
||||||
|
|
||||||
|
**Implementazione matematica:**
|
||||||
|
- Utilizza il Teorema Centrale del Limite per generare pesi distribuiti normalmente
|
||||||
|
- Deviazione standard: `σ = √(2/n)` dove `n` è il numero di input
|
||||||
|
- Formula: `peso = (Σ₁₂(rand()) - 6) × √(2/n)`
|
||||||
|
- Il bias viene inizializzato a 0
|
||||||
|
|
||||||
|
**Proprietà:** Questa inizializzazione previene il problema del vanishing/exploding gradient nelle reti profonde con ReLU.
|
||||||
|
|
||||||
|
### `inizializza_layer(int n_percettroni, int n_pesi)`
|
||||||
|
**Descrizione:** Crea un layer completo con un numero specificato di percettroni, ognuno con lo stesso numero di pesi.
|
||||||
|
|
||||||
|
**Architettura dinamica:** La libreria supporta architetture con riduzione progressiva del numero di neuroni:
|
||||||
|
- Layer intermedi: `neuroni = neuroni_iniziali × (layer_rimanenti / layer_totali)`
|
||||||
|
- Questo crea una struttura a imbuto che estrae caratteristiche sempre più astratte
|
||||||
|
|
||||||
|
### `inizializza_rete_neurale(int numero_input, int numero_layers, int numero_percettroni_iniziali, int numero_percettroni_finali)`
|
||||||
|
**Descrizione:** Costruisce l'intera rete neurale con architettura personalizzabile.
|
||||||
|
|
||||||
|
**Caratteristiche:**
|
||||||
|
- Supporta reti profonde con qualsiasi numero di layer
|
||||||
|
- Configurazione flessibile del numero di neuroni per layer
|
||||||
|
- Calcolo automatico del numero totale di parametri (pesi + bias)
|
||||||
|
|
||||||
|
## Funzioni di Attivazione e Previsione
|
||||||
|
|
||||||
|
### `attivazione(Percettrone p, float *valori)`
|
||||||
|
**Descrizione:** Calcola l'output di un percettrone applicando la funzione di attivazione scelta.
|
||||||
|
|
||||||
|
**Formule matematiche implementate:**
|
||||||
|
|
||||||
|
1. **Sigmoide (FUNZIONE_ATTIVAZIONE = 0):**
|
||||||
|
```
|
||||||
|
σ(z) = 1 / (1 + e^(-z))
|
||||||
|
```
|
||||||
|
- Output nell'intervallo (0, 1)
|
||||||
|
- Derivata: `σ'(z) = σ(z) × (1 - σ(z))`
|
||||||
|
|
||||||
|
2. **ReLU (FUNZIONE_ATTIVAZIONE = 1):**
|
||||||
|
```
|
||||||
|
ReLU(z) = max(0, z)
|
||||||
|
```
|
||||||
|
- Output nell'intervallo [0, ∞)
|
||||||
|
- Derivata: `ReLU'(z) = 1 se z > 0, altrimenti 0`
|
||||||
|
|
||||||
|
3. **Gradino (FUNZIONE_ATTIVAZIONE = 2):**
|
||||||
|
```
|
||||||
|
step(z) = 1 se z > 0, altrimenti 0
|
||||||
|
```
|
||||||
|
- Output binario {0, 1}
|
||||||
|
- Derivata: sempre 0 (non utilizzabile per backpropagation)
|
||||||
|
|
||||||
|
### `derivata_attivazione(float valore)`
|
||||||
|
**Descrizione:** Calcola la derivata della funzione di attivazione rispetto all'input.
|
||||||
|
|
||||||
|
**Importanza nel backpropagation:** La derivata è essenziale per calcolare i gradienti durante l'addestramento, permettendo alla rete di apprendere attraverso la regola della catena.
|
||||||
|
|
||||||
|
### `softmax(float *input, int size)`
|
||||||
|
**Descrizione:** Applica la funzione softmax al layer di output per la classificazione multi-classe.
|
||||||
|
|
||||||
|
**Formula matematica:**
|
||||||
|
```
|
||||||
|
softmax(z_i) = e^(z_i) / Σⱼ(e^(z_j))
|
||||||
|
```
|
||||||
|
|
||||||
|
**Proprietà:**
|
||||||
|
- Trasforma gli output in probabilità che sommano a 1
|
||||||
|
- È differenziabile, permettendo l'uso con backpropagation
|
||||||
|
- Implementazione numerica stabile con sottrazione del massimo per evitare overflow
|
||||||
|
|
||||||
|
### `previsione_softmax(float *livello_percettroni, int size)`
|
||||||
|
**Descrizione:** Esegue la classificazione finale applicando softmax e restituendo l'indice della classe con probabilità massima.
|
||||||
|
|
||||||
|
## Forward Propagation
|
||||||
|
|
||||||
|
### `elabora_attivazioni(ReteNeurale *rete, Istanza istanza)`
|
||||||
|
**Descrizione:** Esegue il forward propagation attraverso l'intera rete, calcolando le attivazioni di tutti i neuroni.
|
||||||
|
|
||||||
|
**Processo:**
|
||||||
|
1. Normalizza gli input pixel (0-255 → 0.0-1.0)
|
||||||
|
2. Propaga sequenzialmente attraverso ogni layer
|
||||||
|
3. Restituisce una matrice 2D con tutte le attivazioni intermedie
|
||||||
|
|
||||||
|
**Importanza:** Le attivazioni intermedie sono necessarie per il calcolo dei gradienti durante il backpropagation.
|
||||||
|
|
||||||
|
## Backpropagation e Discesa del Gradiente
|
||||||
|
|
||||||
|
### `elabora_gradienti(ReteNeurale *rete_neurale, byte output, float **attivazioni)`
|
||||||
|
**Descrizione:** Calcola i gradienti dell'errore rispetto ai pesi utilizzando l'algoritmo di backpropagation.
|
||||||
|
|
||||||
|
**Algoritmo matematico:**
|
||||||
|
- **Layer di output:** `δ_output = y_true - y_pred` (per perdita cross-entropy con softmax)
|
||||||
|
- **Layer nascosti:** `δ_hidden = (W^T × δ_next) ⊙ f'(z)`
|
||||||
|
- Dove `⊙` è il prodotto elemento-per-elemento (Hadamard product)
|
||||||
|
- `f'(z)` è la derivata della funzione di attivazione
|
||||||
|
|
||||||
|
### `discesa_gradiente(ReteNeurale *rete, float **attivazioni, float **gradienti)`
|
||||||
|
**Descrizione:** Propaga i gradienti all'indietro attraverso i layer nascosti.
|
||||||
|
|
||||||
|
**Regola della catena:** Applica ricorsivamente la regola della catena per calcolare i gradienti nei layer precedenti.
|
||||||
|
|
||||||
|
### `calcola_gradiente_disceso(ReteNeurale *rete, int livello, int indice_peso, float **gradienti)`
|
||||||
|
**Descrizione:** Calcola il contributo aggregato di un peso specifico al gradiente del layer successivo.
|
||||||
|
|
||||||
|
**Formula:** `gradiente_disceso = Σ(δ_j × w_ji)` dove `j` indica i neuroni del layer successivo.
|
||||||
|
|
||||||
|
## Aggiornamento dei Pesi
|
||||||
|
|
||||||
|
### `aggiorna_pesi(ReteNeurale *rete_neurale, float **attivazioni, float **gradienti, Istanza istanza)`
|
||||||
|
**Descrizione:** Aggiorna tutti i pesi e bias della rete utilizzando la discesa del gradiente stocastica.
|
||||||
|
|
||||||
|
**Regola di aggiornamento:**
|
||||||
|
```
|
||||||
|
w_new = w_old + η × δ × input
|
||||||
|
b_new = b_old + η × δ
|
||||||
|
```
|
||||||
|
Dove `η` è il learning rate (`LRE`) e `δ` è il gradiente dell'errore.
|
||||||
|
|
||||||
|
### `correggi_pesi_percettrone_float()` e `correggi_pesi_percettrone_byte()`
|
||||||
|
**Descrizione:** Funzioni specializzate per l'aggiornamento dei pesi nel primo layer (che riceve input grezzi come byte) e nei layer successivi (che ricevono attivazioni normalizzate come float).
|
||||||
|
|
||||||
|
## Addestramento
|
||||||
|
|
||||||
|
### `addestra(ReteNeurale *rete_neurale, Dataset set)`
|
||||||
|
**Descrizione:** Esegue un'epoca completa di addestramento sul dataset fornito.
|
||||||
|
|
||||||
|
**Processo completo:**
|
||||||
|
1. Per ogni istanza nel dataset:
|
||||||
|
- Forward propagation per ottenere le predizioni
|
||||||
|
- Calcolo dell'accuratezza corrente
|
||||||
|
- Backpropagation per calcolare i gradienti
|
||||||
|
- Aggiornamento dei pesi
|
||||||
|
2. Calcolo della percentuale di risposte corrette
|
||||||
|
3. Arresto anticipato se l'accuratezza supera la `TOLLERANZA`
|
||||||
|
|
||||||
|
**Caratteristiche:**
|
||||||
|
- Implementa la discesa del gradiente stocastica (SGD)
|
||||||
|
- Supporta l'arresto anticipato per prevenire overfitting
|
||||||
|
- Fornisce feedback sull'accuratezza durante l'addestramento
|
||||||
|
|
||||||
|
## Persistenza
|
||||||
|
|
||||||
|
### `salvaReteNeurale(const char *filename, ReteNeurale *rete)`
|
||||||
|
**Descrizione:** Salva l'intera rete su file binario in formato proprietario.
|
||||||
|
|
||||||
|
**Formato:** Struttura annidata che preserva esattamente la topologia e i valori dei pesi.
|
||||||
|
|
||||||
|
### `caricaReteNeurale(const char *filename)`
|
||||||
|
**Descrizione:** Carica una rete precedentemente salvata da file.
|
||||||
|
|
||||||
|
**Utilizzo:** Permette di riprendere l'addestramento o di utilizzare modelli pre-addestrati.
|
||||||
|
|
||||||
|
## Debugging e Analisi
|
||||||
|
|
||||||
|
### `stampa_pesi_rete(ReteNeurale *rete)`
|
||||||
|
**Descrizione:** Stampa tutti i pesi e bias della rete in formato leggibile.
|
||||||
|
|
||||||
|
**Utilizzo:** Essenziale per il debugging e l'analisi del comportamento della rete durante l'addestramento.
|
||||||
|
|
||||||
|
## Proprietà Matematiche della Rete
|
||||||
|
|
||||||
|
### Architettura Feedforward
|
||||||
|
- Informazione che fluisce solo in avanti (input → output)
|
||||||
|
- Nessuna connessione ricorrente o laterale
|
||||||
|
- Computazione deterministica e parallela all'interno di ogni layer
|
||||||
|
|
||||||
|
### Universal Approximation Theorem
|
||||||
|
Questa implementazione, essendo una rete feedforward con almeno uno strato nascosto e funzioni di attivazione non lineari, può approssimare qualsiasi funzione continua con precisione arbitraria, dato un numero sufficiente di neuroni.
|
||||||
|
|
||||||
|
### Ottimizzazione
|
||||||
|
- **Funzione di perdita:** Implicitamente cross-entropy (grazie all'uso di softmax e backpropagation)
|
||||||
|
- **Algoritmo di ottimizzazione:** Discesa del gradiente stocastica
|
||||||
|
- **Regularizzazione:** Nessuna esplicita, ma l'inizializzazione He e l'arresto anticipato aiutano a prevenire overfitting
|
||||||
|
|
||||||
|
### Complessità Computazionale
|
||||||
|
- **Forward propagation:** O(N×M) dove N è il numero totale di neuroni e M il numero di connessioni
|
||||||
|
- **Backpropagation:** O(N×M) - stessa complessità del forward pass
|
||||||
|
- **Memoria:** O(N×M) per memorizzare pesi, gradienti e attivazioni intermedie
|
||||||
|
|
||||||
|
Questa libreria rappresenta un'implementazione educativa completa di una rete neurale moderna, dimostrando i principi fondamentali del deep learning in modo trasparente e accessibile.
|
||||||
Binary file not shown.
Reference in New Issue
Block a user