Team I.A. Italia

12 min

Reti Neurali con python tutorial completo

Aggiornato il: 4 giu 2022


 
Introduzione alle reti neurali con Python
 
In questo articolo, vedremo come costruire reti neurali con Python e capiremo meglio l'apprendimento profondo creando una spiegazione per le previsioni del modello.
 

Prima della lettura vi consigliamo un bel Caffè


 
Il Deep Learning è un tipo di apprendimento automatico che imita il modo in cui gli umani acquisiscono determinati tipi di conoscenza ed è diventato più popolare nel corso degli anni rispetto ai modelli standard. Mentre gli algoritmi tradizionali sono lineari, i modelli di Deep Learning, generalmente Reti Neurali, sono impilati in una gerarchia di crescente complessità e astrazione (quindi il "profondo" in Deep Learning).

Le reti neurali si basano su un insieme di unità collegate (neuroni), che, proprio come le sinapsi nel cervello, in grado di trasmettere un segnale ad altri neuroni, modo che, comportandosi come le cellule cerebrali interconnesse, possono imparare e prendere decisioni in un modo più umano.


 
Oggi il Deep Learning è così popolare che molte aziende vogliono usarlo anche se non lo comprendono pienamente. Spesso i data scientist devono prima semplificare questi complessi algoritmi per il Business, e poi spiegare e giustificare i risultati dei modelli, cosa non sempre semplice con le Reti Neurali. Penso che il modo migliore per farlo sia attraverso la visualizzazione.


 
Ci siamo presi un po di tempo per creare questo articolo con del codice Python utile che può essere facilmente applicato in altri casi simili (basta copiare, incollare, adattare) e percorrere ogni riga di codice con commenti in modo da poter replicare gli esempi.


 
In particolare, vedremo:

  1. Configurazione dell'ambiente, tensorflow vs pytorch.

  2. Scomposizione delle reti neurali artificiali, input, output, strati nascosti, funzioni di attivazione.

  3. Deep Learning con reti neurali profonde.

  4. Progettazione del modello con tensorflow/keras .

  5. Visualizzazione di reti neurali con Python.

  6. Formazione e test del modello.

  7. Spiegare i modelli con shap.

Scarica GRATUITAMENTE il pdf dell'articolo sulle reti NEURALI e PYTHON

Configurazione ambiente per creare e sviluppare Reti neurali o Modelli di Deep Learning

Esistono due librerie principali per la creazione di reti neurali:

  1. TensorFlow (sviluppato da Google)

  2. PyTorch (sviluppato da Facebook)


 
Queste due librerie sono preferite dalla community e dalle aziende perché possono sfruttare la potenza delle GPU NVIDIA. Ciò è molto utile, e talvolta necessario, per elaborare grandi set di dati come un corpus di testo o una galleria di immagini.


 
Per questo tutorial, useremo TensorFlow e Keras , un modulo di livello superiore molto più intuitivo rispetto a TensorFlow e PyTorch puri , anche se un po' più lenti.


 
Il primo passo è installare TensorFlow tramite il terminale:

pip install tensorflow #python <3
 
pip3 install tensorflow #python >=3
 
!pip install tensorflow #google colab


 
Se vuoi abilitare il supporto GPU, puoi leggere la documentazione ufficiale. Dopo averlo configurato, le tue istruzioni Python verranno tradotte in CUDA dalla tua macchina ed elaborate dalle GPU, quindi i tuoi modelli funzioneranno incredibilmente più velocemente.


 
Ora possiamo importare sul nostro notebook i moduli principali da TensorFlow Keras e iniziare a codificare:

from tensorflow.keras import models, layers, utils, backend as K
 
import matplotlib.pyplot as plt
 
import shap


 
Reti neurali artificiali cosa sono

Le ANN sono costituite da strati con una dimensione di input e una di output. Quest'ultimo è determinato dal numero di neuroni (detti anche “nodi”), un'unità computazionale che collega gli input pesati tramite una funzione di attivazione (che aiuta il neurone ad accendersi/spegnersi). I pesi , come nella maggior parte degli algoritmi di apprendimento automatico, vengono inizializzati e ottimizzati casualmente durante l'addestramento per ridurre al minimo una funzione di perdita.
 
I livelli possono essere raggruppati come:
 

  • Il livello di input ha il compito di passare il vettore di input alla rete neurale. Se abbiamo una matrice di 3 caratteristiche (forma N x 3), questo livello prende 3 numeri come input e passa gli stessi 3 numeri al livello successivo.

  • I livelli nascosti rappresentano i nodi intermedi, applicano diverse trasformazioni ai numeri per migliorare l'accuratezza del risultato finale e l'output è definito dal numero di neuroni.

  • Livello di output che restituisce l'output finale della rete neurale. Se stiamo eseguendo una semplice classificazione binaria o regressione, il livello di output avrà solo 1 neurone (in modo che restituisca solo 1 numero). Nel caso di una classificazione multiclasse con 5 classi diverse, il livello di output deve avere 5 neuroni.

La forma più semplice di ANN è il Perceptron , un modello con un solo strato, molto simile al modello di regressione lineare. Chiedere cosa succede all'interno di un Perceptron equivale a chiedere cosa succede all'interno di un singolo nodo di una Rete Neurale multistrato… scomponiamolo.


 
Supponiamo di avere un set di dati di N righe, 3 funzioni e 1 variabile di destinazione (ovvero 1/0) binario:
 

set di dati di N righe, 3 feature e 1 variabile di target


 

Proprio come in ogni altro caso d'uso di apprendimento automatico, addestreremo un modello per prevedere l'obiettivo utilizzando le funzionalità riga per riga.

Partiamo dalla prima riga


 

 

 
Cosa significa "Creare un modello"?

Cercare dei migliori parametri in una formula matematica che minimizzi l'errore delle tue previsioni. Nei modelli di regressione (es. regressione lineare) bisogna trovare i pesi migliori, nei modelli ad albero (es. random forest) si tratta di trovare i migliori punti di splitting...
 

 

Si inizializzano dei pesi w1, w2, w3


 

Di solito, i pesi vengono inizializzati in modo casuale e quindi modificati man mano che l'apprendimento procede. Qui li imposterò tutti come 1:
 

 

adesso abbiamo semplicemente assegnato a w1,w2,w3 = 1 e successivamente fatto x1*w1 + x2*w2 + x3*w3


 
Finora non abbiamo fatto nulla di diverso da una regressione lineare (che è abbastanza semplice da capire per l'azienda). Ora, passiamo da un modello lineare

Σ( xi*wi )=Y ad uno non lineare f( Σ(xi*wi) )=Y … entra nella funzione di attivazione.
 

 

Ora, passiamo da un modello lineare Σ( xi*wi )=Y ad uno non lineare f( Σ(xi*wi) )=Y


 
La funzione di attivazione definisce l'output di quel nodo. Ce ne sono molte e si possono anche creare alcune funzioni personalizzate, puoi trovare i dettagli nella documentazione ufficiale e dare un'occhiata a questo cheat sheet . Se impostassimo una semplice funzione lineare nel nostro esempio, non avremmo alcuna differenza da un modello di regressione lineare.
 

Funzione identità


 

 
Ma noi invece useremo una funzione di attivazione del passo binario che restituisce solo 1 o 0:

Funzione passo binario


 

 

Mettiamo insieme tutto quello che abbiamo visto fin ora

Abbiamo l'output del nostro Perceptron, una rete neurale a strato singolo che prende alcuni input e restituisce 1 output. Ora l'addestramento del modello continuerebbe confrontando l'output con l'obiettivo, calcolando l'errore e ottimizzando i pesi, ripetendo l'intero processo ancora e ancora.
 

Ecco cosa accade dentro un neurone


 

 
Ed ecco la rappresentazione comune di un neurone:

rappresentazione comune di un neurone


 

 

Reti neurali profonde

Si potrebbe dire che tutti i modelli di Deep Learning sono Reti Neurali ma non tutte le Reti Neurali sono modelli di Deep Learning. In generale, l'apprendimento "profondo" si applica quando l'algoritmo ha almeno 2 livelli nascosti (quindi 4 livelli in totale inclusi input e output).


 
Immagina di replicare il processo del neurone 3 volte contemporaneamente: poiché ogni nodo (somma pesata e funzione di attivazione) restituisce un valore, avremmo il primo strato nascosto con 3 output.
 

 

replicare il processo del neurone 3 volte


 
Ora ripetiamo usando quei 3 output come input per il secondo livello nascosto , che restituisce 3 nuovi numeri. Infine, aggiungeremo un livello di output (solo 1 nodo) per ottenere la previsione finale del nostro modello.
 

3 output come input per il secondo livello nascosto , che restituisce 3 nuovi numeri. Infine, aggiungeremo un livello di output


 
Ricorda che i livelli possono avere un diverso numero di neuroni e una diversa funzione di attivazione, e in ogni nodo vengono allenati dei pesi per ottimizzare il risultato finale. Ecco perché più livelli aggiungi, maggiore è il numero di parametri addestrabili.


 
Ora puoi rivedere il processo completo di una rete neurale, Ti consigliamo di prenderti un paio di minuti e osservare più e più volte.
 

Ora puoi rivedere il processo completo di una rete neurale, Ti consigliamo di prenderti un paio di minuti e osservare più e più volte.


 
Si prega di notare che, per mantenerlo il più semplice possibile, non ho menzionato alcuni dettagli che potrebbero non essere di interesse per il Business, ma di cui uno scienziato dei dati dovrebbe assolutamente essere a conoscenza. In particolare:
 

  • Bias : all'interno di ogni neurone, la combinazione lineare di input e pesi include anche un bias, simile alla costante in un'equazione lineare, quindi la formula completa di un neurone è

f( (Xi * Wi ) + bias )

  • Backpropagation : durante l'addestramento, il modello apprende propagando nuovamente l'errore nei nodi e aggiornando i parametri (pesi e bias) per ridurre al minimo la perdita.

  • Gradient Descent : l'algoritmo di ottimizzazione utilizzato per addestrare le reti neurali che trova il minimo locale della funzione di perdita effettuando ripetuti passaggi nella direzione della discesa più ripida.


 

Progettazione del modello di Deep Learning

Il modo più semplice per costruire una rete neurale con TensorFlow è con la classe Sequential di Keras. Usiamolo per creare il Perceptron del nostro esempio precedente, quindi un modello con un solo strato Denso. È lo strato più elementare in quanto fornisce tutti i suoi input a tutti i neuroni, ciascuno dei quali fornisce un output.

model = models.Sequential(name="Perceptron", layers=[ layers.Dense( #a fully connected layer
 
name="dense",
 
input_dim=3, #with 3 features as the input
 
units=1, #and 1 node because we want 1 output
 
activation='linear' #f(x)=x
 
)
 
])
 
model.summary()

Output codice sopra scritto

La funzione di riepilogo fornisce un'istantanea della struttura e delle dimensioni (in termini di parametri da addestrare). In questo caso, abbiamo solo 4 (3 pesi e 1 inclinazione), quindi è piuttosto leggero.


 
Se vuoi usare una funzione di attivazione che non è già inclusa in Keras , come la funzione di step binario che ho mostrato nell'esempio visivo, devi sporcarti le mani con TensorFlow grezzo :

# definiamo la funzione
 
import tensorflow as tfdef binary_step_activation(x):
 
##return 1 if x>0 else 0
 
return K.switch(x>0, tf.math.divide(x,x), tf.math.multiply(x,0))
 
# build the model
 
model = models.Sequential(name="Perceptron", layers=[
 
layers.Dense(
 
name="dense",
 
input_dim=3,
 
units=1,
 
activation=binary_step_activation
 
)
 
])
 

 


 

 
Ora proviamo a passare dal Perceptron a una rete neurale profonda. Probabilmente ti starai facendo alcune domande:
 

  1. Quanti strati devo usare? La risposta giusta è "provare diverse varianti e vedere cosa funziona". Di solito lavoro con 2 livelli nascosti Dense con Dropout, una tecnica che riduce l'overfitting impostando casualmente gli input a 0. I livelli nascosti sono utili per superare la non linearità dei dati, quindi se non hai bisogno di non linearità puoi evitare strati nascosti. Troppi livelli nascosti porteranno al sovradattamento.

provare diverse varianti e vedere cosa funziona


 

  1. Quanti neuroni? Il numero di neuroni nascosti dovrebbe essere compreso tra la dimensione del livello di input e la dimensione del livello di output. La mia regola pratica è (numero di ingressi + 1 uscita)/2 .

  2. Quale funzione di attivazione? Ce ne sono tanti e non si può dire che uno sia assolutamente migliore. Comunque la più usata è ReLU , una funzione lineare a tratti che restituisce l'output solo se è positivo, ed è usata principalmente per i layer nascosti. Inoltre, il livello di output deve avere un'attivazione compatibile con l'output previsto. Ad esempio, la funzione lineare è adatta per problemi di regressione mentre il Sigmoide è spesso utilizzato per la classificazione.


 

Presumo un set di dati di input di N funzionalità e 1 variabile di destinazione binaria (molto probabilmente un caso d'uso di classificazione).

n_features = 10model = models.Sequential(name="DeepNN", layers=[
 
### hidden layer 1
 
layers.Dense(name="h1", input_dim=n_features,
 
units=int(round((n_features+1)/2)),
 
activation='relu'),
 
layers.Dropout(name="drop1", rate=0.2),
 

 
### hidden layer 2
 
layers.Dense(name="h2", units=int(round((n_features+1)/4)),
 
activation='relu'),
 
layers.Dropout(name="drop2", rate=0.2),
 

 
### layer output
 
layers.Dense(name="output", units=1, activation='sigmoid')
 
])
 
model.summary()


 

Si prega di notare che la classe Sequential non è l'unico modo per costruire una rete neurale con Keras . La classe Model offre maggiore flessibilità e controllo sui livelli e può essere utilizzata per creare modelli più complessi con più input/output. Ci sono due grandi differenze:
 

  • Il layer Input deve essere specificato mentre nella classe Sequential è implicito nella dimensione di input del primo layer Dense.

  • I layer vengono salvati come oggetti e possono essere applicati agli output di altri layer come: output = layer(…)(input)

Ecco come puoi usare la classe Model per costruire il nostro Perceptron e DeepNN:
 

 
# Perceptron
 
inputs = layers.Input(name="input", shape=(3,))
 
outputs = layers.Dense(name="output", units=1,
 
activation='linear')(inputs)
 
model = models.Model(inputs=inputs, outputs=outputs,
 
name="Perceptron")
 
# DeepNN
 
### layer input
 
inputs = layers.Input(name="input", shape=(n_features,))### hidden layer 1
 
h1 = layers.Dense(name="h1", units=int(round((n_features+1)/2)), activation='relu')(inputs)
 
h1 = layers.Dropout(name="drop1", rate=0.2)(h1)### hidden layer 2
 
h2 = layers.Dense(name="h2", units=int(round((n_features+1)/4)), activation='relu')(h1)
 
h2 = layers.Dropout(name="drop2", rate=0.2)(h2)### layer output
 
outputs = layers.Dense(name="output", units=1, activation='sigmoid')(h2)model = models.Model(inputs=inputs, outputs=outputs, name="DeepNN")


 
Si può sempre verificare se il numero di parametri nel riepilogo del modello è lo stesso di quello di Sequential .


 
Visualizzare i modelli di apprendimento profondo

Ricorda, stiamo raccontando una storia al business e la visualizzazione è il nostro miglior alleato. Ho preparato una funzione per tracciare la struttura di una rete neurale artificiale dal suo modello TensorFlow , ecco il codice completo:


 
Proviamolo sui nostri 2 modelli, prima il Perceptron usando questa semplice riga:

visualize_nn (model, description=True, figsize=(10,8))

Visualizzare i modelli di apprendimento profondo

quindi la rete neurale profonda:
 

Visualizzare i modelli di apprendimento profondo


 

 
TensorFlow fornisce anche uno strumento per tracciare la struttura del modello, potresti volerlo usare per reti neurali più complesse con livelli più complicati (CNN, RNN, …). Usando questa riga di codice potrai visualizzare la struttura della rete.


 
utils.plot_model(model, to_file='model.png', show_shapes=True, show_layer_names=True)
 

Come visualizzare la struttura di una rete neurale


 

 
E adesso Vediamo come Allenare e Valutare le nostre reti neurali


 
Infine, è il momento di addestrare il nostro modello di Deep Learning. Affinché possa funzionare, dobbiamo "compilare", o per dirla in un altro modo, dobbiamo definire l' ottimizzatore, la funzione di perdita e le metriche . Di solito uso l' ottimizzatore Adam , un algoritmo di ottimizzazione sostitutivo per la discesa del gradiente (il migliore tra gli ottimizzatori adattivi). Gli altri argomenti dipendono dal caso d'uso.


 
Nei problemi di classificazione (binaria), è necessario utilizzare una perdita di entropia incrociata ( binaria) che confronta ciascuna delle probabilità previste con l'output effettivo della classe. Per quanto riguarda le metriche, mi piace monitorare sia la Precisione che il punteggio F1, una metrica che combina Precisione e Richiamo (quest'ultimo deve essere implementato in quanto non è già incluso in TensorFlow ).


 
# define metriche
 
def Recall(y_true, y_pred):
 
true_positives = K.sum(K.round(K.clip(y_true * y_pred, 0, 1)))
 
possible_positives = K.sum(K.round(K.clip(y_true, 0, 1)))
 
recall = true_positives / (possible_positives + K.epsilon())
 
return recall
 

 
def Precision(y_true, y_pred):
 
true_positives = K.sum(K.round(K.clip(y_true * y_pred, 0, 1)))
 
predicted_positives = K.sum(K.round(K.clip(y_pred, 0, 1)))
 
precision = true_positives / (predicted_positives + K.epsilon())
 
return precision
 

 
def F1(y_true, y_pred):
 
precision = Precision(y_true, y_pred)
 
recall = Recall(y_true, y_pred)
 
return 2*((precision*recall)/(precision+recall+K.epsilon()))
 

 
# compila la rete neurale
 
model.compile(optimizer='adam', loss='binary_crossentropy',
 
metrics=['accuracy',F1])


 
D'altra parte, nei problemi di regressione, di solito imposto il MAE come perdita e R-quadrato come metrica.

# definisci le metriche
 
def R2(y, y_hat):
 
ss_res = K.sum(K.square(y - y_hat))
 
ss_tot = K.sum(K.square(y - K.mean(y)))
 
return ( 1 - ss_res/(ss_tot + K.epsilon()) )
 
# compile the neural network
 
model.compile(optimizer='adam', loss='mean_absolute_error',
 
metrics=[R2])


 
Prima di iniziare l'addestramento, dobbiamo anche decidere le Epoche e i Batch : poiché il set di dati potrebbe essere troppo grande per essere elaborato tutto in una volta, viene suddiviso in batch (maggiore è la dimensione del batch, maggiore è lo spazio di memoria necessario). La backpropagation ed il conseguente aggiornamento dei parametri avviene ad ogni batch. Un'epoca è un passaggio sull'intero set di allenamento. Quindi, se hai 100 osservazioni e la dimensione del batch è 20, ci vorranno 5 batch per completare 1 epoca. La dimensione del batch dovrebbe essere un multiplo di 2 (comune: 32, 64, 128, 256) perché i computer di solito organizzano la memoria con una potenza di 2. Tendo a iniziare con 100 epoche con una dimensione del batch di 32.


 
Durante l'addestramento, ci aspetteremmo di vedere le metriche migliorare e la perdita diminuire epoca per epoca. Inoltre, è buona norma conservare una parte dei dati (20%-30%) per la convalida. In altre parole, il modello metterà da parte questa frazione di dati per valutare la perdita e le metriche alla fine di ogni epoca, al di fuori dell'addestramento.
 
Supponendo che tu abbia i tuoi dati pronti in alcuni array X e y (in caso contrario puoi semplicemente generare dati casuali come


 
import numpy as np
 
X = np.random.rand(1000,10)
 
y = np.random.choice([1,0], size=1000)
 

è possibile avviare e visualizzare la formazione come segue:


 
# train/validation
 
training = model.fit(x=X, y=y, batch_size=32, epochs=100, shuffle=True, verbose=0, validation_split=0.3)
 
# plot
 
metrics = [k for k in training.history.keys() if ("loss" not in k) and ("val" not in k)]
 
fig, ax = plt.subplots(nrows=1, ncols=2, sharey=True, figsize=(15,3))
 

 
## training
 
ax[0].set(title="Training")
 
ax11 = ax[0].twinx()
 
ax[0].plot(training.history['loss'], color='black') ax[0].set_xlabel('Epochs')
 
ax[0].set_ylabel('Loss', color='black')
 
for metric in metrics:
 
ax11.plot(training.history[metric], label=metric) ax11.set_ylabel("Score", color='steelblue')
 
ax11.legend()
 

 
## validation
 
ax[1].set(title="Validation")
 
ax22 = ax[1].twinx()
 
ax[1].plot(training.history['val_loss'], color='black') ax[1].set_xlabel('Epochs')
 
ax[1].set_ylabel('Loss', color='black')
 
for metric in metrics:
 
ax22.plot(training.history['val_'+metric], label=metric) ax22.set_ylabel("Score", color="steelblue")
 
plt.show()


 


 

 
Questi grafici sono presi da due casi d'uso reali che confrontano algoritmi di apprendimento automatico standard con reti neurali.


 
Vediamo ora come Spiegare il nostro Modello


 
Abbiamo addestrato e testato il nostro modello, ma non abbiamo ancora convinto il Business dei risultati… cosa possiamo fare? Facile, costruiamo una spiegazione per mostrare che il nostro modello di Deep Learning non è una scatola nera.


 
Trovo che Shap funzioni molto bene con le Reti Neurali: per ogni previsione, è in grado di stimare il contributo di ogni caratteristica al valore previsto dal modello. Fondamentalmente, risponde alla domanda " perché il modello dice che questo è un 1 e non uno 0? ”.
 
Puoi usare il seguente codice:

def explainer_shap(model, X_names, X_instance, X_train=None, task="classification", top=10):
 

 

 
## create explainer
 
### machine learning
 

 
if X_train is None:
 
explainer=shap.TreeExplainer(model)
 
shap_values=explainer.shap_values(X_instance)
 

 
### deep learning
 

 
else:
 
explainer=shap.DeepExplainer(model, data=X_train[:100])
 
shap_values=explainer.shap_values(X_instance.reshape(1,-1))[0].reshape(-1)
 

 
## plot
 

 
### classification
 

 
if task=="classification":
 
shap.decision_plot(explainer.expected_value, shap_values, link='logit', feature_order='importance',features=X_instance, feature_names=X_names, feature_display_range=slice(-1,-top-1,-1))
 

 
### regression
 
else:
 
shap.waterfall_plot(explainer.expected_value[0], shap_values, features=X_instance, feature_names=X_names, max_display=top)


 
Tieni presente che questa funzione può essere eseguita anche su altri modelli di Machine Learning (ad es. Regressione lineare, foresta casuale), non solo sulle reti neurali. Come puoi leggere dal codice, se l' argomento X_train viene mantenuto come None, la mia funzione presuppone che non sia Deep Learning.


 
Proviamolo sugli esempi di classificazione e regressione:


 
i = 1
 
explainer_shap(model,
 
X_names=list_feature_names,
 
X_instance=X[i],
 
X_train=X,
 
task="classification", #task="regression"
 
top=10)
 

Esempio di classificazione.

Esempio di regressione.

Abbiamo Finito

Scarica GRATUITAMENTE il pdf dell'articolo sulle reti NEURALI e PYTHON


 
Questo articolo è stato un tutorial per dimostrare come progettare e costruire reti neurali artificiali, profonde e non.


 
Nella seconda parte del tutorial, abbiamo utilizzato TensorFlow per creare alcune reti neurali, dal Perceptron a una più complessa. Quindi, abbiamo addestrato il modello di Deep Learning e valutato la sua spiegabilità sia per i casi d'uso di classificazione che di regressione. Speriamo davvero ti sia piaciuto! Commenta o condividi il Post.

Altro sulle reti neurali :

Vuoi mettere in pratica quello che hai letto ?

  1. Scarica Progetti già pronti

  2. Lavora con il nostro editor online senza dover installare librerie

  3. Usa i nostri set di Dati


 

 
Oppure segui i tutorial correlati :