# IA subsimbolica: reti neurali

<details>

<summary>Artefatti NotebookLM</summary>

* [sintesi video](https://notebooklm.google.com/notebook/e3e3403b-f0e7-443f-8cf5-3ac03c4c7237?artifactId=7173f82e-1304-4e48-9047-dca2a09d73da)
* [sintesi audio](https://notebooklm.google.com/notebook/e3e3403b-f0e7-443f-8cf5-3ac03c4c7237?artifactId=4e9dda0f-9414-44d6-8707-5b9137434c45)
* [sintesi audio](https://notebooklm.google.com/notebook/e3e3403b-f0e7-443f-8cf5-3ac03c4c7237?artifactId=ac526adf-c5e3-4666-9b07-ae252aaa8f2d): processi di apprendimento artificiali e umani
* [quiz](https://notebooklm.google.com/notebook/e3e3403b-f0e7-443f-8cf5-3ac03c4c7237?artifactId=4f081c31-92f0-4a52-b676-080b6f5b076e)

</details>

1. [Modelli computazionali](#modelli-computazionali)
2. [Reti neurali artificiali](#reti-neurali-artificiali)
3. [Caratteristiche delle reti neurali](#caratteristiche-delle-reti-neurali)
4. [Modelli di neuroni](#modelli-di-neuroni)
5. [Reti neurali come grafi diretti](#reti-neurali-come-grafi-diretti)
6. [Architetture di reti](#architetture-di-reti)
7. [Rappresentazione della conoscenza pregressa](#rappresentazione-della-conoscenza-pregressa)
8. [Processi di apprendimento](#processi-di-apprendimento)

\
Questa parte è tratta da:

* Simon Haykin. **Neural Networks and Learning Machines**, 3rd Edition, 2009 \[Capitolo 1]
* Stephen Wolfram. **What is chatGPT doing and why does it work?** [Stephen Wolfram Writings](https://writings.stephenwolfram.com/2023/02/what-is-chatgpt-doing-and-why-does-it-work), 2023.

## Modelli computazionali

Supponiamo di voler sapere (come fece Galileo alla fine del 1500) quanto tempo impiegherà una palla di cannone lanciata da ogni piano della Torre di Pisa a toccare il suolo. Si potrebbe misurare il tempo in ogni caso e compilare una tabella dei risultati. Oppure si potrebbe fare ciò che è l'essenza della scienza: creare un modello che fornisca una sorta di procedura per calcolare la risposta, anziché limitarsi a misurare e ricordare ogni caso.

Immaginiamo di avere dati (in qualche modo idealizzati) su quanto tempo impiega una palla di cannone a cadere da diverse altezze. Mettiamo sull'asse delle x l'altezza e sull'asse delle y il tempo:

<figure><img src="https://3096303588-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLaIrbNpGYnY3gphqyxHI%2Fuploads%2FSVndWGSmxAJ39KibqIq4%2Fcaduta%20grave%201.png?alt=media&#x26;token=400fdf75-4c7b-4223-b432-df4f5b9fff55" alt="" width="375"><figcaption></figcaption></figure>

Potremmo fare un'ipotesi matematica, ad esempio usare una funzione lineare (una retta, detta di regressione) del tipo $$y = a x + b$$, dove $$y$$ è la variabile tempo, $$x$$ la variabile altezza, e $$a, b$$ sono dei parametri costanti ma incogniti, come modello per interpolare i dati:

<figure><img src="https://3096303588-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLaIrbNpGYnY3gphqyxHI%2Fuploads%2FUAet1u3EytDkwENrn6VQ%2Fcaduta%20grave%202.png?alt=media&#x26;token=71bbbbb2-9edb-4815-90b4-01c306c24653" alt="" width="375"><figcaption></figcaption></figure>

Potremmo scegliere diverse rette. Ma quella visualizzata sopra è quella che in media si avvicina di più ai dati che ci vengono forniti, cioè quella che minimizza l'**errore** misurato come somma dei quadrati dei residui (differenze) tra i valori reali osservati e quelli previsti dal modello.

Potremmo anche provare qualcosa di matematicamente più complicato - ad esempio la funzione polinomiale $$y = a + b \cdot \sqrt{x}$$ - e verificare che in questo caso abbiamo un modello migliore (con meno errore):

<figure><img src="https://3096303588-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLaIrbNpGYnY3gphqyxHI%2Fuploads%2FTIRccd4GAWrdTcLzADOu%2Fcaduta%20grave%203.png?alt=media&#x26;token=f17e6567-cd8a-4bbf-8f99-961b19b46b50" alt="" width="375"><figcaption></figcaption></figure>

In effetti, abbiamo usato come curva di interpolazione la formula che esprime il tempo $$t$$ della caduta di un grave da altezza $$h$$ assumendo di essere sulla terra con forza di gravità $$g$$ è:

$$
t = \sqrt{\frac{2h}{g}}
$$

Qualsiasi modello si utilizzi ha una particolare struttura di fondo: il tipo di funzione, come quella lineare, polinomiale, esponenziale e altre ancora. Ogni famiglia di modelli ha dei parametri liberi, una sorta di manopole da impostare per adattarsi ai dati risolvendo un problema di minimizzazione dell'errore. Ad esempio, in $$y = a + b x$$, i parametri liberi sono $$a, b$$.&#x20;

Ricordiamo sempre che ogni modello è una astrazione, e dunque una semplificazione, della realtà, ovvero:

> Una mappa non è il territorio. [Alfred Korzybski ](https://it.wikipedia.org/wiki/Alfred_Korzybski)

<figure><img src="https://3096303588-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLaIrbNpGYnY3gphqyxHI%2Fuploads%2F3bFxeTDf0wrbQCpZ21ik%2FMagrittePipe.webp?alt=media&#x26;token=63b5442d-6f64-473c-a732-fa85a52b70c4" alt=""><figcaption><p><em>Il tradimento delle immagini (Questo non è una pipa),</em> René Magritte (1929) </p></figcaption></figure>

<figure><img src="https://3096303588-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLaIrbNpGYnY3gphqyxHI%2Fuploads%2FTGGmS6rhEx14dd6hVkXA%2Fextrapolating.png?alt=media&#x26;token=548d1ef0-b822-41af-ba88-e4b8e0fc7f1e" alt=""><figcaption><p>Usare i modelli con cautela. Fonte: <a href="https://xkcd.com/605/">xkcd</a></p></figcaption></figure>

L'esempio che abbiamo fatto sopra riguarda la creazione di un modello per dati numerici che provengono essenzialmente dalla fisica e per i quali abbiamo una relazione esplicita, una formula matematica, tra dati di ingresso e risposta del modello.&#x20;

Per realizzare modelli per compiti di tipo umano, come ad esempio modelli che riconoscono immagini o che riconoscono e generano il linguaggio naturale umano, dobbiamo cambiare strategia. Per una cosa del genere non abbiamo (almeno per ora) nulla di simile a formule matematiche esplicite e spiegabili. Quindi come potrebbe essere un tale modello?

Consideriamo il problema del riconoscimento di immagini che contengono cifre numeriche, come quelle mostrate in figura sotto.

<figure><img src="https://3096303588-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLaIrbNpGYnY3gphqyxHI%2Fuploads%2F9QUK82I1D0sc2wMG07FB%2Fdigits1.png?alt=media&#x26;token=3f56ed4b-7bcd-4eac-b704-c3a00144887c" alt=""><figcaption></figcaption></figure>

Se consideriamo il valore del livello di grigio di ogni pixel $$i$$ come una variabile $$x\_i$$, esiste una funzione di tutte queste variabili che, una volta valutata, ci dica quale cifra è disegnata nell'immagine?&#x20;

Come vedremo parlando di reti neurali artificiali, è di fatto possibile costruire una funzione di questo tipo, ma tale funzione non è particolarmente semplice. In ogni caso il risultato finale è che se inseriamo in questa funzione l'insieme dei valori dei pixel di un'immagine, ne uscirà il numero che specifica di quale cifra si tratta.

<figure><img src="https://3096303588-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLaIrbNpGYnY3gphqyxHI%2Fuploads%2FnFvPsvpJ5FRgxeDpxtvq%2Fdigits2.png?alt=media&#x26;token=62eea06c-6a03-4d88-8b77-439d3fddd524" alt=""><figcaption></figcaption></figure>

## Reti neurali artificiali

La ricerca sulle **reti neurali artificiali** (*artificial neural networks*, o ANN), comunemente chiamate reti neurali, è stata motivata fin dall'inizio dalla consapevolezza che il cervello umano calcola in modo completamente diverso dal computer digitale convenzionale. Il cervello è un sistema di elaborazione delle informazioni altamente **complesso**, **non lineare** e **parallelo**. Ha la capacità di organizzare i suoi componenti strutturali, noti come **neuroni**, in modo da eseguire determinati calcoli (ad esempio, il riconoscimento di pattern, la percezione e il controllo motorio) molto velocemente.

Ad esempio, consideriamo il sonar di un pipistrello. I pipistrelli utilizzano una tecnica chiamata ecolocazione per localizzare le loro prede e navigare nell'ambiente circostante. L'ecolocazione è un sistema biologico che coinvolge l'emissione di suoni ad alta frequenza e l'ascolto dell'eco riflesso per ottenere informazioni sull'ambiente circostante. Ecco come funziona:

1. **Emissione di suoni:** i pipistrelli emettono ultrasuoni a frequenze molto elevate, al di fuori della gamma uditiva umana. Questi suoni vengono emessi attraverso la bocca o il naso del pipistrello, a seconda della specie.
2. **Propagazione degli ultrasuoni:** gli ultrasuoni si propagano attraverso l'ambiente circostante. Quando incontrano un oggetto solido, come una preda o un ostacolo, parte dell'energia degli ultrasuoni viene riflessa indietro verso il pipistrello.
3. **Ascolto dell'eco:** il pipistrello ascolta attentamente l'eco degli ultrasuoni riflessi. Sulla base del tempo trascorso tra l'emissione del suono e la ricezione dell'eco, nonché dalla frequenza e dall'intensità dell'eco, il pipistrello può determinare la distanza, la direzione e persino la forma degli oggetti circostanti.
4. **Adattamento in tempo reale:** i pipistrelli sono in grado di adattare la frequenza e il ritmo dell'ecolocazione in tempo reale a seconda delle caratteristiche dell'ambiente e delle prede presenti.
5. **Invarianza**: il processo è essenzialmente indipendente dal movimento del bersaglio e dal movimento del pipistrello stesso.

Le complesse computazioni neurali necessarie per estrarre tutte queste informazioni dall'eco del bersaglio avvengono in un cervello grande come una prugna.&#x20;

Possiamo dare la seguente definizione di rete neurale vista come macchina adattativa:

> Una rete neurale è un processore **distribuito** e **parallelo** composto da semplici unità di elaborazione chiamate **neuroni** che ha una naturale propensione a immagazzinare la conoscenza esperienziale e a renderla disponibile per l'uso. Assomiglia al cervello per due aspetti:
>
> 1. La conoscenza viene acquisita dalla rete dal suo ambiente attraverso un processo di **apprendimento**.
> 2. Il processo di apprendimento memorizzare la conoscenza acquisita usando le forze delle connessioni tra neuroni, note come **pesi sinaptici**.

La modifica dei pesi sinaptici costituisce il metodo tradizionale per la progettazione delle reti neurali. Tuttavia, è anche possibile che una rete neurale modifichi la propria **topologia**, il che è motivato dal fatto che i neuroni del cervello umano possono morire e possono crescere nuove connessioni sinaptiche.

## Caratteristiche delle reti neurali

Le reti neurali posseggono svariate capacità che consentono di trovare buone **soluzioni approssimate a problemi complessi** che sono intrattabili su larga scala.

### Apprendimento

Una rete neurale ha la capacità di apprendere e quindi di generalizzare. La **generalizzazione** si riferisce alla produzione da parte della rete neurale di output ragionevoli per input non incontrati durante l'addestramento.

Un paradigma popolare di **apprendimento**, chiamato apprendimento con insegnante o apprendimento supervisionato, prevede la modifica dei pesi sinaptici di una rete neurale mediante l'applicazione di una serie di esempi di addestramento etichettati. Ogni esempio consiste in un unico segnale di ingresso e in una corrispondente risposta desiderata (target). Alla rete viene presentato un esempio scelto a caso dall'insieme e i pesi sinaptici (parametri liberi) della rete vengono modificati per minimizzare la differenza tra la risposta desiderata e la risposta effettiva della rete prodotta dal segnale di ingresso.&#x20;

L'addestramento della rete viene ripetuto per molti esempi dell'insieme, finché la rete non raggiunge uno stato stazionario in cui non si verificano più cambiamenti significativi nei pesi sinaptici. In questo modo la rete apprende dagli esempi costruendo una mappatura input-output per il problema in questione.

### Parallelismo

In una struttura parallela, diversi componenti del sistema possono calcolare simultaneamente in modo **indipendente**. In particolare, i neuroni delle reti neurali sono tipicamente raggruppati in strati. La computazione di uno strato influenza lo strato successivo ma la computazione dei singoli neuroni all'interno del medesimo strato è indipendente e dunque può essere eseguita in parallelo. La parallelizzazione è realizzata su hardware specializzato, come le unità di elaborazione grafica (GPU) o le unità di elaborazione tensoriale (TPU).

### Non linearità

Si riferisce al fatto che la relazione tra l'ingresso e l'uscita di una rete neurale non è una semplice funzione lineare. Nei sistemi lineari, l'uscita è una combinazione lineare dell'ingresso, ad esempio $$F(x) = ax + b$$. Un esempio di funzione non lineare è la funzione logistica:&#x20;

$$
F(x) = \frac{1}{1 + e^{-ax}}
$$

La non linearità permette alle reti neurali di apprendere e rappresentare schemi e relazioni complesse dei dati.&#x20;

### Adattabilità e stabilità

Quando opera in un ambiente non stazionario (ovvero che cambia nel tempo), una rete neurale può essere progettata per modificare i pesi sinaptici in tempo reale. Come regola generale, questa adattabilità rende più robusta la prestazione della rete quando opera in un ambiente non stazionario.

Va sottolineato, tuttavia, che l'adattabilità non sempre porta alla robustezza; anzi, può fare l'esatto contrario. Ad esempio, un sistema troppo adattivo può cambiare rapidamente e quindi tendere a rispondere ai minimi cambiamenti dell'ambiente, causando un drastico degrado delle prestazioni del sistema. Un sistema d'allarme non si deve attivare se una molecola d'aria si sposta, ma solo se c'è un cambiamento significativo.

La rete deve quindi raggiungere un buon **compromesso tra adattabilità e** **stabilità** che gli permette di ignorare i cambiamenti irrilevanti ma rispondere a cambiamenti significativi nell'ambiente; un problema noto come dilemma della stabilità-adattabilità.

### Tolleranza ai guasti

Una rete neurale ha il potenziale di essere intrinsecamente tollerante ai guasti, o nel senso che **le sue prestazioni degradano in modo graduale** in condizioni operative avverse. Ad esempio, se un neurone o i suoi collegamenti sono danneggiati, il recupero di un dato memorizzato è invalidato. Tuttavia, a causa della natura distribuita delle informazioni memorizzate nella rete, il danno deve essere esteso a molti neuroni prima che la risposta complessiva della rete sia seriamente compromessa.&#x20;

## Modelli di neuroni

Il **neurone** è l'unità di elaborazione dell'informazione fondamentale per il funzionamento di una rete neurale.&#x20;

<figure><img src="https://3096303588-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLaIrbNpGYnY3gphqyxHI%2Fuploads%2FVycykHIymvhqz9MLJIBD%2Fneuron1.png?alt=media&#x26;token=85bc0f8a-0191-49ae-a043-59f4d145f8a2" alt=""><figcaption><p>Schema a blocchi di un neurone</p></figcaption></figure>

Qui identifichiamo gli elementi fondamentali del modello neurale:

1. Un insieme di **segnali di ingresso** $$x\_i$$ che raccolgono gli ingressi provienienti dai neuroni pre-sinaptici;
2. Un insieme di **sinapsi**, o collegamenti, ognuno dei quali è caratterizzato da un **peso**, detto anche forza. In particolare, il segnale di ingresso $$x\_i$$ associato alla sinapsi $$i$$ collegata al neurone $$k$$ viene moltiplicato per il peso sinaptico $$w\_{ki}$$. È importante notare il modo in cui sono scritti i pedici del peso sinaptico $$w\_{ki}$$. Il primo pedice di $$w\_{ki}$$ si riferisce al neurone in questione, mentre il secondo pedice si riferisce al neurone pre-sinaptico che fornisce l'ingresso. In sostanza, l'insieme di tutti i pesi sinaptici si può rappresentare con una **matrice** $$W = (w\_{i,j})$$:&#x20;

   1. La **riga** di indice $$k$$ della matrice indica i collegamenti in **ingresso** del neurone $$k$$ con **neuroni pre-sinaptici**&#x20;
   2. La **colonna** di indice $$k$$ della matrice indica i collegamenti in **uscita** del neurone $$k$$ con **neuroni post-sinaptici**&#x20;

   Il peso sinaptico di un neurone artificiale può includere valori negativi e positivi.
3. Un **combinatore** $$\Sigma$$ per sommare i segnali di ingresso, ponderati per i rispettivi pesi sinaptici del neurone; in questo caso abbiamo un combinatore *lineare* perché i pesi vengono moltiplicati per gli ingressi e sommati.
4. Un **bias** applicato dall'esterno, indicato con $$b\_k$$. Il bias influenza la soglia di attivazione per il neurone. Esso determina quanto deve essere forte l'input combinato affinché il neurone si attivi. In particolare permette al neurone di attivarsi anche quando tutti gli input sono zero.
5. Una **funzione di attivazione** $$\varphi(\cdot)$$ per limitare l'ampiezza dell'uscita di un neurone in un determinato intervallo.
6. Una **risposta** $$y\_k$$, ovvero l'uscita del neurone.

In formule, possiamo descrivere questo modello per un neurone $$k$$ come segue:

$$
\begin{array}{lcl} u\_k & = & \sum\_{i=1}^{m} w\_{ki} x\_i \ v\_k & = & u\_k + b\_k \ y\_k & = & \varphi(u\_k + b\_k) \end{array}
$$

dove:

* $$u\_k$$ è l'uscita del **combinatore lineare**;
* $$v\_k$$ è il **potenziale di attivazione** (detto anche campo locale indotto);
* $$\varphi$$ è la **funzione di attivazione**;
* $$y\_k$$ è il **segnale di uscita** del neurone.

Possiamo riformulare il modello includendo il bias tra gli input, ovvero aggiungendo un nuovo ingresso $$x\_0 = 1$$ con peso $$w\_{k0} = b\_k$$, come mostrato nella figura seguente.

<figure><img src="https://3096303588-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLaIrbNpGYnY3gphqyxHI%2Fuploads%2Fmgk3PtVnJW3ayFPljKtb%2Fneuron2.png?alt=media&#x26;token=71953dac-8963-4d77-8aea-b79f54ba429b" alt=""><figcaption><p>Schema di un neurone che include il bias tra gli input</p></figcaption></figure>

La nuova formulazione matematica è dunque:

$$
\begin{array}{lcl} v\_k & = & \sum\_{i=0}^{m} w\_{ki}  x\_i\ y\_k & = & \varphi(v\_k) \end{array}
$$

dove $$x\_0 = 1$$ e $$w\_{k0} = b\_k$$.

<details>

<summary>Reti neurali biologiche</summary>

Le componenti descritte per le reti neurali artificiali hanno dei corrispettivi nelle reti neurali biologiche:

1. Nelle reti neurali biologiche il concetto analogo a quello di **pesi** trova nella forza o efficacia delle connessioni sinaptiche tra i neuroni.  In particulare la sinapsi può potenziare o inibire il segnale. Si noti però che i pesi biologici non possono essere negativi.
2. Anche nelle reti biologiche il **soma** del neurone aggrega gli input provenienti dai neuroni pre-sinaptici che sono stati già modulati dalla forza delle sinapsi e se la loro somma supera un certo valore soglia emette un output che attraverso l'assone raggiunge i neuroni post-sinaptici.
3. I neuroni biologici hanno un "potenziale di riposo", ovvero una carica elettrica di base quando non sono attivi. Questo potenziale di riposo può essere considerato analogo al **bias**, in quanto determina la soglia di attivazione del neurone. Nelle reti biologiche, il bias può variare nel tempo. Ad esempio, alcuni neurotrasmettitori, come il glutammato, tendono ad aumentare l'eccitabilità dei neuroni, mentre altri tendono a diminuirla.

</details>

### Tipi di funzioni di attivazione

In teoria, ogni neurone può avere una funzione di attivazione diversa. In pratica, la funzione di attivazione è la medesima per la rete, oppure varia per alcuni strati della rete, ad esempio quello finale, ed è costante per gli altri strati.

Una semplice funzione di attivazione è la **funzione soglia** (*threshold function*), definita come segue:

$$
\varphi(v) = \left{\begin{array}{lrl} 1 & \text{se } v \geq 0 \ 0 & \text{se } v < 0 \ \end{array}\right.
$$

Dunque con questa funzione l'uscita è binaria (0 o 1) a seconda che il potenziale di attivazione sia negativo o non-negativo, ovvero vale la proprietà "tutto o niente". Un neurone di questo tipo viene chiamato **modello McCulloch-Pitts**, in riconoscimento del lavoro pionieristico svolto da McCulloch e Pitts (1943).

La **funzione sigmoide**, il cui grafico è a forma di S, è di gran lunga la forma più comune di funzione di attivazione utilizzata nella costruzione di reti neurali. È definita come una funzione strettamente crescente che presenta un equilibrio aggraziato tra comportamento lineare e non lineare. Un esempio di funzione sigmoide è la **funzione logistica**, definita da:

$$
\varphi(v) = \frac{1}{1 + e^{-av}}
$$

dove $$a$$ è il parametro di pendenza della funzione logistica. Variando il parametro $$a$$, si ottengono funzioni logistiche con pendenze diverse. Al limite, quando il parametro della pendenza si avvicina all'infinito, la funzione logistica diventa semplicemente una funzione soglia. Mentre una funzione soglia assume il valore di 0 o 1, una funzione sigmoide assume un intervallo continuo di valori da 0 a 1.

<figure><img src="https://3096303588-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLaIrbNpGYnY3gphqyxHI%2Fuploads%2FACEAWzNbGIE1qMGguUFk%2Fsigmoid.png?alt=media&#x26;token=f1b60c1f-d016-49b9-849f-704657d23751" alt="" width="375"><figcaption><p>Funzione soglia (a) e sigmoide (b)</p></figcaption></figure>

Le funzioni di attivazione definite finora vanno da 0 a 1. A volte è auspicabile che la funzione di attivazione vada da -1 a 1. In particolare, la funzione soglia è ora definita come:

$$
\varphi(v) = \left{\begin{array}{ll} 1 & \text{se } v \geq 0 \ 0 & \text{se } v = 0 \ -1 & \text{se } v < 0 \ \end{array}\right.
$$

che viene comunemente chiamata **funzione signum**.

Per la forma corrispondente di una funzione sigmoide, possiamo usare la funzione **tangente iperbolica**, ovvero il rapporto tra seno e coseno iperbolici, definita da:

$$
\varphi(v) = \mathrm{tanh}(v) = \frac{\mathrm{sinh}(v)}{\mathrm{cosh}(v)} = \frac{e^v - e^{-v}}{e^v + e^{-v}} = \frac{1 - e^{-2v}}{1 + e^{-2v}}
$$

<figure><img src="https://3096303588-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLaIrbNpGYnY3gphqyxHI%2Fuploads%2FgNdYqUqWjeTOGasvVtN6%2Ftanh.png?alt=media&#x26;token=0a059344-c9f0-4b2c-af2b-dc1980ec479f" alt="" width="375"><figcaption><p>Grafico della tengente iperbolica</p></figcaption></figure>

La funzione di attivazione **ReLU** è una delle più semplici e popolari nel campo delle reti neurali. ReLU sta per **Rectified Linear Unit**, ed è definita come:

$$
\text{ReLU}(x) = \max(0, x)
$$

Quindi:

* Se $$x > 0$$, allora $$\text{ReLU}(x) = x$$
* Se $$x \leq 0$$, allora $$\text{ReLU}(x) = 0$$

<figure><img src="https://3096303588-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLaIrbNpGYnY3gphqyxHI%2Fuploads%2FroK0Vq3FQg1fSQbC80J9%2FReLU.png?alt=media&#x26;token=8246a76e-5904-498d-b04b-209ca65756d2" alt="" width="375"><figcaption></figcaption></figure>

ReLU è molto semplice da calcolare e a differenza delle altre funzioni viste non schiaccia l’input in intervalli molto piccoli (come \[0, 1] o \[-1, 1]). In compenso, se un neurone riceve sempre input negativi, la ReLU restituisce sempre 0 e **quel neurone smette di imparare**.

Il modello neurale descritto finora è **deterministico**, nel senso che il suo comportamento input-output è definito con precisione per tutti gli input. Per alcune applicazioni delle reti neurali, è auspicabile basare l'analisi su un modello neurale **stocastico**. In questo modello, alla funzione di attivazione del modello McCulloch-Pitts viene data un'interpretazione probabilistica. In particolare, a un neurone è consentito di risiedere solo in uno dei due stati, diciamo 0 o 1. La decisione di un neurone di attivarsi (cioè di cambiare il suo stato da spento ad acceso) è probabilistica: ad esempio, se c'è una probabilità del 90% a favore di 1 e 10% a favore di 0, allora il neurone avrà una probabilità di 9 su 10 di accendersi, e di 1 su 10 di rimanere spento.&#x20;

Sia $$x$$ lo stato del neurone e $$P(v)$$ la probabilità di accensione, dove $$v$$ è il potenziale di attivazione del neurone. Possiamo quindi scrivere:

$$
x = \left{\begin{array}{ll} 1 & \text{con probabilità } P(v)\ 0 & \text{con probabilità } 1 - P(v) \ \end{array}\right.
$$

Una scelta standard per $$P(v)$$ è la funzione di forma logistica con parametro $$a = 1/T$$:

$$
P(v) = \frac{1}{1 + e^{-v/T}}
$$

dove $$T$$ è una pseudo-temperatura utilizzata per controllare l'incertezza del neurone di accendersi. Si noti che quando $$T$$ tende a 0, il parametro di pendenza $$a$$ tende a infinito e il neurone stocastico si riduce a una forma "fredda" priva di incertezza, cioè al modello deterministico di McCulloch-Pitts. Viceversa quando la temperatura aumenta, cresce anche l'incertezza, ovvero la componente stocastica, del modello.

## Reti neurali come grafi diretti

I diagrammi a blocchi del modello di un neurone artificiale possono essere semplificati utilizzando l'idea dei grafi di flusso del segnale, senza sacrificare nessuno dei dettagli funzionali del modello.&#x20;

Un **grafo di flusso del segnale** è una rete di collegamenti diretti che sono interconnessi in determinati punti chiamati nodi. Si veda la figura seguente.

<figure><img src="https://3096303588-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLaIrbNpGYnY3gphqyxHI%2Fuploads%2FjmajtV4Wdw9DjEja7Nxk%2Fsignal-flow1.png?alt=media&#x26;token=2fec144d-26da-47bc-8f55-1f8434384712" alt="" width="332"><figcaption><p>Grafi di flusso del segnale</p></figcaption></figure>

Il flusso dei segnali nelle varie parti del grafo è dettato da tre regole fondamentali:

* **Regola 1**. Un segnale scorre lungo un collegamento solo nella direzione definita dalla freccia sul collegamento (vedere le parti (a) e (b) della figura precedente).&#x20;

  Si possono distinguere due diversi tipi di collegamenti:

  * **Collegamenti sinaptici**, il cui comportamento è regolato da una relazione lineare ingresso-uscita. In particolare, il segnale del nodo $$x\_i$$ viene moltiplicato per il peso sinaptico $$w\_{ki}$$ per produrre il segnale del nodo $$y\_k$$ (vedi parte (a) della figura precedente).
  * **Collegamenti di attivazione**, il cui comportamento è governato da una relazione tipicamente non lineare ingresso-uscita, corrispondente ad funzione di attivazione $$\varphi(\cdot)$$ (vedi parte (b) della figura precedente).
* **Regola 2**. Il segnale di un nodo è uguale alla somma algebrica di tutti i segnali che entrano nel nodo in questione attraverso i collegamenti in entrata (si veda la parte (c) della figura precedente).
* **Regola 3**. Il segnale di un nodo viene trasmesso a ciascun collegamento in uscita che ha origine da quel nodo (si veda la parte (d) della figura precedente).

Ad esempio, utilizzando queste regole, possiamo costruire il grafo del flusso del segnale del modello di un neurone che abbiamo descritto in precedenza. Questo è chiaramente più semplice in apparenza, ma contiene tutti i dettagli funzionali del modello originale.

<figure><img src="https://3096303588-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLaIrbNpGYnY3gphqyxHI%2Fuploads%2FziVOrUvUYenUQ2XZBgmT%2Fsignal-flow2.png?alt=media&#x26;token=7864ff38-ff8c-41b7-92a8-52eab7f20654" alt="" width="375"><figcaption><p>Grafo di flusso di un neurone</p></figcaption></figure>

Un grafo diretto, così definito, è **completo** nel senso che descrive non solo il flusso di segnali da neurone a neurone (flusso inter-neuronale), ma anche il flusso di segnali all'interno di ciascun neurone (flusso intra-neuronale). Quando, tuttavia, l'attenzione si limita al flusso di segnali da neurone a neurone, possiamo utilizzare una forma astratta di questo grafo, omettendo i dettagli del flusso di segnali all'interno dei singoli neuroni. Un tale grafo diretto è chiamato **grafo dell'architettura** della rete neurale.

<figure><img src="https://3096303588-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLaIrbNpGYnY3gphqyxHI%2Fuploads%2FgzYEIUZGaQfU1Yj5fX8U%2Fsignal-flow3.png?alt=media&#x26;token=1d19c251-3b50-436e-9a40-1f7a8055f380" alt="" width="375"><figcaption><p>Grafo dell'architettura di un neurone</p></figcaption></figure>

### Retroazione (feedback)

Si parla di **retroazione** (*feedback*) in un sistema dinamico quando l'uscita di un elemento del sistema influenza, direttamente o indirettamente, l'ingresso di quello stesso elemento, dando così origine a uno o più percorsi chiusi (*loop*) per la trasmissione di segnali all'interno del sistema.

In effetti, la retroazione si verifica in quasi tutte le parti del sistema nervoso di ogni animale.  Le reti neurali biologiche sono fortemente ricorrenti. I neuroni biologici sono interconnessi in modi altamente ciclici. Esistono loop locali (tra pochi neuroni) e loop a lungo raggio. Le informazioni possono circolare più volte prima di arrivare a una risposta e questo rende possibile la memoria, l’attenzione, il contesto, e forse anche la coscienza.

Ad esempio, si consideri il **circuito talamo-coticale**. Il talamo riceve segnali dal mondo esterno (vista, udito, tatto...) o da altre parti del cervello. Li invia alla corteccia, che li elabora: riconosce un volto, capisce una parola, sente una melodia. La corteccia manda segnali di ritorno al talamo, creando un circuito. Il talamo modifica il modo in cui invierà i prossimi segnali, in base a quello che la corteccia ha già capito.

Inoltre, come vedremo, il feedback svolge un ruolo importante nello studio di una classe speciale di reti neurali artificiali, note come **reti ricorrenti**.

La figura seguente mostra il grafo del flusso del segnale di un sistema di retroazione a loop singolo, in cui sono presenti un segnale di ingresso $$x\_j$$, un segnale interno $$x'\_j$$ e un segnale di uscita $$y\_k$$. Il sistema è composto da un percorso di andata e uno di ritorno, caratterizzati rispettivamente dalle funzioni di attivazione $$A$$ e $$B$$.

<figure><img src="https://3096303588-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLaIrbNpGYnY3gphqyxHI%2Fuploads%2FlMcGBsUwegZFrrqsoM2i%2Ffeedback.png?alt=media&#x26;token=2c32747c-074a-48b9-bd65-f443024630a2" alt="" width="375"><figcaption><p>Grafo di flusso con retroazione</p></figcaption></figure>

Possiamo descrivere matematicamente questo sistema ricorrente come segue:

$$
\begin{array}{lcl} y\_k (n) & = & A(x'\_j (n)) \ x'\_j(n) & = & x\_j(n) + B(y\_k(n-1)) \end{array}
$$

Riscrivendo il segnale interno otteniamo un'**equazione ricorsiva** in cui segnale di uscita $$y\_k$$ in un dato istante $$n-1$$ influenza il medesimo segnale all'istante successivo $$n$$:

$$
y\_k(n) = A(x\_j (n) + B(y\_k(n-1)))
$$

## Architetture di reti

Il modo in cui i neuroni di una rete neurale sono strutturati è intimamente legato all'algoritmo di apprendimento utilizzato per addestrare la rete. La classificazione degli algoritmi di apprendimento verrà presa in considerazione più avanti; qui ci concentriamo sulle architetture (strutture) delle reti. In generale, possiamo identificare tre classi fondamentalmente diverse di architetture di rete.

### Reti in avanti a singolo strato

In una rete neurale a strati, i neuroni sono organizzati in forma di strati (*layer*). Nella forma più semplice di rete a strati, abbiamo uno strato di ingresso di nodi sorgente che proietta direttamente su uno strato di uscita di neuroni, ma non viceversa.&#x20;

In altre parole, in questa rete la computazione è strettamente in avanti (*feedforward*), dagli ingressi all'uscita. Una rete di questo tipo è chiamata **rete neurale in avanti** (FFNN, *Feedforward Neural Network*) a singolo strato, con la designazione "a singolo strato" riferita allo strato di uscita di neuroni di calcolo. Non contiamo lo strato di ingresso dei nodi sorgente perché in essi non viene eseguita alcuna computazione.

Ad esempio, la rete in figura ha 4 input ognuno dei quali è connesso a 4 neuroni di output:

<figure><img src="https://3096303588-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLaIrbNpGYnY3gphqyxHI%2Fuploads%2FO6qd8hTQwGsOSvB7Jk9I%2Farchiteture1.png?alt=media&#x26;token=1e8f3669-6b71-4de8-9cc2-4bfcd8cee5ac" alt="" width="375"><figcaption><p>Rete feedforward a singolo strato</p></figcaption></figure>

Vediamo l'equazione matematica che descrive la rete. Per ciascun neurone di output $$y\_j$$ (con $$j = 1, 2, 3, 4$$):

$$
y\_j = f\left(\sum\_{i=1}^{4} w\_{ji} x\_i + b\_j\right)
$$

dove:

* $$x\_i$$ sono gli ingressi (input layer, con $$i = 1, 2, 3, 4$$)
* $$w\_{ji}$$ è il peso associato al collegamento tra il nodo di input $$i$$ e il neurone di output $$j$$
* $$b\_j$$ è il bias del neurone $$j$$
* $$f(\cdot)$$ è la funzione di attivazione&#x20;

Usando la notazione vettoriale risulta tutto più conciso:

$$
\mathbf{y} = f(\mathbf{W} \mathbf{x} + \mathbf{b})
$$

dove:

* $$\mathbf{x} \in \mathbb{R}^4$$ è il vettore degli input
* $$\mathbf{W} \in \mathbb{R}^{4 \times 4}$$ è la matrice quadrata con 4 righe e 4 collonne che contiene i pesi
  * esiste una riga della matrice per ogni neurone di output che contiene i pesi delle connessioni che arrivano dagli input
  * esiste una colonna della matrice per ogni nodo di input che contiene i pesi delle connessioni che raggiungono i neuroni di output
* $$\mathbf{b} \in \mathbb{R}^4$$ è il vettore dei bias
* $$f$$ è applicata elemento per elemento al vettore risultante

#### Esempio numerico

Input:

$$
\mathbf{x} =
\begin{bmatrix}
1 \\
-1 \\
0.5 \\
2
\end{bmatrix}
$$

Pesi:

$$
\mathbf{W} =
\begin{bmatrix}
0.2 & -0.1 & 0.4 & 0.3 \\
-0.5 & 0.2 & 0.1 & -0.2 \\
0.3 & 0.3 & -0.2 & 0.1 \\
0.1 & 0.2 & 0.2 & 0.5
\end{bmatrix}
$$

Bias:

$$
\mathbf{b} =
\begin{bmatrix}
0.1 \\
0 \\
-0.1 \\
0.2
\end{bmatrix}
$$

Calcoliamo il del prodotto matrice-vettore:

$$
\begin{aligned}
\mathbf{W} \cdot \mathbf{x} =
\begin{bmatrix}
0.2 \cdot 1 + (-0.1) \cdot (-1) + 0.4 \cdot 0.5 + 0.3 \cdot 2 \\
-0.5 \cdot 1 + 0.2 \cdot (-1) + 0.1 \cdot 0.5 + (-0.2) \cdot 2 \\
0.3 \cdot 1 + 0.3 \cdot (-1) + (-0.2) \cdot 0.5 + 0.1 \cdot 2 \\
0.1 \cdot 1 + 0.2 \cdot (-1) + 0.2 \cdot 0.5 + 0.5 \cdot 2
\end{bmatrix}
=============

\begin{bmatrix}
0.2 + 0.1 + 0.2 + 0.6 = 1.1 \\
-0.5 - 0.2 + 0.05 - 0.4 = -1.05 \\
0.3 - 0.3 - 0.1 + 0.2 = 0.1 \\
0.1 - 0.2 + 0.1 + 1.0 = 1.0
\end{bmatrix}
\end{aligned}
$$

Aggiungiamo il bias:

$$
\mathbf{z} = \mathbf{W} \cdot \mathbf{x} + \mathbf{b} =
\begin{bmatrix}
1.1 + 0.1 = 1.2 \\
-1.05 + 0 = -1.05 \\
0.1 - 0.1 = 0.0 \\
1.0 + 0.2 = 1.2
\end{bmatrix}
$$

Applichiamo la funzione di attivazione (supponiamo ReLU) e otteniamo il risultato finale, ovvero il valore dell'output $$y$$:

$$
y =\text{ReLU}(\mathbf{z}) =
\begin{bmatrix}
\max(0, 1.2) = 1.2 \\
\max(0, -1.05) = 0.0 \\
\max(0, 0.0) = 0.0 \\
\max(0, 1.2) = 1.2
\end{bmatrix}
$$

### Reti in avanti multistrato

La seconda classe di reti neurali in avanti si distingue per la presenza di uno o più **strati nascosti**, i cui nodi di calcolo sono chiamati neuroni nascosti; il termine "nascosto" si riferisce al fatto che questa parte della rete neurale non è vista direttamente né dall'ingresso né dall'uscita della rete.&#x20;

> Aggiungendo uno o più strati nascosti, la rete è in grado di estrarre statistiche di ordine superiore dai suoi ingressi. In un certo senso, la rete acquisisce una **prospettiva globale** nonostante la sua **connettività locale**.

In una rete multi-strato, i nodi sorgenti o di input alimentano il primo strato. Il secondo strato è alimentato dalle uscite del primo strato e così via fino all'ultimo strato, ovvero i neuroni di output, che forniscono la risposta della rete al vettore di ingresso. La computazione avviene in avanti, per questo la rete si chiama **feedforward**.&#x20;

> In generale, una rete neurale calcola una funzione che trasforma un vettore di ingresso di numeri reali in un vettore di uscita di numeri reali, possibilmente di dimensioni diverse, passando per zero o più strati nascosti di computazione.

Nella figuara che segue, i 10 nodi di input riforniscono i 4 neuroni del primo strato nascosto. I segnali di uscita di questo strato vengono utilizzati come input per il secondo strato di 2 neuroni, che rappresenta l'output della rete. La rete è **totalmente connessa**, nel senso che ogni nodo (incluso l'ingresso) è collegato a tutti i nodi dello strato successivo. In questo caso, la rete calcola una funziona che trasforma un vettore a 10 componenti in un vettore a 2 componenti.&#x20;

<figure><img src="https://3096303588-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLaIrbNpGYnY3gphqyxHI%2Fuploads%2FIceDLAN3ZnVHjUqADjgM%2Farchiteture2.png?alt=media&#x26;token=e7d057b9-75a2-45b9-b147-6ed6eb58dab3" alt="" width="375"><figcaption><p>Rete feedforward a più strati</p></figcaption></figure>

#### Equazione matematica

Abbiamo:

* **Input layer**: $$x \in \mathbb{R}^{10}$$
* **Hidden layer**: $$h \in \mathbb{R}^{4}$$
* **Output layer**: $$y \in \mathbb{R}^{2}$$

Possiamo riscrivere l'equazione completa della rete neurale feedforward a due strati come segue. Per lo strato nascosto (hidden layer) abbiamo:

$$
\mathbf{h} = f^{(1)}\left( \mathbf{W}^{(1)} \mathbf{x} + \mathbf{b}^{(1)} \right)
$$

dove:

* $$\mathbf{x} \in \mathbb{R}^{10}$$ è il vettore di input
* $$\mathbf{W}^{(1)} \in \mathbb{R}^{4 \times 10}$$ è una matrice rettangolare con 4 righe e 10 colonne che contiene i pesi tra input e hidden layer
* $$\mathbf{b}^{(1)} \in \mathbb{R}^4$$ è il bias dello strato nascosto
* $$f^{(1)}$$ è la funzione di attivazione dello strato nascosto

Per lo strato di uscita (output layer) abbiamo:

$$
\mathbf{y} = f^{(2)}\left( \mathbf{W}^{(2)} \mathbf{h} + \mathbf{b}^{(2)} \right)
$$

dove:

* $$\mathbf{W}^{(2)} \in \mathbb{R}^{2 \times 4}$$ è una matrice rettangolare con 2 righe e 4 colonne che contiene i pesi tra hidden e output layer
* $$\mathbf{b}^{(2)} \in \mathbb{R}^2$$ è il bias dello strato di output
* $$f^{(2)}$$ è la funzione di attivazione dello strato di output

L'equazione finale complessiva compone le due precedenti:

$$
\mathbf{y} = f^{(2)}\left( \mathbf{W}^{(2)} \cdot f^{(1)}\left( \mathbf{W}^{(1)} \mathbf{x} + \mathbf{b}^{(1)} \right) + \mathbf{b}^{(2)} \right)
$$

Vediamo in questo caso il codice in Python che implementa la funzione calcolata dalla rete su un esempio specifico:

```python
import numpy as np

# Input vector (10 features)
x = np.array([1, 0, -1, 2, 0.5, -0.5, 1, 1, 0, -1])

# Pesi e bias del layer nascosto (4 neuroni)
W1 = np.array([
    [0.2, -0.1, 0.4, 0.5, -0.3, 0.1, 0.2, -0.4, 0.3, 0.1],
    [-0.3, 0.6, -0.2, 0.1, 0.2, -0.1, 0.4, 0.3, -0.5, 0.2],
    [0.1, -0.2, 0.5, -0.3, 0.3, 0.2, -0.1, 0.2, 0.1, 0.4],
    [0.4, 0.3, -0.1, 0.2, -0.2, 0.3, -0.3, 0.1, -0.4, 0.2]
])
b1 = np.array([0.1, -0.2, 0.05, 0.0])

# ReLU activation function
def relu(x):
    return np.maximum(0, x)

# Output del layer nascosto
h = relu(W1 @ x + b1)

# Pesi e bias del layer di output (2 neuroni)
W2 = np.array([
    [0.3, -0.2, 0.5, -0.1],
    [-0.4, 0.1, 0.3, 0.2]
])
b2 = np.array([0.2, -0.1])

# Output finale (senza funzione di attivazione finale, quindi lineare)
y = W2 @ h + b2

# Stampa del risultato
print("Output finale della rete:")
print(y)

```

Le reti feedforward computano in un solo passaggio solo in avanti. Sono più semplici da implementare e addestrare e computazionalmente efficienti dato che si prestano meglio ad essere parallelizzate. Di contro, non hanno memoria e dunque non adatte a dati sequenziali (es. testo, audio, serie temporali) che necessitano di capire un contesto (es. una parola in una frase). Sono invece più adatta a dati statici (es. immagini, classificazione).

### Reti ricorrenti

Una **rete neurale ricorrente** (RNN, *Recurrent Neural Network*) si distingue da una rete neurale feedforward per la presenza di almeno un **ciclo di retroazione** (*feedback loop*).&#x20;

Nella rete ricorrente in figura esiste un singolo strato di neuroni, con ogni neurone che restituisce il suo segnale di uscita agli ingressi di tutti gli *altri* neuroni diversi da sé stesso. Si noti che la retroazione in questo caso è **indiretta**: lo stato di ogni neurone non è influenzato direttamente ma solo indirettamente dallo stato del neurone stesso. Quindi non ci sono cicli di **auto-retroazione** (*self-feedback loop*), ovvero situazioni in cui l'uscita di un neurone viene reimmessa direttamente nel suo ingresso. Si noti che i loop di retroazione comportano l'uso particolari elementi indicati con $$z^{-1}$$, la cui uscita è ritardata di un'unità di tempo rispetto all'ingresso.&#x20;

<figure><img src="https://3096303588-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLaIrbNpGYnY3gphqyxHI%2Fuploads%2Flk2fTOj6lEHetfw8ZSXA%2Farchiteture3.png?alt=media&#x26;token=b8086718-f9d9-4de5-9bd5-9eb7d0ff6615" alt="" width="375"><figcaption><p>Rete ricorrente priva di auto-retroazione</p></figcaption></figure>

#### Equazione matematica

Chiamiamo i neuroni $$h\_1, h\_2, h\_3, h\_4$$. Sia $$\mathbf{h}(t) = \[h\_1(t), h\_2(t), h\_3(t), h\_4(t)]^\top$$ lo stato dei 4 neuroni al tempo $$t$$. Ogni neurone $$h\_i(t)$$ è funzione degli altri 3 neuroni al tempo $$t-1$$, quindi:

$$
h\_i(t) = f\left( \sum\_{\substack{j=1 \ j \ne i}}^{4} w\_{ij} \cdot h\_j(t-1) + b\_i \right)
$$

oppure in forma vettoriale:

$$
\mathbf{h}(t) = f\left( \mathbf{W} \cdot \mathbf{h}(t-1) + \mathbf{b} \right)
$$

con:

* $$\mathbf{W} \in \mathbb{R}^{4 \times 4}$$: matrice dei pesi, con **zero sulla diagonale** ($$w\_{ii} = 0$$) per escludere il self-feedback
* $$\mathbf{b} \in \mathbb{R}^4$$: bias
* $$f$$: funzione di attivazione applicata elemento per elemento

#### Esempio numerico

Sia:

$$
\mathbf{W} =
\begin{bmatrix}
0 & 1 & 2 & -1 \\
1 & 0 & -1 & 0.5 \\
-0.5 & 1 & 0 & 1 \\
1 & -1 & 1 & 0 \\
\end{bmatrix}
\quad
\mathbf{b} =
\begin{bmatrix}
0.5 \\
0 \\
-0.5 \\
1 \\
\end{bmatrix}
\quad
f = \text{ReLU}
$$

Stato iniziale al tempo $$t = 0$$:

$$
\mathbf{h}(0) =
\begin{bmatrix}
0 \ 1 \ -1 \ 2
\end{bmatrix}
$$

Calcolo di $$\mathbf{h}(1)$$:

$$
\mathbf{W} \cdot \mathbf{h}(0) =
\begin{bmatrix}
0 \cdot 0 + 1 \cdot 1 + 2 \cdot (-1) + (-1) \cdot 2 \\
1 \cdot 0 + 0 \cdot 1 + (-1) \cdot (-1) + 0.5 \cdot 2 \\
-0.5 \cdot 0 + 1 \cdot 1 + 0 \cdot (-1) + 1 \cdot 2 \\
1 \cdot 0 + (-1) \cdot 1 + 1 \cdot (-1) + 0 \cdot 2 \\
\end{bmatrix}
=============

\begin{bmatrix}
1 -2 -2 = -3 \\
1 + 1 = 2 \\
1 + 2 = 3 \\
-1 -1 = -2 \\
\end{bmatrix}
$$

Somma con il bias:

$$
\mathbf{z} =
\begin{bmatrix}
-3 + 0.5 = -2.5 \\
2 + 0 = 2 \\
3 - 0.5 = 2.5 \\
-2 + 1 = -1 \\
\end{bmatrix}
$$

Applichiamo ReLU:

$$
\mathbf{h}(1) = \text{ReLU}(\mathbf{z}) =
\begin{bmatrix}
0 \\
2 \\
2.5 \\
0
\end{bmatrix}
$$

Ecco il codice Python che calcola lo stato dei neuroni per 10 iterazioni:

```python
import numpy as np
import matplotlib.pyplot as plt

# Parametri della rete
W = np.array([
    [0, 1, 2, -1],
    [1, 0, -1, 0.5],
    [-0.5, 1, 0, 1],
    [1, -1, 1, 0]
])
b = np.array([0.5, 0.0, -0.5, 1.0])

# Funzione di attivazione ReLU
def relu(x):
    return np.maximum(0, x)

# Inizializzazione stato iniziale h(0)
h0 = np.array([0.0, 1.0, -1.0, 2.0])

# Simula l'evoluzione temporale
timesteps = 10
H = np.zeros((timesteps, 4))
H[0] = h0

for t in range(1, timesteps):
    H[t] = relu(W @ H[t-1] + b)

# Plot dell'evoluzione temporale di ciascun neurone
plt.figure(figsize=(10, 6))
for i in range(4):
    plt.plot(H[:, i], label=f'h{i+1}(t)')
plt.title('Evoluzione temporale degli stati dei 4 neuroni')
plt.xlabel('Tempo t')
plt.ylabel('Attivazione')
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.show()
```

Nella figura successiva viene illustrata un'altra classe di reti ricorrenti con neuroni nascosti. Le connessioni di retroazione mostrate provengono sia dai neuroni nascosti (i due più in basso) sia dai neuroni di uscita (i due più in alto). Inoltre, sono presenti cicli di auto-retroazione: l'uscita di ogni neurone ritorna come ingresso al neurone stesso e agli altri neuroni della rete. Vi sono due ingressi che confluiscono nei due neuroni di output.

<figure><img src="https://3096303588-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLaIrbNpGYnY3gphqyxHI%2Fuploads%2F3qpAh13g7e330KEqnGo6%2Farchiteture4.png?alt=media&#x26;token=b6015055-bce3-48ae-bfbb-31d14f2263ea" alt="" width="375"><figcaption><p>Rete ricorrente con auto-retroazione</p></figcaption></figure>

#### Equazione matematica

Abbiamo:

* 2 input $$\mathbf{x}(t) \in \mathbb{R}^2$$
* 2 neuroni nascosti $$\mathbf{h}(t) \in \mathbb{R}^2$$
* 2 neuroni di output $$\mathbf{y}(t) \in \mathbb{R}^2$$
* Ogni neuroni riceve segnali dagli altri neuroni, incluso sé stesso, al tempo precedente
* In particolare, i neuroni di output ricevono anche segnali dagli input correnti

Definiamo:

$$
\mathbf{z}(t-1) = \begin{bmatrix} \mathbf{h}(t-1) \ \mathbf{y}(t-1) \end{bmatrix} \in \mathbb{R}^4
$$

un vettore che giustappone lo stato dei neuroni nascosti e di uscita.

Stato nascosto:

$$
\mathbf{h}(t) = f\_h \left(\mathbf{W}\_{zh} \cdot \mathbf{z}(t-1) + \mathbf{b}\_h \right)
$$

Stato di output:

$$
\mathbf{y}(t) = f\_y \left( \mathbf{W}*{xy} \cdot \mathbf{x}(t) + \mathbf{W}*{zy} \cdot \mathbf{z}(t-1) + \mathbf{b}\_y \right)
$$

dove:

* $$\mathbf{W}\_{xy} \in \mathbb{R}^{2 \times 2}$$: pesi da input a output
* $$\mathbf{W}*{zh}, \mathbf{W}*{zy} \in \mathbb{R}^{2 \times 4}$$: pesi da feedback totale (i 4 neuroni) a hidden/output
* $$\mathbf{b}\_h, \mathbf{b}\_y \in \mathbb{R}^2$$: bias
* $$f\_h, f\_y$$: funzioni di attivazione

Le reti ricorrenti computano un valore dinamico, che dipende dal passare del tempo, e non statico come le reti in avanti. Implementano in questo modo una **memoria interna** (possono ricordare eventi passati) e quindi sono più adatte per lavorare su dati che necessitano di memorizzare un **contesto** per essere compresi, come testo, audio o serie temporali. La memoria è però spesso limitata nel tempo (da pochi step precedenti) e oggi queste reti sono superate in molti casi dall'architettura Transformer.

## Rappresentazione della conoscenza pregressa

La **conoscenza** si riferisce alle informazioni memorizzate da una persona o da una macchina per interpretare, prevedere e rispondere in modo appropriato al mondo esterno.&#x20;

Uno dei compiti principali di una rete neurale è quello di apprendere un modello del mondo (ambiente circostante) in cui è inserita e di mantenere il modello sufficientemente coerente con il mondo reale, in modo da raggiungere gli obiettivi specificati dell'applicazione di interesse. La conoscenza del mondo consiste in due tipi di informazioni:

1. Lo stato del mondo conosciuto, rappresentato da fatti relativi a ciò che è e ciò che è stato conosciuto; questa forma di conoscenza è definita **conoscenza pregresse** e **invarianti.**
2. Le **osservazioni** (misure) del mondo, ottenute per mezzo di sensori progettati per sondare l'ambiente in cui la rete neurale dovrebbe operare. Le osservazioni sono la base per estrarre gli esempi utilizzati per **addestrare** la rete neurale.

Esistono quattro regole generali per la rappresentazione della conoscenza:

1. **Regola 1.** Input simili (tratti da classi che si assomigliano) devono produrre rappresentazioni di conoscenza (pesi sinaptici) simili all'interno della rete.
2. **Regola 2.** Input diversi (tratti da classi disparate) devono produrre rappresentazioni ampiamente diverse nella rete.
3. **Regola 3.** Se una particolare caratteristica è importante, allora ci dovrebbe essere un gran numero di neuroni coinvolti nella rappresentazione di quell'elemento nella rete.
4. **Regola 4.** Le informazioni pregresse e gli invarianti dovrebbero essere incorporate nella progettazione di una rete neurale ogni volta che sono disponibili, in modo da semplificare la progettazione della rete evitando di doverle apprendere.

### Come incorporare la conoscenza pregressa

La regola 4 della rappresentazione della conoscenza è particolarmente importante perché, rispettandola correttamente, si ottiene una rete neurale con una struttura specializzata. Questo è altamente auspicabile per diverse ragioni:

1. Le reti biologiche visive e uditive sono note per essere molto specializzate.
2. Una rete neurale con struttura specializzata ha di solito un numero inferiore di parametri liberi da regolare rispetto a una rete completamente connessa. Di conseguenza, la rete specializzata richiede un set di dati più piccolo per l'addestramento, apprende più velocemente e spesso generalizza meglio.
3. La velocità di trasmissione delle informazioni attraverso una rete specializzata (*throughput*) è accelerata.
4. Il costo di costruzione di una rete specializzata si riduce grazie alle sue dimensioni ridotte rispetto alla sua controparte completamente connessa.

Si noti, tuttavia, che l'incorporazione di conoscenze pregresse nella progettazione di una rete neurale limita l'applicazione della rete al problema specifico affrontato dalla conoscenza di interesse.

Una questione importante da affrontare, ovviamente, è come sviluppare una struttura specializzata incorporando informazioni pregresse nella sua progettazione. Possiamo utilizzare una combinazione di due tecniche:

1. la **restrizione dell'architettura** della rete, ottenuta attraverso l'uso di connessioni locali note come campi recettivi. Il **campo recettivo** di un neurone è definito come quella regione del campo di ingresso su cui gli stimoli in arrivo possono influenzare il segnale di uscita prodotto dal neurone.&#x20;
2. la **limitazione della scelta dei pesi sinaptici**, che si realizza attraverso l'uso della condivisione dei pesi.

Ad esempio, si consideri la rete feedforward parzialmente connessa rappresentata nella figura successiva.&#x20;

<figure><img src="https://3096303588-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLaIrbNpGYnY3gphqyxHI%2Fuploads%2FTWelvfzPePAn31nljNkR%2Farchiteture5.png?alt=media&#x26;token=1be74dd0-e4e2-4189-83c4-27e701e94405" alt="" width="375"><figcaption></figcaption></figure>

Questa rete ha un'architettura ristretta per definizione. I primi sei nodi sorgente costituiscono il campo recettivo del primo neurone nascosto, i secondi sei sono il campo ricettivo del secondo neurone nascosto e così via. Quindi c'è una forte intersezione tra i campi recettivi dei neuroni nascosti. Inoltre, possiamo aggiungere un ulteriore vincolo sulla condivisione dei pesi facendo in modo che ogni neurone nascosco utilizzi gli stessi pesi per le 6 connessioni di ingresso.

### Come incorporare gli invarianti

Consideriamo i seguenti fenomeni fisici:

* Quando un oggetto di interesse ruota, l'immagine dell'oggetto percepita da un osservatore cambia in modo corrispondente, ma l'oggetto è il medesimo.
* Una persona può parlare con voce bassa o alta, in modo lento o veloce, ma le parole sono le stesse.

Un sistema di riconoscimento di oggetti o un sistema di riconoscimento vocale deve essere in grado di gestire una serie di trasformazioni del segnale osservato, ovvero produrre risultati che sono **invarianti rispetto a queste trasformazioni** (la rotazione dell'oggetto o il cambio di voce umana).

Esistono almeno tre tecniche per rendere le reti neurali di tipo classificatore invarianti alle trasformazioni:

1. **Invarianza per struttura**. L'invarianza può essere imposta a una rete strutturandone opportunamente la topologia. In particolare, le connessioni e i pesi sinaptici tra i neuroni della rete vengono create in modo che le versioni trasformate dello stesso input siano costrette a produrre lo stesso output.
2. **Invarianza per addestramento**. La rete viene addestrata presentandole un certo numero di esempi diversi dello stesso oggetto, scelti in modo da corrispondere a diverse trasformazioni dell'oggetto. Se il numero di esempi è sufficientemente grande e se la rete viene addestrata per imparare a discriminare tra le diverse viste dell'oggetto, possiamo aspettarci che la rete generalizzi correttamente a trasformazioni diverse da quelle che le vengono presentate.
3. **Spazio delle caratteristiche invarianti**. La terza tecnica si basa sulla premessa che sia possibile estrarre caratteristiche che definiscono il contenuto informativo essenziale di un insieme di dati in ingresso e che siano invarianti rispetto alle trasformazioni dell'ingresso. Se si utilizzano tali caratteristiche, la rete come classificatore viene sollevata dall'onere di dover delineare la gamma di trasformazioni di un oggetto.

## Processi di apprendimento

Così come esistono diversi modi in cui noi stessi impariamo dall'ambiente che ci circonda, lo stesso vale per le reti neurali. In senso lato, possiamo classificare i **processi di apprendimento** attraverso i quali funzionano le reti neurali come segue: apprendimento con un insegnante (o supervisionato) e apprendimento senza insegnante (o non supervisionato). Una via di mezzo è l'apprendimento per rinforzo.&#x20;

**L'apprendimento supervisionato**, il metodo più utilizzato, prevede l'addestramento di un modello su dati etichettati, in cui ogni esempio in ingresso è accompagnato dalla corrispondente risposta. Questa guida permette al modello di apprendere una mappatura tra gli input e gli output desiderati, consentendogli di generalizzare a nuovi dati non visti. I compiti di classificazione e regressione esemplificano la versatilità dell'apprendimento supervisionato, applicato con successo al filtraggio dello spam e al riconoscimento delle immagini.

Al contrario, l'**apprendimento non supervisionato** opera su dati non etichettati, privi di categorie o etichette predefinite. Il compito del modello è quello di scoprire schemi e strutture nascoste all'interno dei dati stessi senza sapere a priori quali sono. Questa capacità trova applicazione nel clustering, dove gli elementi in uno spazio vengono raggruppati in base alla loro somiglianza, e nel rilevamento delle anomalie, dove i valori anomali vengono identificati come deviazioni dalla norma.

L'**apprendimento per rinforzo** si distingue dalle sue controparti supervisionate e non supervisionate perché immerge l'agente in un ambiente interattivo. L'agente impara interagendo con l'ambiente, compiendo azioni e ricevendo ricompense o penalità in base ai risultati. Questo approccio per tentativi ed errori (*trial-and-error*) consente all'agente di sviluppare una politica (*policy*, una sorta di strategia), un insieme di regole che guidano le sue azioni alla ricerca della massimizzazione della ricompensa cumulativa. I giochi, la robotica e la finanza sono domini in cui l'apprendimento per rinforzo ha dimostrato notevole successo.

### Apprendimento supervisionato

L'apprendimento con un insegnante è anche definito apprendimento supervisionato. La figura successiva mostra un diagramma a blocchi che illustra questa forma di apprendimento.

<figure><img src="https://3096303588-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLaIrbNpGYnY3gphqyxHI%2Fuploads%2FrQVNdmK1cLlDvGvD22pR%2Flearning1.png?alt=media&#x26;token=8b5b5992-c65a-45d6-bb25-783bf682f172" alt="" width="375"><figcaption></figcaption></figure>

In termini concettuali, possiamo pensare che l'insegnante abbia una conoscenza dell'ambiente e che tale conoscenza sia rappresentata da una serie di esempi di input-output. L'ambiente, tuttavia, è sconosciuto alla rete neurale (nella figura, l'ambiente è esterno al ciclo di retroazione colorato in azzurro). Supponiamo ora che l'insegnante e la rete neurale siano entrambi esposti a un vettore di addestramento (cioè un esempio) tratto dallo stesso ambiente. In virtù della conoscenza pregressa, l'insegnante è in grado di fornire alla rete neurale una risposta desiderata per quel vettore di addestramento. La risposta desiderata rappresenta l'azione ottimale che la rete neurale deve eseguire.

I parametri della rete vengono quindi regolati sotto l'influenza combinata del vettore di addestramento e del segnale di errore. Il segnale di errore è definito come la differenza tra la risposta desiderata e la risposta effettiva data dalla rete. Questa regolazione viene effettuata in modo iterativo, passo dopo passo, con l'obiettivo di far sì che la rete neurale emuli l'insegnante.

In questo modo, la conoscenza dell'ambiente a disposizione dell'insegnante viene **trasferita** alla rete neurale attraverso l'addestramento e immagazzinata sotto forma di pesi sinaptici fissi, che rappresentano la memoria a lungo termine. Quando si raggiunge questa condizione, si può fare a meno dell'insegnante e lasciare che la rete neurale si occupi dell'ambiente da sola.

Ad esempio, immaginiamo che la rete neurale debba distinguere le immagini di un gatto da quello di un bambino. Potremmo fornire alla rete un certo numero di immagini associate all'etichetta "Gatto" o "Bambino". In fase di addestramento, per ogni immagine fornita, la rete vede solo l'immagine, senza conoscere l'etichetta (ovvero la semantica). Se la rete risponde correttamente, nulla viene fatto. Altrimenti i pesi della rete vengono modificati opportunamente. Quando la rete risponde sufficientemente bene, l'addestramento è concluso.

Più precisamente, la tecnica usata per modificare i pesi è detta **retropropagazione** (*backpropagation*). Il processo è chiamato backpropagation perché consiste nel lavorare a ritroso dallo strato di uscita a quello di ingresso, regolando sistematicamente i pesi in base all'errore (la differenza tra l'uscita prevista e quella effettiva).

Ecco una descrizione passo per passo del funzionamento della retropropagazione ([qui](https://en.wikipedia.org/wiki/Gradient_descent) una animazione):

1. **Passaggio in avanti**: In primo luogo, un input viene fatto passare attraverso la rete neurale strato per strato (dall'input all'output) per produrre una previsione. Questa operazione è nota come passaggio in avanti.
2. **Calcolo della perdita**: Una volta che la rete produce un'uscita, la differenza tra questa uscita e il valore vero (target) viene calcolata utilizzando una funzione di perdita (*loss function*).&#x20;
3. **Passaggio all'indietro**: Qui avviene la vera azione della retropropagazione. Partendo dallo strato di uscita, l'errore viene utilizzato per calcolare le derivate parziali della funzione di perdita rispetto a ciascun peso sinaptico della rete, che rappresenta una variabile delle funzione di perdita. Il **gradiente** è un vettore che contiene le derivate parziali della funzione di perdita per ogni peso e quindi ci indica la direzione e la velocità di discesa nello spazio multidimensionale di tutti i pesi. In sostanza il gradiente ci indica i pesi sinaptici maggiormente responsabili dell'errore.
4. **Aggiornamento dei pesi**: Il gradiente calcolato durante il passaggio all'indietro viene utilizzato per apportare piccole modifiche ai pesi. Di solito si tratta di una semplice operazione di addizione, in cui una parte del gradiente (scalata da un tasso di apprendimento) viene aggiunta a ciascun peso.
5. **Iterazione**: Questo processo (passaggio in avanti, calcolo della perdita, passaggio indietro, aggiornamento dei pesi) viene ripetuto per molte iterazioni (o epoche) sul set di dati di addestramento, finché la rete non ottiene prestazioni sufficienti.

Un'analogia per la retropropagazione potrebbe essere il tentativo di trovare il punto più basso in un terreno collinare mentre si è bendati. Si percepisce la pendenza del terreno sotto i piedi e si fanno dei passi nella direzione che sembra essere di massima discesa.&#x20;

<details>

<summary>Funzione di perdita per la regressione</summary>

Nel caso di compiti di regressione, in cui l'obiettivo è prevedere valori continui, una delle funzioni di perdita più comunemente utilizzate è la funzione di perdita **Mean Squared Error (MSE)**.

L'MSE viene calcolato con la seguente formula:

$$\text{MSE} = \frac{1}{n} \sum\_{i=1}^n (\hat{y}\_i - y\_i)^2$$

Dove:

* $$n$$ è il numero di elementi del dataset
* $$\hat{y}\_i$$ è il valore previsto per l'i-esimo dato
* $$y\_i$$ è il valore effettivo dell'i-esimo dato

Uno dei vantaggi dell'MSE è che è differenziabile, il che consente di utilizzare algoritmi di ottimizzazione efficienti come la discesa del gradiente, in cui le derivate vengono calcolate per aggiornare i pesi del modello. Infatti, in una rete neurale, la risposta prevista del modello, e quindi anche la funzione MSE, ha come variabili i pesi sinaptici della rete. Quindi i pesi possono essere calibrati minimizzando la funzione MSE, ovvero riducendo al minimo l'errore. &#x20;

</details>

L'apprendimento supervisionato è uno strumento per risolvere un'ampia varietà di problemi, tra cui:

* **Riconoscimento di immagini**. Classificare immagini di oggetti, come volti o automobili.
* **Elaborazione del linguaggio naturale**. Classificare testi, ad esempio assegnare ad un testo un sentimento positivo, neutro o negativo.
* **Sistemi di raccomandazione**. Raccomandare prodotti, film o musica agli utenti in base al loro comportamento passato e al comportamento di utenti simili.

### Apprendimento per rinforzo

L'apprendimento per rinforzo è un tipo di apprendimento in cui un **agente** interagisce con un **ambiente** per **massimizzare una ricompensa**. L'agente non ha accesso alle regole complete dell'ambiente, quindi deve imparare per tentativi ed errori.

Il processo di apprendimento per rinforzo è tipicamente suddiviso in quattro fasi:

1. **Osservazione**: l'agente osserva l'ambiente e raccoglie informazioni sul suo stato attuale.
2. **Decisione**: l'agente utilizza le informazioni ricavate dall'osservazione per decidere un'azione da intraprendere.
3. **Azione**: l'agente intraprende l'azione scelta e osserva il cambiamento dell'ambiente che ne risulta.
4. **Ricompensa**: l'agente riceve una ricompensa o una penalità in base al risultato della sua azione.

> L'obiettivo dell'agente è imparare una **politica**, ovvero una mappatura dagli stati di conoscenza alle azioni che massimizzi la ricompensa cumulativa attesa.&#x20;

La figura successiva mostra un diagramma a blocchi che illustra questa forma di apprendimento. Si noti che a differenza dell'apprendimento supervisionato in questo caso l'ambiente è interno al feedback loop del sistema. In altri termini, la rete impara provando e sbagliando nell'ambiente. Inoltre, nel diagramma è presente la figura del **critico**, che a differenza dell'insegnante dell'apprendimento supervisionato, ha il compito di fornire rinforzi (ricompense o penalità) all'agente in base a come questi si agisce nell'ambiente. Il critico è una forma di insegnante che non fornisce all'agente la soluzione finale ma indica se l'agente è sulla giusta via per raggiungerla.

<figure><img src="https://3096303588-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLaIrbNpGYnY3gphqyxHI%2Fuploads%2F0Ehe022WcWNT2hIZ815P%2Flearning2.png?alt=media&#x26;token=114c0a5d-cae3-4a81-8352-e50b05b534d4" alt="" width="375"><figcaption></figcaption></figure>

Per esempio, consideriamo l'IA [Botto](https://botto.com/) che genera opere d'arte digitale. Ogni opera creata viene valutata criticamente da una comunità di umani. La comunità funge da critico d'arte e in questo modo Botto impara una porpria **politica artistica**, proseguendo la propria ricerca artistica nella direzione delle opere maggiormente apprezzate. &#x20;

L'apprendimento per rinforzo è stato applicato per risolvere un'ampia varietà di problemi, tra cui:

* **Giochi**: è stato utilizzato per sviluppare agenti in grado di giocare a livelli sovrumani. Ad esempio, AlphaGo sviluppato da DeepMind è stato addestrato con questa tecnica.
* **Robotica**: è stato utilizzato per sviluppare robot in grado di camminare, afferrare oggetti e navigare in labirinti.
* **Finanza**: può essere utilizzato per sviluppare algoritmi di trading in grado di prendere decisioni basate su dati di mercato in tempo reale.

### Apprendimento non supervisionato

L'apprendimento non supervisionato è un tipo di apprendimento automatico in cui il modello viene addestrato su **dati non etichettati**. Ciò significa che i dati non hanno etichette o categorie predefinite. L'obiettivo del modello è quello di trovare schemi e strutture nei dati senza alcuna guida da parte dell'uomo.

<figure><img src="https://3096303588-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLaIrbNpGYnY3gphqyxHI%2Fuploads%2FAGYCuhsZEwfY2faYIN43%2Funsupervised-learning.png?alt=media&#x26;token=b2f07b1f-5850-4914-a6c1-8157336c23de" alt="" width="362"><figcaption></figcaption></figure>

Riconsideriamo l'esempio di sopra del riconoscimento di immagini di gatti e bambini. In tal caso le immagini non hanno l'etichetta semantica. Il compito della rete è quello di classificare ogni immagine in gruppi. Verosimilmente, la rete creerà due gruppi, una per i gatti e una per i bambini. Infatti i gatti tendono ad avere caratteristiche diverse, come il fatto che camminano con quattro zampe, il fatto di avere la coda e il pelo. Si noti che la rete non sa che i gruppi corrispondono semanticamente a gatti e bambini; sa solo che le immagini hanno una distribuzione statistica di pixel differente e quindi le separa. Se nel dataset di addestramento ci sono molti bambini che gattonano, questi potrebbero essere scambiati per gatti, oppure la rete potrebbe creare un gruppo a parte per questi esempi.

Alcuni esempi in cui l'apprendimento non supervisionato viene tipicamente usato sono:

1. **Clustering**: si tratta di raggruppare un insieme di elementi in uno spazio in base alla loro somiglianza (esiste una metrica che misura quanto distanti sono due elementi). Ad esempio, un algoritmo di clustering può essere utilizzato per raggruppare i clienti in diversi segmenti in base alle loro abitudini di acquisto.
2. **Rilevamento di anomalie**: si tratta di identificare gli insiemi di dati che sono diversi dal resto dei dati. Ad esempio, un algoritmo di rilevamento delle anomalie potrebbe essere utilizzato per identificare le transazioni fraudolente in un set di dati finanziari.

<details>

<summary>Paralleli nell'apprendimento umano</summary>

* **Supervisionato**: è come quando un insegnante ti spiega una regola, ti dà esempi e ti corregge se sbagli. Tu impari dagli errori.
* **Non-supervisionato**: è come quando un insegnante ti lascia libero di scoprire prima di capire, ad esempio ti fa leggere un testo mai visto prima e poi ti chiede di esporlo
* **Per rinforzo**: è come quando impari facendo, ad esempio costruisci un circuito danneggiando le componenti se non metti le giuste resistenze e hai il piacere di utilizzarlo o mostrarlo ad altri se lo hai costruito correttamente. È l’apprendimento della conseguenza, del piacere e del dolore.

Potremmo dire che tutti noi impariamo attraverso una combinazione dinamica di questi tre modi. Un maestro ci insegna (supervisionato), il mondo ci parla in segreti da decifrare (non supervisionato), e la vita ci premia o ci ferisce per ciò che facciamo (rinforzo).

</details>
