Bildklassifizierung unter Verwendung eines vorgefertigten Modells

In dieser Lektion lernen Sie, ein vorab trainiertes Modell zu verwenden, um Objekte in einem bestimmten Bild zu erkennen. Du wirst benutzensqueezenet vorab trainiertes Modul, das die Objekte in einem bestimmten Bild mit großer Genauigkeit erkennt und klassifiziert.

Öffne eine neue Juypter notebook und befolgen Sie die Schritte zum Entwickeln dieser Bildklassifizierungsanwendung.

Bibliotheken importieren

Zuerst importieren wir die erforderlichen Pakete mit dem folgenden Code:

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

Als nächstes haben wir einige eingerichtet variables - -

INPUT_IMAGE_SIZE = 227
mean = 128

Die für das Training verwendeten Bilder haben offensichtlich unterschiedliche Größen. Alle diese Bilder müssen für ein genaues Training in eine feste Größe konvertiert werden. Ebenso müssen die Testbilder und das Bild, das Sie in der Produktionsumgebung vorhersagen möchten, in die Größe konvertiert werden, die der während des Trainings verwendeten entspricht. Daher erstellen wir eine oben genannte VariableINPUT_IMAGE_SIZE Wert haben 227. Daher werden wir alle unsere Bilder in die Größe konvertieren227x227 bevor Sie es in unserem Klassifikator verwenden.

Wir deklarieren auch eine Variable namens mean Wert haben 128, die später zur Verbesserung der Klassifizierungsergebnisse verwendet wird.

Als nächstes werden wir zwei Funktionen zur Verarbeitung des Bildes entwickeln.

Bildverarbeitung

Die Bildverarbeitung besteht aus zwei Schritten. Die erste besteht darin, die Größe des Bildes zu ändern, und die zweite darin, das Bild zentral zuzuschneiden. Für diese beiden Schritte werden zwei Funktionen zum Ändern der Größe und zum Zuschneiden geschrieben.

Bildgröße ändern

Zuerst schreiben wir eine Funktion zum Ändern der Bildgröße. Wie bereits erwähnt, ändern wir die Größe des Bildes auf227x227. Definieren wir also die Funktionresize wie folgt -

def resize(img, input_height, input_width):

Wir erhalten das Seitenverhältnis des Bildes, indem wir die Breite durch die Höhe teilen.

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

Wenn das Seitenverhältnis größer als 1 ist, bedeutet dies, dass das Bild breit ist, dh im Querformat. Wir passen jetzt die Bildhöhe an und geben das verkleinerte Bild mit dem folgenden Code zurück:

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)

Wenn das Seitenverhältnis ist less than 1zeigt es die portrait mode. Wir passen die Breite jetzt mit dem folgenden Code an:

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)

Wenn das Seitenverhältnis gleich ist 1Wir nehmen keine Höhen- / Breitenanpassungen vor.

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

Der vollständige Funktionscode dient unten als Kurzreferenz -

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)

Wir werden nun eine Funktion zum Zuschneiden des Bildes um seine Mitte schreiben.

Bildausschnitt

Wir erklären das crop_image Funktion wie folgt -

def crop_image(img,cropx,cropy):

Wir extrahieren die Abmessungen des Bildes mit der folgenden Anweisung:

y,x,c = img.shape

Wir erstellen einen neuen Ausgangspunkt für das Bild mit den folgenden zwei Codezeilen:

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

Schließlich geben wir das zugeschnittene Bild zurück, indem wir ein Bildobjekt mit den neuen Dimensionen erstellen.

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

Der gesamte Funktionscode dient unten als Kurzreferenz -

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]

Jetzt werden wir Code schreiben, um diese Funktionen zu testen.

Bild verarbeiten

Kopieren Sie zunächst eine Bilddatei in images Unterordner in Ihrem Projektverzeichnis. tree.jpgDatei wird in das Projekt kopiert. Der folgende Python-Code lädt das Bild und zeigt es auf der Konsole an:

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')

Die Ausgabe ist wie folgt -

Beachten Sie, dass die Größe des Originalbilds beträgt 600 x 960. Wir müssen dies an unsere Spezifikation von anpassen227 x 227. Rufen Sie unsere früher definiertenresizeFunktion erledigt diesen Job.

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')

Die Ausgabe ist wie folgt -

Beachten Sie, dass jetzt die Bildgröße ist 227 x 363. Wir müssen das beschneiden227 x 227für den endgültigen Feed zu unserem Algorithmus. Zu diesem Zweck nennen wir die zuvor definierte Erntefunktion.

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')

Unten erwähnt ist die Ausgabe des Codes -

Zu diesem Zeitpunkt hat das Bild die Größe 227 x 227und ist bereit für die weitere Verarbeitung. Wir tauschen jetzt die Bildachsen aus, um die drei Farben in drei verschiedene Zonen zu extrahieren.

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

Unten ist die Ausgabe angegeben -

CHW Image Shape: (3, 227, 227)

Beachten Sie, dass die letzte Achse jetzt die erste Dimension im Array ist. Wir werden nun die drei Kanäle mit dem folgenden Code zeichnen:

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))

Die Ausgabe ist unten angegeben -

Schließlich führen wir einige zusätzliche Verarbeitungen für das Bild durch, z. B. das Konvertieren Red Green Blue zu Blue Green Red (RGB to BGR)Entfernen des Mittelwerts für bessere Ergebnisse und Hinzufügen der Achse für die Stapelgröße mithilfe der folgenden drei Codezeilen:

# 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)

Zu diesem Zeitpunkt befindet sich Ihr Bild in NCHW formatund ist bereit für die Einspeisung in unser Netzwerk. Als nächstes laden wir unsere vorab trainierten Modelldateien und geben das obige Bild zur Vorhersage ein.

Vorhersagen von Objekten im verarbeiteten Bild

Wir richten zuerst die Pfade für die ein init und predict Netzwerke, die in den vorgefertigten Modellen von Caffe definiert sind.

Festlegen von Modelldateipfaden

Denken Sie aus unserer früheren Diskussion daran, dass alle vorgefertigten Modelle in der installiert sind modelsMappe. Wir richten den Pfad zu diesem Ordner wie folgt ein:

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

Wir haben den Weg zum init_net Protobuf-Datei der squeezenet Modell wie folgt -

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

Ebenso haben wir den Weg zum predict_net protobuf wie folgt -

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

Wir drucken die beiden Pfade zu Diagnosezwecken -

print(INIT_NET)
print(PREDICT_NET)

Der obige Code zusammen mit der Ausgabe dient hier als Kurzreferenz -

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)

Die Ausgabe wird unten erwähnt -

/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

Als nächstes erstellen wir einen Prädiktor.

Prädiktor erstellen

Wir lesen die Modelldateien mit den folgenden zwei Anweisungen:

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

Der Prädiktor wird erstellt, indem Zeiger auf die beiden Dateien als Parameter an die übergeben werden Predictor Funktion.

p = workspace.Predictor(init_net, predict_net)

Das pObjekt ist der Prädiktor, der zum Vorhersagen der Objekte in einem bestimmten Bild verwendet wird. Beachten Sie, dass jedes Eingabebild im NCHW-Format vorliegen muss, wie wir es zuvor getan habentree.jpg Datei.

Objekte vorhersagen

Das Vorhersagen der Objekte in einem bestimmten Bild ist trivial - nur eine einzige Befehlszeile ausführen. Wir nennenrun Methode auf der predictor Objekt für eine Objekterkennung in einem bestimmten Bild.

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

Die Vorhersageergebnisse sind jetzt in der verfügbar results Objekt, das wir zur besseren Lesbarkeit in ein Array konvertieren.

results = np.asarray(results)

Drucken Sie die Abmessungen des Arrays zum besseren Verständnis mit der folgenden Anweisung:

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

Die Ausgabe ist wie unten gezeigt -

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

Wir werden jetzt die unnötige Achse entfernen -

preds = np.squeeze(results)

Die oberste Prädikation kann jetzt abgerufen werden, indem Sie die nehmen max Wert in der preds Array.

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

Die Ausgabe ist wie folgt -

Prediction: 984
Confidence: 0.89235985

Wie Sie sehen, hat das Modell ein Objekt mit einem Indexwert vorhergesagt 984 mit 89%Vertrauen. Der Index von 984 macht für uns wenig Sinn, um zu verstehen, welche Art von Objekt erkannt wird. Wir müssen den stringifizierten Namen für das Objekt anhand seines Indexwerts ermitteln. Die Art der Objekte, die das Modell zusammen mit den entsprechenden Indexwerten erkennt, ist in einem Github-Repository verfügbar.

Nun werden wir sehen, wie der Name für unser Objekt mit dem Indexwert 984 abgerufen wird.

Stringifizierendes Ergebnis

Wir erstellen ein URL-Objekt für das Github-Repository wie folgt:

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

Wir lesen den Inhalt der URL -

response = urllib2.urlopen(codes)

Die Antwort enthält eine Liste aller Codes und deren Beschreibungen. Nachfolgend sind einige Zeilen der Antwort aufgeführt, damit Sie verstehen, was sie enthält.

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

Wir iterieren nun das gesamte Array, um unseren gewünschten Code von 984 mit a zu finden for Schleife wie folgt -

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")

Wenn Sie den Code ausführen, wird die folgende Ausgabe angezeigt:

Model predicts rapeseed with 0.89235985 confidence

Sie können das Modell jetzt auf einem anderen Bild ausprobieren.

Vorhersage eines anderen Bildes

Um ein anderes Bild vorherzusagen, kopieren Sie einfach die Bilddatei in das imagesOrdner Ihres Projektverzeichnisses. Dies ist das Verzeichnis, in dem unsere früherentree.jpgDatei wird gespeichert. Ändern Sie den Namen der Bilddatei im Code. Wie unten gezeigt, ist nur eine Änderung erforderlich

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

Das Originalbild und das Vorhersageergebnis sind unten dargestellt -

Die Ausgabe wird unten erwähnt -

Model predicts pretzel with 0.99999976 confidence

Wie Sie sehen, kann das vorab trainierte Modell Objekte in einem bestimmten Bild mit großer Genauigkeit erkennen.

Vollständige Quelle

Die vollständige Quelle für den obigen Code, der ein vorab trainiertes Modell zur Objekterkennung in einem bestimmten Bild verwendet, wird hier als Kurzreferenz angegeben.

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")

Zu diesem Zeitpunkt wissen Sie, wie Sie ein vorab trainiertes Modell verwenden, um die Vorhersagen für Ihren Datensatz durchzuführen.

Als nächstes lernen Sie, wie Sie Ihre definieren neural network (NN) Architekturen in Caffe2und trainieren Sie sie auf Ihrem Datensatz. Wir werden nun lernen, wie man eine triviale Einzelschicht-NN erstellt.