CNTK - Convolutional Neural Network
Lassen Sie uns in diesem Kapitel untersuchen, wie ein Convolutional Neural Network (CNN) in CNTK aufgebaut wird.
Einführung
Convolutional Neural Networks (CNNs) bestehen ebenfalls aus Neuronen mit lernbaren Gewichten und Vorurteilen. Deshalb sind sie auf diese Weise wie gewöhnliche neuronale Netze (NNs).
Wenn wir uns an die Arbeitsweise gewöhnlicher NNs erinnern, empfängt jedes Neuron eine oder mehrere Eingaben, nimmt eine gewichtete Summe und durchläuft eine Aktivierungsfunktion, um die endgültige Ausgabe zu erzeugen. Hier stellt sich die Frage: Wenn CNNs und gewöhnliche NNs so viele Ähnlichkeiten aufweisen, was unterscheidet diese beiden Netzwerke dann voneinander?
Was unterscheidet sie von der Behandlung von Eingabedaten und Layertypen? Die Struktur der Eingabedaten wird in gewöhnlichen NN ignoriert und alle Daten werden in ein 1-D-Array konvertiert, bevor sie in das Netzwerk eingespeist werden.
Die Architektur des Convolutional Neural Network kann jedoch die 2D-Struktur der Bilder berücksichtigen, verarbeiten und es ihnen ermöglichen, die für Bilder spezifischen Eigenschaften zu extrahieren. Darüber hinaus haben CNNs den Vorteil, eine oder mehrere Faltungsschichten und eine Poolschicht zu haben, die die Hauptbausteine von CNNs sind.
Auf diese Schichten folgen eine oder mehrere vollständig verbundene Schichten wie bei Standard-Mehrschicht-NNs. Wir können uns CNN also als einen Sonderfall vollständig verbundener Netzwerke vorstellen.
CNN-Architektur (Convolutional Neural Network)
Die Architektur von CNN ist im Grunde eine Liste von Schichten, die das dreidimensionale, dh Breite, Höhe und Tiefe des Bildvolumens in ein dreidimensionales Ausgabevolumen umwandeln. Ein wichtiger Punkt, der hier zu beachten ist, ist, dass jedes Neuron in der aktuellen Schicht mit einem kleinen Patch der Ausgabe der vorherigen Schicht verbunden ist, was dem Überlagern eines N * N-Filters auf dem Eingabebild gleicht.
Es werden M-Filter verwendet, bei denen es sich im Grunde um Feature-Extraktoren handelt, die Features wie Kanten, Ecken usw. extrahieren. Es folgen die Ebenen [INPUT-CONV-RELU-POOL-FC] die verwendet werden, um Convolutional Neural Networks (CNNs) aufzubauen -
INPUT- Wie der Name schon sagt, enthält diese Ebene die Rohpixelwerte. Rohe Pixelwerte bedeuten die Daten des Bildes wie sie sind. Beispiel: INPUT [64 × 64 × 3] ist ein 3-Kanal-RGB-Bild mit der Breite 64, der Höhe 64 und der Tiefe 3.
CONV- Diese Schicht ist einer der Bausteine von CNNs, da der größte Teil der Berechnung in dieser Schicht erfolgt. Beispiel - Wenn wir 6 Filter für den oben genannten INPUT [64 × 64 × 3] verwenden, kann dies zu einem Volumen [64 × 64 × 6] führen.
RELU- Auch als gleichgerichtete lineare Einheitsschicht bezeichnet, die eine Aktivierungsfunktion auf die Ausgabe der vorherigen Schicht anwendet. Auf andere Weise würde RELU dem Netzwerk eine Nichtlinearität hinzufügen.
POOL- Diese Schicht, dh die Pooling-Schicht, ist ein weiterer Baustein von CNNs. Die Hauptaufgabe dieser Schicht ist das Downsampling, was bedeutet, dass sie unabhängig auf jedem Slice des Eingangs arbeitet und dessen Größe räumlich ändert.
FC- Es wird als vollständig verbundene Ebene oder genauer als Ausgabeebene bezeichnet. Es wird verwendet, um die Bewertung der Ausgabeklasse zu berechnen, und die resultierende Ausgabe ist ein Volumen der Größe 1 * 1 * L, wobei L die Zahl ist, die der Klassenbewertung entspricht.
Das folgende Diagramm zeigt die typische Architektur von CNNs−
CNN-Struktur erstellen
Wir haben die Architektur und die Grundlagen von CNN gesehen, jetzt werden wir mit CNTK ein Faltungsnetzwerk aufbauen. Hier werden wir zuerst sehen, wie die Struktur des CNN zusammengesetzt wird, und dann werden wir uns ansehen, wie die Parameter des CNN trainiert werden.
Zuletzt werden wir sehen, wie wir das neuronale Netzwerk verbessern können, indem wir seine Struktur mit verschiedenen Layer-Setups ändern. Wir werden den MNIST-Bilddatensatz verwenden.
Lassen Sie uns zunächst eine CNN-Struktur erstellen. Wenn wir ein CNN zum Erkennen von Mustern in Bildern erstellen, gehen wir im Allgemeinen wie folgt vor:
Wir verwenden eine Kombination aus Faltungs- und Pooling-Schichten.
Eine oder mehrere versteckte Schichten am Ende des Netzwerks.
Schließlich beenden wir das Netzwerk mit einer Softmax-Schicht zur Klassifizierung.
Mit Hilfe der folgenden Schritte können wir die Netzwerkstruktur aufbauen
Step 1- Zuerst müssen wir die erforderlichen Ebenen für CNN importieren.
from cntk.layers import Convolution2D, Sequential, Dense, MaxPooling
Step 2- Als nächstes müssen wir die Aktivierungsfunktionen für CNN importieren.
from cntk.ops import log_softmax, relu
Step 3- Danach müssen wir die importieren, um die Faltungsschichten später zu initialisieren glorot_uniform_initializer wie folgt -
from cntk.initializer import glorot_uniform
Step 4- Um Eingabevariablen zu erstellen, importieren Sie die input_variableFunktion. Und importierendefault_option Funktion, um die Konfiguration von NN etwas zu vereinfachen.
from cntk import input_variable, default_options
Step 5- Um nun die Eingabebilder zu speichern, erstellen Sie ein neues input_variable. Es wird drei Kanäle enthalten, nämlich rot, grün und blau. Es hätte die Größe von 28 mal 28 Pixel.
features = input_variable((3,28,28))
Step 6- Als nächstes müssen wir eine andere erstellen input_variable um die Etiketten zu speichern, um vorherzusagen.
labels = input_variable(10)
Step 7- Jetzt müssen wir die erstellen default_optionfür die NN. Und wir müssen die verwendenglorot_uniform als Initialisierungsfunktion.
with default_options(initialization=glorot_uniform, activation=relu):
Step 8- Als nächstes müssen wir eine neue erstellen, um die Struktur des NN festzulegen Sequential Ebenenset.
Step 9- Jetzt müssen wir ein hinzufügen Convolutional2D Schicht mit a filter_shape von 5 und a strides Einstellung von 1, innerhalb des SequentialEbenenset. Aktivieren Sie außerdem das Auffüllen, damit das Bild aufgefüllt wird, um die ursprünglichen Abmessungen beizubehalten.
model = Sequential([
Convolution2D(filter_shape=(5,5), strides=(1,1), num_filters=8, pad=True),
Step 10- Jetzt ist es Zeit, eine hinzuzufügen MaxPooling Schicht mit filter_shape von 2 und a strides Einstellung 2, um das Bild um die Hälfte zu komprimieren.
MaxPooling(filter_shape=(2,2), strides=(2,2)),
Step 11- Jetzt müssen wir wie in Schritt 9 einen weiteren hinzufügen Convolutional2D Schicht mit a filter_shape von 5 und a stridesEinstellung 1, 16 Filter verwenden. Aktivieren Sie außerdem das Auffüllen, damit die Größe des von der vorherigen Pooling-Ebene erzeugten Bilds beibehalten wird.
Convolution2D(filter_shape=(5,5), strides=(1,1), num_filters=16, pad=True),
Step 12- Fügen Sie nun wie in Schritt 10 eine weitere hinzu MaxPooling Schicht mit a filter_shape von 3 und a strides Einstellung 3, um das Bild auf ein Drittel zu reduzieren.
MaxPooling(filter_shape=(3,3), strides=(3,3)),
Step 13- Fügen Sie zum Schluss eine dichte Schicht mit zehn Neuronen für die 10 möglichen Klassen hinzu, die das Netzwerk vorhersagen kann. Verwenden Sie a, um das Netzwerk in ein Klassifizierungsmodell umzuwandelnlog_siftmax Aktivierungsfunktion.
Dense(10, activation=log_softmax)
])
Vollständiges Beispiel zum Erstellen einer CNN-Struktur
from cntk.layers import Convolution2D, Sequential, Dense, MaxPooling
from cntk.ops import log_softmax, relu
from cntk.initializer import glorot_uniform
from cntk import input_variable, default_options
features = input_variable((3,28,28))
labels = input_variable(10)
with default_options(initialization=glorot_uniform, activation=relu):
model = Sequential([
Convolution2D(filter_shape=(5,5), strides=(1,1), num_filters=8, pad=True),
MaxPooling(filter_shape=(2,2), strides=(2,2)),
Convolution2D(filter_shape=(5,5), strides=(1,1), num_filters=16, pad=True),
MaxPooling(filter_shape=(3,3), strides=(3,3)),
Dense(10, activation=log_softmax)
])
z = model(features)
CNN mit Bildern trainieren
Da wir die Struktur des Netzwerks erstellt haben, ist es Zeit, das Netzwerk zu trainieren. Bevor wir jedoch mit dem Training unseres Netzwerks beginnen, müssen wir Minibatch-Quellen einrichten, da das Training eines NN, der mit Bildern arbeitet, mehr Speicher benötigt als die meisten Computer.
Wir haben bereits in früheren Abschnitten Minibatch-Quellen erstellt. Im Folgenden finden Sie den Python-Code zum Einrichten von zwei Minibatch-Quellen:
Da haben wir die create_datasource Funktion können wir jetzt zwei separate Datenquellen erstellen (Training und Testen einer), um das Modell zu trainieren.
train_datasource = create_datasource('mnist_train')
test_datasource = create_datasource('mnist_test', max_sweeps=1, train=False)
Nachdem wir die Bilder vorbereitet haben, können wir mit dem Training unseres NN beginnen. Wie in den vorherigen Abschnitten können wir die Zugmethode für die Verlustfunktion verwenden, um das Training zu starten. Es folgt der Code dafür -
from cntk import Function
from cntk.losses import cross_entropy_with_softmax
from cntk.metrics import classification_error
from cntk.learners import sgd
@Function
def criterion_factory(output, targets):
loss = cross_entropy_with_softmax(output, targets)
metric = classification_error(output, targets)
return loss, metric
loss = criterion_factory(z, labels)
learner = sgd(z.parameters, lr=0.2)
Mit Hilfe des vorherigen Codes haben wir den Verlust und den Lernenden für den NN eingerichtet. Der folgende Code trainiert und validiert die NN−
from cntk.logging import ProgressPrinter
from cntk.train import TestConfig
progress_writer = ProgressPrinter(0)
test_config = TestConfig(test_datasource)
input_map = {
features: train_datasource.streams.features,
labels: train_datasource.streams.labels
}
loss.train(train_datasource,
max_epochs=10,
minibatch_size=64,
epoch_size=60000,
parameter_learners=[learner],
model_inputs_to_streams=input_map,
callbacks=[progress_writer, test_config])
Vollständiges Implementierungsbeispiel
from cntk.layers import Convolution2D, Sequential, Dense, MaxPooling
from cntk.ops import log_softmax, relu
from cntk.initializer import glorot_uniform
from cntk import input_variable, default_options
features = input_variable((3,28,28))
labels = input_variable(10)
with default_options(initialization=glorot_uniform, activation=relu):
model = Sequential([
Convolution2D(filter_shape=(5,5), strides=(1,1), num_filters=8, pad=True),
MaxPooling(filter_shape=(2,2), strides=(2,2)),
Convolution2D(filter_shape=(5,5), strides=(1,1), num_filters=16, pad=True),
MaxPooling(filter_shape=(3,3), strides=(3,3)),
Dense(10, activation=log_softmax)
])
z = model(features)
import os
from cntk.io import MinibatchSource, StreamDef, StreamDefs, ImageDeserializer, INFINITELY_REPEAT
import cntk.io.transforms as xforms
def create_datasource(folder, train=True, max_sweeps=INFINITELY_REPEAT):
mapping_file = os.path.join(folder, 'mapping.bin')
image_transforms = []
if train:
image_transforms += [
xforms.crop(crop_type='randomside', side_ratio=0.8),
xforms.scale(width=28, height=28, channels=3, interpolations='linear')
]
stream_definitions = StreamDefs(
features=StreamDef(field='image', transforms=image_transforms),
labels=StreamDef(field='label', shape=10)
)
deserializer = ImageDeserializer(mapping_file, stream_definitions)
return MinibatchSource(deserializer, max_sweeps=max_sweeps)
train_datasource = create_datasource('mnist_train')
test_datasource = create_datasource('mnist_test', max_sweeps=1, train=False)
from cntk import Function
from cntk.losses import cross_entropy_with_softmax
from cntk.metrics import classification_error
from cntk.learners import sgd
@Function
def criterion_factory(output, targets):
loss = cross_entropy_with_softmax(output, targets)
metric = classification_error(output, targets)
return loss, metric
loss = criterion_factory(z, labels)
learner = sgd(z.parameters, lr=0.2)
from cntk.logging import ProgressPrinter
from cntk.train import TestConfig
progress_writer = ProgressPrinter(0)
test_config = TestConfig(test_datasource)
input_map = {
features: train_datasource.streams.features,
labels: train_datasource.streams.labels
}
loss.train(train_datasource,
max_epochs=10,
minibatch_size=64,
epoch_size=60000,
parameter_learners=[learner],
model_inputs_to_streams=input_map,
callbacks=[progress_writer, test_config])
Ausgabe
-------------------------------------------------------------------
average since average since examples
loss last metric last
------------------------------------------------------
Learning rate per minibatch: 0.2
142 142 0.922 0.922 64
1.35e+06 1.51e+07 0.896 0.883 192
[………]
Bildtransformationen
Wie wir gesehen haben, ist es schwierig, NN zu trainieren, die für die Bilderkennung verwendet werden, und sie benötigen viele Daten, um auch zu trainieren. Ein weiteres Problem ist, dass sie dazu neigen, Bilder, die während des Trainings verwendet werden, zu stark anzupassen. Lassen Sie uns anhand eines Beispiels sehen, dass es für unser Modell schwierig ist, Gesichter zu erkennen, die in eine andere Richtung gedreht wurden, wenn wir Fotos von Gesichtern in aufrechter Position haben.
Um dieses Problem zu lösen, können wir die Bildvergrößerung verwenden, und CNTK unterstützt bestimmte Transformationen beim Erstellen von Minibatch-Quellen für Bilder. Wir können verschiedene Transformationen wie folgt verwenden
Wir können Bilder, die für das Training verwendet werden, zufällig mit nur wenigen Codezeilen zuschneiden.
Wir können auch eine Skala und Farbe verwenden.
Lassen Sie uns anhand des folgenden Python-Codes sehen, wie wir die Liste der Transformationen ändern können, indem wir eine Zuschneidetransformation in die Funktion aufnehmen, mit der die Minibatch-Quelle früher erstellt wurde.
import os
from cntk.io import MinibatchSource, StreamDef, StreamDefs, ImageDeserializer, INFINITELY_REPEAT
import cntk.io.transforms as xforms
def create_datasource(folder, train=True, max_sweeps=INFINITELY_REPEAT):
mapping_file = os.path.join(folder, 'mapping.bin')
image_transforms = []
if train:
image_transforms += [
xforms.crop(crop_type='randomside', side_ratio=0.8),
xforms.scale(width=28, height=28, channels=3, interpolations='linear')
]
stream_definitions = StreamDefs(
features=StreamDef(field='image', transforms=image_transforms),
labels=StreamDef(field='label', shape=10)
)
deserializer = ImageDeserializer(mapping_file, stream_definitions)
return MinibatchSource(deserializer, max_sweeps=max_sweeps)
Mit Hilfe des obigen Codes können wir die Funktion um eine Reihe von Bildtransformationen erweitern, sodass wir das Bild während des Trainings zufällig zuschneiden können, um mehr Variationen des Bildes zu erhalten.