Kapitel T2: PyTorch

Updates dieser Seite:

Überblick

In diesem Kapitel konzentrieren wir uns auf Neuronale Netze in PyTorch, also wie sie erzeugt, konfiguriert und trainiert werden. Wir sehen außerdem, wie man die in PyTorch mitgelieferten Datensätze (z.B. FashionMNIST) nutzt. Zum Schluss sehen wir uns kurz ein äquivalenten Netz in Keras an, damit man innerhalb des Kapitels den direkten Vergleich ziehen kann.

1 Neuronale Netze

In PyTorch muss man für jedes Netz eine eigene Klasse anlegen. Für das Training programmiert man die Schleife über alle Epochen selbst. Was anfangs - besonders im Vergleich zu Keras - etwas sperrig scheint, erlaubt später eine mehr Kontrolle und regt mehr zum Experimentieren an.

Wir beginnen mit der Definition von zwei Beispielnetzen, einem Feedforwad-Netz (FNN) und einem Konvolutionsnetz (CNN).

1.1 FNN mit drei Schichten

In PyTorch definiert man ein neues Netz als Unterklasse von nn.Module.

Die Klasse nn.Linear wiederum repräsentiert eine traditionelle Schicht, die wir auch fully connected nennen. In Keras entspricht das einem "Dense Layer".

Siehe: torch.nn.Module, torch.nn.Linear

Wir bauen hier ein Netz mit 784 Eingabeneuronen, 200 Zwischenneuronen und 10 Ausgabeneuronen. Als Aktivierungsfunktion wählen wir ReLU.

Funktionale Schreibweise

In der funktionalen Schreibweise, erzeugen wir im Konstruktor Objekte für alle Schichten und rufen in der Methode forward die Schichten auf und schicken den Output gegebenfalls noch durch Funktionen wie ReLU.

Sanity Check: Wir schicken eine zufällige 28x28-Matrix durch das Netz. Das Netz erwartet einen 4-dimensionalen Tensor der Form:

(Batches, Kanäle, Zeilen, Spalten)

Wir sehen uns die Parameter der ersten Schicht an. Es handelt sich um eine 200x784-Matrix mit den Gewichten von den 784 Eingabeneuronen zu den 200 Neuronen der Zwischenschicht.

Kompakte Schreibweise

Mit einem Objekt vom Typ Sequential kann man die Schichten und die Verarbeitung etwas kompakter schreiben. Die Schreibung erinnert auch an die Schreibweise in Keras.

Wieder ein Datencheck:

1.2 CNN

Als nächstes bauen wir ein Konvolutionsnetz.

Dazu verwenden wir die Klassen Conv2d und MaxPool2d:

Bei der Konv-Schicht entspricht die Anzahl der Filter auch der Anzahl der Kanäle der Ausgabe.

Siehe auch torch.nn.Conv2d, torch.nn.MaxPool2d

Im Beispielnetz haben wir folgende Schichten:

  1. Inputschicht: (28x28x1)
  2. Konv-Schicht: 6 Filter der Größe 5x5x1, Output (24x24x6)
  3. Pooling-Schicht: Größe 2x2, Stride 2, Output (12x12x6)
  4. Konv-Schicht: 16 Filter der Größe 5x5x6, Output (8x8x16)
  5. Pooling-Schicht: Größe 2x2, Stride 2, Output (4x4x6)
  6. FC-Schicht: 80 Neuronen
  7. FC-Ausgabeschicht: 10 Neuronen

Funktionale Schreibweise

In der funktionalen Schreibweise kann die Verarbeitung in forward etwas unübersichtlich werden.

Sanity check:

Kompakte Schreibweise

Die kompakte Schreibweise mit Sequential ist deutlich lesbarer als die funktionale Schreibweise.

Auch hier ein kurzer Sanity check.

2 Daten

Als Datensatz nehmen wir FashionMNIST, also (Farb-)Bilddaten mit Kleidungsstücken.

Zum Akquirieren von Daten benötigen wir das Paket "torchvision". Das darin vorkommende "vision" kommt von "computer vision", d.h. es geht um Operationen im Bereich Bildverarbeitung.

Hier können Sie sehen, welche Datensätze in PyTorch enthalten sind: https://pytorch.org/vision/stable/datasets.html

Wir benötigen die folgenden Imports:

2.1 Daten laden

Die folgenden Zeilen laden die Daten herunter (es sei denn, sie sind bereits vorhanden) und legen sie im Unterverzeichnis "data" ab. In unserem Fall wird das Verzeichnis "data/FashionMNIST" angelegt und dort die Daten hineingeschrieben.

Die Daten sind Bilddaten (PIL image, PIL = python image library) und müssen explizit mit dem "transform"-Argument in PyTorch-Tensoren umgewandelt werden.

Siehe auch: https://pytorch.org/vision/stable/datasets.html#fashion-mnist

2.2 DataLoader erzeugen

Ein Loader ist eine Datenstruktur, über die man iterieren kann, so dass man in einer For-Schleife jede Entität nacheinander abarbeitet.

Hier wird ein wichtiger Hyperparameter definiert:

Wir geben eine Batchgröße von 64 an. Ein "Batch" ist ein Tensor, der - in unserem Fall - 64 Trainingsbeispiele mit jeweils Features und Zielwert enthält. Der Loader enthält entsprechend eine Liste von allen Batches.

2.3 Daten inspizieren

Wir sehen uns die Dimensionen des jeweils ersten Tensors (X und y) in den Trainingsdaten an:

Auf der Feature-Seite $X$ ist der erste Tensor ein Batch von 64 Tensoren der Form 1x28x28. Die "1" bezieht sich auf die Anzahl der Kanäle, bei einem Graustufenbild ist das nur einer.

Bei den Labels $y$ haben wir 64 Integer-Werte.

Wenn wir "enumerate" benutzen, können wir eine Laufvariable für die Batchnummer mitführen. Das werden wir später noch verwenden.

In dem $X$ oben steckt noch den Tensor des ersten Batches. Mit X[0][0] bekommt das erste Bild und den ersten (und einzigen) Kanal und kann es mit imshow (image show) plotten.

Die dazugehörige Kategorie ist:

3 Training

3.1 Hyperparameter

Zunächst definieren wir zwei weitere Hyperparameter:

Definition der Fehlerfunktion:

Festlegen des Optimierungsverfahrens:

3.2 Trainings- und Testfunktion

Jetzt definieren wir das Trainingsprozedere:

Eine separate Funktion für das Evaluieren des Modells auf den Testdaten.

3.3 Training FNN

Wir trainieren unser einfaches Feedforward-Netz.

3.4 Training CNN

3.5 Visualisierung

Wir sehen uns den Verlauf des Fehlers und der Accuracy über die Epochen an.

Vorab der Import und eine Hilfsfunktion.

Wir zeichnen Loss und Accuracy jeweils für Trainingsdaten (blaue) und Testdaten (grün).

4 Vergleich mit Keras

Hier wollen wir uns das identische CNN in Keras ansehen.

4.1 Netz

Hier zum Vergleich nochmal die PyTorch-Definition:

4.2 Daten