234 lines
9.9 KiB
Markdown
234 lines
9.9 KiB
Markdown
# 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. |