Tiefes Lernen mit PyTorch: Training, Validierung und Genauigkeit

Einführung

Im Bereich des Deep Learnings bieten die meisten Frameworks keine vorgefertigten Trainings-, Validierungs- und Genauigkeitsfunktionen. Viele Ingenieure finden daher den Einstieg in diese Funktionalitäten schwierig, wenn sie erstmals Datenwissenschaftsprobleme angehen. In den meisten Fällen implementieren Entwickler diese Prozesse manuell, was komplex werden kann. Um diese Funktionen zu schreiben, muss man die Prozesse genau verstehen. Dieses Anfängertutorial erklärt die genannten Prozesse auf einer höheren Ebene und zeigt, wie sie in PyTorch umgesetzt und kombiniert werden, um ein konvolutionales neuronales Netzwerk für eine Klassifizierungsaufgabe zu trainieren.

Voraussetzungen

  • Bereite den Datensatz vor und verarbeite ihn (z. B. Normalisierung, Größenänderung).
  • Nutze DataLoader für Batching und Shuffle-Training sowie Validierungsdaten.
  • Definiere ein neuronales Netzwerkmodell mit torch.nn.Module.
  • Wähle eine passende Verlustfunktion (z. B. nn.CrossEntropyLoss für Klassifizierungen).
  • Wähle einen Optimierer (z. B. Adam, SGD).
  • Implementiere Schleifen, um Modellgewichte zu aktualisieren, Verluste zu berechnen und Lernraten anzupassen.
  • Bewerte die Modellleistung mit einer Validierungsschleife.
  • Berechne die Genauigkeit mit torch.max für Klassifizierungsaufgaben.

Importe und Setup

Nachfolgend sind einige der Bibliotheken aufgeführt, die für diese Aufgabe benötigt werden. Gradient Notebook’s Deep-Learning-Laufzeiten enthalten sie vorinstalliert.

 
import torch
import torch.nn as nn
import torch.nn.functional as F
import torchvision
import torchvision.transforms as transforms
import torchvision.datasets as Datasets
from torch.utils.data import Dataset, DataLoader
import numpy as np
import matplotlib.pyplot as plt
import cv2
from tqdm.notebook import tqdm
if torch.cuda.is_available():
  device = torch.device('cuda:0')
  print('Running on the GPU')
else:
  device = torch.device('cpu')
  print('Running on the CPU')

Anatomie neuronaler Netzwerke

Neuronale Netzwerke bestehen aus Zahlen: Gewichten und Verzerrungen, die als Parameter bezeichnet werden. Ein Netzwerk mit 20 Millionen Parametern enthält 20 Millionen Zahlen, die jede Dateninstanz beeinflussen. Beispielsweise werden bei einem 28 x 28 Pixel großen Bild alle 784 Pixel von den 20 Millionen Parametern transformiert.

Modellziel

Das unten definierte ConvNet hat eine Ausgabeschicht, die einen zweielementigen Vektor erzeugt. Ziel des Modells ist es, eine binäre Klassifizierungsaufgabe zu lösen.

 
class ConvNet(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(3, 8, 3, padding=1)
        self.batchnorm1 = nn.BatchNorm2d(8)
        self.conv2 = nn.Conv2d(8, 8, 3, padding=1)
        self.batchnorm2 = nn.BatchNorm2d(8)
        self.pool2 = nn.MaxPool2d(2)
        self.conv3 = nn.Conv2d(8, 32, 3, padding=1)
        self.batchnorm3 = nn.BatchNorm2d(32)
        self.conv4 = nn.Conv2d(32, 32, 3, padding=1)
        self.batchnorm4 = nn.BatchNorm2d(32)
        self.pool4 = nn.MaxPool2d(2)
        self.conv5 = nn.Conv2d(32, 128, 3, padding=1)
        self.batchnorm5 = nn.BatchNorm2d(128)
        self.conv6 = nn.Conv2d(128, 128, 3, padding=1)
        self.batchnorm6 = nn.BatchNorm2d(128)
        self.pool6 = nn.MaxPool2d(2)
        self.conv7 = nn.Conv2d(128, 2, 1)
        self.pool7 = nn.AvgPool2d(3)

    def forward(self, x):
        x = x.view(-1, 3, 32, 32)
        output_1 = self.conv1(x)
        output_1 = F.relu(output_1)
        output_1 = self.batchnorm1(output_1)
        output_2 = self.conv2(output_1)
        output_2 = F.relu(output_2)
        output_2 = self.pool2(output_2)
        output_2 = self.batchnorm2(output_2)
        output_3 = self.conv3(output_2)
        output_3 = F.relu(output_3)
        output_3 = self.batchnorm3(output_3)
        output_4 = self.conv4(output_3)
        output_4 = F.relu(output_4)
        output_4 = self.pool4(output_4)
        output_4 = self.batchnorm4(output_4)
        output_5 = self.conv5(output_4)
        output_5 = F.relu(output_5)
        output_5 = self.batchnorm5(output_5)
        output_6 = self.conv6(output_5)
        output_6 = F.relu(output_6)
        output_6 = self.pool6(output_6)
        output_6 = self.batchnorm6(output_6)
        output_7 = self.conv7(output_6)
        output_7 = self.pool7(output_7)
        output_7 = output_7.view(-1, 2)
        return F.softmax(output_7, dim=1)

Das richtige Training

Trainiere das Modell, indem du Daten in Batches aufteilst, den Verlust berechnest (Forward Propagation) und die Parameter anpasst (Backpropagation). Wiederhole diesen Vorgang für alle Batches, bis das Training abgeschlossen ist.

 
def train(network, training_set, batch_size, optimizer, loss_function):
    loss_per_batch = []
    train_loader = DataLoader(training_set, batch_size)
    print('Training...')
    
    for images, labels in tqdm(train_loader):
        images, labels = images.to(device), labels.to(device)
        optimizer.zero_grad()
        classifications = network(images)
        loss = loss_function(classifications, labels)
        loss_per_batch.append(loss.item())
        loss.backward()
        optimizer.step()
    
    print('Fertig!')
    return loss_per_batch

[/dm_code_snippet>

Generalisierung und Validierung

Testen Sie die optimierten Parameter auf einem separaten Validierungsdatensatz, um sicherzustellen, dass sie auf neue Daten generalisiert werden können. Während der Validierung erfolgt keine weitere Optimierung der Parameter.

 
def validate(network, validation_set, batch_size, loss_function):
    """
    Validiert die Parameteroptimierungen des Modells.
    """
    loss_per_batch = []
    network.eval()
    val_loader = DataLoader(validation_set, batch_size)
    print('Validierung...')
    
    with torch.no_grad():
        for images, labels in tqdm(val_loader):
            images, labels = images.to(device), labels.to(device)
            classifications = network(images)
            loss = loss_function(classifications, labels)
            loss_per_batch.append(loss.item())
    
    print('Fertig!')
    return loss_per_batch

Leistungsmessung

Vergleichen Sie die Vorhersagen des Modells mit den tatsächlichen Labels, um die Genauigkeit zu berechnen. Dies gilt insbesondere bei Klassifizierungsaufgaben mit ausgewogenen Datensätzen.

 
def accuracy(network, dataset):
    """
    Berechnet die Genauigkeit des Modells.
    """
    network.eval()
    total_correct = 0
    total_instances = 0
    dataloader = DataLoader(dataset, 64)
    
    with torch.no_grad():
        for images, labels in tqdm(dataloader):
            images, labels = images.to(device), labels.to(device)
            classifications = torch.argmax(network(images), dim=1)
            correct_predictions = sum(classifications == labels).item()
            total_correct += correct_predictions
            total_instances += len(images)
    
    return round(total_correct / total_instances, 3)

Datensatz

Verwenden Sie den CIFAR-10-Datensatz, um die Prozesse in der Praxis zu demonstrieren. Der Datensatz enthält Bilder mit einer Auflösung von 32 x 32 Pixeln, die in 10 Klassen unterteilt sind.

 
# Laden der Trainingsdaten
training_set = Datasets.CIFAR10(root='./', download=True,
                                transform=transforms.ToTensor())

# Laden der Validierungsdaten
validation_set = Datasets.CIFAR10(root='./', download=True, train=False,
                                  transform=transforms.ToTensor())

Architektur des ConvNet

Passen Sie das ConvNet an, um einen Vektor mit 10 Elementen auszugeben, da es sich um eine Klassifizierungsaufgabe mit 10 Klassen handelt. Hier ist der Code:

 
class ConvNet(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(3, 8, 3, padding=1)
        self.batchnorm1 = nn.BatchNorm2d(8)
        self.conv2 = nn.Conv2d(8, 8, 3, padding=1)
        self.batchnorm2 = nn.BatchNorm2d(8)
        self.pool2 = nn.MaxPool2d(2)
        self.conv3 = nn.Conv2d(8, 32, 3, padding=1)
        self.batchnorm3 = nn.BatchNorm2d(32)
        self.conv4 = nn.Conv2d(32, 32, 3, padding=1)
        self.batchnorm4 = nn.BatchNorm2d(32)
        self.pool4 = nn.MaxPool2d(2)
        self.conv5 = nn.Conv2d(32, 128, 3, padding=1)
        self.batchnorm5 = nn.BatchNorm2d(128)
        self.conv6 = nn.Conv2d(128, 128, 3, padding=1)
        self.batchnorm6 = nn.BatchNorm2d(128)
        self.pool6 = nn.MaxPool2d(2)
        self.conv7 = nn.Conv2d(128, 10, 1)
        self.pool7 = nn.AvgPool2d(3)

    def forward(self, x):
        x = x.view(-1, 3, 32, 32)
        output_1 = self.conv1(x)
        output_1 = F.relu(output_1)
        output_1 = self.batchnorm1(output_1)
        output_2 = self.conv2(output_1)
        output_2 = F.relu(output_2)
        output_2 = self.pool2(output_2)
        output_2 = self.batchnorm2(output_2)
        output_3 = self.conv3(output_2)
        output_3 = F.relu(output_3)
        output_3 = self.batchnorm3(output_3)
        output_4 = self.conv4(output_3)
        output_4 = F.relu(output_4)
        output_4 = self.pool4(output_4)
        output_4 = self.batchnorm4(output_4)
        output_5 = self.conv5(output_4)
        output_5 = F.relu(output_5)
        output_5 = self.batchnorm5(output_5)
        output_6 = self.conv6(output_5)
        output_6 = F.relu(output_6)
        output_6 = self.pool6(output_6)
        output_6 = self.batchnorm6(output_6)
        output_7 = self.conv7(output_6)
        output_7 = self.pool7(output_7)
        output_7 = output_7.view(-1, 10)
        return F.softmax(output_7, dim=1)

Zusammenführung der Prozesse

Kombinieren Sie das Training und die Validierung in einer Funktion oder Klasse, um den gesamten Prozess zu optimieren und synchron zu halten.

 
# Instanziieren des Modells
model = ConvNet()
# Definieren des Optimierers
optimizer = torch.optim.Adam(model.parameters(), lr=3e-4)

# Training
training_losses = train(network=model, training_set=training_set, 
                        batch_size=64, optimizer=optimizer, 
                        loss_function=nn.CrossEntropyLoss())

# Validierung
validation_losses = validate(network=model, validation_set=validation_set, 
                             batch_size=64, loss_function=nn.CrossEntropyLoss())

# Genauigkeit berechnen
training_accuracy = accuracy(model, training_set)
print(f'Training Accuracy: {training_accuracy}')

validation_accuracy = accuracy(model, validation_set)
print(f'Validation Accuracy: {validation_accuracy}')

Abschlussbemerkungen

Dieses Tutorial zeigt, wie Sie Trainings-, Validierungs- und Genauigkeitsprozesse in PyTorch implementieren. Die Schritte wurden in eine effiziente und wiederverwendbare Struktur integriert, die sich für reale Projekte anwenden lässt.

Kostenlosen Account erstellen

Registrieren Sie sich jetzt und erhalten Sie Zugang zu unseren Cloud Produkten.

Das könnte Sie auch interessieren: