Entwicklung & Code
Dynamic Consistency Boundaries: Flexible Konsistenz statt starrer Aggregates
Vielleicht kennen Sie das: Sie arbeiten an einem System mit Event-Sourcing (oder Sie möchten ein neues System damit aufbauen) und haben das Gefühl, dass Sie eigentlich schon recht weit sind. Sie haben eine gute Vorstellung davon, was Ihre Entitäten sind. Sie haben bereits erste Event-Typen formuliert, vielleicht sogar schon die ersten Commands. Doch dann kommt der Punkt, an dem Sie eine zentrale Frage beantworten müssen:
„Wie schneide ich eigentlich meine Aggregates?“
Golo Roden ist Gründer und CTO von the native web GmbH. Er beschäftigt sich mit der Konzeption und Entwicklung von Web- und Cloud-Anwendungen sowie -APIs, mit einem Schwerpunkt auf Event-getriebenen und Service-basierten verteilten Architekturen. Sein Leitsatz lautet, dass Softwareentwicklung kein Selbstzweck ist, sondern immer einer zugrundeliegenden Fachlichkeit folgen muss.
Und plötzlich wird alles kompliziert. Sie merken, dass die Entscheidung, wo Sie Ihre Konsistenzgrenzen ziehen, gar nicht so einfach ist. Sie ist im Gegenteil sogar eine der schwierigsten Entscheidungen in einem Event-getriebenen System und gleichzeitig leider auch eine der folgenreichsten. In diesem Blogpost möchte ich Ihnen zeigen, warum das so ist, warum Aggregates problematisch sein können und was Sie dagegen beziehungsweise stattdessen tun können.
Empfohlener redaktioneller Inhalt
Mit Ihrer Zustimmung wird hier ein externes YouTube-Video (Google Ireland Limited) geladen.
Dynamic Consistency Boundaries (DCB): Nie wieder Aggregates schneiden! // deutsch
Falls Sie mit Event-Sourcing noch nicht viel Erfahrung haben, empfehle ich Ihnen für den Einstieg zunächst das Video „Event-Sourcing – das einzige Video, das Du brauchst„. Dort erkläre ich Ihnen ausführlich, was Event-Sourcing überhaupt ist, wie es grundsätzlich funktioniert, wie man Events schreibt und sie nachher wieder liest, und warum das Ganze überhaupt sinnvoll ist.
Willkommen in der Stadtbibliothek!
Lassen Sie uns mit einem Beispiel beginnen – einem Beispiel, das ich inzwischen in vielen meiner Beiträge verwende, weil es einerseits einfach genug ist, um anschaulich und übersichtlich zu bleiben, und andererseits genug Komplexität bietet, um echte Probleme sichtbar zu machen. Die Rede ist von einer fiktiven Stadtbibliothek. Dort können Leserinnen und Leser Bücher ausleihen, sie bei Bedarf verlängern oder irgendwann (hoffentlich zumindest) zurückgeben. Es gibt außerdem Vormerkungen, Mahnungen und manchmal auch Strafen in Form von Gebühren, zum Beispiel, wenn etwas zu spät oder beschädigt zurückgegeben wird.
Natürlich gibt es auch Regeln, wie das Ganze ablaufen soll, beispielsweise:
„Eine Leserin oder ein Leser darf maximal drei Bücher gleichzeitig ausleihen.“
Oder:
„Ein Buch darf nur dann verlängert werden, wenn es nicht schon von jemand anderem vorgemerkt wurde.“
Das klingt zunächst recht einfach. Wenn Sie die Vorgaben jedoch in ein Event-basiertes System bringen möchten, werden Sie schnell merken: Die Umsetzung ist alles andere als trivial. Ein wesentlicher Grund dafür liegt in den Aggregates, die übrigens ironischerweise eigentlich gar nichts mit Event-Sourcing zu tun haben, da sie ursprünglich ein Konzept aus dem Domain-Driven Design (DDD) sind.
Aggregates sind transaktionale Konsistenzgrenzen
In DDD, und damit oft auch im Event-Sourcing, sind Aggregates die zentralen Konsistenzgrenzen. Sie kapseln Geschäftslogik, sie schützen Invarianten, sie garantieren, dass innerhalb ihrer Grenzen keine fachlich ungültigen Zustände entstehen können, und so weiter. Wenn Sie zum Beispiel ein Book-Aggregate haben, muss es sicherstellen, dass ein Buch nicht doppelt ausgeliehen werden kann oder nur dann zurückgegeben werden kann, wenn es vorher tatsächlich ausgeliehen wurde. Das klingt zunächst sinnvoll, und in vielen Fällen funktioniert es auch gut. Aber eben nicht immer. Aggregates haben ihren Preis. Wie es im Englischen so schön heißt: There is no free lunch.
Das Schneiden eines Aggregate ist eine weitreichende Entscheidung. Es bestimmt nicht nur, wo Konsistenz gilt, sondern auch, wie Sie Events strukturieren, wie Sie Commands modellieren, wie Sie dementsprechend Ihre APIs gestalten, wie Sie Ihre Event-Streams aufbauen, wie Sie diese speichern und wieder lesen. Kurz gesagt: Es bestimmt einen großen Teil Ihrer (Daten-)Architektur. Genau deshalb ist diese Entscheidung so wichtig – und gleichzeitig auch gefährlich.
Sie müssen sie nämlich sehr früh treffen, oft bevor Sie überhaupt genau wissen, wie Ihre Domäne im Detail funktioniert. Sie treffen also eine Entscheidung mit großer Tragweite auf der Basis von sehr wenig Wissen. Und sobald Sie sie einmal getroffen haben, wird es sehr schwierig, sie noch einmal zu revidieren.
Das Schlimmste an alldem: Aggregates sind keine isolierten Konzepte. Sie beeinflussen Ihr gesamtes System. Sie können sie nicht einfach umschneiden. Sie können sie nicht zur Laufzeit neu anordnen. Sie können sie nicht modular ersetzen wie einzelne Services oder Datenbanktabellen. Wenn Sie ein Aggregate falsch schneiden, zahlen Sie diesen Preis oft über Jahre.
Ein Beispiel aus der Praxis
Um das anschaulich zu machen, nehmen wir noch einmal das Beispiel aus der Bibliothek: Wir hatten gesagt, dass eine Leserin oder ein Leser maximal drei Bücher gleichzeitig ausgeliehen haben darf. Wenn Sie nun sagen
„Okay, dann mache ich einfach ein Reader-Aggregate“,
dann müssen Sie dort alle Ausleihen zusammenführen. Das bedeutet: Jedes Mal, wenn jemand ein Buch ausleihen möchte, müssen Sie alle bisherigen Ausleihen dieser Person kennen. Das wiederum bedeutet: Sie brauchen eine Event-Historie, die das abbildet – also einen Stream, der diese Informationen enthält. Doch was ist, wenn Sie stattdessen pro Ausleihe ein eigenes Aggregate haben wollen, also ein Loan-Aggregate?
Dann fehlt Ihnen plötzlich der Überblick: Sie wissen nicht, wie viele aktive Ausleihen es gibt, weil jede Ausleihe in einem eigenen Stream steckt. Sie müssten sie erst zusammenführen, was bei Event-Sourcing nicht trivial ist, da auf Event-Sourcing spezialisierte Datenbanken in der Regel keine Joins oder sonstige relationale Abfragen erlauben. Oder Sie entscheiden sich, das Buch als Aggregate zu modellieren. Dann steht die Regel aber völlig außerhalb des Kontexts dieses Aggregate, weil sie sich nicht auf ein einzelnes Buch, sondern auf die Summe der ausgeliehenen Bücher pro Leserin beziehungsweise pro Leser bezieht. Egal, wie Sie es schneiden – es passt nie so richtig.
Das Problem mit den Aggregates
Das eigentliche Problem: Aggregates sind statisch, viele Regeln sind in der Realität jedoch dynamisch. Aggregates sind strukturell, viele Geschäftsregeln dagegen semantisch. Aggregates orientieren sich an Objekten, viele Invarianten betreffen jedoch Beziehungen, Kombinationen oder Mengen. All das führt dazu, dass Sie Ihr Modell über kurz oder lang an die Struktur Ihrer Aggregate anpassen, statt Ihre Geschäftslogik so ausdrücken zu können, wie sie fachlich sinnvoll wäre.
Vielleicht war das früher weniger ein Problem. Solange Event-Sourcing ein Nischenthema für einige wenige war, konnte man sich mit komplexen Aggregates arrangieren. Das ändert sich jedoch derzeit. Event-Sourcing kommt langsam, aber stetig im Alltag an. Immer mehr Teams interessieren sich dafür, immer mehr Projekte setzen das Konzept produktiv ein. Websites wie CQRS.com und eventsourcing.ai oder Produkte wie EventSourcingDB (alle von the native web GmbH) tragen ihren Teil dazu bei. Doch je mehr Event-Sourcing in der Breite eingesetzt wird, desto mehr Menschen stoßen auf genau diese Fragen:
- Wie schneide ich meine Aggregates?
- Wie drücke ich Regeln aus, die sich nicht sauber in einem Objekt zusammenfassen lassen?
- Wie gehe ich mit Konsistenz um, wenn mehrere Dinge zusammenhängen?
Kurz: Was lange als Randproblem galt, wird für viele Entwicklerinnen und Entwickler zur Alltagsfrage. Wir brauchen Lösungen, die dem gerecht werden.
Eventual statt Strong Consistency
Es kommt noch etwas hinzu: Manche Regeln betreffen nicht nur mehrere Entitäten, sondern sogar mehrere Aggregates. Dann wird es richtig kompliziert. Stellen Sie sich vor, jemand möchte ein Buch verlängern. Um zu prüfen, ob das erlaubt ist, müssen Sie wissen: Ist das Buch aktuell überhaupt ausgeliehen? Ist es von der richtigen Person ausgeliehen? Ist es noch nicht vorgemerkt? All diese Informationen liegen in unterschiedlichen Kontexten vor: Die Ausleihe ist eine Transaktion zwischen der Leserin oder dem Leser und dem Buch. Die Vormerkung ist ein separater Kontext: Sie hängt zwar am Buch, ist aber kein Teil der Ausleihe. Die maximale Anzahl an Verlängerungen kann je nach Bibliotheksregelung ebenfalls eine Rolle spielen. Versuchen Sie, das alles in ein einziges Aggregate zu pressen. Das geht in der Regel entweder gar nicht oder nur um den Preis enormer Komplexität.
Viele Systeme akzeptieren in solchen Fällen die sogenannte Eventual Consistency. Das heißt: Sie lassen die Verlängerung zunächst durchgehen und prüfen dann asynchron, ob die Operation tatsächlich gültig war. Wenn nicht, erzeugen sie ein Kompensations-Event, schicken eine Benachrichtigung oder markieren den Zustand als ungültig. Das funktioniert technisch, ist aber aus fachlicher Sicht unsauber. Sie modellieren damit keine echte Invariante mehr, sondern einen nachträglichen Reparaturmechanismus.
Ergänzend enthalten viele Systeme sogenannte Prozessmanager oder Sagas, die diese Prüfungen orchestrieren. Sie führen mehrere Streams zusammen, lesen parallele Zustände, berechnen Ergebnisse und entscheiden auf Basis von Zeitverhalten, Idempotenz und Zustandskombinationen. Auch das funktioniert, ist jedoch schwer zu durchschauen, zu testen und zu warten. Oft ist es ein völlig überdimensioniertes Konstrukt für eine fachlich eigentlich einfache Regel.
Kill the Aggregate!
Genau deshalb stellt sich die Frage: Geht das nicht auch anders? Kann man Konsistenz nicht so modellieren, wie man sie eigentlich denkt? Also nicht in Form eines Objekts, das alles weiß, sondern in Form einer Regel, die einfach prüft: Gilt das, was ich fachlich will? Genau das ist die Idee hinter Dynamic Consistency Boundaries (oder kurz DCBs).
Dieser Begriff wurde von der italienischen Informatikerin Sara Pellegrini geprägt, die in einem Vortrag mit dem Titel „Kill Aggregate!“ (nach einigen Minuten mit englischen Untertiteln) vor ein paar Jahren genau dieses Paradigma infrage gestellt hat: Muss Konsistenz wirklich immer an einem Objekt hängen? Oder geht es auch anders, nämlich dynamisch, operationsspezifisch und regelbasiert? Stellen Sie sich vor, Sie formulieren eine Regel nicht in Form eines Aggregate, sondern als direkte Bedingung auf die Event-Historie. Zum Beispiel:
„Zähle alle Events vom Typ bookLoaned
, bei denen die Leser-ID 23 ist und für die noch kein bookReturned
-Event existiert. Wenn die Anzahl kleiner als drei ist, ist die Operation erlaubt.“
Das ist alles. Keine Aggregates. Kein Slicing. Keine Refactoring-Hölle. Keine Joins. Keine Prozessmanager. Keine Sagas. Einfach nur eine Regel: direkt formuliert, direkt überprüft und direkt durchgesetzt. Das ist die Stärke von Dynamic Consistency Boundaries: Sie machen die Konsistenzprüfung zum Teil der Operation und nicht zum Teil der Struktur.
Voraussetzungen für DCBs
Damit das in der Praxis funktioniert, müssen einige Voraussetzungen erfüllt sein. Erstens benötigen Sie Zugriff auf alle relevanten Events. Sie müssen also in der Lage sein, bestimmte Event-Typen zu filtern, zum Beispiel alle bookLoaned
-Events für eine bestimmte Nutzerin oder einen bestimmten Nutzer. Zweitens brauchen Sie die Möglichkeit, Bedingungen zu formulieren. Sie wollen etwas ausdrücken können wie:
„Wenn Bedingung X erfüllt ist, dann (und nur dann) schreibe Event Y.“
Drittens benötigen Sie ein System, das diese Bedingungen verlässlich prüft – serverseitig und atomar. Wenn Sie die Bedingungen im Anwendungscode prüfen und dann das Event schreiben, haben Sie wieder eine Race Condition. Diese drei Punkte zusammen bilden das Fundament für DCBs.
Genau das wird künftig zum Beispiel von der auf Event-Sourcing spezialisierten Datenbank EventSourcingDB unterstützt (die von meinem Unternehmen the native web entwickelt wird), und zwar über die eigens für EventSourcingDB entwickelte, deklarative Sprache EventQL. Sie können sich EventQL wie eine Art SQL vorstellen, nur für Events. Mit EventQL können Sie solche Regeln direkt formulieren und zukünftig beim Schreiben von Events in die EventSourcingDB als Vorbedingung angeben. Die Bedingung wird dann beim Schreiben des Events direkt im Server geprüft. Wenn sie erfüllt ist, wird das Event geschrieben. Wenn nicht, wird der Vorgang abgelehnt, und Sie können entsprechend reagieren. Das ist dann echte Konsistenz auf der Basis von realen Events – mit klaren Regeln, ohne Umwege.
Sie können damit Regeln abbilden, wie beispielsweise:
- Ein Gutschein darf nur einmal eingelöst werden.
- Ein Benutzername darf nicht doppelt vergeben sein.
- Eine Anwenderin darf sich nur einmal mit demselben Token einloggen.
- Eine Rechnung darf nur dann geschrieben werden, wenn der Auftrag abgeschlossen ist.
- Ein Buch darf nur dann zurückgegeben werden, wenn es vorher tatsächlich ausgeliehen wurde.
Werden klassische Aggregates überflüssig?
All das sind Beispiele für Regeln, die sich schwer oder gar nicht mit klassischen Aggregates umsetzen lassen – zumindest nicht ohne großen Aufwand und Nebenwirkungen. Mit Dynamic Consistency Boundaries und EventQL werden sie hingegen trivial.
Das bedeutet nicht, dass Aggregates vollständig überflüssig werden. Es gibt nach wie vor viele Anwendungsfälle, in denen sie sinnvoll sind, insbesondere wenn Sie komplexe Zustandsübergänge modellieren oder interne Logik kapseln möchten. Sie benötigen sie jedoch nicht mehr zwingend für jede Regel. Das ist der entscheidende Punkt. Sie können jetzt wählen: Sie können fachliche Regeln direkt ausdrücken, so wie Sie sie verstehen, und entscheiden, ob Sie dafür wirklich ein Aggregate brauchen oder ob eine dynamische Konsistenzgrenze nicht vielleicht die bessere Wahl ist.
(rme)
Entwicklung & Code
Android-Terminal: Hinweise auf GPU-Beschleunigung | heise online
In einer aktuellen Canary-Version von Android sind neue Hinweise auf eine GPU-Beschleunigung für Linux-Anwendungen aufgetaucht. Wie Android Authority berichtet, enthält Build 2509 eine bislang versteckte Option mit der Bezeichnung „Graphics Acceleration“, die einen Wechsel vom bekannten CPU-basierten Renderer (Lavapipe) auf eine GPU-beschleunigte Variante ermöglichen soll.
Die Funktion verweist offenbar auf gfxstream, ein in Android Open Source Project (AOSP) dokumentiertes Framework, das Grafikbefehle aus einer virtuellen Umgebung direkt an die Host-GPU weiterleiten kann. Auf diese Weise ließen sich Linux-Programme unter Android künftig deutlich flüssiger darstellen – etwa bei grafikintensiven Tools oder Anwendungen mit GUI-Oberfläche.
Im Praxistest zeigte sich die Funktion allerdings noch nicht einsatzbereit: Zwar ließ sich der versteckte Schalter aktivieren, eine tatsächliche GPU-Beschleunigung trat aber nicht ein. Auch von offizieller Seite gibt es bislang keine Bestätigung oder Details dazu, ob und wann die Neuerung in eine stabile Android-Version einfließen soll.
Die Funde deuten dennoch darauf hin, dass Google daran arbeitet, das Linux-Terminal auf Android langfristig leistungsfähiger zu machen – möglicherweise als Teil einer Strategie, Android stärker für klassische Desktop- und Entwicklerszenarien zu öffnen. Bis konkrete Informationen oder stabile Implementierungen vorliegen, bleibt die GPU-Beschleunigung allerdings ein experimentelles Feature mit unklarem Zeitplan.
(nb)
Entwicklung & Code
Rails-Entwicklerinnen und -Entwickler forken sich von Heinemeier Hansson weg
Eine Gruppe von Ruby-on-Rails-Entwicklerinnen und -Entwicklern ruft in einem offenen Brief dazu auf, einen Fork von Rails ins Leben zu rufen, der sich vom Gründer David Heinemeier Hansson (DHH) distanziert.
Der Aufruf an das Rails-Core-Team und die Community schlägt vor, die Zusammenarbeit mit Heinemeier Hansson abzubrechen, Rails mit einem neuen Namen zu forken und einen modernen Code of Conduct aufzustellen. Die Unterzeichnenden werfen Heinemeier Hansson private rassistische und transphobe Ansichten vor und berufen sich insbesondere auf zwei Blog-Einträge von ihm: „As I remember London“ und „Gender and Sexuality Alliances in primary school at CIS?!“.
Dass das Vorhaben der Rails-Gruppe sich vermutlich als schwierig erweist, sehen die Autoren selbst: „Wir erkennen an, dass das ein schwieriger Prozess ist … Wie auch immer, wissen wir es nicht, wenn wir es nicht probiert haben.“ Der Aufruf firmiert unter dem Namen Plan vert nach einer französischen Sabotagegruppe aus dem Zweiten Weltkrieg, die Anschläge auf Eisenbahneinrichtungen verübt hat.
David Heinemeier Hansson (DHH) antwortet bislang nur in einem X-Kommentar direkt auf den offenen Brief.
David Heinemeier Hansson hat bisher nur in einem X-Kommentar direkt auf den offenen Brief reagiert: „Das ist die gleiche Handvoll hysterischer Individuen, die dieselben Riten und Rituale aufführen, wie sie es jedes Jahr machen“.
In den Tagen zuvor gab es schon Unruhe in der Ruby-on-Rails-Community, da Ruby Central Projekte wie RubyGems an sich gezogen hat, ohne andere Maintainer und die Community im Vorfeld in diese Schritte einzubinden.
Update
26.09.2025,
10:37
Uhr
Inzwischen gibt es ein X-Posting von Heinemeier Hansson: „Dieser dämliche Brief, der zu nichts führen wird, hat nicht einmal 50 Unterschriften gesammelt. Wer mit klarem Verstand würde auch so eine offensichtliche Selbstdeklaration als ‚Stell mich niemals ein‘ unterschreiben.“
(who)
Entwicklung & Code
Künstliche Neuronale Netze im Überblick 10: Graphneuronale Netzwerke
Neuronale Netze sind der Motor vieler Anwendungen in KI und GenAI. Diese Artikelserie gibt einen Einblick in die einzelnen Elemente. Der zehnte Teil der Serie stellt graphneuronale Netze vor.
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.
Graphneuronale Netzwerke (Graph Neural Networks, GNN) erweitern das Konzept der neuronalen Berechnung von regulären Gitternetzen auf unregelmäßige Graphstrukturen und ermöglichen so Deep Learning für Daten, deren Beziehungen sich am besten durch Knoten und Kanten ausdrücken lassen. Ein Graph G besteht aus einer Menge von Knoten V und einer Menge von Kanten E zwischen diesen Knoten. Jeder Knoten i trägt einen Merkmalsvektor xᵢ, und das Muster der Kanten codiert, wie Informationen zwischen den Knoten fließen sollen.
Im Zentrum vieler GNNs steht ein Paradigma der Nachrichtenübermittlung. In jeder Schicht des Netzwerks sammelt jeder Knoten Informationen von seinen Nachbarn (aggregiert sie), transformiert diese aggregierte Nachricht und aktualisiert dann seine eigene Merkmalsdarstellung. Durch das Stapeln mehrerer Schichten können Knoten Informationen aus immer größeren Nachbarschaften einbeziehen.
Eine der einfachsten und am weitesten verbreiteten Formen der Graphfaltung ist das Graph Convolutional Network (GCN). Angenommen, wir haben N Knoten mit jeweils einem d-dimensionalen Merkmalsvektor, die in einer Matrix X ∈ ℝᴺˣᵈ gesammelt sind. Sei A ∈ ℝᴺˣᴺ die Adjazenzmatrix des Graphen, wobei Aᵢⱼ = 1 ist, wenn eine Kante vom Knoten i zum Knoten j besteht, und sonst Null. Um die eigenen Merkmale jedes Knotens einzubeziehen, addieren wir die Identitätsmatrix I zu A, wodurch à = A + I entsteht. Anschließend berechnen wir die Gradmatrix D̃, wobei D̃ᵢᵢ = Σⱼ Ãᵢⱼ ist. Eine einzelne GCN-Schicht transformiert X nach folgender Regel in neue Merkmale H ∈ ℝᴺˣᵈ′:
H = σ( D̃⁻½ · Ã · D̃⁻½ · X · W )
Hier ist W ∈ ℝᵈˣᵈ′ eine lernbare Gewichtungsmatrix und σ eine elementweise Nichtlinearität wie ReLU. Die symmetrische Normalisierung D̃⁻½ Ã D̃⁻½ stellt sicher, dass Nachrichten von Knoten mit hohem Grad diejenigen von Knoten mit niedrigem Grad nicht überlagern.
Nachfolgend steht eine minimale PyTorch-Implementierung einer einzelnen GCN-Schicht. Ich erkläre jeden Schritt ausführlich.
In diesem Code ist die Adjazenzmatrix ein dichter Tensor der Form (N, N). Zunächst fügen wir Selbstschleifen hinzu, indem wir mit der Identität summieren. Anschließend berechnen wir den Grad jedes Knotens, indem wir die Zeilen von à summieren. Durch Ziehen der inversen Quadratwurzel dieser Grade und Bilden einer Diagonalmatrix erhalten wir D̃⁻½. Multipliziert man D̃⁻½ mit beiden Seiten von Ã, erhält man die normalisierte Adjazenz. Die Knotenmerkmale X werden mit der Gewichtungsmatrix W multipliziert, um sie in einen neuen Merkmalsraum zu transformieren, und schließlich mischt die normalisierte Adjazenzmatrix diese transformierten Merkmale entsprechend der Graphstruktur. Eine ReLU-Aktivierung fügt Nichtlinearität hinzu.
import torch
import torch.nn as nn
class GCNLayer(nn.Module):
def __init__(self, in_features, out_features):
super(GCNLayer, self).__init__()
# Gewichtungsmatrix W der Form (in_features, out_features)
self.weight = nn.Parameter(torch.randn(in_features, out_features))
def forward(self, X, adjacency):
# Selbstschleifen hinzufügen, indem die Identitätsmatrix zur Adjazenz hinzugefügt wird
A_tilde = adjacency + torch.eye(adjacency.size(0), device=adjacency.device)
# Berechne die Gradmatrix von A_tilde
degrees = A_tilde.sum(dim=1)
# D_tilde^(-1/2) berechnen
D_inv_sqrt = torch.diag(degrees.pow(-0.5))
# Symmetrische Normalisierung: D^(-1/2) * A_tilde * D^(-1/2)
A_normalized = D_inv_sqrt @ A_tilde @ D_inv_sqrt
# Lineare Transformation: X * W
support = X @ self.weight
# Nachrichten weiterleiten: A_normalized * support
out = A_normalized @ support
# Nichtlinearität anwenden
return torch.relu(out)
Durch Stapeln mehrerer solcher Schichten verbessern sich die Ausgaben, zum Beispiel:
class SimpleGCN(nn.Module):
def __init__(self, input_dim, hidden_dim, output_dim):
super(SimpleGCN, self).__init__()
self.gcn1 = GCNLayer(input_dim, hidden_dim)
self.gcn2 = GCNLayer(hidden_dim, output_dim)
def forward(self, X, adjacency):
h1 = self.gcn1(X, adjacency)
# h1 dient als Eingabe für die nächste Schicht
h2 = self.gcn2(h1, adjacency)
return h2
Wir ermöglichen jedem Knoten, Informationen von Knoten zu sammeln, die bis zu zwei Hops entfernt sind. Für eine Klassifizierungsaufgabe, bei der jeder Knoten i ein Label yᵢ in {1,…,C} hat, können wir die endgültigen Ausgaben H ∈ ℝᴺˣᶜ mit einem Kreuzentropieverlust paaren, genau wie bei einer gewöhnlichen Klassifizierung, und durch Gradientenabstieg trainieren.
Über GCNs hinaus berechnen aufmerksamkeitsbasierte Graphennetzwerke kantenspezifische Gewichte, die einem Knoten mitteilen, wie stark er sich auf jeden Nachbarn konzentrieren soll. Das Graph Attention Network (GAT) führt lernbare Aufmerksamkeitskoeffizienten αᵢⱼ ein, die wie folgt definiert sind:
eᵢⱼ = LeakyReLU( aᵀ · [ W·xᵢ ∥ W·xⱼ ] )
αᵢⱼ = softmax_j( eᵢⱼ )
wobei ∥ die Verkettung bezeichnet, a ∈ ℝ²ᵈ′ ein lernbarer Vektor ist und softmax_j über alle Nachbarn von i normalisiert. Die Knotenaktualisierung lautet dann:
hᵢ′ = σ( Σⱼ αᵢⱼ · W·xⱼ ).
Die Implementierung einer GAT-Schicht von Grund auf folgt dem gleichen Muster der Nachrichtenübermittlung, erfordert jedoch die Berechnung von eᵢⱼ für jede Kante und anschließende Normalisierung. Bei großen Graphen verwendet man spärliche Darstellungen oder Bibliotheken wie PyTorch Geometric, um die Effizienz zu gewährleisten.
Graph Neural Networks eröffnen Anwendungsmöglichkeiten in der Chemie, der Analyse sozialer Netzwerke, Empfehlungssystemen und der kombinatorischen Optimierung. Sie bieten eine prinzipielle Möglichkeit, Darstellungen strukturierter Daten zu lernen, bei denen der Kontext jeder Entität durch ihre Beziehungen definiert ist.
Der nächste Teil der Serie beschäftigt sich mit Transformern, einer neuronalen Architektur, die vollständig auf Aufmerksamkeitsmechanismen basiert und ohne Rekursion und Faltung auskommt, um Sequenzen parallel zu verarbeiten.
(rme)
-
UX/UI & Webdesignvor 1 Monat
Der ultimative Guide für eine unvergessliche Customer Experience
-
UX/UI & Webdesignvor 4 Wochen
Adobe Firefly Boards › PAGE online
-
Social Mediavor 1 Monat
Relatable, relevant, viral? Wer heute auf Social Media zum Vorbild wird – und warum das für Marken (k)eine gute Nachricht ist
-
Entwicklung & Codevor 1 Monat
Posit stellt Positron vor: Neue IDE für Data Science mit Python und R
-
Entwicklung & Codevor 3 Wochen
EventSourcingDB 1.1 bietet flexiblere Konsistenzsteuerung und signierte Events
-
UX/UI & Webdesignvor 2 Wochen
Fake It Untlil You Make It? Trifft diese Kampagne den Nerv der Zeit? › PAGE online
-
Digital Business & Startupsvor 3 Monaten
10.000 Euro Tickets? Kann man machen – aber nur mit diesem Trick
-
Digital Business & Startupsvor 3 Monaten
80 % günstiger dank KI – Startup vereinfacht Klinikstudien: Pitchdeck hier