Entwicklung & Code
Künstliche Neuronale Netze im Überblick 8: Hybride Architekturen
Neuronale Netze sind der Motor vieler Anwendungen in KI und GenAI. Diese Artikelserie gibt einen Einblick in die einzelnen Elemente. Der achte Teil widmet sich hybriden Architekturen.
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.
Daten in der realen Welt haben oft mehrere Strukturdimensionen. Videos weisen beispielsweise sowohl räumliche Muster innerhalb jedes Frames als auch zeitliche Muster über Frames hinweg auf. Hybride Architekturen kombinieren die Stärken von Convolutional-, Recurrent- und Attention-basierten Schichten, um solche komplexen Daten zu modellieren. Dieses Kapitel veranschaulicht zwei gängige Muster: Convolution gefolgt von Recurrence und Convolution kombiniert mit Self-Attention (Selbstaufmerksamkeit).
Ein klassisches Hybridmodell für die Videoklassifizierung wendet zunächst unabhängig voneinander eine Reihe von Faltungsschichten auf jedes Bild an und erzeugt so einen Bildvektor, der die räumliche Struktur erfasst. Diese Bildvektoren werden dann in ein rekurrentes Netzwerk eingespeist, das zeitliche Abhängigkeiten modelliert. Konkret nehmen wir an, wir haben einen Stapel von Videos, die als Tensor der Form (batch_size
, seq_len
, channels
, height
, width
) dargestellt sind. Wir können zunächst alle Frames umformen und durch ein 2D-CNN verarbeiten, dann die zeitliche Achse wiederherstellen und ein LSTM (Long Short-Term Memory) anwenden:
import torch
import torch.nn as nn
Klasse CNNLSTM(nn.Module):
def __init__(self, num_classes, cnn_out_dim=128, hidden_dim=64):
super(CNNLSTM, self).__init__()
# Ein einfaches CNN, das (C,H,W) auf cnn_out_dim abbildet
self.cnn = nn.Sequential(
nn.Conv2d(3, 32, kernel_size=3, padding=1),
nn.ReLU(),
nn.MaxPool2d(2), # halbiert H,W
nn.Conv2d(32, 64, 3, padding=1),
nn.ReLU(),
nn.AdaptiveAvgPool2d((1,1)) # globales Merkmal
)
# Lineare Schicht zum Abflachen der CNN-Ausgabe
self.fc = nn.Linear(64, cnn_out_dim)
# LSTM zur Modellierung der zeitlichen Abfolge von Frame-Merkmalen
self.lstm = nn.LSTM(input_size=cnn_out_dim,
hidden_size=hidden_dim,
num_layers=1,
batch_first=True)
# Endgültiger Klassifikator, der die LSTM-Ausgabe den Klassenlogits zuordnet
self.classifier = nn.Linear(hidden_dim, num_classes)
def forward(self, videos):
# videos: (batch, seq_len, C, H, W)
b, t, c, h, w = videos.shape
# Batch und Zeit für CNN-Verarbeitung zusammenführen
frames = videos.view(b * t, c, h, w)
features = self.cnn(frames) # (b*t, 64, 1, 1)
features = features.view(b * t, 64)
features = self.fc(features) # (b*t, cnn_out_dim)
# Batch- und Zeitdimensionen wiederherstellen
features = features.view(b, t, -1) # (b, t, cnn_out_dim)
# LSTM erwartet (Batch, seq_len, Merkmal)
lstm_out, _ = self.lstm(features) # (b, t, hidden_dim)
# Verwenden Sie den endgültigen versteckten Zustand von LSTM für die Klassifizierung
final = lstm_out[:, -1, :] # (b, hidden_dim)
logits = self.classifier(final) # (b, num_classes)
return logits
# Anwendungsbeispiel
model = CNNLSTM(num_classes=10)
dummy_videos = torch.randn(4, 16, 3, 64, 64) # Stapel mit jeweils 4, 16 Frames
outputs = model(dummy_videos) # (4, 10)
In diesem Code reduziert das adaptive Average-Pooling jede Feature-Map auf eine einzige Zahl und wandelt die räumliche Karte in einen Vektor der Länge 64 um. Die lineare Schicht projiziert diesen Vektor für jedes Frame in ein 128-dimensionales Feature. Durch die Umformung des Tensors zurück zu (batch, seq_len, feature_dim)
speisen wir die Frame-Features in ein LSTM ein, das erfasst, wie sich Muster im Laufe der Zeit entwickeln. Schließlich nehmen wir die letzte Ausgabe des LSTM und leiten sie durch einen linearen Klassifikator, um Klassenscores zu erzeugen.
Ein alternativer hybrider Ansatz ersetzt das rekurrente Netzwerk durch einen Aufmerksamkeitsmechanismus. Nach der Extraktion der Merkmalskarten mit einem CNN (Convolutional Neural Network) kann man jeden räumlichen Ort (oder jeden Frame) als Token behandeln und Selbstaufmerksamkeit anwenden, um langfristige Abhängigkeiten zu modellieren. Der Kern der Selbstaufmerksamkeit ist die Skalarproduktformel, die für einen Satz von Abfrage-, Schlüssel- und Wertvektoren Q, K und V berechnet:
Attention(Q, K, V) = softmax( (Q·Kᵀ) / √d_k ) · V
Hier ist d_k die Dimension der Schlüsselvektoren, und softmax erzeugt Aufmerksamkeitsgewichte, die für jede Abfrage eins ergeben. In PyTorch kann man eine einzelne Multi-Head-Attention-Schicht wie folgt implementieren:
import torch.nn.functional as F
class CNNAttention(nn.Module):
def __init__(self, cnn_out_dim=128, num_heads=4):
super().__init__()
# CNN-Merkmalsextraktor (ähnlich wie zuvor)
self.cnn = nn.Sequential(
nn.Conv2d(3, 64, 3, padding=1),
nn.ReLU(),
nn.MaxPool2d(2),
nn.Conv2d(64, cnn_out_dim, 3, padding=1),
nn.ReLU()
)
# Multi-Head-Aufmerksamkeitsschicht
self.attn = nn.MultiheadAttention(embed_dim=cnn_out_dim,
num_heads=num_heads,
batch_first=True)
# Klassifikator
self.classifier = nn.Linear(cnn_out_dim, 10)
def forward(self, images):
# Bilder: (Batch, C, H, W)
features = self.cnn(images) # (b, cnn_out_dim, H', W')
b, d, h, w = features.shape
# Räumliche Dimensionen in Sequenz abflachen
seq = features.view(b, d, h*w).permute(0, 2, 1)
# Selbstaufmerksamkeit über räumliche Token
attn_out, _ = self.attn(seq, seq, seq) # (b, h*w, d)
# Über Tokens hinweg durch Mittelwertbildung bündeln
pooled = attn_out.mean(dim=1) # (b, d)
logits = self.classifier(pooled) # (b, 10)
return logits
# Anwendungsbeispiel
model = CNNAttention()
dummy_images = torch.randn(4, 3, 32, 32)
outputs = model(dummy_images) # (4,10)
Dieses hybride Design verwendet die Faltungsschichten, um ein räumliches Gitter aus Merkmalsvektoren zu erzeugen. Durch Abflachen des Gitters zu einer Sequenz der Länge H′·W′ behandeln wir jeden Ort als Token. Das Modul nn.MultiheadAttention
berechnet mehrere Sätze von Abfragen, Schlüsseln und Wertprojektionen, verkettet diese und projiziert sie zurück in die ursprüngliche Dimension, sodass das Modell vielfältige Beziehungen zwischen räumlichen Regionen erfassen kann. Durch Mittelwertbildung über alle Tokens erhält man eine globale Darstellung, die der Klassifikator verwenden kann.
Hybride Architekturen ermöglichen es, Lokalität, Sequenz und globalen Kontext in einem einzigen Modell zu nutzen. Sie kommen in Anwendungen zum Einsatz, die vom Verstehen von Videos bis zur Bildbeschriftung und darüber hinaus reichen.
Der nächste Teil der Serie blickt in die Zukunft der neuronalen Netze und zeigt auf, welche Trends, die nächste Generation von Modellen prägen.
(rme)