Bilderkennung mit maschinellem Lernen auf Python, Convolutional Neural Network

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

Nach der Vorverarbeitung der Daten ist es an der Zeit, unser Modell für die Bilderkennungsaufgabe zu erstellen. Eine der Techniken ist die Verwendung von Convolution Neural Network.

Dieser Artikel folgt dem Artikel, den ich über Bildverarbeitung geschrieben habe. Nachdem die Daten für die Bilderkennungsaufgabe zur Verfügung gestellt wurden, ist es an der Zeit, einen Algorithmus zu erstellen, der die Aufgabe ausführt. Unter vielen Techniken, die verwendet werden, um Bilder als Multilayer-Perzeptron-Modell zu erkennen, erscheint das Convolution Neural Network (CNN) als sehr effizient. In diesem Artikel erfahren Sie, wie Sie ein CNN erstellen und auf einen Datensatz mit Bildern anwenden.

Wenn wir zum ersten Mal mit der Erstellung eines Bilderkennungsmodells beginnen, ist es normalerweise eine gute Idee, es anhand eines relativ einfachen Datensatzes zu trainieren und auszuwerten.

Eine der einfachsten Aufgaben, die wir ausführen können, ist die handschriftliche Ziffernerkennung. Bei einem Bild einer handgeschriebenen Ziffer (d.h., 0, 1, …, 9), wir möchten, dass unser Modell seinen numerischen Wert korrekt klassifizieren kann. Obwohl diese Aufgabe relativ einfach zu sein scheint, wird sie im wirklichen Leben häufig verwendet, z. B. beim automatischen Extrahieren von Kreditkartennummern aus einem Bild. Der Datensatz, den wir für die Ziffernerkennung verwenden werden, ist der MNIST-Datensatz, der für die auf maschinellem Lernen basierende Ziffernerkennung verwendet wird.

Die Datenbank des MNIST (Modified National Institute of Standards and Technology) enthält 60.000 Trainingsbeispiele und 10.000 Testbeispiele. Die Datenbank enthält graustufige handgeschriebene Ziffern, deren Größe an ein 20×20-Pixel-Feld angepasst wurde, das dann in einem 28×28-Bild zentriert (mit Leerzeichen aufgefüllt) wurde. Die MNIST-Datenbank ist über Python zugänglich.

In diesem Artikel zeige ich Ihnen, wie Sie Ihr Convolutional Neural Network mit keras, der High-Level-API von TensorFlow, codieren. Ich verwende Tensorflow 2.0 in diesem Artikel.

1- Initialisierung

Da jedes Graustufenbild die Abmessungen 28×28 hat, gibt es 784 Pixel pro Bild. Daher entspricht jedes Eingabebild einem Tensor von 784 normalisierten Gleitkommawerten zwischen 0,0 und 1,0. Die Bezeichnung für ein Bild ist ein One-Hot-Tensor mit 10 Klassen (jede Klasse repräsentiert eine Ziffer). In Bezug auf unseren Code haben wir img_rows = 28 , img_cols = 28 und num_classes = 10 . Somit hat die Eingabe die Form (number_examples, img_rows, img_cols), also 60000x28x28.
Ein weiteres wichtiges Element einzurichten ist die random Seed, wie wir den Startpunkt halten wollen, wenn ein Computer eine Zufallszahlenfolge erzeugt.

Wir importieren auch den MNIST-Datensatz.

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- Umformen und Neuskalieren

Wie im vorherigen Abschnitt erwähnt, haben Eingaben eine Form (number_examples, img_rows, img_cols). Um die Daten jedoch mit unserem Convolutional Neural Network zu verwenden, müssen wir sie in das NHWC-Format bringen.

Das NHWC-Format hat eine Form mit vier Dimensionen:

  1. Anzahl der Bilddatenbeispiele (Stapelgröße)
  2. Höhe jedes Bildes
  3. Breite jedes Bildes
  4. Kanäle pro Bild

Die Höhe und Breite jedes Bildes aus dem Datensatz ist img_rows und img_cols, während die Anzahl der Kanäle 1 ist (da die Bilder Graustufen sind).

Außerdem enthält jedes Pixel einen Graustufenwert, der durch eine ganze Zahl zwischen 0 und 255 quantifiziert wird. Daher ist die Datenbank normalisiert, um Gleitkommawerte zwischen 0,0 und 1,0 zu haben. In diesem Fall entspricht 0,0 einem Graustufenpixelwert von 255 (Reinweiß), während 1.0 entspricht einem Graustufenpixelwert von 0 (reines Schwarz).

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

3- Casting label Vektoren Y

Wir müssen unsere Klassen in Vektoren umwandeln. Dazu tippen wir auf die folgende Zeile:

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

Um diesen Schritt besser zu erklären, sollten Sie diesen Artikel lesen.

Nachdem wir unsere Daten verarbeitet haben, können wir mit dem Modellbau beginnen.

Convolution Neural Network model

Wie am Ende des Artikels erwähnt, den ich über Bildverarbeitung geschrieben habe, spielen Filter eine große Rolle bei der Bilderkennung. Wir verwenden Filter, um Eingaben zu transformieren und Funktionen zu extrahieren, mit denen unser Modell bestimmte Bilder erkennen kann. Ein sehr übergeordnetes Beispiel hierfür wäre ein Kurvenerkennungsfilter, mit dem unser Modell zwischen Ziffern mit Kurven und Ziffern ohne Kurven unterscheiden kann.

1- Filter

Wie alle Gewichtungen neuronaler Netze sind die Gewichtungen des Filters trainierbare Variablen. Wir trainieren unser neuronales Netzwerk (über die Kernmatrixgewichte), um Filter zu erzeugen, die in der Lage sind, die nützlichsten versteckten Funktionen zu extrahieren.

Wenn die Eingabedaten mehrere Kanäle haben, hat ein Filter eine separate Kernelmatrix pro Kanal. Das MNIST-Dataset hat nur einen Kanal, aber für andere Arten von Bilddaten (z. B. RGB) würden wir das Modell trainieren, um optimale Gewichte für die Kernmatrix jedes Kanals zu erhalten.

2-Faltung

Wir haben jetzt den Brennpunkt der faltungsneuralen Netze erreicht: die Faltung. Die Faltung stellt dar, wie wir unsere Filtergewichte auf die Eingabedaten anwenden. Die Hauptoperation, die von einer Faltung verwendet wird, ist das Matrixpunktprodukt, dh eine Summation über das elementweise Produkt zweier Matrizen.

Die von Matrixpunktprodukten in einer Faltung hängt von den Abmessungen der Eingabedaten und der Kernmatrix sowie von der Schrittgröße ab. Die Schrittgröße ist der vertikale / horizontale Versatz der Kernelmatrix, wenn sie sich entlang der Eingabedaten bewegt.

3-Padding

Manchmal, wenn wir die Punktproduktoperation wie zuvor ausführen, verwenden wir keine Zeile oder Spalte. Um dieses Phänomen zu vermeiden, können wir Polsterung verwenden.

Wenn wir also alle Eingabedaten in unserer Faltung verwenden möchten, können wir die Eingabedatenmatrix mit 0 auffüllen. Dies bedeutet, dass wir Zeilen / Spalten, die vollständig aus 0 bestehen, zu den Kanten der Eingabedatenmatrix hinzufügen. Da 0 multipliziert mit einer beliebigen Zahl zu 0 führt, wirkt sich das Auffüllen nicht auf Matrixpunktprodukte aus. Dies ist wichtig, weil wir unserer Faltung keine Verzerrungen hinzufügen möchten.

4-Faltungsschicht

Eine Faltungsschicht in einem CNN wendet mehrere Filter auf den Eingangstensor an. Während jeder Filter eine separate Kernmatrix für jeden der Eingangskanäle hat, ist das Gesamtergebnis der Faltung eines Filters die Summe der Faltungen über alle Eingangskanäle hinweg.

Durch Hinzufügen weiterer Filter zu einer Faltungsebene kann die Ebene verborgene Funktionen besser extrahieren. Dies geht jedoch auf Kosten zusätzlicher Trainingszeit und Rechenkomplexität, da Filter dem Modell zusätzliche Gewichte hinzufügen. Die Anzahl der Kanäle für die Ausgabedaten entspricht der Anzahl der Filter, die die Faltungsschicht verwendet.

Pooling

Während die Faltungsschicht wichtige versteckte Features extrahiert, kann die Anzahl der Features immer noch ziemlich groß sein. Wir können Pooling verwenden, um die Größe der Daten in den Dimensionen Höhe und Breite zu reduzieren. Dadurch kann das Modell weniger Berechnungen durchführen und letztendlich schneller trainieren. Es verhindert auch eine Überanpassung, indem nur die hervorstechendsten Merkmale extrahiert und mögliche Verzerrungen oder ungewöhnliche Merkmale ignoriert werden, die nur in wenigen Beispielen zu finden sind.

Wie funktioniert Pooling?

Ähnlich wie bei einer Faltung verwenden wir Filtermatrizen beim Pooling. Der Pooling-Filter hat jedoch keine Gewichtungen und führt auch keine Matrixpunktprodukte aus. Stattdessen wird eine Reduktionsoperation auf Unterabschnitte der Eingabedaten angewendet.

Die Art des Poolings, die normalerweise in CNNs verwendet wird, wird als Max Pooling bezeichnet. Die Filter von max Pooling verwenden die max-Operation, um die maximale Anzahl in jeder Submatrix der Eingabedaten zu erhalten.

Mehrere Schichten

1- Hinzufügen zusätzlicher Schichten

Wie alle neuronalen Netze können CNNs von zusätzlichen Schichten profitieren. Die zusätzlichen Schichten ermöglichen es einem CNN, im Wesentlichen mehrere Filter zur Verwendung auf den Bilddaten zu stapeln. Ähnlich wie beim Aufbau eines neuronalen Netzwerks müssen wir jedoch darauf achten, wie viele zusätzliche Schichten wir hinzufügen. Wenn wir einem Modell zu viele Ebenen hinzufügen, besteht die Gefahr, dass es zu stark an die Trainingsdaten angepasst wird und daher sehr schlecht verallgemeinert wird. Darüber hinaus erhöht jede zusätzliche Schicht die Rechenkomplexität und erhöht die Trainingszeit für unser Modell.

2- Filter erhöhen

Normalerweise erhöhen wir die Anzahl der Filter in einer Faltungsschicht, je tiefer sie in unserem Modell ist. In diesem Fall hat unsere zweite Faltungsschicht 64 Filter, verglichen mit den 32 Filtern der ersten Faltungsschicht. Je tiefer die Faltungsschicht ist, desto detaillierter werden die extrahierten Merkmale. Beispielsweise kann die erste Faltungsschicht Filter aufweisen, die Merkmale wie Linien, Kanten und Kurven extrahieren. Wenn wir zur zweiten Ebene gelangen, könnten die Filter der Faltungsschicht jetzt mehr Unterscheidungsmerkmale extrahieren, wie den scharfen Winkel einer 77 oder die sich kreuzenden Kurven einer 88.

Vollständig verbundene Schicht

1-Vollständig verbundene Schicht

Wir wenden eine vollständig verbundene Schicht der Größe 1024 (d. h. Die Anzahl der Neuronen in der Schicht) auf die Ausgabedaten der zweiten Pooling-Schicht an. Die Anzahl der Einheiten ist etwas willkürlich. Genug, um mächtig zu sein, aber nicht so sehr, um zu ressourcenintensiv zu sein. Der Zweck der vollständig verbundenen Ebene besteht darin, die Datenfeatures zu aggregieren, bevor wir sie in Klassen konvertieren. Auf diese Weise kann das Modell bessere Vorhersagen treffen, als wenn wir die Pooling-Ausgabe direkt in Klassen konvertiert hätten.

2-Abflachung

Die Daten, die wir in unserem Modell verwendet haben, haben das NHWC-Format. Um jedoch eine vollständig verbundene Ebene zu verwenden, müssen die Daten eine Matrix sein, wobei die Anzahl der Zeilen die Stapelgröße und die Spalten die Datenmerkmale darstellen. Dieses Mal müssen wir in die entgegengesetzte Richtung umformen und von NHWC in eine 2D-Matrix konvertieren.

Dropout

1- Co-Adaptation

Co-Adaptation bezieht sich darauf, wenn mehrere Neuronen in einer Schicht dieselben oder sehr ähnliche versteckte Merkmale aus den Eingabedaten extrahieren. Dies kann passieren, wenn die Verbindungsgewichte für zwei verschiedene Neuronen nahezu identisch sind.

Wenn eine vollständig verbundene Schicht eine große Anzahl von Neuronen aufweist, ist eine Koanpassung wahrscheinlicher. Dies kann aus zwei Gründen ein Problem sein. Erstens ist es eine Verschwendung von Berechnungen, wenn redundante Neuronen dieselbe Ausgabe berechnen. Zweitens, wenn viele Neuronen die gleichen Merkmale extrahieren, erhöht dies die Bedeutung dieser Merkmale für unser Modell. Dies führt zu einer Überanpassung, wenn die doppelt extrahierten Features nur für den Trainingssatz spezifisch sind.

2-Dropout

Die Art und Weise, wie wir die Koanpassung für vollständig verbundene Schichten mit vielen Neuronen minimieren, besteht darin, Dropout während des Trainings anzuwenden. In Dropout schalten wir bei jedem Trainingsschritt zufällig einen Bruchteil der Neuronen einer Schicht aus, indem wir die Neuronenwerte auf Null setzen.

Soft-Max-Schicht

Da es 10 mögliche Ziffern gibt, die ein MNIST-Bild sein kann, verwenden wir eine vollständig verbundene Schicht mit 10 Neuronen, um die Klassen für jede Ziffernklasse zu erhalten. Die Softmax-Funktion wird auf die Klassen angewendet, um sie in Wahrscheinlichkeiten pro Klasse umzuwandeln.

Das Modell bauen

Jetzt können wir unser Modell bauen. Hier ist der Code:

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

Der Modelltyp, den wir verwenden werden, ist sequentiell. Dies ist der einfachste Weg, ein Modell in Keras zu erstellen. Es ermöglicht Ihnen, ein Modell Schicht für Schicht zu erstellen.

Wir verwenden die add() -Methode, um Ebenen an unser Modell anzuhängen. Für die Zwecke unseres Einführungsbeispiels reicht es aus, sich der Einfachheit halber auf dichte Schichten zu konzentrieren. Jede Dense() -Schicht akzeptiert als erstes erforderliches Argument eine ganze Zahl, die die Anzahl der Neuronen angibt. Der Typ der Aktivierungsfunktion für den Layer wird mit dem optionalen Argument activation definiert, dessen Eingabe der Name der Aktivierungsfunktion im Zeichenfolgenformat ist. Beispiele sind Relu, Tanh, Elu, Sigmoid, Softmax.

In diesem neuronalen Netzwerk haben wir 2 Faltungsschichten, denen jedes Mal eine Pooling-Schicht folgt. Dann glätten wir die Daten, um eine dichte Ebene hinzuzufügen, auf die wir Dropout mit einer Rate von 0,5 anwenden. Schließlich fügen wir eine dichte Ebene hinzu, um jedes Bild der richtigen Klasse zuzuordnen.

Kompilieren des Modells

Als nächstes müssen wir unser Modell kompilieren. Das Kompilieren des Modells erfordert drei Parameter: Optimierer, Verlust und Metriken.

Der Optimierer steuert die Lernrate. Wir werden ‘adam’ als Optimierer verwenden. Adam ist im Allgemeinen ein guter Optimierer für viele Fälle. Der adam Optimizer passt die Lernrate während des gesamten Trainings an.

Die Lernrate bestimmt, wie schnell die optimalen Gewichte für das Modell berechnet werden. Eine kleinere Lernrate kann zu genaueren Gewichten führen (bis zu einem bestimmten Punkt), aber die Verkleinerung ist die Rechenzeit.

Wir werden ‘categorical_crossentropy’ für unsere Verlustfunktion verwenden. Dies ist die häufigste Wahl für die Klassifizierung. Eine niedrigere Punktzahl zeigt an, dass das Modell eine bessere Leistung erbringt.

Um die Interpretation noch einfacher zu machen, verwenden wir die Metrik ‘Genauigkeit’, um die Genauigkeitsbewertung im Validierungssatz anzuzeigen, wenn wir das Modell trainieren.

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

Das Modell trainieren

Jetzt werden wir unser Modell trainieren. Zum Trainieren verwenden wir die Funktion ‘fit ()’ in unserem Modell mit den folgenden Parametern: Trainingsdaten (X_train), Zieldaten (Y_train), Validierungsdaten und die Anzahl der Epochen.

Für unsere Validierungsdaten verwenden wir den Testsatz, der uns in unserem Datensatz zur Verfügung gestellt wurde, den wir in X_test und Y_test aufgeteilt haben.

Die Anzahl der Epochen gibt an, wie oft das Modell die Daten durchläuft. Je mehr Epochen wir durchlaufen, desto mehr wird sich das Modell bis zu einem bestimmten Punkt verbessern. Danach hört das Modell auf, sich in jeder Epoche zu verbessern. Für unser Modell setzen wir die Anzahl der Epochen auf 3.

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

Bewerten Sie das Modell

Jetzt haben wir unser Modell trainiert und können seine Leistung bewerten:

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

Somit haben wir eine Genauigkeit von 99,3% und einen Verlust von 0,025 auf dem Testset, was sehr gut ist. Wir können das Modell immer noch verbessern, indem wir die Anzahl der Pakete erhöhen und eine Losgröße einführen.

Vorhersagen treffen

Wenn Sie die tatsächlichen Vorhersagen sehen möchten, die unser Modell für die Testdaten gemacht hat, können wir die Funktion predict_classes . Wir können dies auch tun, indem wir die Predict-Funktion verwenden, um ein Array mit 10 Zahlen zu erhalten. Diese Zahlen sind die Wahrscheinlichkeiten, dass das Eingabebild jede Ziffer darstellt (0-9). Der Array-Index mit der höchsten Zahl repräsentiert die Modellvorhersage. Die Summe jedes Arrays ist gleich 1 (da jede Zahl eine Wahrscheinlichkeit ist).

Um dies zu zeigen, zeigen wir die Vorhersagen für die ersten 4 Bilder im Testset.Hinweis: Wenn wir neue Daten haben, können wir unsere neuen Daten in die predict-Funktion eingeben, um die Vorhersagen zu sehen, die unser Modell für die neuen Daten macht. Da wir keine neuen unsichtbaren Daten haben, werden wir Vorhersagen vorerst anhand des Testsets anzeigen.

#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

Die tatsächlichen Ergebnisse zeigen, dass die ersten vier Bilder ebenfalls 7, 2,1 und 0 sind. Unser Modell richtig vorhergesagt!

Gesamtes Modell

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

Fortsetzung folgt…

In diesem Artikel habe ich mich mit dem zweiten Teil der Bilderkennung befasst, bei dem ein neuronales Faltungsnetzwerk aufgebaut wird.

Ich hoffe, Sie haben in diesem Artikel gefunden, wofür Sie hierher gekommen sind, und bleiben Sie für die nächsten Folgen dieser Bilderkennungsreise bei mir!

PS: Ich bin derzeit ein Master of Engineering Student in Berkeley, und wenn Sie das Thema diskutieren möchten, können Sie mich gerne erreichen. Hier ist meine E-Mail.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.