il riconoscimento delle Immagini con la Macchina di Apprendimento su Python, Convolutional Rete Neurale

fonte: the irish times, Pól Ó Muirí

Dopo la pre-elaborazione di dati, è il momento di costruire il nostro modello di eseguire l’Immagine compito di riconoscimento. Una delle tecniche sta usando la rete neurale di convoluzione.

Questo articolo segue l’articolo che ho scritto sull’elaborazione delle immagini. Dopo aver reso i dati disponibili per l’attività di riconoscimento delle immagini, è il momento di creare un algoritmo che eseguirà l’attività. Tra le molte tecniche utilizzate per riconoscere le immagini come modello perceptron multistrato, la rete neurale a convoluzione (CNN) appare molto efficiente. In questo articolo, vedremo come costruire una CNN e come applicarla su un set di dati di immagini.

Quando iniziamo a costruire un modello di riconoscimento delle immagini per la prima volta, di solito è una buona idea addestrarlo e valutarlo su un set di dati relativamente semplice.

Uno dei compiti più semplici che possiamo eseguire è il riconoscimento delle cifre scritte a mano. Data un’immagine di una cifra scritta a mano (cioè, 0, 1, …, 9), vogliamo che il nostro modello sia in grado di classificare correttamente il suo valore numerico. Anche se questo compito sembra relativamente semplice, in realtà è usato abbastanza spesso nella vita reale, come ad esempio estrarre automaticamente i numeri di carta di credito da una foto. Il set di dati che useremo per il riconoscimento delle cifre è il set di dati MNIST, che è il set di dati utilizzato per il riconoscimento delle cifre basato sull’apprendimento automatico.

Il database MNIST (Modified National Institute of Standards and Technology) contiene 60.000 esempi di formazione e 10.000 esempi di test. Il database contiene cifre scritte a mano in scala di grigi che sono state ridimensionate per adattarsi a una casella di 20×20 pixel, che è stata poi centrata in un’immagine 28×28 (riempita con spazi bianchi). Il database MNIST è accessibile tramite Python.

In questo articolo, ti mostrerò come codificare la tua rete neurale convoluzionale usando keras, l’API di alto livello di TensorFlow. Sto usando tensorflow 2.0 in questo articolo.

1 – Inizializzazione

Poiché ogni immagine in scala di grigi ha dimensioni 28×28, ci sono 784 pixel per immagine. Pertanto, ogni immagine di input corrisponde a un tensore di 784 valori in virgola mobile normalizzati tra 0.0 e 1.0. L’etichetta per un’immagine è un tensore a caldo con 10 classi (ogni classe rappresenta una cifra). In termini di codice, abbiamo img_rows = 28, img_cols = 28 e num_classes = 10. Quindi l’input ha forma (number_examples, img_rows, img_cols) quindi 60000x28x28.
Un altro elemento importante da impostare è il seme casuale come vogliamo mantenere il punto di partenza quando un computer genera una sequenza numerica casuale.

Importiamo anche il set di dati MNIST.

import tensorflow as tf # tensorflow 2.0
from keras.datasets import mnist
import numpy as npseed=0
np.random.seed(seed) # fix random seed
tf.random.set_seed(seed)# input image dimensions
num_classes = 10 # 10 digits
img_rows, img_cols = 28, 28 # number of pixels
# the data, shuffled and split between train and test sets
(X_train, Y_train), (X_test, Y_test) = mnist.load_data()

2 – Rimodellamento e ridimensionamento

Come menzionato nella sezione precedente, gli input hanno forma (number_examples, img_rows, img_cols). Tuttavia, al fine di utilizzare i dati con la nostra rete neurale convoluzionale, abbiamo bisogno di ottenere in formato NHWC.

Il formato NHWC ha una forma con quattro dimensioni:

  1. Numero di campioni di dati (dimensione dei lotti)
  2. Altezza di ogni immagine
  3. Larghezza di ogni immagine
  4. Canali per immagine

L’altezza e la larghezza di ogni immagine dal set di dati è img_rows e img_cols, mentre il numero di canali 1 (dal momento che le immagini sono in scala di grigi).

Inoltre, ogni pixel contiene un valore in scala di grigi quantificato da un numero intero compreso tra 0 e 255. Quindi, il database è normalizzato per avere valori in virgola mobile tra 0.0 e 1.0. In questo caso, 0.0 corrisponde a un valore di pixel in scala di grigi di 255 (bianco puro), mentre 1.0 corrisponde a un valore di pixel in scala di grigi pari a 0 (nero puro).

X_train = X_train.reshape(X_train.shape, img_rows, img_cols, 1) 
X_test = X_test.reshape(X_test.shape, img_rows, img_cols, 1)input_shape = (img_rows, img_cols, 1)# cast floats to single precision
X_train = X_train.astype('float32')
X_test = X_test.astype('float32')# rescale data in interval
X_train /= 255
X_test /= 255

Vettori di etichette 3 – Casting Y

Dobbiamo trasformare le nostre classi in vettori. Noi questa toccando la riga seguente:

Y_train = keras.utils.to_categorical(Y_train, num_classes)
Y_test = keras.utils.to_categorical(Y_test, num_classes)

Per avere una migliore spiegazione di questo passo, si dovrebbe vedere questo articolo.

Ora che abbiamo elaborato i nostri dati, possiamo iniziare a costruire il modello.

Modello di rete neurale a convoluzione

Come menzionato alla fine dell’articolo che ho scritto sull’elaborazione delle immagini, i filtri svolgono un ruolo enorme nel riconoscimento delle immagini. Utilizziamo i filtri per trasformare gli input ed estrarre funzionalità che consentono al nostro modello di riconoscere determinate immagini. Un esempio molto alto di questo sarebbe un filtro di rilevamento della curva, che consente al nostro modello di distinguere tra cifre con curve e cifre senza curve.

1 – Filtri

Come tutti i pesi della rete neurale, i pesi del filtro sono variabili addestrabili. Alleniamo la nostra rete neurale (tramite i pesi della matrice del kernel) per produrre filtri in grado di estrarre le funzionalità nascoste più utili.

Quando i dati di input hanno più canali, un filtro avrà una matrice del kernel separata per canale. Il set di dati MNIST ha solo un canale, ma per altri tipi di dati di immagine (ad esempio RGB), addestreremmo il modello per ottenere pesi ottimali per la matrice del kernel di ciascun canale.

2-Convoluzione

Ora abbiamo raggiunto il punto focale delle reti neurali convoluzionali: la convoluzione. La convoluzione rappresenta il modo in cui applichiamo i pesi del filtro ai dati di input. L’operazione principale utilizzata da una convoluzione è il prodotto a punti della matrice, cioè una somma sul prodotto elemento-saggio di due matrici.

Il numero di dot matrix prodotti in una convoluzione dipende dalle dimensioni dei dati di input e kernel matrix, così come stride dimensioni. La dimensione del passo è l’offset verticale / orizzontale della matrice del kernel mentre si muove lungo i dati di input.

3-Padding

A volte, quando eseguiamo l’operazione dot product come visto prima, non usiamo una riga o una colonna. Per evitare questo fenomeno possiamo usare il padding.

Quindi, se vogliamo usare tutti i dati di input nella nostra convoluzione, possiamo tamponare la matrice di dati di input con 0. Ciò significa che aggiungiamo righe / colonne fatte interamente di 0 ai bordi della matrice di dati di input. Poiché 0 moltiplicato per qualsiasi numero risulta in 0, il padding non influisce sui prodotti matrix dot. Questo è importante perché non vogliamo aggiungere distorsioni alla nostra convoluzione.

4-Livello di convoluzione

Un livello di convoluzione in una CNN applica più filtri al tensore di input. Mentre ogni filtro ha una matrice kernel separata per ciascuno dei canali di ingresso, il risultato complessivo della convoluzione di un filtro è la somma delle circonvoluzioni su tutti i canali di ingresso.

L’aggiunta di più filtri a un livello di convoluzione consente al livello di estrarre meglio le funzionalità nascoste. Tuttavia, ciò comporta il costo di ulteriori tempi di allenamento e complessità computazionale, poiché i filtri aggiungono pesi aggiuntivi al modello. Il numero di canali per i dati di output è uguale al numero di filtri utilizzati dal livello di convoluzione.

Pooling

Mentre il livello di convoluzione estrae importanti funzionalità nascoste, il numero di funzionalità può ancora essere piuttosto grande. Possiamo usare il pooling per ridurre la dimensione dei dati nelle dimensioni di altezza e larghezza. Ciò consente al modello di eseguire meno calcoli e, infine, allenarsi più velocemente. Inoltre, impedisce l’overfitting, estraendo solo le caratteristiche più salienti e ignorando potenziali distorsioni o caratteristiche non comuni trovate solo in alcuni esempi.

Come funziona il pooling?

Simile a una convoluzione, usiamo matrici di filtro nel pooling. Tuttavia, il filtro di pooling non ha pesi, né esegue prodotti a punti matrice. Invece, applica un’operazione di riduzione alle sottosezioni dei dati di input.

Il tipo di pooling che viene solitamente utilizzato in CNNs è indicato come max pooling. I filtri di max pooling utilizzano l’operazione max per ottenere il numero massimo in ogni submatrix dei dati di input.

Livelli multipli

1 – Aggiunta di livelli aggiuntivi

Come tutte le reti neurali, le CNN possono beneficiare di livelli aggiuntivi. I livelli aggiuntivi consentono a una CNN di impilare essenzialmente più filtri insieme per l’uso sui dati dell’immagine. Tuttavia, simile alla costruzione di qualsiasi rete neurale, dobbiamo stare attenti a quanti livelli aggiuntivi aggiungiamo. Se aggiungiamo troppi livelli a un modello, corriamo il rischio di averlo overfit ai dati di allenamento e quindi generalizzare molto male. Inoltre, ogni livello aggiuntivo aggiunge complessità computazionale e aumenta il tempo di allenamento per il nostro modello.

2 – Aumentare i filtri

Di solito aumentiamo il numero di filtri in uno strato di convoluzione più è profondo nel nostro modello. In questo caso, il nostro secondo strato di convoluzione ha 64 filtri, rispetto ai 32 filtri del primo strato di convoluzione. Più profondo è il livello di convoluzione, più dettagliate diventano le caratteristiche estratte. Ad esempio, il primo livello di convoluzione può avere filtri che estraggono caratteristiche come linee, bordi e curve. Quando arriviamo al secondo livello, i filtri del livello di convoluzione potrebbero ora estrarre più caratteristiche distintive, come l’angolo acuto di un 77 o le curve intersecanti di un 88.

Livello completamente connesso

1-Livello completamente connesso

Applichiamo un livello completamente connesso di dimensione 1024 (cioè il numero di neuroni nel livello) ai dati di output del secondo livello di pooling. Il numero di unità è in qualche modo arbitrario. Abbastanza per essere potente, ma non tanto da essere troppo dispendioso in termini di risorse. Lo scopo del livello completamente connesso è quello di aggregare le funzionalità dei dati prima di convertirli in classi. Ciò consente al modello di fare previsioni migliori rispetto a se avessimo appena convertito l’output di pooling direttamente nelle classi.

2-Appiattimento

I dati che abbiamo utilizzato nel nostro modello sono del formato NHWC. Tuttavia, per utilizzare un livello completamente connesso, abbiamo bisogno che i dati siano una matrice, in cui il numero di righe rappresenta la dimensione del batch e le colonne rappresentano le funzionalità dei dati. Questa volta abbiamo bisogno di rimodellare nella direzione opposta e convertire da NHWC a una matrice 2-D.

Dropout

1 – Co-adattamento

Il co-adattamento si riferisce a quando più neuroni in un livello estraggono le stesse, o molto simili, caratteristiche nascoste dai dati di input. Questo può accadere quando i pesi di connessione per due neuroni diversi sono quasi identici.

Quando uno strato completamente connesso ha un gran numero di neuroni, è più probabile che si verifichi il co-adattamento. Questo può essere un problema per due motivi. In primo luogo, è uno spreco di calcolo quando abbiamo neuroni ridondanti che calcolano lo stesso output. In secondo luogo, se molti neuroni stanno estraendo le stesse caratteristiche, aggiunge più significato a quelle caratteristiche per il nostro modello. Ciò porta a un overfitting se le funzionalità estratte duplicate sono specifiche solo per il set di allenamento.

2-Dropout

Il modo in cui minimizziamo il co-adattamento per strati completamente connessi con molti neuroni è applicando dropout durante l’allenamento. In dropout, spegniamo casualmente una frazione dei neuroni di uno strato ad ogni fase di allenamento azzerando i valori dei neuroni.

Soft-max Layer

Poiché ci sono 10 cifre possibili che un’immagine MNIST può essere, usiamo un livello completamente connesso a 10 neuroni per ottenere le classi per ogni classe di cifre. La funzione Softmax viene applicata alle classi per convertirle in probabilità per classe.

Costruire il modello

Ora siamo pronti a costruire il nostro modello. Ecco il codice:

from keras.models import Sequential
from keras.layers import Dense, Conv2D, Flatten
from keras.layers import MaxPooling2D, Dropoutmodel = Sequential()#add model layers
model.add(Conv2D(32, kernel_size=(5, 5),
activation='relu',
input_shape=input_shape))
model.add(MaxPooling2D(pool_size=(2, 2)))# add second convolutional layer with 20 filters
model.add(Conv2D(64, (5, 5), activation='relu'))
# add 2D pooling layer
model.add(MaxPooling2D(pool_size=(2, 2)))
# flatten data
model.add(Flatten())
# add a dense all-to-all relu layer
model.add(Dense(1024, activation='relu'))
# apply dropout with rate 0.5
model.add(Dropout(0.5))
# soft-max layer
model.add(Dense(num_classes, activation='softmax'))

Il tipo di modello che useremo è Sequenziale. Sequenziale è il modo più semplice per costruire un modello in Keras. Ti permette di costruire un modello strato per strato.

Usiamo il metodo add () per collegare i livelli al nostro modello. Ai fini del nostro esempio introduttivo, è sufficiente concentrarsi su strati densi per semplicità. Ogni strato Denso() accetta come primo argomento richiesto un numero intero che specifica il numero di neuroni. Il tipo di funzione di attivazione per il livello è definito utilizzando l’argomento opzionale di attivazione, il cui input è il nome della funzione di attivazione in formato stringa. Gli esempi includono relu, tanh, elu, sigmoid, softmax.

In questa rete neurale, abbiamo 2 livelli di convoluzione seguiti ogni volta da un livello di pooling. Quindi appiattiamo i dati per aggiungere uno strato denso su cui applichiamo dropout con una velocità di 0,5. Infine, aggiungiamo un livello denso per allocare ogni immagine con la classe corretta.

Compilazione del modello

Successivamente, dobbiamo compilare il nostro modello. La compilazione del modello richiede tre parametri: ottimizzatore, perdita e metriche.

L’ottimizzatore controlla il tasso di apprendimento. Useremo ‘adam’ come nostro ottimizzatore. Adam è generalmente un buon ottimizzatore da utilizzare per molti casi. adam optimizer regola il tasso di apprendimento durante l’allenamento.

Il tasso di apprendimento determina la velocità con cui vengono calcolati i pesi ottimali per il modello. Un tasso di apprendimento più piccolo può portare a pesi più accurati (fino a un certo punto), ma il ridimensionamento è il tempo di calcolo.

Useremo ‘categorical_crossentropy’ per la nostra funzione di perdita. Questa è la scelta più comune per la classificazione. Un punteggio più basso indica che il modello sta eseguendo meglio.

Per rendere le cose ancora più facili da interpretare, useremo la metrica ‘precisione’ per vedere il punteggio di precisione sul set di convalida quando addestriamo il modello.

#compile model using accuracy to measure model performance
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=)

Formazione del modello

Ora ci alleneremo il nostro modello. Per allenarsi, useremo la funzione’ fit () ‘ sul nostro modello con i seguenti parametri: dati di allenamento (X_train), dati di destinazione (Y_train), dati di validazione e il numero di epoche.

Per i nostri dati di convalida, useremo il set di test fornito nel nostro set di dati, che abbiamo diviso in X_test e Y_test.

Il numero di epoche è il numero di volte in cui il modello scorrerà i dati. Più epoche corriamo, più il modello migliorerà, fino a un certo punto. Dopo quel punto, il modello smetterà di migliorare durante ogni epoca. Per il nostro modello, imposteremo il numero di epoche su 3.

#train the model
model.fit(X_train, Y_train, validation_data=(X_test, Y_test), epochs=3)

Valutare il modello

Ora abbiamo formato il nostro modello siamo in grado di valutare le sue prestazioni:

# evaluate the model
score = model.evaluate(X_test, Y_test, verbose=1)
# print performance
print()
print('Test loss:', score)
print('Test accuracy:', score)

Così, abbiamo un’accuratezza del 99,3% e una perdita di 0.025 sul set di test che è molto buono. Possiamo ancora migliorare il modello aumentando il numero di epoca e introducendo una dimensione del lotto.

Fai previsioni

Se vuoi vedere le previsioni effettive che il nostro modello ha fatto per i dati di test, possiamo usare la funzione predict_classes. Possiamo anche a questo utilizzando la funzione predict darà una matrice con 10 numeri. Questi numeri sono le probabilità che l’immagine di input rappresenti ogni cifra (0-9). L’indice di matrice con il numero più alto rappresenta la previsione del modello. La somma di ogni array è uguale a 1 (poiché ogni numero è una probabilità).

Per mostrare questo, mostreremo le previsioni per le prime 4 immagini nel set di test.

Nota: se abbiamo nuovi dati, possiamo inserire i nostri nuovi dati nella funzione predict per vedere le previsioni che il nostro modello fa sui nuovi dati. Dal momento che non abbiamo nuovi dati invisibili, mostreremo le previsioni utilizzando il set di test per ora.

#predict first 4 images in the test set
model.predict_classes(X_test)

#predict first 4 images in the test set
model.predict(X_test)

We can see that our model predicted 7, 2, 1 and 0 for the first four images.

Let’s compare this with the actual results.

#actual results for first 4 images in test set
y_test

I risultati attuali dimostrano che le prime quattro immagini sono anche 7, 2, 1 e 0. Il nostro modello previsto correttamente!

Whole model

import tensorflow as tf # tensorflow 2.0
from keras.datasets import mnist
import numpy as np
seed=0
np.random.seed(seed) # fix random seed
tf.random.set_seed(seed)
# input image dimensions
num_classes = 10 # 10 digitsimg_rows, img_cols = 28, 28 # number of pixels# the data, shuffled and split between train and test sets
(X_train, Y_train), (X_test, Y_test) = mnist.load_data()X_train = X_train.reshape(X_train.shape, img_rows, img_cols, 1)
X_test = X_test.reshape(X_test.shape, img_rows, img_cols, 1)
input_shape = (img_rows, img_cols, 1)# cast floats to single precision
X_train = X_train.astype('float32')
X_test = X_test.astype('float32')# rescale data in interval
X_train /= 255
X_test /= 255Y_train = keras.utils.to_categorical(Y_train, num_classes)
Y_test = keras.utils.to_categorical(Y_test, num_classes)from keras.models import Sequential
from keras.layers import Dense, Conv2D, Flatten
from keras.layers import MaxPooling2D, Dropout
model = Sequential()#add model layers
model.add(Conv2D(32, kernel_size=(5, 5),
activation='relu',
input_shape=input_shape))
model.add(MaxPooling2D(pool_size=(2, 2)))
# add second convolutional layer with 20 filters
model.add(Conv2D(64, (5, 5), activation='relu'))
# add 2D pooling layer
model.add(MaxPooling2D(pool_size=(2, 2)))
# flatten data
model.add(Flatten())
# add a dense all-to-all relu layer
model.add(Dense(1024, activation='relu'))
# apply dropout with rate 0.5
model.add(Dropout(0.5))
# soft-max layer
model.add(Dense(num_classes, activation='softmax'))#compile model using accuracy to measure model performance
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=)#train the model
model.fit(X_train, Y_train, validation_data=(X_test, Y_test), epochs=3)# evaluate the model
score = model.evaluate(X_test, Y_test, verbose=1)# print performance
print()
print('Test loss:', score)
print('Test accuracy:', score)#predict first 4 images in the test set
model.predict(X_test)model.predict_classes(X_test)#actual results for first 4 images in test set
Y_test

To be continued

In questo articolo, ho affrontato la seconda parte del riconoscimento delle immagini che sta costruendo una rete neurale a convoluzione.

Spero che tu abbia trovato quello per cui sei venuto qui in questo articolo e rimani con me per i prossimi episodi di questo viaggio di riconoscimento delle immagini!

PS: Attualmente sono uno studente di Master of Engineering a Berkeley, e se vuoi discutere l’argomento, sentiti libero di contattarmi. Ecco la mia email.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.