Entwicklung & Code

Künstliche Neuronale Netze im Überblick 6: Convolutional Neural Networks


Neuronale Netze sind der Motor vieler Anwendungen in KI und GenAI. Diese Artikelserie gibt einen Einblick in die einzelnen Elemente. Der sechste Teil widmet sich den Convolutional Neural Networks (CNNs).




Prof. Dr. Michael Stal arbeitet seit 1991 bei Siemens Technology. Seine Forschungsschwerpunkte umfassen Softwarearchitekturen für große komplexe Systeme (Verteilte Systeme, Cloud Computing, IIoT), Eingebettte Systeme und Künstliche Intelligenz.

Er berät Geschäftsbereiche in Softwarearchitekturfragen und ist für die Architekturausbildung der Senior-Software-Architekten bei Siemens verantwortlich.

Convolutional Neural Networks, im Deutschen auch faltungsneuronale Netze genannt, sind für die Verarbeitung von Daten mit einer gitterartigen Topologie wie Bildern konzipiert. Anstatt jede Eingabe vollständig mit jeder Ausgabe zu verbinden, verknüpft ein Convolutional Layer jede Ausgabe mit einem lokalisierten Bereich der Eingabe. Diese lokalisierte Verbindung nutzt die räumliche Struktur der Daten, um die Anzahl der Parameter zu reduzieren und Muster zu erfassen, die auch bei einer Verschiebung über die Eingabe hinweg aussagekräftig bleiben.

Das Herzstück einer Faltungsschicht ist die diskrete zweidimensionale Faltungsoperation. Wenn wir das Eingangsbild mit I und einen lernfähigen Filter oder Kernel mit K bezeichnen, dann wird die Faltung an der räumlichen Position (i, j) durch die doppelte Summe definiert:

(I * K)[i, j] = Σ_{m=0}^{k_h−1} Σ_{n=0}^{k_w−1} K[m, n] · I[i + m, j + n]

Hier sind k_h und k_w die Höhe und Breite des Kernels. Das Ergebnis ist eine Merkmalskarte, die alle Stellen im Bild hervorhebt, an denen das vom Kernel kodierte Muster auftritt.

PyTorch stellt eine 2D-Faltungsschicht durch die Klasse torch.nn.Conv2d bereit. Dieses Modul verwaltet einen Satz von Filtern mit der Form (out_channels, in_channels, k_h, k_w) und wendet sie auf einen gebündelten Eingabetensor der Form (batch_size, in_channels, height, width). Die Faltung verwendet außerdem einen Stride-Parameter, um Positionen zu überspringen, und einen Padding-Parameter, um einen Rand aus Nullen um die Eingabe herum einzufügen. Die Höhe und Breite der Ausgabe werden berechnet durch:

H_out = floor((H_in + 2·padding − dilation·(k_h − 1) − 1) / stride + 1)

W_out = floor((W_in + 2·padding − dilation·(k_w − 1) − 1) / stride + 1)

Nachfolgender Code erstellt eine Faltungsschicht und wendet sie auf einen Stapel von RGB-Bildern mit einer Größe von jeweils 32×32 Pixeln an.


import torch
import torch.nn as nn

# Erstellen Sie einen Stapel von acht RGB-Bildern mit einer Größe von 32×32
batch_size, in_channels, H, W = 8, 3, 32, 32
images = torch.randn(batch_size, in_channels, H, W)

# Definieren Sie eine Faltungsschicht mit 16 Ausgangskanälen, einem 3×3-Kernel, einem Schritt von eins und einer Auffüllung von eins
conv = nn.Conv2d(in_channels=3, out_channels=16, kernel_size=3, stride=1, padding=1)

# Wende die Faltung auf die Bilder an
features = conv(images)

# features hat die Form (8, 16, 32, 32)


Wenn die Schrittweite eins ist und die Auffüllung gleich (kernel_size−1)/2 für ungerade Kernel-Größen ist, hat die Ausgabe-Feature-Map die gleichen räumlichen Dimensionen wie die Eingabe. Die Beibehaltung der Dimensionen auf diese Weise ist in frühen Phasen der Bildverarbeitungsnetzwerke üblich. Im Gegensatz dazu führt ein Stride größer als eins oder die Verwendung von Pooling-Layern zu einer Verringerung der räumlichen Dimensionen. Ein Zwei-mal-Zwei-Max-Pooling-Layer mit Stride zwei halbiert beispielsweise sowohl die Höhe als auch die Breite seiner Eingabe.

Pooling führt eine Form der lokalen Translationsinvarianz ein und reduziert den Rechenaufwand in tieferen Schichten. Eine Max-Pooling-Operation über ein p×p-Fenster ersetzt jedes Fenster durch seinen Maximalwert, während Average Pooling das Fenster durch seinen Mittelwert ersetzt. Im Code erstellt man eine Pooling-Schicht, indem man torch.nn.MaxPool2d oder torch.nn.AvgPool2d instanziiert.

Convolutional Layers lassen sich sequenziell stapeln, um tiefe Merkmalshierarchien aufzubauen. Frühe Schichten lernen, einfache Muster wie Kanten und Texturen zu erkennen, und spätere Schichten kombinieren diese Muster zu abstrakteren Darstellungen wie Formen und Objekten. Nach mehreren Convolutional- und Pooling-Stufen flacht man die resultierenden Merkmalkarten oft zu einem Vektor ab und leitet diesen durch vollständig verbundene Schichten, um eine Klassifizierung oder Regression durchzuführen.

Ein minimales Convolutional Network in PyTorch könnte wie folgt aussehen. Jede Zeile des Codes erfasst einen Aspekt der Architektur.


import torch
import torch.nn as nn

class SimpleCNN(nn.Module):
    def __init__(self, num_classes=10):
        super(SimpleCNN, self).__init__()
        # Erster Faltungsblock: 3→16 Kanäle, Kernel 3×3, Auffüllung zur Beibehaltung der Größe
        self.conv1 = nn.Conv2d(in_channels=3, out_channels=16, kernel_size=3, padding=1)
        
        # Normalisieren Sie jede Merkmalskarte über den Batch auf einen Mittelwert von Null und eine Varianz von Eins
        self.bn1 = nn.BatchNorm2d(num_features=16)
        # Einführen von  Nichtlinearität
        self.relu = nn.ReLU()
        # Zweiter Faltungsblock: 16→32 Kanäle
        self.conv2 = nn.Conv2d(in_channels=16, out_channels=32, kernel_size=3, padding=1)
        self.bn2 = nn.BatchNorm2d(num_features=32)
        # Downsampling um den Faktor zwei
        self.pool = nn.MaxPool2d(kernel_size=2, stride=2)
        
        # Vollständig verbundene Schicht, die abgeflachten Merkmale auf Klassenscores abbildet
        self.fc = nn.Linear(in_features=32 * 16 * 16, out_features=num_classes)

    def forward(self, x):
        x = self.conv1(x)
        x = self.bn1(x)
        x = self.relu(x)
        x = self.conv2(x)
        x = self.bn2(x)
        x = self.relu(x)
        x = self.pool(x)
        x = x.view(x.size(0), -1)
        scores = self.fc(x)
        return scores

model = SimpleCNN(num_classes=10)
input_tensor = torch.randn(8, 3, 32, 32)
output_scores = model(input_tensor)
# output_scores hat die Form (8, 10)


Der erste Faltungsblock wandelt die dreikanalige Eingabe in sechzehn Merkmalskarten gleicher räumlicher Größe um. Die Batch-Normalisierung stabilisiert anschließend die Verteilung der Aktivierungen, was häufig das Training beschleunigt. Eine ReLU-Nichtlinearität führt die erforderliche Nichtlinearität ein. Der zweite Block wiederholt dieses Muster und reduziert nach dem Max-Pooling die Höhe und Breite jeder Merkmalskarte von 32 auf 16. Schließlich formen wir alle Merkmalskarten in einen zweidimensionalen Tensor der Form (batch_size, 32×16×16) um und leiten ihn durch eine lineare Schicht, um eine Bewertung pro Klasse zu erzeugen.

Convolutional Neural Networks bilden die Grundlage für modernste Modelle in der Bildverarbeitung und darüber hinaus.

Der nächste Teil der Serie widmet sich rekursiven neuronalen Netzen, die für die Verarbeitung sequenzieller Daten ausgelegt sind.


(rme)



Source link

Beliebt

Die mobile Version verlassen