aggiornato readme e documentazione con ai

This commit is contained in:
2026-03-27 17:07:20 +01:00
parent 7aac8ceac2
commit 4b652b4e4d
7 changed files with 430 additions and 137 deletions
+234
View File
@@ -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.