Il deep learning è un sottoinsieme del machine learning ed è un insieme di algoritmi ispirati alla struttura e al funzionamento del cervello.
TensorFlow è il secondo framework di machine learning che Google ha creato e usato per progettare, costruire e addestrare modelli di deep learning. Puoi usare la libreria TensorFlow per fare calcoli numerici, il che di per sé non sembra nulla di speciale, ma questi calcoli vengono eseguiti con grafi di flusso dei dati. In questi grafi, i nodi rappresentano operazioni matematiche, mentre gli archi rappresentano i dati, che di solito sono array di dati multidimensionali o tensori, che vengono comunicati tra questi archi.
Vedi? Il nome “TensorFlow” deriva dalle operazioni che le reti neurali eseguono su array di dati multidimensionali o tensori! È letteralmente un flusso di tensori. Per ora, questo è tutto ciò che ti serve sapere sui tensori, ma andrai più a fondo nelle prossime sezioni!
Il tutorial di oggi su TensorFlow per principianti ti introdurrà al deep learning in modo interattivo:
Per capire bene i tensori, è utile avere un po’ di conoscenze operative di algebra lineare e calcolo vettoriale. Hai già letto nell’introduzione che i tensori sono implementati in TensorFlow come array di dati multidimensionali, ma potrebbe servire un po’ più di introduzione per comprendere a fondo i tensori e il loro uso nel machine learning.
Vettori nel Piano
Prima di entrare nei vettori nel piano, è una buona idea rivedere brevemente il concetto di “vettore”; I vettori sono tipi speciali di matrici, che sono array rettangolari di numeri. Poiché i vettori sono collezioni ordinate di numeri, sono spesso visti come matrici colonna: hanno una sola colonna e un certo numero di righe. In altri termini, puoi anche considerare i vettori come grandezze scalari a cui è stata assegnata una direzione.
Ricorda: un esempio di scalare è “5 metri” o “60 m/sec”, mentre un vettore è, per esempio, “5 metri a nord” o “60 m/sec a est”. La differenza tra i due è ovviamente che il vettore ha una direzione. Tuttavia, questi esempi che hai visto finora potrebbero sembrare lontani dai vettori che potresti incontrare quando lavori con problemi di machine learning. È normale; La lunghezza di un vettore matematico è un numero puro: è assoluta. La direzione, invece, è relativa: è misurata rispetto a una direzione di riferimento e ha unità in radianti o gradi. Di solito si assume che la direzione sia positiva e in rotazione antioraria rispetto alla direzione di riferimento.
Visivamente, ovviamente, rappresenti i vettori come frecce, come puoi vedere nell’immagine sopra. Ciò significa che puoi considerare i vettori anche come frecce che hanno direzione e lunghezza. La direzione è indicata dalla punta della freccia, mentre la lunghezza è indicata dalla lunghezza della freccia.
E i vettori nel piano?
I vettori nel piano sono l’impostazione più diretta dei tensori. Sono molto simili ai vettori “regolari” che hai visto sopra, con la sola differenza che si trovano in uno spazio vettoriale. Per capire meglio, partiamo da un esempio: hai un vettore che è 2 X 1. Questo significa che il vettore appartiene all’insieme dei numeri reali che vengono accoppiati due alla volta. O, detto diversamente, fanno parte del piano bidimensionale. In tali casi, puoi rappresentare i vettori sul piano delle coordinate (x,y) con frecce o semirette.
Lavorando da questo piano di coordinate in posizione standard, dove i vettori hanno l’estremità all’origine (0,0), puoi ricavare la coordinata x guardando la prima riga del vettore, mentre troverai la coordinata y nella seconda riga. Ovviamente, questa posizione standard non deve essere sempre mantenuta: i vettori possono spostarsi parallelamente a se stessi nel piano senza subire cambiamenti.
Nota che, analogamente, per i vettori di dimensione 3 X 1, si parla di spazio tridimensionale. Puoi rappresentare il vettore come una figura tridimensionale con frecce che puntano a posizioni nello spazio del vettore: sono disegnate sugli assi standard x, y e z.
È bello avere questi vettori e rappresentarli sul piano delle coordinate, ma in sostanza li hai per poter eseguire operazioni su di essi e una cosa che può aiutarti a farlo è esprimere i vettori come basi o vettori unitari.
I vettori unitari sono vettori con modulo pari a uno. Spesso riconoscerai il vettore unitario da una lettera minuscola con un circonflesso, o “cappello”. I vettori unitari tornano utili se vuoi esprimere un vettore 2D o 3D come somma di due o tre componenti ortogonali, come gli assi x− e y−, o l’asse z−.
E quando parli di esprimere un vettore, per esempio, come somma di componenti, vedrai che stai parlando di vettori componenti, cioè due o più vettori la cui somma è quel vettore dato.
Consiglio: guarda questo video, che spiega cosa sono i tensori con l’aiuto di semplici oggetti domestici!
Tensori
Oltre ai vettori nel piano, anche covettori e operatori lineari sono altri due casi che hanno tutti e tre una cosa in comune: sono casi specifici di tensori. Ricordi ancora come un vettore è stato caratterizzato nella sezione precedente come grandezze scalari a cui è stata data una direzione. Un tensore, quindi, è la rappresentazione matematica di un’entità fisica che può essere caratterizzata da un modulo e da più direzioni.
E, proprio come rappresenti uno scalare con un singolo numero e un vettore con una sequenza di tre numeri in uno spazio tridimensionale, per esempio, un tensore può essere rappresentato da un array di 3^R numeri in uno spazio tridimensionale.
La “R” in questa notazione rappresenta il rango del tensore: ciò significa che in uno spazio tridimensionale, un tensore di rango 2 può essere rappresentato da 3 alla potenza di 2, cioè 9 numeri. In uno spazio N-dimensionale, gli scalari richiederanno ancora un solo numero, i vettori richiederanno N numeri e i tensori richiederanno N^R numeri. Questo spiega perché spesso senti dire che gli scalari sono tensori di rango 0: poiché non hanno direzione, puoi rappresentarli con un numero.
Con questo in mente, è relativamente facile riconoscere scalari, vettori e tensori e distinguerli: gli scalari possono essere rappresentati da un singolo numero, i vettori da un insieme ordinato di numeri e i tensori da un array di numeri.
Ciò che rende i tensori così unici è la combinazione di componenti e vettori di base: i vettori di base si trasformano in un certo modo tra sistemi di riferimento e le componenti si trasformano in modo tale da mantenere invariata la combinazione tra componenti e vettori di base.
Installare TensorFlow
Ora che sai di più su TensorFlow, è il momento di iniziare e installare la libreria. Qui è utile sapere che TensorFlow fornisce API per Python, C++, Haskell, Java, Go, Rust, e c’è anche un pacchetto di terze parti per R chiamato tensorflow.
Consiglio: se vuoi saperne di più sui pacchetti di deep learning in R, considera di dare un’occhiata al tutorial keras: Deep Learning in R di DataCamp.
In questo tutorial, scaricherai una versione di TensorFlow che ti permetterà di scrivere il codice per il tuo progetto di deep learning in Python. Nella pagina di installazione di TensorFlow troverai alcuni dei modi più comuni e le istruzioni più recenti per installare TensorFlow usando virtualenv, pip, Docker e, infine, anche altri modi per installare TensorFlow sul tuo computer personale.
Nota Puoi anche installare TensorFlow con Conda se lavori su Windows. Tuttavia, poiché l’installazione di TensorFlow è supportata dalla community, è meglio controllare le istruzioni ufficiali di installazione.
Ora che hai completato il processo di installazione, è il momento di verificare che TensorFlow sia stato installato correttamente importandolo nel tuo workspace con l’alias tf:
Nota che l’alias che hai usato nella riga di codice sopra è una sorta di convenzione: serve a garantirti di rimanere coerente con altri sviluppatori che usano TensorFlow nei progetti di data science da un lato e con i progetti open-source TensorFlow dall’altro.
Primi Passi con TensorFlow: le Basi
In genere scriverai programmi TensorFlow, che eseguirai come blocchi; A prima vista questo è un po’ contraddittorio quando lavori con Python. Tuttavia, se vuoi, puoi anche usare l’Interactive Session di TensorFlow, che puoi utilizzare per lavorare in modo più interattivo con la libreria. Questo è particolarmente comodo se sei abituato a lavorare con IPython.
Per questo tutorial, ti concentrerai sulla seconda opzione: ti aiuterà a partire con il deep learning in TensorFlow. Ma prima di andare oltre, proviamo alcune cose semplici prima di passare ai pesi massimi.
Per prima cosa, importa la libreria tensorflow con l’alias tf, come visto nella sezione precedente. Poi inizializza due variabili che in realtà sono costanti. Passa un array di quattro numeri alla funzione constant().
Nota che potresti anche passare un intero, ma più spesso ti troverai a lavorare con array. Come hai visto nell’introduzione, i tensori riguardano gli array! Quindi assicurati di passare un array :) Successivamente, puoi usare multiply() per moltiplicare le due variabili. Memorizza il risultato nella variabile result. Infine, stampa result con la funzione print().
# Import `tensorflow`
import tensorflow as tf
# Initialize two constants
x1 = tf.constant([1,2,3,4])
x2 = tf.constant([5,6,7,8])
# Multiply
result = tf.multiply(x1, x2)
# Print the result
print(result)
Nota che nel blocco di codice DataCamp Light sopra hai definito delle costanti. Tuttavia, ci sono altri due tipi di valori che puoi potenzialmente usare, ovvero i placeholder, che sono valori non assegnati e che verranno inizializzati dalla sessione quando la esegui. Come suggerisce il nome, è solo un segnaposto per un tensore che verrà sempre alimentato quando la sessione viene eseguita; Ci sono anche le Variable, che sono valori che possono cambiare. Le costanti, come avrai già capito, sono valori che non cambiano.
Il risultato delle righe di codice è un tensore astratto nel grafo di calcolo. Tuttavia, contrariamente a quanto potresti aspettarti, il result non viene effettivamente calcolato. Definisce solo il modello, ma non è stato eseguito alcun processo per calcolare il risultato. Lo vedi nella stampa a video: non c’è davvero il risultato che vuoi vedere (cioè, 30). Questo significa che TensorFlow ha una valutazione “pigra”!
Tuttavia, se vuoi vedere il risultato, devi eseguire questo codice in una sessione interattiva. Puoi farlo in vari modi, come mostrato nei blocchi DataCamp Light qui sotto:
# Import `tensorflow`
import tensorflow as tf
# Initialize two constants
x1 = tf.constant([1,2,3,4])
x2 = tf.constant([5,6,7,8])
# Multiply
result = tf.multiply(x1, x2)
# Intialize the Session
sess = tf.Session()
# Print the result
print(sess.run(result))
# Close the session
sess.close()
Nota che puoi anche usare le seguenti righe di codice per avviare una Sessione interattiva, eseguire result e chiudere automaticamente la Sessione dopo aver stampato output:
# Import `tensorflow`
import tensorflow as tf
# Initialize two constants
x1 = tf.constant([1,2,3,4])
x2 = tf.constant([5,6,7,8])
# Multiply
result = tf.multiply(x1, x2)
# Initialize Session and run `result`
with tf.Session() as sess:
output = sess.run(result)
print(output)
Nei blocchi di codice sopra hai appena definito una Sessione di default, ma è anche utile sapere che puoi passare anche delle opzioni. Puoi, per esempio, specificare l’argomento config e poi usare il protocol buffer ConfigProto per aggiungere opzioni di configurazione per la tua sessione.
Per esempio, se aggiungi
config=tf.ConfigProto(log_device_placement=True)Offerto da
alla tua Sessione, fai in modo di registrare il dispositivo GPU o CPU assegnato a un’operazione. Otterrai quindi informazioni su quali dispositivi sono usati nella sessione per ogni operazione. Potresti usare anche la seguente configurazione di sessione, per esempio, quando usi vincoli soft per il posizionamento dei device:
config=tf.ConfigProto(allow_soft_placement=True)Offerto da
Ora che hai installato e importato TensorFlow nel tuo workspace e hai visto le basi per lavorare con questo pacchetto, è il momento di mettere da parte per un attimo tutto questo e concentrarti sui dati. Come sempre, prima ti prenderai il tempo di esplorare e capire meglio i tuoi dati prima di iniziare a modellare la rete neurale.
Segnali Stradali Belgi: Contesto
Anche se il tema del traffico è generalmente noto a tutti voi, non fa male rivedere brevemente le osservazioni incluse in questo dataset per verificare di aver capito tutto prima di iniziare. In sostanza, in questa sezione, acquisirai la conoscenza del dominio necessaria per proseguire con questo tutorial.
Ovviamente, dato che sono belga, mi assicurerò che ti arrivino anche alcune chicche :)
I segnali stradali belgi sono di solito in olandese e francese. È utile saperlo, ma per il dataset con cui lavorerai non è troppo importante!
In Belgio ci sono sei categorie di segnali stradali: segnali di pericolo, di precedenza, di divieto, di obbligo, segnali relativi alla sosta e alla fermata sulla strada e, infine, segnali di indicazione.
Il 1° gennaio 2017, più di 30.000 segnali stradali sono stati rimossi dalle strade belghe. Erano tutti segnali di divieto relativi alla velocità.
Parlando di rimozioni, l’onnipresenza dei segnali stradali è stata un tema di discussione costante in Belgio (e, per estensione, in tutta l’Unione Europea).
Caricamento ed Esplorazione dei Dati
Ora che hai raccolto qualche informazione di contesto in più, è il momento di scaricare il dataset qui. Dovresti ottenere i due file zip elencati accanto a "BelgiumTS for Classification (cropped images)", che si chiamano "BelgiumTSC_Training" e "BelgiumTSC_Testing".
Consiglio: se hai scaricato i file o lo farai dopo aver completato questo tutorial, dai un’occhiata alla struttura delle cartelle dei dati che hai scaricato! Vedrai che le cartelle dei dati di test e di training contengono 61 sottocartelle, che sono i 62 tipi di segnali stradali che userai per la classificazione in questo tutorial. Inoltre, scoprirai che i file hanno estensione .ppm, cioè Portable Pixmap Format. Hai scaricato immagini dei segnali stradali!
Iniziamo a importare i dati nel tuo workspace. Partiamo dalle righe di codice che appaiono sotto la funzione definita dall’utente (UDF) load_data():
Per prima cosa, imposta il tuo ROOT_PATH. Questo percorso è quello in cui hai creato la directory con i tuoi dati di training e test.
Poi puoi aggiungere i percorsi specifici al tuo ROOT_PATH con l’aiuto della funzione join(). Memorizzi questi due percorsi specifici in train_data_directory e test_data_directory.
Vedrai che poi puoi chiamare la funzione load_data() e passarle train_data_directory.
Ora, la funzione load_data() inizia raccogliendo tutte le sottodirectory presenti in train_data_directory; Lo fa con l’aiuto della list comprehension, che è un modo piuttosto naturale di costruire liste: in pratica dice che, se trovi qualcosa in train_data_directory, controllerai due volte se è una directory e, se lo è, la aggiungerai alla tua lista. Ricorda che ogni sottodirectory rappresenta un’etichetta.
Poi devi ciclare attraverso le sottodirectory. Per prima cosa inizializzi due liste, labels e images. Quindi raccogli i percorsi delle sottodirectory e i nomi dei file delle immagini memorizzate in queste sottodirectory. Successivamente, puoi raccogliere i dati nelle due liste con la funzione append().
defload_data(data_directory):
directories =[d for d in os.listdir(data_directory)if os.path.isdir(os.path.join(data_directory, d))]
labels =[]
images =[]for d in directories:
label_directory = os.path.join(data_directory, d)
file_names =[os.path.join(label_directory, f)for f in os.listdir(label_directory)if f.endswith(".ppm")]for f in file_names:
images.append(skimage.data.imread(f))
labels.append(int(d))return images, labels
ROOT_PATH ="/your/root/path"
train_data_directory = os.path.join(ROOT_PATH,"TrafficSigns/Training")
test_data_directory = os.path.join(ROOT_PATH,"TrafficSigns/Testing")
images, labels = load_data(train_data_directory)Offerto da
Nota che nel blocco di codice sopra, i dati di training e di test si trovano in cartelle chiamate "Training" e "Testing", che sono entrambe sottodirectory di un’altra directory "TrafficSigns". Su una macchina locale, potrebbe apparire come "/Users/Name/Downloads/TrafficSigns", con due sottocartelle chiamate "Training" e "Testing".
Con i dati caricati, è il momento di un po’ di ispezione! Puoi iniziare con un’analisi piuttosto semplice con l’aiuto degli attributi ndim e size dell’array images:
Nota che le variabili images e labels sono liste, quindi potresti dover usare np.array() per convertire le variabili in un array nel tuo workspace. Qui è già stato fatto per te!
# Print the `images` dimensions
print(images.ndim)
# Print the number of `images`'s elements
print(images.size)
# Print the first instance of `images`
images[0]
Nota che images[0] che hai stampato è in realtà una singola immagine rappresentata da array in array! Questo può sembrare controintuitivo all’inizio, ma è qualcosa a cui ti abituerai man mano che andrai avanti a lavorare con immagini in applicazioni di machine learning o deep learning.
Poi, puoi anche dare un’occhiata a labels, ma a questo punto non dovresti vedere troppe sorprese:
# Print the `labels` dimensions
print(labels.ndim)
# Print the number of `labels`'s elements
print(labels.size)
# Count the number of labels
print(len(set(labels)))
Questi numeri ti danno già qualche informazione su quanto è andato a buon fine l’import e sulla dimensione esatta dei dati. A prima vista, tutto è stato eseguito come ti aspettavi, e vedi che la dimensione dell’array è considerevole se consideri che stai trattando con array annidati.
Consiglio prova ad aggiungere i seguenti attributi ai tuoi array per ottenere più informazioni sul layout della memoria, sulla lunghezza in byte di un elemento dell’array e sul totale di byte consumati dagli elementi dell’array con gli attributi flags, itemsize e nbytes. Puoi testarlo nella console IPython nel blocco DataCamp Light sopra!
Poi puoi anche dare un’occhiata alla distribuzione dei segnali stradali:
# Import the `pyplot` module
import matplotlib.pyplot as plt
# Make a histogram with 62 bins of the `labels` data
plt.hist(labels, 62)
# Show the plot
plt.show()
Ottimo lavoro! Ora diamo uno sguardo più da vicino all’istogramma che hai creato!
Si vede chiaramente che non tutti i tipi di segnali stradali sono rappresentati allo stesso modo nel dataset. È qualcosa con cui ti confronterai più avanti quando manipolerai i dati prima di iniziare a modellare la tua rete neurale.
A prima vista, vedi che ci sono etichette più presenti nel dataset rispetto ad altre: le etichette 22, 32, 38 e 61 saltano sicuramente all’occhio. Al momento, è utile tenerlo a mente, ma approfondirai sicuramente nella prossima sezione!
Visualizzare i Segnali Stradali
Le piccole analisi o verifiche precedenti ti hanno già dato un’idea dei dati con cui stai lavorando, ma quando i tuoi dati consistono per lo più di immagini, il passo che dovresti fare per esplorarli è visualizzarli.
Diamo un’occhiata ad alcuni segnali stradali a caso:
Innanzitutto, assicurati di importare il modulo pyplot del pacchetto matplotlib con il comune alias plt.
Quindi, creerai una lista con 4 numeri casuali. Questi verranno usati per selezionare segnali stradali dall’array images che hai appena ispezionato nella sezione precedente. In questo caso, scegli 300, 2250, 3650 e 4000.
Poi dirai che per ogni elemento nella lunghezza di quella lista, quindi da 0 a 4, creerai dei subplot senza assi (così non rubano la scena e l’attenzione è solo sulle immagini!). In questi subplot, mostrerai un’immagine specifica dall’array images in accordo con il numero all’indice i. Nel primo ciclo, passerai 300 a images[], nel secondo 2250, e così via. Infine, regolerai i subplot in modo che ci sia abbastanza spazio in larghezza tra di loro.
L’ultima cosa che resta è mostrare il grafico con la funzione show()!
Ecco fatto:
# Import the `pyplot` module of `matplotlib`import matplotlib.pyplot as plt
# Determine the (random) indexes of the images that you want to see
traffic_signs =[300,2250,3650,4000]# Fill out the subplots with the random images that you defined for i inrange(len(traffic_signs)):
plt.subplot(1,4, i+1)
plt.axis('off')
plt.imshow(images[traffic_signs[i]])
plt.subplots_adjust(wspace=0.5)
plt.show()Offerto da
Come avrai intuito dalle 62 etichette incluse nel dataset, i segnali sono diversi tra loro.
Cos’altro noti? Dai un’altra occhiata ravvicinata alle immagini qui sotto:
Queste quattro immagini non hanno la stessa dimensione!
Puoi ovviamente giocare con i numeri contenuti nella lista traffic_signs e approfondire questa osservazione, ma ciò non toglie che questa è un’osservazione importante di cui dovrai tenere conto quando inizierai a manipolare i dati in modo da poterli dare in pasto alla rete neurale.
Confermiamo l’ipotesi delle dimensioni differenti stampando la forma, i valori minimi e massimi delle immagini specifiche che hai incluso nei subplot.
Il codice qui sotto somiglia molto a quello che hai usato per creare il grafico sopra, ma differisce per il fatto che qui alternerai dimensioni e immagini invece di tracciare solo le immagini una accanto all’altra:
# Import `matplotlib`import matplotlib.pyplot as plt
# Determine the (random) indexes of the images
traffic_signs =[300,2250,3650,4000]# Fill out the subplots with the random images and add shape, min and max valuesfor i inrange(len(traffic_signs)):
plt.subplot(1,4, i+1)
plt.axis('off')
plt.imshow(images[traffic_signs[i]])
plt.subplots_adjust(wspace=0.5)
plt.show()print("shape: {0}, min: {1}, max: {2}".format(images[traffic_signs[i]].shape,
images[traffic_signs[i]].min(),
images[traffic_signs[i]].max()))Offerto da
Nota come usi il metodo format() sulla stringa "shape: {0}, min: {1}, max: {2}" per riempire gli argomenti {0}, {1} e {2} che hai definito.
Ora che hai visto immagini singole, potresti anche voler rivedere l’istogramma stampato nei primi passi dell’esplorazione dei dati; Puoi farlo facilmente tracciando una panoramica di tutte le 62 classi e un’immagine appartenente a ciascuna classe:
# Import the `pyplot` module as `plt`import matplotlib.pyplot as plt
# Get the unique labels
unique_labels =set(labels)# Initialize the figure
plt.figure(figsize=(15,15))# Set a counter
i =1# For each unique label,for label in unique_labels:# You pick the first image for each label
image = images[labels.index(label)]# Define 64 subplots
plt.subplot(8,8, i)# Don't include axes
plt.axis('off')# Add a title to each subplot
plt.title("Label {0} ({1})".format(label, labels.count(label)))# Add 1 to the counter
i +=1# And you plot this first image
plt.imshow(image)# Show the plot
plt.show()Offerto da
Nota che anche se definisci 64 subplot, non tutti mostreranno immagini (dato che ci sono solo 62 etichette!). Nota anche che, ancora una volta, non includi assi per assicurarti che l’attenzione dei lettori non si allontani troppo dall’argomento principale: i segnali stradali!
Come avevi in gran parte ipotizzato nell’istogramma sopra, ci sono sensibilmente più segnali stradali con etichette 22, 32, 38 e 61. Questa ipotesi è ora confermata in questo grafico: vedi che ci sono 375 istanze con etichetta 22, 316 con etichetta 32, 285 con etichetta 38 e, infine, 282 con etichetta 61.
Una delle domande più interessanti che potresti porti ora è se c’è una connessione tra tutte queste istanze: magari sono tutte segnali di indicazione?
Diamo uno sguardo più da vicino: vedi che le etichette 22 e 32 sono segnali di divieto, ma che le etichette 38 e 61 sono rispettivamente di indicazione e di precedenza. Questo significa che non c’è una connessione immediata tra queste quattro, a parte il fatto che metà dei segnali con una presenza sostanziale nel dataset sono di tipo proibitivo.
Estrazione delle Caratteristiche
Ora che hai esplorato a fondo i tuoi dati, è il momento di sporcarti le mani! Ricapitoliamo brevemente cosa hai scoperto per assicurarci di non dimenticare alcun passaggio nella manipolazione:
Le dimensioni delle immagini erano disuguali;
Ci sono 62 etichette o valori target (le etichette partono da 0 e finiscono a 61);
La distribuzione dei valori dei segnali stradali è piuttosto diseguale; Non c’era una vera connessione tra i segnali molto presenti nel dataset.
Ora che hai un’idea chiara di cosa migliorare, puoi iniziare a manipolare i tuoi dati in modo che siano pronti per essere alimentati alla rete neurale o a qualsiasi altro modello tu voglia utilizzare. Iniziamo con l’estrazione di alcune feature: ridimensionerai le immagini e convertirai in scala di grigi le immagini contenute nell’array images. Effettuerai questa conversione di colore principalmente perché il colore conta meno in domande di classificazione come quella a cui stai cercando di rispondere ora. Per il riconoscimento, però, il colore ha un ruolo importante! In quei casi, non è necessario fare questa conversione!
Ridimensionamento delle Immagini
Per affrontare le diverse dimensioni, ridimensionerai le immagini; Puoi farlo facilmente con l’aiuto della libreria skimage o Scikit-Image, che è una raccolta di algoritmi per l’elaborazione di immagini.
In questo caso, il modulo transform tornerà utile, poiché offre la funzione resize(); Vedrai che userai ancora una volta la list comprehension per ridimensionare ogni immagine a 28 per 28 pixel. Ancora una volta, vedi com’è formata la lista: per ogni immagine che trovi nell’array images, eseguirai l’operazione di trasformazione presa in prestito dalla libreria skimage. Infine, memorizzerai il risultato nella variabile images28:
# Import the `transform` module from `skimage`from skimage import transform
# Rescale the images in the `images` array
images28 =[transform.resize(image,(28,28))for image in images]Offerto da
È stato abbastanza facile, vero?
Nota che le immagini ora sono quadridimensionali: se converti images28 in un array e ci concateni l’attributo shape, vedrai che la stampa indica che le dimensioni di images28 sono (4575, 28, 28, 3). Le immagini sono a 784 dimensioni (perché sono 28 per 28 pixel).
Puoi verificare il risultato del ridimensionamento riutilizzando il codice che hai usato sopra per tracciare le 4 immagini casuali con l’aiuto della variabile traffic_signs. Non dimenticare solo di cambiare tutti i riferimenti da images a images28.
Guarda il risultato qui:
Nota che, avendo ridimensionato, i valori min e max sono cambiati; Sembrano essere tutti negli stessi intervalli ora, il che è ottimo perché così non è necessariamente necessario normalizzare i dati!
Conversione in Scala di Grigi
Come detto nell’introduzione a questa sezione del tutorial, il colore nelle immagini conta meno quando stai cercando di rispondere a una domanda di classificazione. Ecco perché ti prenderai anche la briga di convertire le immagini in scala di grigi.
Nota, tuttavia, che puoi anche testare in autonomia cosa succederebbe ai risultati finali del tuo modello se non portassi a termine questo specifico passaggio.
Proprio come per il ridimensionamento, puoi contare di nuovo sulla libreria Scikit-Image per darti una mano; In questo caso, è il modulo color con la sua funzione rgb2gray() che devi usare per arrivare dove ti serve.
Sarà semplice e veloce!
Non dimenticare, però, di convertire la variabile images28 di nuovo in un array, poiché la funzione rgb2gray() si aspetta un array come argomento.
# Import `rgb2gray` from `skimage.color`from skimage.color import rgb2gray
# Convert `images28` to an array
images28 = np.array(images28)# Convert `images28` to grayscale
images28 = rgb2gray(images28)Offerto da
Ricontrolla il risultato della conversione in scala di grigi tracciando alcune delle immagini; Qui puoi di nuovo riutilizzare e adattare leggermente parte del codice per mostrare le immagini modificate:
import matplotlib.pyplot as plt
traffic_signs =[300,2250,3650,4000]for i inrange(len(traffic_signs)):
plt.subplot(1,4, i+1)
plt.axis('off')
plt.imshow(images28[traffic_signs[i]], cmap="gray")
plt.subplots_adjust(wspace=0.5)# Show the plot
plt.show()Offerto da
Nota che devi effettivamente specificare la mappa dei colori, o cmap, impostandola su "gray" per tracciare le immagini in scala di grigi. Questo perché imshow() usa di default, beh, una mappa di colori simile a una heatmap. Leggi di più qui.
Consiglio: dato che hai riutilizzato parecchio questa funzione nel tutorial, potresti valutare come trasformarla in una funzione :)
Questi due passaggi sono molto basilari; Altre operazioni che potresti provare sui tuoi dati includono data augmentation (rotazione, sfocatura, traslazione, variazione di luminosità, …). Se vuoi, potresti anche impostare un’intera pipeline di operazioni di manipolazione dati attraverso cui far passare le immagini.
Deep Learning con TensorFlow
Ora che hai esplorato e manipolato i tuoi dati, è il momento di costruire l’architettura della tua rete neurale con l’aiuto del pacchetto TensorFlow!
Progettare la Rete Neurale
Proprio come potresti aver fatto con Keras, è il momento di costruire la tua rete neurale, layer per layer.
Se non l’hai già fatto, importa tensorflow nel tuo workspace con il consueto alias tf. Quindi, puoi inizializzare il Grafo con Graph(). Usi questa funzione per definire il calcolo. Nota che con il Grafo non calcoli nulla, perché non contiene valori. Definisce solo le operazioni che vuoi eseguire più tardi.
In questo caso, imposti un contesto di default con as_default(), che restituisce un context manager che rende questo specifico Grafo il grafo di default. Usi questo metodo se vuoi creare più grafi nello stesso processo: con questa funzione, hai un grafo di default globale a cui verranno aggiunte tutte le operazioni se non crei esplicitamente un nuovo grafo.
Ora sei pronto per aggiungere operazioni al grafo. Come potresti ricordare lavorando con Keras, costruisci il modello e poi, compilando, definisci una funzione di loss, un ottimizzatore e una metrica. Ora tutto questo avviene in un unico passaggio quando lavori con TensorFlow:
Per prima cosa, definisci i placeholder per input ed etichette perché non inserirai ancora i dati “reali”. Ricorda che i placeholder sono valori non assegnati che verranno inizializzati dalla sessione quando la esegui. Quindi quando finalmente eseguirai la sessione, questi placeholder riceveranno i valori del tuo dataset che passi alla funzione run()!
Poi costruisci la rete. Inizi appiattendo l’input con flatten(), che ti darà un array di forma [None, 784] invece di [None, 28, 28], che è la forma delle immagini in scala di grigi.
Dopo aver appiattito l’input, costruisci un layer completamente connesso che genera logits di dimensione [None, 62]. I logits sono la funzione che opera sull’output non scalato dei layer precedenti e che usa la scala relativa per capire che le unità sono lineari.
Con il percettrone multistrato costruito, puoi definire la funzione di loss. La scelta della loss dipende dal compito: in questo caso, usi
sparse_softmax_cross_entropy_with_logits()Offerto da
Questa calcola l’entropia incrociata softmax sparsa tra logits ed etichette. In altre parole, misura l’errore di probabilità in compiti di classificazione discreta in cui le classi si escludono a vicenda. Questo significa che ogni voce appartiene esattamente a una classe. Qui, un segnale stradale può avere una sola etichetta. Ricorda che, mentre la regressione è usata per prevedere valori continui, la classificazione è usata per prevedere valori discreti o classi di punti dati. Incapsuli questa funzione con reduce_mean(), che calcola la media degli elementi sulle dimensioni di un tensore.
Vuoi anche definire un ottimizzatore di training; Alcuni degli algoritmi di ottimizzazione più popolari sono lo Stochastic Gradient Descent (SGD), ADAM e RMSprop. A seconda dell’algoritmo che scegli, dovrai tarare alcuni parametri, come il learning rate o il momentum. In questo caso, scegli l’ottimizzatore ADAM, per cui imposti il learning rate a 0.001.
Infine, inizializzi le operazioni da eseguire prima di passare all’addestramento.
# Import `tensorflow` import tensorflow as tf
# Initialize placeholders
x = tf.placeholder(dtype = tf.float32, shape =[None,28,28])
y = tf.placeholder(dtype = tf.int32, shape =[None])# Flatten the input data
images_flat = tf.contrib.layers.flatten(x)# Fully connected layer
logits = tf.contrib.layers.fully_connected(images_flat,62, tf.nn.relu)# Define a loss function
loss = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(labels = y,
logits = logits))# Define an optimizer
train_op = tf.train.AdamOptimizer(learning_rate=0.001).minimize(loss)# Convert logits to label indexes
correct_pred = tf.argmax(logits,1)# Define an accuracy metric
accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))Offerto da
Hai appena creato con successo la tua prima rete neurale con TensorFlow!
Se vuoi, puoi anche stampare i valori di (quasi) tutte le variabili per un rapido riepilogo o controllo di ciò che hai appena codificato:
print("images_flat: ", images_flat)print("logits: ", logits)print("loss: ", loss)print("predicted_labels: ", correct_pred)Offerto da
Consiglio: se vedi un errore come “module 'pandas' has no attribute 'computation'”, valuta di aggiornare il pacchetto dask eseguendo pip install --upgrade dask dalla riga di comando. Vedi questo post su StackOverflow per maggiori informazioni.
Esecuzione della Rete Neurale
Ora che hai costruito il modello layer per layer, è il momento di eseguirlo! Per farlo, devi prima inizializzare una sessione con Session() a cui puoi passare il tuo graph definito nella sezione precedente. Poi puoi eseguire la sessione con run(), a cui passi le operazioni inizializzate sotto forma della variabile init che hai definito nella sezione precedente.
Poi puoi usare questa sessione inizializzata per avviare epoche o cicli di training. In questo caso, scegli 201 perché vuoi poter registrare l’ultimo loss_value; Nel ciclo, esegui la sessione con l’ottimizzatore di training e la metrica di loss (o di accuratezza) definita nella sezione precedente. Passi anche un argomento feed_dict, con cui alimenti i dati al modello. Ogni 10 epoche, otterrai un log che ti dà più informazioni sulla loss o sul costo del modello.
Come hai visto nella sezione sulle basi di TensorFlow, non è necessario chiudere manualmente la sessione; viene fatto per te. Tuttavia, se vuoi provare una configurazione diversa, probabilmente dovrai farlo con sess.close() se hai definito la tua sessione come sess, come nel blocco di codice seguente:
tf.set_random_seed(1234)
sess = tf.Session()
sess.run(tf.global_variables_initializer())for i inrange(201):print('EPOCH', i)
_, accuracy_val = sess.run([train_op, accuracy], feed_dict={x: images28, y: labels})if i %10==0:print("Loss: ", loss)print('DONE WITH EPOCH')Offerto da
Ricorda che puoi anche eseguire il seguente pezzo di codice, ma quello chiuderà immediatamente la sessione dopo, proprio come visto nell’introduzione di questo tutorial:
tf.set_random_seed(1234)with tf.Session()as sess:
sess.run(tf.global_variables_initializer())for i inrange(201):
_, loss_value = sess.run([train_op, loss], feed_dict={x: images28, y: labels})if i %10==0:print("Loss: ", loss)Offerto da
Nota che usi global_variables_initializer() perché la funzione initialize_all_variables() è deprecata.
Hai ora addestrato con successo il tuo modello! Non è stato poi così difficile, vero?
Valutare la tua Rete Neurale
Non ci sei ancora del tutto; Devi ancora valutare la tua rete neurale. In questo caso, puoi già provare a dare un’occhiata a quanto bene si comporta il tuo modello scegliendo 10 immagini casuali e confrontando le etichette previste con quelle reali.
Puoi prima stamparle, ma perché non usare matplotlib per tracciare i segnali stradali stessi e fare un confronto visivo?
# Import `matplotlib`import matplotlib.pyplot as plt
import random
# Pick 10 random images
sample_indexes = random.sample(range(len(images28)),10)
sample_images =[images28[i]for i in sample_indexes]
sample_labels =[labels[i]for i in sample_indexes]# Run the "correct_pred" operation
predicted = sess.run([correct_pred], feed_dict={x: sample_images})[0]# Print the real and predicted labelsprint(sample_labels)print(predicted)# Display the predictions and the ground truth visually.
fig = plt.figure(figsize=(10,10))for i inrange(len(sample_images)):
truth = sample_labels[i]
prediction = predicted[i]
plt.subplot(5,2,1+i)
plt.axis('off')
color='green'if truth == prediction else'red'
plt.text(40,10,"Truth: {0}\nPrediction: {1}".format(truth, prediction),
fontsize=12, color=color)
plt.imshow(sample_images[i], cmap="gray")
plt.show()Offerto da
Tuttavia, guardare solo immagini casuali non ti dà molte informazioni su quanto bene il tuo modello si comporti davvero. Ecco perché caricherai i dati di test.
Nota che usi la funzione load_data(), che hai definito all’inizio di questo tutorial.
# Import `skimage`from skimage import transform
# Load the test data
test_images, test_labels = load_data(test_data_directory)# Transform the images to 28 by 28 pixels
test_images28 =[transform.resize(image,(28,28))for image in test_images]# Convert to grayscalefrom skimage.color import rgb2gray
test_images28 = rgb2gray(np.array(test_images28))# Run predictions against the full test set.
predicted = sess.run([correct_pred], feed_dict={x: test_images28})[0]# Calculate correct matches
match_count =sum([int(y == y_)for y, y_ inzip(test_labels, predicted)])# Calculate the accuracy
accuracy = match_count /len(test_labels)# Print the accuracyprint("Accuracy: {:.3f}".format(accuracy))Offerto da
Ricorda di chiudere la sessione con sess.close() nel caso in cui tu non abbia usato with tf.Session() as sess: per avviare la tua sessione TensorFlow.
Dove Andare Dopo?
Se vuoi continuare a lavorare con questo dataset e il modello che hai messo insieme in questo tutorial, prova le seguenti cose:
Applica una LDA regolarizzata sui dati prima di alimentarli al tuo modello. È un suggerimento che arriva da uno degli articoli originali, scritto dai ricercatori che hanno raccolto e analizzato questo dataset.
Puoi anche, come detto nel tutorial stesso, dare un’occhiata ad altre operazioni di data augmentation che puoi eseguire sulle immagini dei segnali stradali. Inoltre, potresti anche provare a perfezionare ulteriormente questa rete; Quella che hai creato ora era piuttosto semplice.
Early stopping: tieni traccia dell’errore di training e di testing mentre addestri la rete neurale. Interrompi l’addestramento quando entrambi gli errori scendono e poi improvvisamente risalgono: è un segno che la rete neurale ha iniziato a overfittare i dati di training.
Se vuoi continuare a lavorare con le immagini, dai sicuramente un’occhiata al tutorial su scikit-learn di DataCamp, che affronta il dataset MNIST con l’aiuto di PCA, K-Means e Support Vector Machines (SVM). Oppure dai un’occhiata ad altri tutorial come questo che usa il dataset dei segnali stradali belgi.
Scopri i 15 migliori server MCP remoti che stanno trasformando lo sviluppo AI nel 2026. Scopri come migliorano automazione, ragionamento, sicurezza e velocità dei workflow.
Il deep learning è un sottoinsieme del machine learning ed è un insieme di algoritmi ispirati alla struttura e al funzionamento del cervello.
TensorFlow è il secondo framework di machine learning che Google ha creato e usato per progettare, costruire e addestrare modelli di deep learning. Puoi usare la libreria TensorFlow per fare calcoli numerici, il che di per sé non sembra nulla di speciale, ma questi calcoli vengono eseguiti con grafi di flusso dei dati. In questi grafi, i nodi rappresentano operazioni matematiche, mentre gli archi rappresentano i dati, che di solito sono array di dati multidimensionali o tensori, che vengono comunicati tra questi archi.
Vedi? Il nome “TensorFlow” deriva dalle operazioni che le reti neurali eseguono su array di dati multidimensionali o tensori! È letteralmente un flusso di tensori. Per ora, questo è tutto ciò che ti serve sapere sui tensori, ma andrai più a fondo nelle prossime sezioni!
Il tutorial di oggi su TensorFlow per principianti ti introdurrà al deep learning in modo interattivo:
Scarica il notebook di questo tutorial qui.
Potrebbero anche interessarti un corso su Deep Learning in Python, il tutorial su Keras di DataCamp o il tutorial su keras con R.
Introduzione ai Tensori
Per capire bene i tensori, è utile avere un po’ di conoscenze operative di algebra lineare e calcolo vettoriale. Hai già letto nell’introduzione che i tensori sono implementati in TensorFlow come array di dati multidimensionali, ma potrebbe servire un po’ più di introduzione per comprendere a fondo i tensori e il loro uso nel machine learning.
Vettori nel Piano
Prima di entrare nei vettori nel piano, è una buona idea rivedere brevemente il concetto di “vettore”; I vettori sono tipi speciali di matrici, che sono array rettangolari di numeri. Poiché i vettori sono collezioni ordinate di numeri, sono spesso visti come matrici colonna: hanno una sola colonna e un certo numero di righe. In altri termini, puoi anche considerare i vettori come grandezze scalari a cui è stata assegnata una direzione.
Ricorda: un esempio di scalare è “5 metri” o “60 m/sec”, mentre un vettore è, per esempio, “5 metri a nord” o “60 m/sec a est”. La differenza tra i due è ovviamente che il vettore ha una direzione. Tuttavia, questi esempi che hai visto finora potrebbero sembrare lontani dai vettori che potresti incontrare quando lavori con problemi di machine learning. È normale; La lunghezza di un vettore matematico è un numero puro: è assoluta. La direzione, invece, è relativa: è misurata rispetto a una direzione di riferimento e ha unità in radianti o gradi. Di solito si assume che la direzione sia positiva e in rotazione antioraria rispetto alla direzione di riferimento.
Visivamente, ovviamente, rappresenti i vettori come frecce, come puoi vedere nell’immagine sopra. Ciò significa che puoi considerare i vettori anche come frecce che hanno direzione e lunghezza. La direzione è indicata dalla punta della freccia, mentre la lunghezza è indicata dalla lunghezza della freccia.
E i vettori nel piano?
I vettori nel piano sono l’impostazione più diretta dei tensori. Sono molto simili ai vettori “regolari” che hai visto sopra, con la sola differenza che si trovano in uno spazio vettoriale. Per capire meglio, partiamo da un esempio: hai un vettore che è 2 X 1. Questo significa che il vettore appartiene all’insieme dei numeri reali che vengono accoppiati due alla volta. O, detto diversamente, fanno parte del piano bidimensionale. In tali casi, puoi rappresentare i vettori sul piano delle coordinate (x,y) con frecce o semirette.
Lavorando da questo piano di coordinate in posizione standard, dove i vettori hanno l’estremità all’origine (0,0), puoi ricavare la coordinata x guardando la prima riga del vettore, mentre troverai la coordinata y nella seconda riga. Ovviamente, questa posizione standard non deve essere sempre mantenuta: i vettori possono spostarsi parallelamente a se stessi nel piano senza subire cambiamenti.
Nota che, analogamente, per i vettori di dimensione 3 X 1, si parla di spazio tridimensionale. Puoi rappresentare il vettore come una figura tridimensionale con frecce che puntano a posizioni nello spazio del vettore: sono disegnate sugli assi standard x, y e z.
È bello avere questi vettori e rappresentarli sul piano delle coordinate, ma in sostanza li hai per poter eseguire operazioni su di essi e una cosa che può aiutarti a farlo è esprimere i vettori come basi o vettori unitari.
I vettori unitari sono vettori con modulo pari a uno. Spesso riconoscerai il vettore unitario da una lettera minuscola con un circonflesso, o “cappello”. I vettori unitari tornano utili se vuoi esprimere un vettore 2D o 3D come somma di due o tre componenti ortogonali, come gli assi x− e y−, o l’asse z−.
E quando parli di esprimere un vettore, per esempio, come somma di componenti, vedrai che stai parlando di vettori componenti, cioè due o più vettori la cui somma è quel vettore dato.
Consiglio: guarda questo video, che spiega cosa sono i tensori con l’aiuto di semplici oggetti domestici!
Tensori
Oltre ai vettori nel piano, anche covettori e operatori lineari sono altri due casi che hanno tutti e tre una cosa in comune: sono casi specifici di tensori. Ricordi ancora come un vettore è stato caratterizzato nella sezione precedente come grandezze scalari a cui è stata data una direzione. Un tensore, quindi, è la rappresentazione matematica di un’entità fisica che può essere caratterizzata da un modulo e da più direzioni.
E, proprio come rappresenti uno scalare con un singolo numero e un vettore con una sequenza di tre numeri in uno spazio tridimensionale, per esempio, un tensore può essere rappresentato da un array di 3^R numeri in uno spazio tridimensionale.
La “R” in questa notazione rappresenta il rango del tensore: ciò significa che in uno spazio tridimensionale, un tensore di rango 2 può essere rappresentato da 3 alla potenza di 2, cioè 9 numeri. In uno spazio N-dimensionale, gli scalari richiederanno ancora un solo numero, i vettori richiederanno N numeri e i tensori richiederanno N^R numeri. Questo spiega perché spesso senti dire che gli scalari sono tensori di rango 0: poiché non hanno direzione, puoi rappresentarli con un numero.
Con questo in mente, è relativamente facile riconoscere scalari, vettori e tensori e distinguerli: gli scalari possono essere rappresentati da un singolo numero, i vettori da un insieme ordinato di numeri e i tensori da un array di numeri.
Ciò che rende i tensori così unici è la combinazione di componenti e vettori di base: i vettori di base si trasformano in un certo modo tra sistemi di riferimento e le componenti si trasformano in modo tale da mantenere invariata la combinazione tra componenti e vettori di base.
Installare TensorFlow
Ora che sai di più su TensorFlow, è il momento di iniziare e installare la libreria. Qui è utile sapere che TensorFlow fornisce API per Python, C++, Haskell, Java, Go, Rust, e c’è anche un pacchetto di terze parti per R chiamato
tensorflow.Consiglio: se vuoi saperne di più sui pacchetti di deep learning in R, considera di dare un’occhiata al tutorial keras: Deep Learning in R di DataCamp.
In questo tutorial, scaricherai una versione di TensorFlow che ti permetterà di scrivere il codice per il tuo progetto di deep learning in Python. Nella pagina di installazione di TensorFlow troverai alcuni dei modi più comuni e le istruzioni più recenti per installare TensorFlow usando
virtualenv,pip, Docker e, infine, anche altri modi per installare TensorFlow sul tuo computer personale.Nota Puoi anche installare TensorFlow con Conda se lavori su Windows. Tuttavia, poiché l’installazione di TensorFlow è supportata dalla community, è meglio controllare le istruzioni ufficiali di installazione.
Ora che hai completato il processo di installazione, è il momento di verificare che TensorFlow sia stato installato correttamente importandolo nel tuo workspace con l’alias
tf:Nota che l’alias che hai usato nella riga di codice sopra è una sorta di convenzione: serve a garantirti di rimanere coerente con altri sviluppatori che usano TensorFlow nei progetti di data science da un lato e con i progetti open-source TensorFlow dall’altro.
Primi Passi con TensorFlow: le Basi
In genere scriverai programmi TensorFlow, che eseguirai come blocchi; A prima vista questo è un po’ contraddittorio quando lavori con Python. Tuttavia, se vuoi, puoi anche usare l’Interactive Session di TensorFlow, che puoi utilizzare per lavorare in modo più interattivo con la libreria. Questo è particolarmente comodo se sei abituato a lavorare con IPython.
Per questo tutorial, ti concentrerai sulla seconda opzione: ti aiuterà a partire con il deep learning in TensorFlow. Ma prima di andare oltre, proviamo alcune cose semplici prima di passare ai pesi massimi.
Per prima cosa, importa la libreria
tensorflowcon l’aliastf, come visto nella sezione precedente. Poi inizializza due variabili che in realtà sono costanti. Passa un array di quattro numeri alla funzioneconstant().Nota che potresti anche passare un intero, ma più spesso ti troverai a lavorare con array. Come hai visto nell’introduzione, i tensori riguardano gli array! Quindi assicurati di passare un array :) Successivamente, puoi usare
multiply()per moltiplicare le due variabili. Memorizza il risultato nella variabileresult. Infine, stamparesultcon la funzioneprint().Nota che nel blocco di codice DataCamp Light sopra hai definito delle costanti. Tuttavia, ci sono altri due tipi di valori che puoi potenzialmente usare, ovvero i placeholder, che sono valori non assegnati e che verranno inizializzati dalla sessione quando la esegui. Come suggerisce il nome, è solo un segnaposto per un tensore che verrà sempre alimentato quando la sessione viene eseguita; Ci sono anche le Variable, che sono valori che possono cambiare. Le costanti, come avrai già capito, sono valori che non cambiano.
Il risultato delle righe di codice è un tensore astratto nel grafo di calcolo. Tuttavia, contrariamente a quanto potresti aspettarti, il
resultnon viene effettivamente calcolato. Definisce solo il modello, ma non è stato eseguito alcun processo per calcolare il risultato. Lo vedi nella stampa a video: non c’è davvero il risultato che vuoi vedere (cioè, 30). Questo significa che TensorFlow ha una valutazione “pigra”!Tuttavia, se vuoi vedere il risultato, devi eseguire questo codice in una sessione interattiva. Puoi farlo in vari modi, come mostrato nei blocchi DataCamp Light qui sotto:
Nota che puoi anche usare le seguenti righe di codice per avviare una Sessione interattiva, eseguire
resulte chiudere automaticamente la Sessione dopo aver stampatooutput:Nei blocchi di codice sopra hai appena definito una Sessione di default, ma è anche utile sapere che puoi passare anche delle opzioni. Puoi, per esempio, specificare l’argomento
confige poi usare il protocol bufferConfigProtoper aggiungere opzioni di configurazione per la tua sessione.Per esempio, se aggiungi
alla tua Sessione, fai in modo di registrare il dispositivo GPU o CPU assegnato a un’operazione. Otterrai quindi informazioni su quali dispositivi sono usati nella sessione per ogni operazione. Potresti usare anche la seguente configurazione di sessione, per esempio, quando usi vincoli soft per il posizionamento dei device:
Ora che hai installato e importato TensorFlow nel tuo workspace e hai visto le basi per lavorare con questo pacchetto, è il momento di mettere da parte per un attimo tutto questo e concentrarti sui dati. Come sempre, prima ti prenderai il tempo di esplorare e capire meglio i tuoi dati prima di iniziare a modellare la rete neurale.
Segnali Stradali Belgi: Contesto
Anche se il tema del traffico è generalmente noto a tutti voi, non fa male rivedere brevemente le osservazioni incluse in questo dataset per verificare di aver capito tutto prima di iniziare. In sostanza, in questa sezione, acquisirai la conoscenza del dominio necessaria per proseguire con questo tutorial.
Ovviamente, dato che sono belga, mi assicurerò che ti arrivino anche alcune chicche :)
Caricamento ed Esplorazione dei Dati
Ora che hai raccolto qualche informazione di contesto in più, è il momento di scaricare il dataset qui. Dovresti ottenere i due file zip elencati accanto a "BelgiumTS for Classification (cropped images)", che si chiamano "BelgiumTSC_Training" e "BelgiumTSC_Testing".
Consiglio: se hai scaricato i file o lo farai dopo aver completato questo tutorial, dai un’occhiata alla struttura delle cartelle dei dati che hai scaricato! Vedrai che le cartelle dei dati di test e di training contengono 61 sottocartelle, che sono i 62 tipi di segnali stradali che userai per la classificazione in questo tutorial. Inoltre, scoprirai che i file hanno estensione
.ppm, cioè Portable Pixmap Format. Hai scaricato immagini dei segnali stradali!Iniziamo a importare i dati nel tuo workspace. Partiamo dalle righe di codice che appaiono sotto la funzione definita dall’utente (UDF)
load_data():ROOT_PATH. Questo percorso è quello in cui hai creato la directory con i tuoi dati di training e test.ROOT_PATHcon l’aiuto della funzionejoin(). Memorizzi questi due percorsi specifici intrain_data_directoryetest_data_directory.load_data()e passarletrain_data_directory.load_data()inizia raccogliendo tutte le sottodirectory presenti intrain_data_directory; Lo fa con l’aiuto della list comprehension, che è un modo piuttosto naturale di costruire liste: in pratica dice che, se trovi qualcosa intrain_data_directory, controllerai due volte se è una directory e, se lo è, la aggiungerai alla tua lista. Ricorda che ogni sottodirectory rappresenta un’etichetta.labelseimages. Quindi raccogli i percorsi delle sottodirectory e i nomi dei file delle immagini memorizzate in queste sottodirectory. Successivamente, puoi raccogliere i dati nelle due liste con la funzioneappend().Nota che nel blocco di codice sopra, i dati di training e di test si trovano in cartelle chiamate "Training" e "Testing", che sono entrambe sottodirectory di un’altra directory "TrafficSigns". Su una macchina locale, potrebbe apparire come "/Users/Name/Downloads/TrafficSigns", con due sottocartelle chiamate "Training" e "Testing".
Consiglio: ripassa come scrivere funzioni in Python con il Python Functions Tutorial di DataCamp.
Statistiche sui Segnali Stradali
Con i dati caricati, è il momento di un po’ di ispezione! Puoi iniziare con un’analisi piuttosto semplice con l’aiuto degli attributi
ndimesizedell’arrayimages:Nota che le variabili
imageselabelssono liste, quindi potresti dover usarenp.array()per convertire le variabili in un array nel tuo workspace. Qui è già stato fatto per te!Nota che
images[0]che hai stampato è in realtà una singola immagine rappresentata da array in array! Questo può sembrare controintuitivo all’inizio, ma è qualcosa a cui ti abituerai man mano che andrai avanti a lavorare con immagini in applicazioni di machine learning o deep learning.Poi, puoi anche dare un’occhiata a
labels, ma a questo punto non dovresti vedere troppe sorprese:Questi numeri ti danno già qualche informazione su quanto è andato a buon fine l’import e sulla dimensione esatta dei dati. A prima vista, tutto è stato eseguito come ti aspettavi, e vedi che la dimensione dell’array è considerevole se consideri che stai trattando con array annidati.
Consiglio prova ad aggiungere i seguenti attributi ai tuoi array per ottenere più informazioni sul layout della memoria, sulla lunghezza in byte di un elemento dell’array e sul totale di byte consumati dagli elementi dell’array con gli attributi
flags,itemsizeenbytes. Puoi testarlo nella console IPython nel blocco DataCamp Light sopra!Poi puoi anche dare un’occhiata alla distribuzione dei segnali stradali:
Ottimo lavoro! Ora diamo uno sguardo più da vicino all’istogramma che hai creato!
A prima vista, vedi che ci sono etichette più presenti nel dataset rispetto ad altre: le etichette 22, 32, 38 e 61 saltano sicuramente all’occhio. Al momento, è utile tenerlo a mente, ma approfondirai sicuramente nella prossima sezione!
Visualizzare i Segnali Stradali
Le piccole analisi o verifiche precedenti ti hanno già dato un’idea dei dati con cui stai lavorando, ma quando i tuoi dati consistono per lo più di immagini, il passo che dovresti fare per esplorarli è visualizzarli.
Diamo un’occhiata ad alcuni segnali stradali a caso:
pyplotdel pacchettomatplotlibcon il comune aliasplt.imagesche hai appena ispezionato nella sezione precedente. In questo caso, scegli300,2250,3650e4000.imagesin accordo con il numero all’indicei. Nel primo ciclo, passerai300aimages[], nel secondo2250, e così via. Infine, regolerai i subplot in modo che ci sia abbastanza spazio in larghezza tra di loro.show()!Ecco fatto:
Come avrai intuito dalle 62 etichette incluse nel dataset, i segnali sono diversi tra loro.
Cos’altro noti? Dai un’altra occhiata ravvicinata alle immagini qui sotto:
Queste quattro immagini non hanno la stessa dimensione!
Puoi ovviamente giocare con i numeri contenuti nella lista
traffic_signse approfondire questa osservazione, ma ciò non toglie che questa è un’osservazione importante di cui dovrai tenere conto quando inizierai a manipolare i dati in modo da poterli dare in pasto alla rete neurale.Confermiamo l’ipotesi delle dimensioni differenti stampando la forma, i valori minimi e massimi delle immagini specifiche che hai incluso nei subplot.
Il codice qui sotto somiglia molto a quello che hai usato per creare il grafico sopra, ma differisce per il fatto che qui alternerai dimensioni e immagini invece di tracciare solo le immagini una accanto all’altra:
Nota come usi il metodo
format()sulla stringa"shape: {0}, min: {1}, max: {2}"per riempire gli argomenti{0},{1}e{2}che hai definito.Ora che hai visto immagini singole, potresti anche voler rivedere l’istogramma stampato nei primi passi dell’esplorazione dei dati; Puoi farlo facilmente tracciando una panoramica di tutte le 62 classi e un’immagine appartenente a ciascuna classe:
Nota che anche se definisci 64 subplot, non tutti mostreranno immagini (dato che ci sono solo 62 etichette!). Nota anche che, ancora una volta, non includi assi per assicurarti che l’attenzione dei lettori non si allontani troppo dall’argomento principale: i segnali stradali!
Come avevi in gran parte ipotizzato nell’istogramma sopra, ci sono sensibilmente più segnali stradali con etichette 22, 32, 38 e 61. Questa ipotesi è ora confermata in questo grafico: vedi che ci sono 375 istanze con etichetta 22, 316 con etichetta 32, 285 con etichetta 38 e, infine, 282 con etichetta 61.
Una delle domande più interessanti che potresti porti ora è se c’è una connessione tra tutte queste istanze: magari sono tutte segnali di indicazione?
Diamo uno sguardo più da vicino: vedi che le etichette 22 e 32 sono segnali di divieto, ma che le etichette 38 e 61 sono rispettivamente di indicazione e di precedenza. Questo significa che non c’è una connessione immediata tra queste quattro, a parte il fatto che metà dei segnali con una presenza sostanziale nel dataset sono di tipo proibitivo.
Estrazione delle Caratteristiche
Ora che hai esplorato a fondo i tuoi dati, è il momento di sporcarti le mani! Ricapitoliamo brevemente cosa hai scoperto per assicurarci di non dimenticare alcun passaggio nella manipolazione:
Ora che hai un’idea chiara di cosa migliorare, puoi iniziare a manipolare i tuoi dati in modo che siano pronti per essere alimentati alla rete neurale o a qualsiasi altro modello tu voglia utilizzare. Iniziamo con l’estrazione di alcune feature: ridimensionerai le immagini e convertirai in scala di grigi le immagini contenute nell’array
images. Effettuerai questa conversione di colore principalmente perché il colore conta meno in domande di classificazione come quella a cui stai cercando di rispondere ora. Per il riconoscimento, però, il colore ha un ruolo importante! In quei casi, non è necessario fare questa conversione!Ridimensionamento delle Immagini
Per affrontare le diverse dimensioni, ridimensionerai le immagini; Puoi farlo facilmente con l’aiuto della libreria
skimageo Scikit-Image, che è una raccolta di algoritmi per l’elaborazione di immagini.In questo caso, il modulo
transformtornerà utile, poiché offre la funzioneresize(); Vedrai che userai ancora una volta la list comprehension per ridimensionare ogni immagine a 28 per 28 pixel. Ancora una volta, vedi com’è formata la lista: per ogni immagine che trovi nell’arrayimages, eseguirai l’operazione di trasformazione presa in prestito dalla libreriaskimage. Infine, memorizzerai il risultato nella variabileimages28:È stato abbastanza facile, vero?
Nota che le immagini ora sono quadridimensionali: se converti
images28in un array e ci concateni l’attributoshape, vedrai che la stampa indica che le dimensioni diimages28sono(4575, 28, 28, 3). Le immagini sono a 784 dimensioni (perché sono 28 per 28 pixel).Puoi verificare il risultato del ridimensionamento riutilizzando il codice che hai usato sopra per tracciare le 4 immagini casuali con l’aiuto della variabile
traffic_signs. Non dimenticare solo di cambiare tutti i riferimenti daimagesaimages28.Guarda il risultato qui:
Nota che, avendo ridimensionato, i valori
minemaxsono cambiati; Sembrano essere tutti negli stessi intervalli ora, il che è ottimo perché così non è necessariamente necessario normalizzare i dati!Conversione in Scala di Grigi
Come detto nell’introduzione a questa sezione del tutorial, il colore nelle immagini conta meno quando stai cercando di rispondere a una domanda di classificazione. Ecco perché ti prenderai anche la briga di convertire le immagini in scala di grigi.
Nota, tuttavia, che puoi anche testare in autonomia cosa succederebbe ai risultati finali del tuo modello se non portassi a termine questo specifico passaggio.
Proprio come per il ridimensionamento, puoi contare di nuovo sulla libreria Scikit-Image per darti una mano; In questo caso, è il modulo
colorcon la sua funzionergb2gray()che devi usare per arrivare dove ti serve.Sarà semplice e veloce!
Non dimenticare, però, di convertire la variabile
images28di nuovo in un array, poiché la funzionergb2gray()si aspetta un array come argomento.Ricontrolla il risultato della conversione in scala di grigi tracciando alcune delle immagini; Qui puoi di nuovo riutilizzare e adattare leggermente parte del codice per mostrare le immagini modificate:
Nota che devi effettivamente specificare la mappa dei colori, o
cmap, impostandola su"gray"per tracciare le immagini in scala di grigi. Questo perchéimshow()usa di default, beh, una mappa di colori simile a una heatmap. Leggi di più qui.Consiglio: dato che hai riutilizzato parecchio questa funzione nel tutorial, potresti valutare come trasformarla in una funzione :)
Questi due passaggi sono molto basilari; Altre operazioni che potresti provare sui tuoi dati includono data augmentation (rotazione, sfocatura, traslazione, variazione di luminosità, …). Se vuoi, potresti anche impostare un’intera pipeline di operazioni di manipolazione dati attraverso cui far passare le immagini.
Deep Learning con TensorFlow
Ora che hai esplorato e manipolato i tuoi dati, è il momento di costruire l’architettura della tua rete neurale con l’aiuto del pacchetto TensorFlow!
Progettare la Rete Neurale
Proprio come potresti aver fatto con Keras, è il momento di costruire la tua rete neurale, layer per layer.
Se non l’hai già fatto, importa
tensorflownel tuo workspace con il consueto aliastf. Quindi, puoi inizializzare il Grafo conGraph(). Usi questa funzione per definire il calcolo. Nota che con il Grafo non calcoli nulla, perché non contiene valori. Definisce solo le operazioni che vuoi eseguire più tardi.In questo caso, imposti un contesto di default con
as_default(), che restituisce un context manager che rende questo specifico Grafo il grafo di default. Usi questo metodo se vuoi creare più grafi nello stesso processo: con questa funzione, hai un grafo di default globale a cui verranno aggiunte tutte le operazioni se non crei esplicitamente un nuovo grafo.Ora sei pronto per aggiungere operazioni al grafo. Come potresti ricordare lavorando con Keras, costruisci il modello e poi, compilando, definisci una funzione di loss, un ottimizzatore e una metrica. Ora tutto questo avviene in un unico passaggio quando lavori con TensorFlow:
run()!flatten(), che ti darà un array di forma[None, 784]invece di[None, 28, 28], che è la forma delle immagini in scala di grigi.[None, 62]. I logits sono la funzione che opera sull’output non scalato dei layer precedenti e che usa la scala relativa per capire che le unità sono lineari.reduce_mean(), che calcola la media degli elementi sulle dimensioni di un tensore.0.001.Hai appena creato con successo la tua prima rete neurale con TensorFlow!
Se vuoi, puoi anche stampare i valori di (quasi) tutte le variabili per un rapido riepilogo o controllo di ciò che hai appena codificato:
Consiglio: se vedi un errore come “
module 'pandas' has no attribute 'computation'”, valuta di aggiornare il pacchettodaskeseguendopip install --upgrade daskdalla riga di comando. Vedi questo post su StackOverflow per maggiori informazioni.Esecuzione della Rete Neurale
Ora che hai costruito il modello layer per layer, è il momento di eseguirlo! Per farlo, devi prima inizializzare una sessione con
Session()a cui puoi passare il tuographdefinito nella sezione precedente. Poi puoi eseguire la sessione conrun(), a cui passi le operazioni inizializzate sotto forma della variabileinitche hai definito nella sezione precedente.Poi puoi usare questa sessione inizializzata per avviare epoche o cicli di training. In questo caso, scegli
201perché vuoi poter registrare l’ultimoloss_value; Nel ciclo, esegui la sessione con l’ottimizzatore di training e la metrica di loss (o di accuratezza) definita nella sezione precedente. Passi anche un argomentofeed_dict, con cui alimenti i dati al modello. Ogni 10 epoche, otterrai un log che ti dà più informazioni sulla loss o sul costo del modello.Come hai visto nella sezione sulle basi di TensorFlow, non è necessario chiudere manualmente la sessione; viene fatto per te. Tuttavia, se vuoi provare una configurazione diversa, probabilmente dovrai farlo con
sess.close()se hai definito la tua sessione comesess, come nel blocco di codice seguente:Ricorda che puoi anche eseguire il seguente pezzo di codice, ma quello chiuderà immediatamente la sessione dopo, proprio come visto nell’introduzione di questo tutorial:
Nota che usi
global_variables_initializer()perché la funzioneinitialize_all_variables()è deprecata.Hai ora addestrato con successo il tuo modello! Non è stato poi così difficile, vero?
Valutare la tua Rete Neurale
Non ci sei ancora del tutto; Devi ancora valutare la tua rete neurale. In questo caso, puoi già provare a dare un’occhiata a quanto bene si comporta il tuo modello scegliendo 10 immagini casuali e confrontando le etichette previste con quelle reali.
Puoi prima stamparle, ma perché non usare
matplotlibper tracciare i segnali stradali stessi e fare un confronto visivo?Tuttavia, guardare solo immagini casuali non ti dà molte informazioni su quanto bene il tuo modello si comporti davvero. Ecco perché caricherai i dati di test.
Nota che usi la funzione
load_data(), che hai definito all’inizio di questo tutorial.Ricorda di chiudere la sessione con
sess.close()nel caso in cui tu non abbia usatowith tf.Session() as sess:per avviare la tua sessione TensorFlow.Dove Andare Dopo?
Se vuoi continuare a lavorare con questo dataset e il modello che hai messo insieme in questo tutorial, prova le seguenti cose:
Assicurati di dare un’occhiata al libro Machine Learning With TensorFlow, scritto da Nishant Shukla.
Consiglio dai un’occhiata anche al TensorFlow Playground e a TensorBoard.
Se vuoi continuare a lavorare con le immagini, dai sicuramente un’occhiata al tutorial su scikit-learn di DataCamp, che affronta il dataset MNIST con l’aiuto di PCA, K-Means e Support Vector Machines (SVM). Oppure dai un’occhiata ad altri tutorial come questo che usa il dataset dei segnali stradali belgi.