Classificazione delle immagini utilizzando un modello pre-addestrato

In questa lezione imparerai a utilizzare un modello pre-addestrato per rilevare oggetti in una data immagine. Useraisqueezenet modulo pre-addestrato che rileva e classifica gli oggetti in una data immagine con grande precisione.

Apri un nuovo file Juypter notebook e segui i passaggi per sviluppare questa applicazione di classificazione delle immagini.

Importazione di librerie

Innanzitutto, importiamo i pacchetti richiesti utilizzando il codice seguente:

from caffe2.proto import caffe2_pb2
from caffe2.python import core, workspace, models
import numpy as np
import skimage.io
import skimage.transform
from matplotlib import pyplot
import os
import urllib.request as urllib2
import operator

Successivamente, ne abbiamo impostati alcuni variables -

INPUT_IMAGE_SIZE = 227
mean = 128

Le immagini utilizzate per l'allenamento saranno ovviamente di varie dimensioni. Tutte queste immagini devono essere convertite in una dimensione fissa per un addestramento accurato. Allo stesso modo, anche le immagini di prova e l'immagine che si desidera prevedere nell'ambiente di produzione devono essere convertite nella dimensione, uguale a quella utilizzata durante l'addestramento. Quindi, creiamo una variabile sopra chiamataINPUT_IMAGE_SIZE avere valore 227. Quindi, convertiremo tutte le nostre immagini nella dimensione227x227 prima di usarlo nel nostro classificatore.

Dichiariamo anche una variabile chiamata mean avere valore 128, che viene utilizzato successivamente per migliorare i risultati della classificazione.

Successivamente, svilupperemo due funzioni per l'elaborazione dell'immagine.

Elaborazione delle immagini

L'elaborazione dell'immagine consiste in due fasi. Il primo è ridimensionare l'immagine e il secondo è ritagliare centralmente l'immagine. Per questi due passaggi, scriveremo due funzioni per il ridimensionamento e il ritaglio.

Ridimensionamento dell'immagine

Per prima cosa, scriveremo una funzione per ridimensionare l'immagine. Come detto prima, ridimensioneremo l'immagine a227x227. Quindi definiamo la funzioneresize come segue -

def resize(img, input_height, input_width):

Otteniamo le proporzioni dell'immagine dividendo la larghezza per l'altezza.

original_aspect = img.shape[1]/float(img.shape[0])

Se il rapporto di aspetto è maggiore di 1, indica che l'immagine è ampia, vale a dire che è in modalità orizzontale. Ora regoliamo l'altezza dell'immagine e restituiamo l'immagine ridimensionata utilizzando il codice seguente:

if(original_aspect>1):
   new_height = int(original_aspect * input_height)
   return skimage.transform.resize(img, (input_width,
   new_height), mode='constant', anti_aliasing=True, anti_aliasing_sigma=None)

Se le proporzioni sono less than 1, indica il portrait mode. Ora regoliamo la larghezza utilizzando il seguente codice:

if(original_aspect<1):
   new_width = int(input_width/original_aspect)
   return skimage.transform.resize(img, (new_width,
   input_height), mode='constant', anti_aliasing=True, anti_aliasing_sigma=None)

Se le proporzioni sono uguali a 1, non effettuiamo alcuna regolazione di altezza / larghezza.

if(original_aspect == 1):
   return skimage.transform.resize(img, (input_width,
   input_height), mode='constant', anti_aliasing=True, anti_aliasing_sigma=None)

Il codice funzione completo è fornito di seguito per una rapida consultazione:

def resize(img, input_height, input_width):
   original_aspect = img.shape[1]/float(img.shape[0])
   if(original_aspect>1):
      new_height = int(original_aspect * input_height)
      return skimage.transform.resize(img, (input_width,
	   new_height), mode='constant', anti_aliasing=True, anti_aliasing_sigma=None)
   if(original_aspect<1):
         new_width = int(input_width/original_aspect)
         return skimage.transform.resize(img, (new_width,
         input_height), mode='constant', anti_aliasing=True, anti_aliasing_sigma=None)
   if(original_aspect == 1):
         return skimage.transform.resize(img, (input_width,
         input_height), mode='constant', anti_aliasing=True, anti_aliasing_sigma=None)

Scriveremo ora una funzione per ritagliare l'immagine attorno al suo centro.

Ritaglio dell'immagine

Dichiariamo il crop_image funzionare come segue:

def crop_image(img,cropx,cropy):

Estraiamo le dimensioni dell'immagine usando la seguente dichiarazione:

y,x,c = img.shape

Creiamo un nuovo punto di partenza per l'immagine utilizzando le seguenti due righe di codice:

startx = x//2-(cropx//2)
starty = y//2-(cropy//2)

Infine, restituiamo l'immagine ritagliata creando un oggetto immagine con le nuove dimensioni -

return img[starty:starty+cropy,startx:startx+cropx]

Di seguito viene fornito l'intero codice funzione per una rapida consultazione:

def crop_image(img,cropx,cropy):
   y,x,c = img.shape
   startx = x//2-(cropx//2)
   starty = y//2-(cropy//2)
   return img[starty:starty+cropy,startx:startx+cropx]

Ora scriveremo il codice per testare queste funzioni.

Elaborazione dell'immagine

Innanzitutto, copia un file immagine in images sottocartella all'interno della directory del progetto. tree.jpgil file viene copiato nel progetto. Il seguente codice Python carica l'immagine e la visualizza sulla console:

img = skimage.img_as_float(skimage.io.imread("images/tree.jpg")).astype(np.float32)
print("Original Image Shape: " , img.shape)
pyplot.figure()
pyplot.imshow(img)
pyplot.title('Original image')

L'output è il seguente:

Nota che la dimensione dell'immagine originale è 600 x 960. Dobbiamo ridimensionarlo alla nostra specifica di227 x 227. Chiamando il nostro definito in precedenzaresizela funzione fa questo lavoro.

img = resize(img, INPUT_IMAGE_SIZE, INPUT_IMAGE_SIZE)
print("Image Shape after resizing: " , img.shape)
pyplot.figure()
pyplot.imshow(img)
pyplot.title('Resized image')

L'output è come indicato di seguito:

Nota che ora la dimensione dell'immagine è 227 x 363. Dobbiamo ritagliarlo su227 x 227per il feed finale al nostro algoritmo. Chiamiamo la funzione crop precedentemente definita per questo scopo.

img = crop_image(img, INPUT_IMAGE_SIZE, INPUT_IMAGE_SIZE)
print("Image Shape after cropping: " , img.shape)
pyplot.figure()
pyplot.imshow(img)
pyplot.title('Center Cropped')

Di seguito è menzionato l'output del codice:

A questo punto, l'immagine è di dimensioni 227 x 227ed è pronto per ulteriori elaborazioni. Scambiamo ora gli assi dell'immagine per estrarre i tre colori in tre zone differenti.

img = img.swapaxes(1, 2).swapaxes(0, 1)
print("CHW Image Shape: " , img.shape)

Di seguito è riportato l'output:

CHW Image Shape: (3, 227, 227)

Notare che l'ultimo asse è ora diventato la prima dimensione dell'array. Tracciamo ora i tre canali utilizzando il seguente codice:

pyplot.figure()
for i in range(3):
   pyplot.subplot(1, 3, i+1)
   pyplot.imshow(img[i])
   pyplot.axis('off')
   pyplot.title('RGB channel %d' % (i+1))

L'output è indicato di seguito:

Infine, eseguiamo alcune elaborazioni aggiuntive sull'immagine come la conversione Red Green Blue per Blue Green Red (RGB to BGR), rimuovendo la media per ottenere risultati migliori e aggiungendo l'asse delle dimensioni del batch utilizzando le seguenti tre righe di codice:

# convert RGB --> BGR
img = img[(2, 1, 0), :, :]
# remove mean
img = img * 255 - mean
# add batch size axis
img = img[np.newaxis, :, :, :].astype(np.float32)

A questo punto, la tua immagine è in formato NCHW formated è pronto per essere inserito nella nostra rete. Successivamente, caricheremo i nostri file di modello pre-addestrati e inseriremo l'immagine sopra per la previsione.

Previsione di oggetti nell'immagine elaborata

Per prima cosa impostiamo i percorsi per init e predict reti definite nei modelli pre-addestrati di Caffe.

Impostazione dei percorsi dei file del modello

Ricorda dalla nostra discussione precedente, tutti i modelli pre-addestrati sono installati in modelscartella. Abbiamo impostato il percorso di questa cartella come segue:

CAFFE_MODELS = os.path.expanduser("/anaconda3/lib/python3.7/site-packages/caffe2/python/models")

Abbiamo impostato il percorso per il file init_net protobuf file di squeezenet modello come segue -

INIT_NET = os.path.join(CAFFE_MODELS, 'squeezenet', 'init_net.pb')

Allo stesso modo, abbiamo impostato il percorso per il file predict_net protobuf come segue -

PREDICT_NET = os.path.join(CAFFE_MODELS, 'squeezenet', 'predict_net.pb')

Stampiamo i due percorsi a scopo diagnostico -

print(INIT_NET)
print(PREDICT_NET)

Il codice sopra insieme all'output viene fornito qui come riferimento rapido -

CAFFE_MODELS = os.path.expanduser("/anaconda3/lib/python3.7/site-packages/caffe2/python/models")
INIT_NET = os.path.join(CAFFE_MODELS, 'squeezenet', 'init_net.pb')
PREDICT_NET = os.path.join(CAFFE_MODELS, 'squeezenet', 'predict_net.pb')
print(INIT_NET)
print(PREDICT_NET)

L'output è menzionato di seguito:

/anaconda3/lib/python3.7/site-packages/caffe2/python/models/squeezenet/init_net.pb
/anaconda3/lib/python3.7/site-packages/caffe2/python/models/squeezenet/predict_net.pb

Successivamente, creeremo un predittore.

Creazione del predittore

Leggiamo i file del modello utilizzando le seguenti due istruzioni:

with open(INIT_NET, "rb") as f:
   init_net = f.read()
with open(PREDICT_NET, "rb") as f:
   predict_net = f.read()

Il predittore viene creato passando i puntatori ai due file come parametri al file Predictor funzione.

p = workspace.Predictor(init_net, predict_net)

Il poggetto è il predittore, che viene utilizzato per prevedere gli oggetti in una data immagine. Nota che ogni immagine di input deve essere in formato NCHW come quello che abbiamo fatto in precedenza al nostrotree.jpg file.

Previsione di oggetti

Prevedere gli oggetti in una data immagine è banale: basta eseguire una singola riga di comando. Noi chiamiamorun metodo sul predictor oggetto per il rilevamento di un oggetto in una data immagine.

results = p.run({'data': img})

I risultati della previsione sono ora disponibili in results oggetto, che convertiamo in un array per la nostra leggibilità.

results = np.asarray(results)

Stampa le dimensioni dell'array per la tua comprensione utilizzando la seguente dichiarazione:

print("results shape: ", results.shape)

L'output è come mostrato di seguito:

results shape: (1, 1, 1000, 1, 1)

Ora rimuoveremo l'asse non necessario -

preds = np.squeeze(results)

La previsione più in alto può ora essere recuperata prendendo il file max valore in preds Vettore.

curr_pred, curr_conf = max(enumerate(preds), key=operator.itemgetter(1))
print("Prediction: ", curr_pred)
print("Confidence: ", curr_conf)

L'output è il seguente:

Prediction: 984
Confidence: 0.89235985

Come vedi il modello ha previsto un oggetto con un valore di indice 984 con 89%fiducia. L'indice di 984 non ha molto senso per noi per capire che tipo di oggetto viene rilevato. Dobbiamo ottenere il nome in stringa per l'oggetto usando il suo valore di indice. Il tipo di oggetti che il modello riconosce insieme ai valori di indice corrispondenti sono disponibili in un repository GitHub.

Ora vedremo come recuperare il nome per il nostro oggetto con valore di indice 984.

Risultato stringente

Creiamo un oggetto URL nel repository github come segue:

codes = "https://gist.githubusercontent.com/aaronmarkham/cd3a6b6ac0
71eca6f7b4a6e40e6038aa/raw/9edb4038a37da6b5a44c3b5bc52e448ff09bfe5b/alexnet_codes"

Leggiamo il contenuto dell'URL -

response = urllib2.urlopen(codes)

La risposta conterrà un elenco di tutti i codici e le relative descrizioni. Di seguito sono riportate alcune righe della risposta per la tua comprensione di ciò che contiene:

5: 'electric ray, crampfish, numbfish, torpedo',
6: 'stingray',
7: 'cock',
8: 'hen',
9: 'ostrich, Struthio camelus',
10: 'brambling, Fringilla montifringilla',

Ora iteriamo l'intero array per individuare il codice 984 desiderato utilizzando un file for loop come segue -

for line in response:
   mystring = line.decode('ascii')
   code, result = mystring.partition(":")[::2]
   code = code.strip()
   result = result.replace("'", "")
   if (code == str(curr_pred)):
      name = result.split(",")[0][1:]
      print("Model predicts", name, "with", curr_conf, "confidence")

Quando esegui il codice, vedrai il seguente output:

Model predicts rapeseed with 0.89235985 confidence

Ora puoi provare il modello su un'altra immagine.

Previsione di un'immagine diversa

Per prevedere un'altra immagine, copia semplicemente il file immagine nel file imagescartella della directory del progetto. Questa è la directory in cui il nostro precedentetree.jpgil file viene memorizzato. Cambia il nome del file immagine nel codice. È necessaria una sola modifica come mostrato di seguito

img = skimage.img_as_float(skimage.io.imread("images/pretzel.jpg")).astype(np.float32)

L'immagine originale e il risultato della previsione sono mostrati di seguito:

L'output è menzionato di seguito:

Model predicts pretzel with 0.99999976 confidence

Come puoi vedere, il modello pre-addestrato è in grado di rilevare oggetti in una data immagine con una grande precisione.

Fonte completa

La fonte completa per il codice precedente che utilizza un modello pre-addestrato per il rilevamento di oggetti in una determinata immagine è menzionata qui come riferimento rapido -

def crop_image(img,cropx,cropy):
   y,x,c = img.shape
   startx = x//2-(cropx//2)
   starty = y//2-(cropy//2)
   return img[starty:starty+cropy,startx:startx+cropx]
img = skimage.img_as_float(skimage.io.imread("images/pretzel.jpg")).astype(np.float32)
print("Original Image Shape: " , img.shape)
pyplot.figure()
pyplot.imshow(img)
pyplot.title('Original image')
img = resize(img, INPUT_IMAGE_SIZE, INPUT_IMAGE_SIZE)
print("Image Shape after resizing: " , img.shape)
pyplot.figure()
pyplot.imshow(img)
pyplot.title('Resized image')
img = crop_image(img, INPUT_IMAGE_SIZE, INPUT_IMAGE_SIZE)
print("Image Shape after cropping: " , img.shape)
pyplot.figure()
pyplot.imshow(img)
pyplot.title('Center Cropped')
img = img.swapaxes(1, 2).swapaxes(0, 1)
print("CHW Image Shape: " , img.shape)
pyplot.figure()
for i in range(3):
pyplot.subplot(1, 3, i+1)
pyplot.imshow(img[i])
pyplot.axis('off')
pyplot.title('RGB channel %d' % (i+1))
# convert RGB --> BGR
img = img[(2, 1, 0), :, :]
# remove mean
img = img * 255 - mean
# add batch size axis
img = img[np.newaxis, :, :, :].astype(np.float32)
CAFFE_MODELS = os.path.expanduser("/anaconda3/lib/python3.7/site-packages/caffe2/python/models")
INIT_NET = os.path.join(CAFFE_MODELS, 'squeezenet', 'init_net.pb')
PREDICT_NET = os.path.join(CAFFE_MODELS, 'squeezenet', 'predict_net.pb')
print(INIT_NET)
print(PREDICT_NET)
with open(INIT_NET, "rb") as f:
   init_net = f.read()
with open(PREDICT_NET, "rb") as f:
   predict_net = f.read()
p = workspace.Predictor(init_net, predict_net)
results = p.run({'data': img})
results = np.asarray(results)
print("results shape: ", results.shape)
preds = np.squeeze(results)
curr_pred, curr_conf = max(enumerate(preds), key=operator.itemgetter(1))
print("Prediction: ", curr_pred)
print("Confidence: ", curr_conf)
codes = "https://gist.githubusercontent.com/aaronmarkham/cd3a6b6ac071eca6f7b4a6e40e6038aa/raw/9edb4038a37da6b5a44c3b5bc52e448ff09bfe5b/alexnet_codes"
response = urllib2.urlopen(codes)
for line in response:
   mystring = line.decode('ascii')
   code, result = mystring.partition(":")[::2]
   code = code.strip()
   result = result.replace("'", "")
   if (code == str(curr_pred)):
      name = result.split(",")[0][1:]
      print("Model predicts", name, "with", curr_conf, "confidence")

A questo punto, sai come utilizzare un modello pre-addestrato per eseguire le previsioni sul tuo set di dati.

Il passo successivo è imparare a definire il tuo neural network (NN) architetture in Caffe2e addestrali sul tuo set di dati. Ora impareremo come creare un banale NN a singolo strato.