Interaktive Online-Beispiele IX
(Triangulierung & Tree-Decomposition)
In diesem Abschnitt geht es um
Optimierungen der Triangulierung eines Bayes'schen Netzes zur
Überführung (Tree-Decomposition) in einen
Junction-Tree.
Dies ist die Fortsetzung zu den hier dargestelleten
Beispielen (bitte ggf. zunächst dort nachlesen, wie die
Netze zu bedienen sind).
Evolutionäre Algorithmen
Um ein Bayes'sche Netz in einen Junction-Tree zu
überführen wird das Netz:
zunächst "moralisiert" (paarweise Verbindung
aller Elternknoten eines gemeinsamen Kindknotens durch
eine ungerichtete Kante),
danach in ein komplett ungerichteten Graphen
überführt (jede gerichtete Kante wird durch
eine entsprechende ungerichtete ersetzt)
und schließlich trianguliert (durch weitere
ungerichtete Kanten, die Fill-Ins, wird dafür
gesorgt, dass es keinen nicht abkürzbaren Zyklus
mit mehr als drei Knoten mehr gibt)
In diesem triangulierten Netz werden dann (bzw.
schon während der Triangulierung) die Cliquen
(vollständig verbundene Teilgraphen)
identifiziert und
diese Cliquen dann zu einer Baumstruktur, dem
sogenannten Junction-Tree, verbunden.
Genaueres kann hier
(Junction-Trees) und hier
(Tree-Decomposition) nachgelesen werden. Entscheidender
Knackpunkt ist dabei die Triangulierung. Ein Graph kann
i.d.R. auf unterschiedliche Art und Weise trianguliert
werden. Diese Triangulierung kann dann besser oder
schlechter sein - gemessen z.B. anhand der Anzahl der
benötigten zusätzlichen Fill-In-Kanten, oder
anhand der Cliquen-Größen. Der häufig
verwendete One-Step-Look-Ahead-Algorithmus
(Greedy-Algorithmus) führt in hinreichend komplexen
Netzen selten zu einem optimalen Ergebnis. Mit Evolutionären
Algorithmen, sowie anderen Optimierungsverfahren,
lässt die Güte der erzeugten Junction-Trees (mit
entsprechend erhöhtem Aufwand) deutlich verbessern.
Mein Versuch mit der Ant-Colony-Optimization
kann allerdings als mehr oder weniger gescheitert
angesehen werden.
Unten kann man nun den Evolutionären Ansatz mit ein
paar Rekombinations- und Mutations-Algorithmen und einigen
unterschiedlichen Parameter-Einstellungen durchgespielen.
Das ganze eignet sich allerdings nicht so sehr gut
für ein Java-Script-Beispiel, weil wirklich
hinreichend komplexe Netze mit genügend "Individuen"
(Lösungen) und Generationen einfach sehr lange
Rechenzeiten benötigen. Zudem kann man momentan noch
nicht in den eigentlichen Ablauf "hineinblicken" (evtl.
fällt mir dafür noch was ein...). Bis dahin
sieht man hauptsächlich einen Graph der die Anzahl
Fill-Ins links (vertikale Achse) über den
Generationen (horizontale Achse) angibt. Jeder horizontale
Strich steht dabei für ein Individuum (d.h. eine
Lösung). Je dunkler ein Strich und stärker sein
(rötlicher) Schatten desto mehr Individuen haben
dieselbe Güte (gemessen an der Anzahl Fill-In-Links).
Da die zufällig erzeugten Netze noch recht einfach
sind, findet normalerweise bereits der einfache
One-Step-Lookahead-Algorithmus eine so gute Lösung,
dass diese durch die hier verwendeten Evolutionären
Algorithmus nicht weiter verbessert werden kann. Aus
diesem Grunde macht es wenig Sinn für die
"Erzeugungsart der initialen Individuen" die Einstellung
"Greedy (One-Step-Lookahead)" zu wählen...