PyTorch - Grundlagen

Während diesem Semester werden wir uns intensiv mit PyTorch beschäftigen. Sie benötigen eine funktionierende Installation von PyTorch, um die Aufgaben zu bearbeiten. Sie sollen die offizielle Installationsanleitung von PyTorch befolgen, die Sie hier finden.

Installieren Sie PyTorch mit der passenden Konfiguration für Ihre Hardware und Ihr Betriebssystem. Achten Sie darauf, dass Sie die richtige Version von CUDA auswählen, wenn Sie eine NVIDIA-GPU verwenden möchten.

Überprüfen Sie anschließend ihre Installation, indem Sie die folgenden Befehle in einem Python-Interpreter ausführen:

import torch
print(torch.__version__)
print(torch.cuda.is_available())

Wenn die Installation erfolgreich war, sollten Sie die PyTorch-Version und den Status der CUDA-Verfügbarkeit sehen.

Aufgabe 1: Ein einfaches neuronales Netzwerk erstellen

In dieser Aufgabe werden Sie ein einfaches neuronales Netzwerk mit PyTorch erstellen. Folgen Sie den Schritten in der offiziellen Dokumentation, um ein neuronales Netzwerk zu definieren, es zu trainieren und die Leistung zu bewerten.

Sie arbeiten in der Datei pytorch/simple.py.

Wir wollen das s.g. XOR-Problem lösen, bei dem das Netzwerk lernen soll, die logische XOR-Funktion zu approximieren. Sie sollen ein Netzwerk mit mindestens einem versteckten Layer erstellen, das in der Lage ist, diese Aufgabe zu bewältigen.

Definieren Sie zunächst die Trainingsdaten für das XOR-Problem:

\[\begin{split}\begin{align*} \text{Input} & : \begin{pmatrix} 0 & 0 \\ 0 & 1 \\ 1 & 0 \\ 1 & 1 \end{pmatrix} \\ \text{Output} & : \begin{pmatrix} 0 \\ 1 \\ 1 \\ 0 \end{pmatrix} \end{align*}\end{split}\]

Legen Sie dazu PyTorch-Tensoren für die Eingaben und Ausgaben an. Achten Sie darauf die Tensoren direkt im richtigen Datentyp zu erstellen, z.B. torch.float32 für die Eingaben und torch.long für die Zielklassen. Legen Sie diese Tensoren auf das richtige Gerät (CPU oder GPU) ab, abhängig von Ihrer Hardware. Schauen Sie in die offizielle Dokumentation, wie Sie dies tun können.

Lösung anzeigen

training_data = torch.tensor(
  [[0.0, 0.0], [0.0, 1.0], [1.0, 0.0], [1.0, 1.0]], dtype=torch.float32, device=DEVICE
)
labels = torch.tensor([0, 1, 1, 0], dtype=torch.long, device=DEVICE)

Aufgabe 2: Das Netzwerk definieren

Implementieren Sie nun die Klasse SimpleNetwork, die ein einfaches neuronales Netzwerk mit einem versteckten Layer definiert. PyTorch Module sind Klassen, die von torch.nn.Module erben. Sie managen das registrieren von trainierbaren Parametern und bieten eine einfache Schnittstelle für das Training und die Vorhersage.

Es ist zwingend notwendig, dass Sie die forward-Methode implementieren, die die Vorwärtsausbreitung des Netzwerks definiert. Da unser Netzwerk trainierbare Parameter hat müssen Sie auch die __init__-Methode implementieren, die die Struktur des Netzwerks definiert. Rufen Sie immer in der __init__-Methode die super().__init__()-Methode auf, um die Basisklasse zu initialisieren. Verwenden Sie dann torch.nn.Linear für die Definition der Schichten des Netzwerks.

class pytorch.simple.SimpleNetwork[Quellcode]

Ein einfaches neuronales Netzwerk mit einer versteckten Schicht.

__init__()[Quellcode]

Initialisiert das Netzwerk mit einer versteckten Schicht.

TODO:

  • Rufen Sie die Methode super().__init__() auf, um die Basisklasse zu initialisieren.

  • Definieren Sie die erste voll verbundene Schicht fc1 mit 2 Eingängen und 8 Ausgängen.

  • Definieren Sie die zweite voll verbundene Schicht fc2 mit 8 Eingängen und 2 Ausgängen.

forward(x)[Quellcode]

Führt den Vorwärtsdurchlauf des Netzwerks aus.

TODO:

  • Wenden Sie die erste voll verbundene Schicht fc1 auf die Eingabe x an.

  • Wenden Sie die ReLU-Aktivierungsfunktion (torch.relu) auf die Ausgabe der ersten Schicht fc1 an.

  • Wenden Sie die zweite voll verbundene Schicht fc2 auf die Ausgabe der ReLU-Aktivierung an.

  • Geben Sie die Ausgabe der zweiten Schicht fc2 zurück.

Lösung für den Konstruktor __init__ anzeigen

def __init__(self):
  super().__init__()
  self.fc1 = nn.Linear(2, 8)
  self.fc2 = nn.Linear(8, 2)

Lösung für die Forward-Methode anzeigen

def forward(self, x):
    x = self.fc1(x)
    x = torch.relu(x)
    x = self.fc2(x)
    return x

Aufgabe 3: Das Netzwerk trainieren

Implementieren Sie dann die Methode

pytorch.simple.train_model(model, data, labels, criterion, optimizer, epochs=8000)[Quellcode]

Trainiert das Modell mit den gegebenen Daten und Labels.

Diese Funktion führt das Training des Modells durch, indem sie die Eingabedaten und Labels verwendet, um die Gewichte des Modells zu aktualisieren. Der Verlust wird in jeder 1000. Epoche ausgegeben.

Parameter:

modelnn.Module

Das zu trainierende neuronale Netzwerk.

datatorch.Tensor

Die Eingabedaten für das Training.

labelstorch.Tensor

Die zugehörigen Labels für die Eingabedaten.

criterionnn.Module

Das Kriterium zur Berechnung des Verlusts (z.B. CrossEntropyLoss).

optimizertorch.optim.Optimizer

Der Optimierer, der verwendet wird, um die Gewichte des Modells zu aktualisieren

epochsint, optional

Die Anzahl der Epochen, die das Modell trainiert werden soll (Standard: 8000).

TODO:

Iterieren Sie über die Anzahl der Epochen und führen Sie in jeder Epoche die folgenden Schritte aus:

  • Setzen Sie die Gradienten des Optimierers zurück. (optimizer.zero_grad())

  • Führen Sie einen Vorwärtsdurchlauf des Modells mit den Eingabedaten data durch.

  • Berechnen Sie den Verlust zwischen den Modell-Ausgaben und den Labels mit dem Kriterium criterion.

  • Führen Sie den Rückwärtsdurchlauf durch, um die Gradienten zu berechnen. (loss.backward())

  • Geben Sie den Verlust alle 1000 Epochen aus.

  • Führen Sie den Optimierungsschritt durch, um die Gewichte des Modells zu aktualisieren. (optimizer.step())

um das Netzwerk zu trainieren.

Lösung für die Forward-Methode anzeigen

def train_model(model, data, labels, criterion, optimizer, epochs=8000):
    for epoch in range(epochs):
        optimizer.zero_grad()
        outputs = model(data)
        loss = criterion(outputs, labels)
        loss.backward()
        if epoch % 1000 == 999:
            print(f"Epoch {epoch+1}, Loss: {loss.item()}")
        optimizer.step()

Aufgabe 4: Das Netzwerk testen

Starten Sie das Training des Netzwerks, indem Sie das Skript pytorch/simple.py ausführen.

python pytorch/simple.py

Epoch 1000, Loss: 0.03407074883580208
Epoch 2000, Loss: 0.009740689769387245
Epoch 3000, Loss: 0.005211123265326023
Epoch 4000, Loss: 0.0034439843147993088
Epoch 5000, Loss: 0.0025294627994298935
Epoch 6000, Loss: 0.001979016000404954
Epoch 7000, Loss: 0.0016146576963365078
Epoch 8000, Loss: 0.0013573128962889314
Training complete.
tensor([[ 3.0257, -3.4460],
        [-3.0238,  3.6015],
        [-2.5722,  4.1114],
        [ 3.9732, -2.6664]], device='cuda:0')

Musterlösung

Ein einfaches Netzwerk trainieren - Musterlösung