# Reti neurali

Le reti neurali (NN) o “multilayer perceptron” sono divise in layers ciascun layer è compostto da “neuroni".

I layers possono essere: 1) input, 2) hidden e 3) output. L'input layer può essere considerato come “hidden”.

Ciascun neurone del layer possiene gli input (o features) e un un output.

L'inferenza di una rete neurale consiste nel ricavare i valori del modello e applicarli alla propria rete

per riprodurre un comportamento. (per valori intendo l'insieme dei w e dell b)

La somma di questi output è anche detta “activations”.

[![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/scaled-1680-/lynTrymo92ZvbyNy-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/lynTrymo92ZvbyNy-image.png)

In generale ciascun layer si occupa di “riconoscere” o estrarra specifiche caratteristiche del dataset, nel  
caso di immagini di volti, per esempio, il primo layer riconoscere solo righe orizzonati/verticali, il secondo  
parti del viso e il terzo un viso completo. (è solo un esempio ovviamente)

per es:

[![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/scaled-1680-/e4ddtd0bpRXT6wui-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/e4ddtd0bpRXT6wui-image.png)

ciascun neurone del layer utilizzata una funzione di attivazione, come per es. la regressione logistica, il cui  
output, è il valore di attivazione che diventa l'input del layer successivo:

[![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/scaled-1680-/3OvxTxVRzxfDgoM8-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/3OvxTxVRzxfDgoM8-image.png)

nel secondo layer infatti il vettore di parametri in input vengono dati in pasto alla funzione di regressione logistica del layer:

[![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/scaled-1680-/S4IFKQdmtr4ljk6q-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/S4IFKQdmtr4ljk6q-image.png)

l'output del l'ultimo layer non è più un vettore ma uno scalare (quindi un numero semplice) almeno in questo esempio  
al quale viene applicato una soglio per determinare l'output true o false. (è giusto è un esempio, vedi immagine sotto)

[![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/scaled-1680-/VuVeghyuj1qWgkk8-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/VuVeghyuj1qWgkk8-image.png)

'attivazione di un layer si basa applicando la funzione di attivazione (activation function) che nel caso  
specifico è la sigmoid (ma in realtà che ne sono altre migliori) L'output della funzione di attivazione  
è un vettore di valori che diventa l'input del layer successivo.

Di seguita vengono rappresentati i passaggi per l'elaborazione delle funzioni di attivazioni declinate sui vari layer:

[![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/scaled-1680-/TzPGdLhxzngkYNd8-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/TzPGdLhxzngkYNd8-image.png)

#### Foward propagation

Quando i valori di attivazioni vanno dall'input layer, passando per l'hidden e terminando nell'output  
layer seguendo esattamente questo schema, allora parliamo di “forward propagation”. (da sinistra verso destra)

[![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/scaled-1680-/ahQmE8CorxxA4qdD-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/ahQmE8CorxxA4qdD-image.png)

##### <span style="color: rgb(224, 62, 45);">TensorFlow</span>

I framework maggiormente utilizzati sono TF e PyTorch.

Per ora verrà utilizzato TF con layer “densi".

**Differenze di rappresentazione dei dati tra Numpy e TF**

quando passo i dati a TF, es come input ad un Dense layer, TF converte la matrice

di valori np in un “tensore” che nella pratica è un np “wrappato” per esigenze computazionali e di architettura.

E' possibile convertire un tensore un np applicando il medodo .numpy del tensore che rappresenta il dato.

Di seguito viene rappresentata una tipica rete neurale di tipo “forward propagation” con

due layers di 3 e 1 neurone.

[![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/scaled-1680-/SMLsOVgKYR8Gqy1u-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/SMLsOVgKYR8Gqy1u-image.png)

COMPILE:

Nella definizione di compile tra i vari paramtri viene impostato il totale delle epoche: es: 40

questo significa che ad ogni epica viene elaborato l'intero dataset. Ogni epoca è suddivisa

in batch dove in TF il numero massimo di batch per epoca è 32.

Quindi per es. se il dataset è fatto di 5000 records (dove ogni record ha N feautues, ma questo non conta adess)

il numero di batch per epoca sarà 5000/32 ovvero 157. es.

.

.

Epoch 39/40

157/157 \[==============================\] - 0s 2ms/step - loss: 0.0312

Epoch 40/40

157/157 \[==============================\] - 0s 2ms/step - loss: 0.0294

##### <span style="color: rgb(224, 62, 45);">Vettorizzazione</span>

La vettorizzazione corrispoonde alla moltiplacazione delle matrici  
Supponendo di avere M1 e M2 per moltiplicare bisogna:  
1\) fare trasposta di M1  
2\) moltiplicare la riga 1 per la colonna 1 e via così...

NB:  
1\) il requisito è che la matrice trasposta M1 per la matrice M2 abbiamo il numero di  
colonne di M1 uguale al numero di righe di M2  
2\) inoltre la matrice risultante avrà il numero di righe di M1 trasposta e il numero di colonne di M2

NB2: per fare la trasposta bisogna convertire la collanna (es. 1) nella riga 1.

vedi esempio sotto riportato.

[![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/scaled-1680-/hVgAJ1CQtw7HWQoM-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/hVgAJ1CQtw7HWQoM-image.png)

che si converte in:

[![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/scaled-1680-/HdEQHQEnt91gY6Ti-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/HdEQHQEnt91gY6Ti-image.png)

per effettuare la trasposta di in numpy basta chiare il metodo .T dell'oggetto matrice di np.

[![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/scaled-1680-/9WOQiB2Rr90wyywP-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/9WOQiB2Rr90wyywP-image.png)

che nel codice si traduce:

[![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/scaled-1680-/nRZmabx7weTP0Rp1-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/nRZmabx7weTP0Rp1-image.png)

di seguito un esempio di rete nurale sequenziale di 25 neuroni L1, 15 neuroni L2 e 1 neurone L3

[![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/scaled-1680-/VNWYpGps94oeMNrf-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/VNWYpGps94oeMNrf-image.png)

con TF è possibile visualizzare il dettaglio del modello, da notare il numero di parametri  
che corrisponde - per ciascun layer - alle w + le b. Per esempio in primo layer che è composto  
da 15 neuroni il cui input è un array di 400 valori (sono i 20x20 pixel dell'immagine)  
avrà un totale di 10025 parametri dato da: 400x25 -&gt; w + 25 -&gt; b

[![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/scaled-1680-/J3kqwCzrONdhLk4a-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/J3kqwCzrONdhLk4a-image.png)

nel caso specifico il modello predice la probabilità che il numero si un uno (1)

prediction = model.predict(X\[0\].reshape(1,400)) # a zero

print(f" predicting a zero: {prediction}")

prediction = model.predict(X\[500\].reshape(1,400)) # a one

print(f" predicting a one: {prediction}")

predicting a zero: \[\[0.0191125\]\]

predicting a one: \[\[0.9788295\]\]

The output of the model is interpreted as a probability. In the first example above, the input is a zero. The model predicts the probability that the input is a one is nearly zero. In the second example, the input is a one. The model predicts the probability that the input is a one is nearly one. As in the case of logistic regression, the probability is compared to a threshold to make a final prediction.

##### <span style="color: rgb(224, 62, 45);">Training</span>

<span style="color: rgb(0, 0, 0);">Paragonando i concentti appresi nella prima settimana, costo della funzione, discesa del gradiente  
con quelli appresi nella seconda settimana, rete neuale , modello, fit possiamo riassumere che:</span>

[![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/scaled-1680-/3UqFZb1rPghD8HTH-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/3UqFZb1rPghD8HTH-image.png)

nel modello la funzione di costo è esplicatata dal parametro “loss” e corrisponde alla funzione alla funziona di costo visto  
come media dei valori “loss” (Cost)  
mentre il metodo fot non è altro che il calcolo della discesa del gradiente nella regressione logistica.

#### <span style="color: rgb(224, 62, 45);">Funzioni di attivazione</span>

PERCHE' UTILIZZARE LE FUNZIONI DI ATTIVAZIONE?  
L'uso delle regressione lineare negli hidden layer non serve in quanto basta  
calcolare la regressione lineare a livello di funzione matematica. (vedi settimana 1)  
E in questo caso il modello può essere utulizzato solo per modelli molto semplici.

FUNZIONI DI ATTIVAZIONE PER L'OUTPUT LAYER

Ci sono vari tipi di “funziona di attivazione” ciascuna delle quali  
una sua peculiarità a seconda del fenomeno che si vuole modellare.

Per problemi legati alla classificazione binaria dove l'output è 0/1 or Tryue/False  
la funzione Sigmoid può andar bene. Perchè il modello calcola la probabilità  
di ottenere un output uguale a 1.

Nel caso in cui invece si deve predirre un output che può assumere più valori  
è meglio utilizzare il tipo “linear regression function”. (per es. nel mercato dei titoli)  
In questo caso l'output può quindi assumere sia valori positivi che negativi.

Nel caso in cui invece i valori possono essere varibili ma solo positivi, come per  
esempio il prezzo delle case, allora è meglio utilizzare la funzione “ReLU”

[![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/scaled-1680-/3y0IukbcN5aNkQy5-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/3y0IukbcN5aNkQy5-image.png)

FUNZIONE DI ATTIVAZIONE PER GLI HIDDEN LAYER:  
in generale per gli hidden è meglio utilzzare “ReLU”

#### <span style="color: rgb(224, 62, 45);">Classificazione multiclasse</span>

Come evidenziato negli esempi precedenti, nel caso in cui si voglio classificare un  
evento binario, es. true/false utilizzo la funziona di attivazione Sigmoid.

2\)  
Nel caso di valori lineari, come l'andamento dei prezzi delle case, utilizzo la regressione  
lineare seplice. (permane comunque un unico output che puù assumere diversi valori)

3\)  
Nel caso invece in cui ho più valori in output da prevedere, utilizzo la classificazione multiclasse.  
In questo caso si utilizza la funzione “SoftMax” che nella pratica rappresente la generalizzazione  
della regressione logistica.  
In questo caso ogni attivare del layer di output assume la probabilità che lo isesimo valore si verifichi.  
La probabilità vare tra zero e uno, ovvero da dallo zero al cento per cento.  
La formula per il caloclo della funzione Softmax è:

[![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/scaled-1680-/YDTuF6kABeqO8O0i-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/YDTuF6kABeqO8O0i-image.png)

che generalizzando si può scrivere come:

[![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/scaled-1680-/AGbQdBg4l8Nrfwty-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/AGbQdBg4l8Nrfwty-image.png)

#### <span style="color: rgb(224, 62, 45);">Ottimizzazione avanzata</span>

<span style="color: rgb(0, 0, 0);">La discesa del gradiente è un ottimo algoritmo che utilizza  
piccoli passi per arrivare al minimo del costo della funzione.  
Esiste però un algorirmo più veloce che utilizza degli step “maggiorati”  
che fanno in modo di arrivare al minimo più velocemente. Il nome  
di questo algoritmo è “Adam”.  
Adam sta per “Adaptive Moment Estimation” che nella pratica fa si  
che il passo “learning rate” sia variabile ovvero possa variare da piccolo a grande  
in maniera ottimale.</span>

[![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/scaled-1680-/FqtK3etsl4hAWJ3n-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/FqtK3etsl4hAWJ3n-image.png)

##### <span style="color: rgb(224, 62, 45);">Layer "convoluzionale"</span>

<span style="color: rgb(0, 0, 0);">Oltre al layer fato di neuroni “densi” esite il layer fatto di neuroni “convoluzionari” che  
a differenze dei densi, ricevano solo alcune attivazioni del layer precedente.  
es.</span>

[![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/scaled-1680-/bIyEREPqrxC9ZBVV-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/bIyEREPqrxC9ZBVV-image.png)

##### <span style="color: rgb(224, 62, 45);">Bias validation</span>

Nell'ambuito della fase di training del modello, per valutare l'efficacia utilizziamo  
la midura dell'errore relativamente a:  
1\) il trainset, in genere il 60% dei dati da dare in pasto al modell  
2\) il cross validation set, il 20% dei dati  
3\) il test set, restante 20 %

L'errore relativo al trainset è detto “bias error" che se è alto significa che il modello  
è stato trainito male e quindi bisogna cambiarlo, se è basso puà essere che sia  
in overfitting oppure che vada effettivamente bene

L'errore relativo al cross validation indica quanto si discosta il modello utilizzando  
dei dati che non sono stati utilizzati nella fase di fitting.

La baseling è il riferimento preso da altri modelli diversi da quello che si sta elaborando.

Si possono quindi verificare i seguenti casi:

[![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/scaled-1680-/sSU86DfZuBURqyUM-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/sSU86DfZuBURqyUM-image.png)

Per migliorare il training del modello ci sono alcuni accorgimenti da seguire, di seguito:

[![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/scaled-1680-/Y3YhC0u7IBTZp91s-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/Y3YhC0u7IBTZp91s-image.png)

Nel grafico sottoriportato si può vedere il caso in cui la differenza tra il modello e il riferimento si discosta di molto in peggio, in questo  
caso all'aumentare del numero del trainset la curva tende ad appiattirsi e non miglioare. Il modello quindi ma ba bene

[![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/scaled-1680-/TmjmaYqF6ddj9cdC-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/TmjmaYqF6ddj9cdC-image.png)

Nel caso invece in qui il trainset performi meglio del riferimento, può essere che all'aumentare dei samples l'errore  
di cross validation diminuisca e arriva al livello del riferimento.

[![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/scaled-1680-/m7HwewwaFjWYK8iw-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/m7HwewwaFjWYK8iw-image.png)

In generale trovare bisogna cercare di diminuire i valori di bias e variance attraverso un processo di affinamento  
come sotto rappresentato:

[![image.png](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/scaled-1680-/dm8Q26hYjkddjhqJ-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2022-11/dm8Q26hYjkddjhqJ-image.png)

[![lynTrymo92ZvbyNy-image.png](https://cms.marcocucchi.it/uploads/images/gallery/2023-03/scaled-1680-/1Ww1YfiHEV08eLmT-lyntrymo92zvbyny-image.png)](https://cms.marcocucchi.it/uploads/images/gallery/2023-03/1Ww1YfiHEV08eLmT-lyntrymo92zvbyny-image.png)