Team TrainingLoop
Übersicht
- Mitglieder
- Einleitung
- Ziele
- Confusionmatrix
- One Hot Konvertierung
- Segmentation Pipeline Optimizer
- Fazit
- Ausblick
Mitglieder
Jan-Gerrit Göbel , Karol Baginski , Lukas Schäfer , Markus Rink , Nina Unterberg , Philipp Haker
Einleitung
Das Team Trainingloop beschäftigt sich mit der Verbesserung der Trainingsschleife für eine Segmentierung, die aus Preprocessing, Training des neuronalen Netzes und dem Postprocessing besteht. Auf dieser Seite wird im Abschnitt Ziele zunächst ein Überblick über die Ziele der gesamten Gruppe gegeben. Anschließend werden in den Abschnitten Confusionmatrix> und One Hot Konvertierung die Entwicklungen der beiden erstellten Module beschrieben. Im Abschnitt Segmentation Pipeline Optimizer wird ein Konzept zur Optimierung einer Segmentation Pipeline vorgestellt und ein Ausblick auf die mögliche Umsetzung für Fraunhofer MEVIS gegeben. Anschließend wird das Fazit der gesamten Gruppe gezogen.
Ziele
Das Hauptziel des Teams war es, Module und Konzepte zu entwickeln, die es anderen Personen ermöglichen sollen, neuronale Netze effektiver und effizienter zu trainieren und analysieren. Außerdem soll die Nutzung von einer Pipeline für verschiedene Segmentierungsprobleme ermöglicht werden.
Innerhalb der Gruppe werden drei unterschiedliche Module und Konzepte entwickelt.
Die erste Untergruppe beschäftigt sich mit der Entwicklung eines MeVisLab-Moduls, das ein bereits trainiertes
Netz analysieren und die Ergebnisse übersichtlich darstellen soll.
Im Laufe der Einarbeitung in MeVisLab{} wurde die Confusionmatrix als Darstellungsform gewählt, die als Modul umgesetzt werden soll.
Mithilfe der Ergebnisse dieser Confusionmatrix kann das Training des analysierten Netzes angepasst werden.
Das MeVisLab{}-Modul, welches von der zweiten Untergruppe entwickelt wird, konvertiert die unterschiedlichen Kodierungen,
in denen Datensätze vorliegen können.
In dem Modul werden die Kodierungen in einem One- bzw. Multi-Hot-Vector, als Bitmaske und als Integer Label berücksichtigt.
Dadurch soll das Preprocessing innerhalb der Segmentierungspipeline erleichtert werden.
Die letzte Untergruppe entwirft ein Konzept zur Nutzung eines nnU-Net zur Optimierung einer Segmentierungspipeline für
unterschiedliche Segmentierungsprobleme.
Bisher musste die Pipeline für die Nutzung in unterschiedlichen Aufgabenstellungen manuell angepasst werden,
dieser Vorgang soll automatisiert werden.
Außerdem wird ein Ausblick auf eine mögliche Umsetzung des Konzepts für das Fraunhofer MEVIS gegeben.
Confusionmatrix
Einleitung
In diesem Kapitel wird die Entwicklung des Confusionmatrix-Moduls beschrieben. Als Erstes wird dargestellt, was das Team zur Entwicklung des Moduls angeregt hat und welche Ziele mit dem Modul erreicht werden sollen. Anschließend wird das Konzept der Confusionmatrix erläutert und auf das Vorgehen während der Entwicklung eingegangen. Das Berechnen der Confusionmatrix, sowie weitere Funktionen im Zusammenhang mit der Darstellung und weiteren Verarbeitung, werden in sechs MeVisLab-Modulen implementiert. Daran anschließend wird das Ergebnis der Implementierung präsentiert und die Integration der Confusionmatrix in Challengr beschrieben. Abschließend wird ein Fazit gezogen und ein Ausblick auf eine mögliche Zukunft des Moduls gegeben.
Ziele
Als erste Idee wurde ein Tool vorgeschlagen, das als Hilfe dafür dienen soll, ein trainiertes neuronales Netz auszuwerten. Die Informationen, die durch die Analyse des Netzes gewonnen werden, sollen anschließend eine Verbesserung des Trainings ermöglichen. Das zu entwickelnde Modul soll schnell und übersichtlich anzeigen, wie gut ein Netz trainiert ist. Hierfür soll eine Confusionmatrix erstellt werden, welche die Annotationen eines MRT-Bildes, die durch einen Experten und durch ein neuronales Netz erstellt wurden, miteinander vergleicht. Dabei sollen verschiedene Label der Annotation einzeln verglichen werden, um eine genaue Vorstellung davon vermitteln zu können, in welchen Bereichen ein trainiertes Netz Schwierigkeiten aufweist. Das Modul soll ebenfalls die Möglichkeit bieten, die Bereiche, in denen es gehäuft zu Fehlern in der Annotation durch das neuronale Netz kommt, visuell darzustellen.
Was ist eine Confusionmatrix?
Eine Confusionmatrix oder Error Matrix vergleicht den Soll- und Ist-Zustand bei einem Klassifikationsverfahren.
Die Klassen werden in Reihe und Spalte gleichmäßig aufgelistet und spannen so eine Matrix auf.
Die Reihen repräsentieren dabei die Ground Truth Klassen und die Spalte die vom Netz zugeordnete Klasse oder vice versa.
Ein Feld der Matrix zählt die Anzahl an Zuordnungen, für die das Paar Ground Truth/Prädiktion zutrifft.
Werden alle Klassen getestet und klassifiziert das Netz alle Eingaben korrekt, entsteht in der Matrix eine Diagonale mit
Werten >0. In diesem Szenario haben alle anderen Felder den Wert 0.
Zur Visualisierung wird häufig eine Farbkodierung verwendet, sodass eine Heatmap entsteht.
Für Segmentierung als spezielle Klassifikation wird jeder Voxel je nach Label in der Matrix zugeordnet.
Zum besseren Verständnis wurden die absoluten Werte in Prozentzahlen umgerechnet.
Vorgehen
Da keiner im Team vor dem Projekt bereits mit MeVisLab gearbeitet hatte,
wurden die ersten Wochen dafür verwendet sich mit MeVisLab{} und den Modulen auseinanderzusetzen.
Alle Mitglieder die vorher noch nicht mit Python gearbeitet hatten, haben sich zudem in diese Programmiersprache eingearbeitet.
Während dieser Zeit wurde auch das Ziel dieser Untergruppe spezifiziert und schriftlich festgehalten.
In den folgenden Wochen wurde zunächst ein MeVisLab{}-Modul erstellt welches alle Funktionen in Bezug auf das Ziel umsetzt,
von der Berechnung der Confusion Matrix bis hin zur Darstellung der Matrix, sowie das Anzeigen von Unterschieden in Annotationen.
Auf Anregung durch die Projektleiter wurde das Modul in mehrere Module mit spezialisierten Funktionen aufgeteilt.
So gibt es für jede angedachte Funktion ein eigenständiges Modul.
Der größte daraus entstandene Vorteil ist die beliebige Kombination von benötigten Funktionen und das Weglassen von nicht
benötigten Komponenten.
Die entstandenen Sechs Module und ihre Funktion werden in den folgenden Kapiteln näher erläutert.
Zudem wurde eine Integration in Challengr vorgenommen, um direkt von den entworfenen Modulen zu profitieren und sie schneller
nutzbar zu machen.
Implementierung
LabelComparisonViewer2D
Das LabelComparisonViewer2D Modul soll den Anwender dabei unterstützen Unterschiede zwischen zwei Annotationen zu identifizieren. Das Modul hat drei Eingabefelder: das Bild, die Testannotationen und die Referenzannotationen. Über die Benutzeroberfläche des Moduls können verschiedene Einstellungen vorgenommen werden:
- Festlegung der Anzahl der Test- und Referenzlabels
- Der Modus für die Visualisierung. Es stehen 5 Modi zur Auswahl:
Union, Intersection, Symmetric Difference, Reference Difference und Test Difference.
Vier dieser Modi sind in den Abbildungen 1 a)- d) dargestellt. Das Referenzlabel ist in diesem Beispiel gelb und das Testlabel rot eingefärbt. - Auswahl der Farbe und des Alphawertes des dargestellten Referenz- und Testlabels
Die meiste Logik des Moduls wird über das interne MeVisLab{} Netzwerk realisiert. Über ein ExtractLabels Modul wird jeweils das, durch die GUI, ausgewählte Referenz-/ Testlabel extrahiert. Diese werden über zwei Arithmetic2 Module, je nach eingestelltem Modi, kombiniert. Durch ein SoViewOverlay Modul wird, entsprechend der Einstellungen, die gewünschte Darstellung des Labels erzeugt. Ein SoGroup Modul kombiniert die eingehenden Annotationen. Des Weiteren wird das Hintergrundbild in Kombination mit den Annotationen von einem Viewer geladen und dargestellt. In dem Python Skript des Netzwerks werden vor allem die, über die GUI gesetzten, Werte in die entsprechenden Module des Netzwerkes gesetzt und upgedatet.
RelativeConfuisionMatrix
Das Modul dient der Umwandlung einer Confusion Matrix von absoluten Voxelzahlen in relative Prozentzahlen. Dies dient vor allem der komfortableren Darstellung durch das ViewConfusionMatrix-Modul und in Challengr, kann aber auch als Prozessierung für einen späteren Export durch das ExportConfusionMatrix-Modul genutzt werden. Das Module erwartet als Input eine Confusion Matrix, wie sie programmatisch im ComputeConfusionMatrix-Modul definiert wurde, also als Tupel aus Zeilenreferenzen und der eigentlichen Matrix. Die einzelnen Werte der Matrix werden in Prozentwerte umgerechnet, wobei die Referenz für 100% jeweils der Referenzwert der Zeile des Eintrags darstellt. Daher ist es möglich, dass bei nicht One-Hot-enkodierten Daten Zeilensummen von über 100% auftreten können. Die Zeilenreferenzen der berechneten Matrix werden aufgrund der Angabe als Prozent auf 100 gesetzt. Die Berechnung wird durch den Button in der Moduldarstellung gestartet. Die so berechnete Confusion Matrix in relativen Werten kann daraufhin am Ausgang des Moduls verwendet werden. Sie entspricht derselben programmatischen Definition wie der Output des ComputeConfusionMatrix-Moduls.
ViewConfusionMatrix
Dieses Modul dient der Visualisierung einer Confusionmatrix. Die Matrix wird durch den Input eingegeben und in einer Tabelle dargestellt. Hierbei gibt es einige Darstellungsoptionen:
- Ein Haken bei "input is relativ" kann gesetzt werden, um Matrizen zu verwenden, deren Werte relativ berechnet wurden. Ist dies der Fall, kann zusätzlich konfigurieren werden, wie viele Nachkommastellen in der Tabelle zu sehen sind und ob %-Zeichen hinter den Werten stehen sollen. Zusätzlich wird das Maximum der Werte für die Heat-Map auf 100 gesetzt, um die erwartete Funktion der Heat-Map zu gewährleisten.
- "Toggle heat-map" schaltet die Darstellung einer Heat-Map ein bzw. aus. Die Hot- und Cold-Farben können auf der GUI eingestellt werden. Für ein natürlich wirkendes Verhältnis dieser Farben wird die stevenssche Potenzfunktion verwendet. Das Verhältnis ist das des Maximums der Werte in der Tabelle, im Falle einer Matrix mit Relativen Werten also mindestens 100 und dem aktuellen Zellen-Wert. Ein Verhältnis von 0 entspricht der Cold-Farbe, 1 der Hot-Farbe.
- Weiterhin kann die Darstellung der Werte in der Matrix ganz ein und aus geschaltet werden.
ExportConfusionMatrix
Das ExportConfusionMatrix-Modul dient dem Export einer Confusion Matrix als .csv Datei. Sind die Export-Buttons nicht anklickbar, so hilft bei der Problembehebung ein Feld oben im Modul in dem der Input-Typ angezeigt. So ist schneller zu erkennen, warum die Export-Buttons nicht klick-bar sind. Hier stehen einige Optionen zur Verfügung, die schon im ViewConfusionMatrix-Modul vorkommen:
- Die Angabe, ob die Eingabe relative Werte enthält. Wenn ja, so ist es möglich Prozentzeichen anzuhängen und die Dezimal-Präzision einstellen.
- Zusätzlich besteht die Option, einen benutzerdefinierten Separator zu verwenden. Der default Separator ist das Komma.
Weiterhin kann als Input für das Modul auch der Output des ViewConfusionMatrix-Moduls genutzt werden. In diesem Fall kann, solange das GUI Fenster des Viewers offen ist, ein View als .png exportiert werden. Zusätzlich können die Daten auch direkt aus der Tabelle extrahiert und als .csv gespeichert werden.
ComputeConfusionMatrix
Das ComputeConfusionMatrix Modul berechnet eine Confusionmatrix aus zwei eingegebenen, segmentierten Bildern.
Meist haben beide Bilder eine gleiche Anzahl von Labeln.
Es ist aber auch möglich aus zwei Bildern mit einer unterschiedlichen Anzahl an Labeln eine Matrix zu berechnen.
Die Matrix, welche vom Modul berechnet wird, liefert die Angaben in der Matrix als absolute Voxelanzahl.
Damit beide eingegebenen Bilder die selbe Voxelgröße haben, werden diese durch das Resample3D Modul auf die selbe Größe gebracht. Mit dem ExtractLabels Modul werden alle Label extrahiert, mit dem ExtractAllLabels Modul werden alle Voxel welche kein Label besitzen maskiert, also der Hintergrund des Bildes erfasst. Somit hat ExtractLabels nutzbare Ausgänge in Höhe der verfügbaren Labels. Dies wird technisch begrenzt durch das ExtractLabels Modul auf 7 Label. ExtractAllLabels besitzt nur einen Ausgang auf welchem der Hintergrund maskiert ist. Über das Histogram Modul in Kombination mit dem HistogramParameters Modul, kann von einem Label die Anzahl der dazugehörigen Voxel bestimmen. Zuerst wird die Anzahl der Voxel im Hintergrund der beiden Bilder berechnet. Danach wird das ExtractAllLabels\_reference Modul direkt am Histogram-Modul angebunden. Der Wert in intervalSum des HistogramParameters Modul enthält nun die Anzahl der Voxel, welche als Hintergrund klassifiziert wurden. Das gleiche wird für das ExtractAllLabels\_test Modul wiederholt. Nun kann durch eine logische Konjunktion der Schnitt zwischen zwei Masken berechnet werden. Wenn der Schnitt zwischen der Maske des Labels x des Referenzbildes und der Maske für das Label y des Testbildes errechnet wird, kommt in Kombination mit dem Histogram Modul die Anzahl der Voxel, welche eigentlich als Label x klassifiziert sein sollten, im Testbild aber als Label y klassifiziert wurden heraus. Die Anzahl der Label der beiden Bilder ist bekannt, da sie im Modul eingestellt werden muss. Nun kann über die Kombination aller Label iterieren und den Schnitt, sowie die Anzahl der Voxel in diesem berechnen, und für die Matrix speichern.
StreamComputeConfusionMatrix
Das Modul dient der Berechnung der Confusion Matrix eines gesamten Streams. Hierfür werden die Matrizen der Fälle summiert und als neue Confusion Matrix ausgegeben. Das Modul erwartet zwei Streams als Input, jeweils für Referenz- und Testdaten. Neben den aus den Modul ComputeConfusionMatrix übernommenen Optionen muss noch jeweils der Stream, der die Labels enthält angegeben werden, sowie die Range der Fälle, für die die Matrix berechnet werden soll (s. Abbildung 7). Das Modul iteriert über alle gewünschten Fälle mittels der internen AccessStreamInterface-Module und nutzt das interne ComputeConfusionMatrix-Modul um die Confusion Matrix eines Falls zu berechnen (s. Abbildung 6). Anschließend wird die Matrix auf die bisher berechnete Confusion Matrix summiert. Da dieser Prozess in Abhängigkeit der Dimensionen der Fälle und ihrer Anzahl merkbare Zeit benötigt, wird der Fortschritt durch einen Balken visualisiert. Nach Abschluss der Berechnung kann die Confusion Matrix des gesamten Streams am Output des Moduls verwendet werden. Sie entspricht derselben programmatischen Definition wie der Output des ComputeConfusionMatrix-Moduls.
Ergebnis
Entstanden sind sechs MeVisLab{} Module, welche dazu beitragen sollen ein besseres Verständnis für die Qualität und für die Unterschiede zwischen den Annotation der Referenz- und Trainingsbildern zu entwickeln. Die Module können hintereinander in ein MeVisLab Netzwerk geschaltete werden, um den Benutzer möglichst viele Informationen bereitzustellen. Ein möglicher Anwendungsfall ist in \autoref{confusionmatrix_result} dargestellt. Über die Module ComputeConfusionMatrix und RelativeConfusionMatrix wird die Confusionmatrix berechnet und durch das Modul ViewConfusionMatrix visualisiert. Um die in der Matrix dargestellten Zahlen nochmals besser zu visualisieren, können die entsprechenden Labels einzeln durch das Modul LabelComparisonViewer2D betrachtet werden.
Integration Challengr
CHALLENGR ist ein Tool, welches dem Benutzer dabei unterstützt den Validierungsprozess von Trainingsalgorithmen zu managen. Die Algorithmusvalidierung besteht aus folgenden Schritten:
- Aufbereitung der Eingabedaten des Algorithmus
- Aufbereitung von Referenzdaten
- Ausführung des Algorithmus auf den Eingabedaten
- Evaluierung der Ergebnisse des Algorithmus, durch Erhebung von Metriken und Kennzahlen auf den Referenzdaten
- Visualisierung der Ergebnisse und Vergleich von Evaluierungsergebnissen
Zusammenfassend kann CHALLENGR als eine Struktur betrachtet werden in der Algorithmen gespeichert und Evaluierungsergebnisse durchsucht und visualisiert werden können.
Aufbau
CHALLENGR bringt ein eigenes Command Line Interface mit.
Über dieses kann beispielsweise eine Challenge erstellt oder eine Challenge im CHALLENGR Frontend angezeigt
oder ausgeführt werden.
Folgende Information über den Aufbau von CHALLENGR sind der CHALLENGR Hilfe-Seite entnommen.
Eine angelegte Challenge enthält eine Reihe von Dateien über die diese konfiguriert werden kann.
Die wichtigsten sind:
- config.json: Konfiguration der Challenge, beispielsweise können Trainingssätze und Referenzdaten definiert werden.
- model.py: Definiert eine AlgorithmInput, AlgorithmResult, CaseMetaData, EvaluationResult und ReferenceData Klasse.
- AlgorithmExecution.mlab: Ein MeVisLab Netzwerk für eine remote gesteuerte Ausführung des Algorithmus.
- AlgorithmEvaluation.mlab: Ein MeVisLab Netzwerk für eine remote gesteuerte Algorithmus Evaluation.
- CaseVisualization.mlab: Ein MeVisLab Netzwerk zum Visualisieren von Fällen, welche im CHALLENGR Frontend ausgewählt werden können.
Die Daten, welche in CHALLENGR verfügbar gemacht werden, sind in logischen Einheiten definiert (s. model.py). Alle diese logischen Gruppen erben von der Klasse FieldContainer, welche eine Menge von Field- Objekten halten kann. Ein Field definiert einen Datentyp und stellt die Logik bereit Eigenschaften, wie z.B. den zulässigen Bereich oder den Standartwert, zu halten.
In CHALLENGR können auch mehrere Sitzungen angelegt werden. Eine Sitzung beschreibt eine Ausführung des Algorithmus mit einer spezifischen Parametrisierung, Auswertung der Ergebnisse mit verschiedenen Referenzdaten und Ausführungen. Diese können im Frontend gegenübergestellt und verglichen werden.
Über die CHALLENGR CLI kann ein Server gestartet werden, welcher das CHALLENGR vue-Frontend ausführt und anzeigt. Der Server enthält Rest-API Endpunkte zum Abfragen der CHALLENGR Daten, also beispielsweise der Sitzungen und Evaluierungsergebnisse.
Integration
Das Confusionmatrix-Modul kann an verschiedenen Stellen in CHALLENGR integriert werden. Eine Möglichkeit ist es, das Modul zu dem MeVisLab Netzwerk CaseVisualization.mlab hinzuzufügen. Wird ein Fall über das CHALLENGR Frontend ausgewählt, wird dieser in das Netzwerk geladen. Die geladenen Test- und Referenzbilder können an das Modul CalculateConfusionMatrix weitergeleitet werden. Dieses berechnet die Confusionmatrix und leitet die Ausgabe an das Modul ViewConfusionMatrix weiter, welches die Matrix visualisiert.
Die zweite Möglichkeit besteht darin eine Confusionmatrix direkt im CHALLENGR Frontend anzuzeigen. Bereits existierende Datentypen in CHALLENGR können einzelne Werte und Datensätze enthalten. Allerdings ist die Visualisierung dieser Werte im Frontend auf einzelne Felder beschränkt. Eine Matrix könnte auf diese Weise nur schwer dargestellt werden. Aus diesem Grund ist ein neuer Abschnitt in dem Frontend notwendig, welcher eine Matrix darstellen kann. Um die Darstellung so generisch wie möglich zu halten, wurde die Visualisierung der Confusionmatrix auf die Darstellung einer Tabelle vereinfacht, welche alle Eigenschaften einer Confusionmatrix anzeigen kann. Zusätzlich muss beachtet werden, dass sowohl die Confusionmatrix der current, sowie der compare Sitzung gegenüber gestellt werden können. Die Tabelle muss außerdem in der Lage sein, eine unterschiedliche Anzahl von Reihen und Spalten darzustellen.
In CHALLENGR wurde ein neuer Datentyp Table erstellt, welcher folgende Parameter besitzt:
- label: string- Die Überschrift der Tabelle
- defaultRowLabel: string- Die default Bezeichnung einer Reihe
- defaultColumnLabel: string- Die default Bezeichnung einer Spalte
- rowLabels: [string]- Spezifische Beschriftungen für die Reihen
- columnLabels: [string]- Spezifische Beschriftungen für die Spalten
- colorCells: bool- Falls true werden die Zellen abhängig von ihrem enthalten Wert eingefärbt. Die minimal Färbung ist weiß, die maximale Färbung ist rot. Die minimal/ maximal Werte sind abhängig von dem übergebenen range und optimum
- range: (number, number)- der Zahlenbereich der übergebenen Werte
- optimum: number- Das Optimum der Werte
Die Klasse Table erbt von Field und kann somit durch die Klasse EvaluationResult,
welches von FieldContainer erbt, gehalten werden. Dies ist in Abbildung 9 dargestellt.
In das MeVisLab Netzwerk AlgorithEvaluation.mlab wurde anschließend das Modul ComputeConfusionMatrix, sowie das Modul RelativeConfusionMatrix eingebaut. Die Table-Objekte können über das Python-Skript der AlgorithEvaluation.mlab mit den errechneten Werten befüllt werden.
Um die Table-Objekte im Frontend anzeigen zu können, muss ein API-Aufruf hinzugefügt werden, welcher die Table-Objekte liefert.
Abbildung 10 zeigt die fertige Visualisierung der in Abbildung 9 gezeigten Table-Objekte.
Fazit
Die beschriebenen Ziele wurden vollständig umgesetzt. Statt eines einzelnen Moduls wurden sechs kleine Module entwickelt, die einzelne Funktionen enthalten und so auch in anderen Anwendungsfällen genutzt werden können. Das beschriebene Zusammenspiel der kleinen Module entspricht den gesetzten Zielen. Die zusätzliche Integration des Moduls in Challengr, geht über das angestrebte Ziel eines Confusionmatrix-Moduls in MeVisLab hinaus. Mit diesem Ergebnis wurden die ursprünglichen Ziele des Teams erfüllt und sogar übertroffen.
Ausblick
Es existieren noch einige Möglichkeiten, die entwickelten Module sinnvoll zu erweitern oder zu verbessern.
Beispiele dafür wären grafische Änderungen, wie das Einfügen einer anderen Heat-Map Farbe für die Hauptdiagonale.
Eine Verbesserung kann ebenfalls bei der Laufzeit erreicht werden, die die Module benötigen, um eine oder mehrere Confusionmatrizen
zu berechnen.
Aus den Werten in der Confusionmatrix lassen sich False Positve, True Positive, False Negative und True Negative ablesen. Daraus
werden viele weitere Maße, wie Accuracy oder F-Score berechnet.
Werden diese in Challengr ergänzt, bieten sich mehr Möglichkeiten des Vergleichens von Ergebnissen.
Die fertigen Module sollten durch Mitarbeiter der Arbeitsgruppe geprüft und anschließend für alle Nutzer eingefügt werden.
Zusätzlich zu diesem Schritt ist eine Vorstellung der Module und seiner Erweiterungen durch ein nachfolgendes Projekt denkbar.
One Hot Konvertierung
Motivation
In neuronalen Netz für Klassifikationsproblemen werden die Ergebnisse auf verschiedene Arten kodiert.
Die beiden betrachteten Kodierungen sind One-, bzw. Multi-Hot-Vektoren.
Die Vektoren können verschieden repräsentiert werden, wodurch beim Vergleich von Ausgabewerten von verschiedenen Netzen eine
Konvertierung nötig sein kann.
Dieses Modul bietet eine vereinheitlichte Lösung für die Konvertierung.
Ein für diesen Fall spezifisches Modul, kapselt den nicht visuellen Programmieranteil,
weil das erzeugte Modul die Skripte indirekt aufruft und sich so dem visuellen MeVisLab Stil anpasst.
Einführung
Bei einem neuronalen Netz für Klassifikationsprobleme, korrespondiert die letzte Schicht direkt mit den abzubildenden
Klassen und ergibt so ein Array mit Werten zwischen 0 und 1, wobei die Werte für die Konvertierung auf oder abgerundet werden müssen.
Darf das Netz dabei nur eindeutig Klassifizieren, d.h. das Maximum des Arrays wird zur 1 alle anderen 0, wird von einem
One-Hot-Vektor und andernfalls von Multi-Hot-Vektor gesprochen.
Der One-Hot-Vektor lässt sich allein durch den Index der 1 eindeutig repräsentieren.
Für Multi-Hot-Vektoren werden die 0/1 Werte des Arrays als Binärzahlen interpretiert, welche somit im Speicher kompakter
repräsentiert werden können.
Die Abbildung 11 zeigt diesen Zusammenhang visuell und gibt die Limitationen des unsigned interger 64
Datentypen an.
Mit diesem ist auch das Modul auf 64 Klassen begrenzt.
Implementierung
Das Eingabearray inImage ist ein numpy array mit 6 Dimensionen, welche die MeVisLab Bilddimensionen in umgekehrter Reihenfolge
widerspiegeln. Ihre Form, shape in Numpy, ist (u,t,c,z,y,x), wobei c die Standard Dimension für Labels ist.
u steht hier für user und soll als weitere Option als Dimension für die Konvertierung eingesetzt werden können.
Da es keine feste Bitorder gibt, wurde hier von der Bitorder Big Endian ausgegangen, da diese mit dem Array Zugriff übereinstimmt.
Die numpy Version von MeVisLab ist 1.15, welche die Funktion packbits nur in Bitorder Little Endian
unterstützt, weswegen die Dimension der Label erst gedreht werden muss.
Außerdem geht der Algorithmus nur bis zu 8 Labels, da nur uint8 als Typ unterstützt wird.
Daher wurde stattdessen mit Slicing und Masken gearbeitet.
Abbildung 12 fasst die möglichen Konvertierungen zusammen. Auf die einzelnen Codeabschnitte
wird im Folgenden genauer eingegangen.
-
Um aus der Bitmaske einen Vektor zu bekommen, wird zunächst eine Maske aus 2er Potenzen gebaut. Die daraus entstandene Maske hat für jeden passenden Index einen Teilvektoren mit einer 1 an dieser Stelle. Diese Maske kann durch Numpy's Broadcasting mit einer Zusatzdimension des Eingabe Bildes (inImage) bitweise verundet werden. Die Ergebnisse sind allerdings noch die verundeten Werte und daher in Integer Form auch größer als 1. Um den Wertebereich auf {0,1} zu bringen, wurde hier zu Boolean und dann zurück zu Integer konvertiert.
Das shape von inImage und outImage verändert sich durch die Konvertierungen und wird in calculateOutputImageProperties() und calculateInputSubImageBox() geändert.
result = [] try: result = ((inImage[..., np.newaxis] & (1 << np.arange(ctx.field("numberOfLabels").value))) > 0) * 1 except TypeError: result = ((np.uint64(inImage[..., np.newaxis]) & (1 << np.arange(ctx.field("numberOfLabels").value, dtype=np.uint64))) > 0) * 1 outImage[:] = np.moveaxis(np.squeeze(result, dim), 5, dim)
-
Da die Bitmaske im Grunde eine Konvertierung von Binärer in Dezimaler Darstellung ist, kann ein Multi-Hot-Vektor als Maske für ein Array aus 2er Potenzen genutzt werden, welches dann aufsummiert wird. Praktisch wird hier mit verschieden großen Numpy Arrays gearbeitet.
labels erzeugt diese 2er Potenzen und bringt es in die Form von inImage. Das konvertieren des Multi-Hot-Vektors in Boolean Werte, erzeugt eine Maske. Das inverse dieser Maske setzt in Zeile 3 alle Werte auf 0, welche nicht klassifiziert wurden. So werden sie von der Summe ausgeschlossen. Übrig bleiben die klassifizierten 2er Potenzen, welche in der Summe das skalare Ergebnis bilden.labels = (np.moveaxis(np.broadcast_to((2**np.arange(ctx.field("numberOfLabels").value)), (inImage.shape[:dim] + inImage.shape[dim + 1:] + (ctx.field("numberOfLabels").value,) ) ), 5, dim)).copy() mask = inImage.astype(bool) labels[~mask] = 0 outImage[:] = np.sum(labels, axis=dim)
-
Um die (Integer) Labels in One-Hot-Vektoren umzuwandeln, werden sie als Index Maske auf einer Eye Matrix verwendet. Ein Eye bezeichnet hier eine quadratische Matrix aus Nullen, mit jeweils einer Eins an den Stellen (1,1), (2,2), (3,3) usw. Die erzeugte Dimension wird hinten angehängt, weswegen sie durch moveaxis an die richtige Stelle geschoben wird.
outImage[:] = np.moveaxis(np.squeeze(np.eye(ctx.field("numberOfLabels").value)[inImage], axis=dim), 5, dim)
-
Der Befehl argmax gibt den Index des größten Elements aus einer Liste an. Hier wird nur das Maximum aus der gewählten Dimension gesucht, sodass das One-Hot Encoding in den dazugehörigen Wert übertragen wird.
outImage[:] = np.argmax(inImage, axis=dim)
-
Für die Konvertierung von Label zu Bitmaske werden alle Werte in ihre 2er Potenzen umgerechnet.
outImage[:] = np.exp2(inImage)
Fazit
Das Makromodul konnte fertiggestellt und getestet werden. Im Hinblick auf das große Ziel die Trainingsschleife vereinfachen oder beschleunigen zu können ist damit ein praktisches kleines Werkzeug entstanden. Letztendlich ist es kein Teil des ConfusionMatrix Moduls geworden, kann aber durch seine Kompaktheit für andere Makro Module und MeVisLab Netze genutzt werden. Numpy hat durch die Maskierungs und Slicing Methoden sehr effiziente Umrechnungen ermöglicht, welche außerdem noch recht kompakt sind.
Segmentation Pipeline Optimizer
Einleitung
Ein großes Problem von Segmentierungsalgorithmen stellt die Tatsache dar, dass diese, trotz ihrer guten Ergebnisse, oft hochspezifisch sind. Ein Algorithmus, der darauf optimiert wurde die Leber in bestimmten MRI-Scans zu segmentieren, kann bei CT-Scans, abweichender Auflösung und ähnlichem drastisch an Performanz verlieren. Das stellt vor allem ein Problem für den Einsatz solcher Systeme im klinischen Alltag dar, da aufwendige, manuelle Optimierungen der Algorithmen dort nicht praktikabel sind.
Der Medical Segmentation Decathlon machte sich zur Aufgabe einen soliden Benchmark für die Bewertung und den Vergleich von Algorithmen zur medizinischen Bildsegmentierung zu liefern. Dabei wurde die angesprochene Problematik zum Kern der Challenge. Anstatt, wie in vielen Challenges üblich, die Algorithmen an einer spezifischen Aufgabe zu messen, werden sie an vielen, stark unterschiedlichen Aufgaben gemessen, was die Challenge besonders schwer macht. Die zehn zur Verfügung gestellten Datensätze variieren in der zu segmentierenden anatomischen Struktur, sowie ihrer Anzahl, Größe und Struktur, der Modalität der Daten, der Auflösung, der Anzahl der verfügbaren Daten, etc. Dabei ist keine manuelle Anpassung eines Algorithmus auf die aktuell zu verarbeitenden Daten erlaubt. Somit zwingt die Challenge die Teilnehmer, das Problem der hohen Spezifität der Segmentierungsalgorithmen aktiv anzugehen.
Einen vielversprechenden Ansatz verfolgt das 2018 vorgestellte nnU-Net, das bis jetzt (Mai 2020) die Rangliste des Medical Segmentation Decathlon anführt. Statt einen Algorithmus auf Basis des üblichen Ansatzes einer statischen Segmentation Pipeline aus Preprocessing, U-Net und Postprocessing zu verwenden, adaptiert der Algorithmus die Pipeline dynamisch anhand der aktuellen Daten, noch bevor das Netzwerk auf diesen trainiert wird. Dies widerspricht nicht den Anforderungen der Challenge, da diese Adaption vollautomatisch vollzogen wird. Die Wahl des Pre- und Postprocessings, sowie der Netzwerkarchitektur geschieht anhand der spezifischen Eigenschaften der aktuellen Daten, um so eine bestmögliche Grundlage für das eigentliche Training, und damit der Performanz sicher zu stellen. Dieser Ansatz ermöglicht eine große Bandbreite verschiedenster Daten zuzulassen und gleichzeitig die hohe Performanz von spezifisch optimierten Segmentation Pipelines auszunutzen.
Der nnU-Net Algorithmus ist nur eine Möglichkeit eines solchen Algorithmus, der auf der Prämisse basiet die Segmentation Pipeline vor dem Training anhand der Eigenschaften der Daten zu optimieren. Um die Möglichkeiten dieses Ansatzes und verschiedener dieser Algorithmen im Setting einer bestehende Infrastruktur für neuronale Netzwerke zu erforschen, bietet sich der Aufbau und die Einbindung eines Systems an, das Management und Anwendung dieser Algorithmen ermöglicht. In diesem Abschnitt soll daher das Konzept eines solchen Segmentation Pipeline Optimizers (SPO) dargestellt werden. Das Konzept arbeitet mit wenigen Voraussetzungen, um als Basis für viele konkrete Anwendungsszenarien dienen zu können. Die Schnittstellen zur vorhandenen Infrastruktur sind minimal gehalten und wenig spezifiziert. Des Weiteren ist es flexibel gestaltet, sodass Anpassungen in Form von zusätzlichen Funktionen und dem Abwandeln oder Entfernen vorhandener Funktionen leicht möglich sind. Die Spezifizierung und Anpassung des Basiskonzepts an eine vorhandene Infrastruktur wird beispielhaft am Fraunhofer MEVIS aufgezeigt. Es werden dabei keine Implementierungen vorgenommen, lediglich die möglichen Vorgehensweisen für diese skizziert.
Der Begriff Optimierung wird in diesem Abschnitt im Bezug auf die Optimierung der Segmentation Pipeline verwendet, also die Optimierung von Preprocessing, Postprocessing und Netzwerkarchitektur. Das Training eines Netzwerks, das auch eine Optimierung darstellt, wird hier exkludiert. Der Begriff Architektur bezeichnet wie üblich die Topologie des neuronalen Netzwerks, während mit Softwarearchitektur die Programmstruktur des vorgestellten Systems gemeint ist.
Softwarearchitektur des SPO
Konzept
Die Ausführung einer Segmentation Pipeline (kurz: Pipeline) Optimierung kann in drei unabhängige Prozesse unterteilt werden. Erstens müssen die Daten analysiert werden. Der Optimierungsalgorithmus verwendet bestimmte Eigenschaften der Daten, um abhängig von ihnen die Pipeline anzupassen. Diese Eigenschaften, der Data Report, müssen zunächst berechnet werden, um dem Algorithmus als Input dienen zu können. Zweitens muss der Data Report dem eigentlichen Optimierungsalgorithmus zur Verfügung gestellt werden und dieser berechnet die optimierten Parameter für die Pipeline. Drittens müssen die berechneten Parameter auf die Pipeline angewendet werden. Da das System nicht nur einen Algorithmus zur Pipeline Optimierung zur Verfügung stellen, sondern auch zum Test und Vergleich neuer Algorithmen dienen soll, muss ein Management der Algorithmen als vierter Prozess eingeplant werden, der als zentrale Kontrolleinheit dient.
Die Trennung dieser Prozesse in separate Komponenten hat den Vorteil, die Teilprozesse in gleich mehreren Dimensionen separieren zu können. Zunächst wird eine zeitliche Entkopplung möglich. Dies ist vor allem deswegen zu präferieren, da die Teilprozesse signifikant unterschiedliche Zeiten benötigen. Vor allem die Analyse kann unter Umständen sehr lange in Anspruch nehmen. Insbesondere die Analyse großen Datensätzen bis auf Voxelebene hat erheblichen Zeitbedarf. Die zweite mögliche Art der Trennung betrifft die Anwendungen die verwendet werden. Es sollte nicht davon ausgegangen werden, dass die Tools zur Analyse der Daten die selben sind, die zum Aufbau der Pipeline genutzt werden. Somit wird dem Problem vorgebeugt, dass eine Veränderung eines Tools mit der Notwendigkeit den gesamten SPO neu zu implementieren verbunden ist. Die Minimierung der Abhängigkeit von vorhandenen Tools verhindert, dass das System ein blockierender Faktor für Veränderungen wird. Die letzte mögliche Trennung ist die infrastrukturelle. Die Komponenten müssen nicht auf dem selben Computersystem ausgeführt werden. Dies ermöglicht es Prozesse auf Serverstrukturen zu verlagern, was vor allem bei zeit- und rechenintensiven Prozessen von Vorteil ist. Es ermöglicht zusätzlich Parallelisierung und die Verwendung von spezieller Hardware zur Beschleunigung, zum Beispiel GPUs, ohne die Praktikabilität einzuschränken, sie tendenziell sogar stark zu erhöhen. Insgesamt bewirkt die strikte Trennung der Prozesse in separate Komponenten größtmögliche Flexibilität bei der Implementierung und ermöglicht so für eine Vielzahl von Infrastrukturen geeignet zu sein.
Verschiedene Optimierungsalgorithmen verwenden zu können hat zur Folge, dass die Analyse der Trainingsdaten nicht mehr statisch ist. Die Optimierungsalgorithmen haben unterschiedliche Ansprüche an den Data Report, bezüglich der konkreten Eigenschaften der Daten die für die Optimierung benötigt werden. Aufgrund des hohen Ressourcenverbrauchs der Analyse ist es ineffektiv jedem Optimierungsalgorithmus standardisiert alle möglichen Eigenschaften der Daten zur Verfügung zu stellen. Daher muss der Optimierungsalgorithmus ein Report Scheme zur Verfügung stellen, in dem spezifiziert wird welche Eigenschaften der Trainingsdaten für die Ausführung der Optimierung benötigt werden.
Damit ergeben sich vier Komponenten des SPO:
- Data Analyzer: Dient der Analyse der Eingabedaten und Erstellung des Data Reports
- Optimization Manager: Dient dem Management der Optimierungsalgorithmen, dem Verteilen verwendeter Daten und als User Interface
- Optimization Algorithm: Dient der Berechnung optimierter Pipelineparameter anhand der Eigenschaften von Trainingsdaten
- Optimization Operator: Dient der Anwendung optimierter Pipelineparameter auf eine Pipeline
Da die Möglichkeit zur Entwicklung der Optimierungsalgorithmen ein Hauptziel des Systems ist, sollte hier die größtmögliche Praktikabilität angestrebt werden. Dasselbe gilt für die Optimization, die damit von der Pipeline auf die sie angewendet wird, entkoppelt werden kann. Für das Report Scheme ebenfalls Dateien zu verwenden, ist zum einen dem Fakt geschuldet, dass viele potentielle Formate für den Data Report, wie XML oder JSON, bereits Formate für Schemata bereit stellen. Damit steht ein größeres Softwareökosystem für die Implementierung zur Verfügung. Zum anderen trennt es so Optimierungsalgorithmus und sein Schema. Dies ermöglicht größere Flexibilität bei der Auswahl der verwendeten Sprachen. Insbesondere bieten für Algorithmen verwendete Programmiersprachen oft nicht die Möglichkeit einer übersichtlichen Definition eines Schemas. Hier sind Skriptsprachen, wie Python zwar im Vorteil, dennoch bietet sich auch hier aus Gründen der Übersichtlichkeit eine Trennung von Algorithmus und assoziiertem Report Scheme in zwei Dateien an.
Damit ergeben sich drei Dateiformate, die dem Austausch komplexer Daten zwischen den Komponenten dienen:
- Report Scheme: Definiert die für die Berechnung des assoziierten Optimierungsalgorithmus benötigten Eigenschaften der Trainingsdaten
- Data Report: Enthält bestimmte Eigenschaften eines Trainingsdatensatzes
- Optimization: Enthält die optimierten Parameter der Segmentation Pipeline
Das UML Komponenten Diagramm in Abbildung 13 fasst die Konzeption des Systems auf Ebene der Komponenten zusammen.
Die Formate der Dateien müssen einige Voraussetzungen erfüllen, um im System einsetzbar zu sein. Zunächst muss eine endliche Menge I von möglichen Analysewerten, den Report Items (kurz: Items), festgelegt werden. Diese repräsentieren einzelne Eigenschaften der Trainingsdaten, wie Anzahl der Voxel, Median der Voxelwerte, ob die Trainingsdaten anisotrop sind, etc. Dabei sollte die Aufnahme eines Items zu I davon abhängen, wie hoch der Informationsgehalt ist, ob er sinnvoll in Optimierungsalgorithmen eingesetzt werden kann, wie oft er verwendet wird und ob er sich nur umständlich bzw. gar nicht durch Kombination anderer Items berechnen lässt. Jedem Item wird eine Domäne zugewiesen aus der seine Werte stammen. Die Items sollten des Weiteren parametrisierbar sein, da Items wie Quantile nur mit Parametern sinnvoll und übersichtlich verwendet werden können. Ein Report Scheme stellt dann eine Teilmenge aller Items I und eine Zuweisung der Items zu konkreten Parameterwerten dar. Ein Data Report stellt ein Report Scheme dar, in dem jedem Item nicht nur passende Parameterwerte, sondern auch jedem Item selbst ein passender Wert zugewiesen wird. Formal lässt sich dies so definieren($$[i]\ :=\ \{n\in\mathbb{N}\ |\ n \leq i\} \\ dom(f) = A,\ img(f) = B\ |\ f: \ A \rightarrow B$$): Grundmengen: $$ \mathcal{I} \quad \text{(endliche Menge der Report Items)} \\ \mathcal{P} \quad \text{(endliche Menge der Parameter)} \\ \mathbb{D} = \{Integer, Boolean, \dots\} \quad \text{(endliche Menge der Wertebereiche)} $$
Zuweisung von Wertebereichen (O s.u.): $$ \delta: \ (\mathcal{I} \cup \mathcal{P} \cup \mathcal{O}) \rightarrow \mathbb{D} $$
Zuweisung von Parametern zu Items: $$ \phi:\ \mathcal{I} \rightarrow\ \bigcup_{i\in\mathbb{N}_0}\{f\ |\ f: \ [n] \rightarrow \mathcal P \} $$
Definition eines Report Schemes S: $$ S\ :=\ (I, w_P), \\ I \subseteq \mathcal{I}, \\ w_P:\ I \rightarrow\ \bigcup_{n\in\mathbb{N}_0} \{ f\ |\ f:\ [n] \rightarrow \bigcup_{D\in \mathbb{D}} D \}, \\ \forall i \in \mathcal{I}, p \in \mathcal{P}:\ w_P(i)(p) \in \delta(\phi(i)(p)), \\ \quad \forall i \in \mathcal{I}: \ dom(w_P(i)) = dom(\phi(i)) $$
Definition eines Data Reports R: $$ R \ := \ (I, w_P, w_I), \\ (I,w_P) \text{ ist ein Report Scheme}, \\ w_I : \ I \rightarrow \bigcup_{D\in\mathbb{D}} D,\\ \forall i \in \mathcal{I}: \ w_I(i) \in \delta(i) $$
Bei Überladung der Items wird φ zu einer Multifunktion.
Zudem kann noch die Eigenschaft von Data Reports und Schemes definiert werden in einer Teilbeziehung ≤ zu stehen, da diese Eigenschaft dafür genutzt wird die Verwendbarkeit unspezifischer Data Reports für einen anderen Algorithmus zu prüfen. Eine Report oder Scheme ist ein Unterreport eines anderen Schemes oder Reports, wenn jedes Report Item und seine Parameterwerte auch im anderen vorhanden sind. Seien $$ R_n = (I_n, w_{P,n}, w_{I,n}),\ n \in \{1,2\} $$
Data Reports und dementsprechend $$ S_n = (I_n, w_{P,n}) $$
Data Schemes. Dann ist $$ X_1 $$
Teilschema von $$ X_2,\ X \in \{S,R\} $$
geschrieben $$ X_1 \leq X_2 $$
, wenn $$ f|_A = A \rightarrow img(f),\ x \mapsto f(x)\ |\ A \subseteq dom(f) $$
: $$ \sigma(X) := \begin{cases} (I, w_P) & |\ X = (I, w_p, w_I) \\ (I, w_p) & |\ X = (I, w_p) \end{cases} \qquad \text{(Schemafunktion)} \\ \ \\ X_1 \leq X_2 \ :\Leftrightarrow \ \sigma(X_1) \leq \sigma(X_2) \\ \ \\ (I_1, w_{P,1}) \leq (I_2, w_{P,2}) \ :\Leftrightarrow \ I_1 \subseteq I_2 \ \land \ w_{P,1} = w_{P,2}|{}_{I_1} $$
Ein ähnliche Definition muss für die Optimization festgelegt werden. Es müssen Optimization Items mit Wertebereich festgelegt werden. Zusätzlich müssen den Items Standardwerte zugewiesen werden, um Teiloptimierungen der Parameter leichter vornehmen zu können. Eine erzeugte Optimization entspricht dann einer Zuweisung einer Teilmenge der Optimization Items zu geeigneten Werten. Die eigentliche Optimierungsfunktion, entspricht dann der Kombination der berechneten Parameter mit der Standardfunktion, wobei explizite Werte in der Optimization, implizite Werte aus der Standardfunktion überschreiben. Dies lässt sich formalisieren: $$ \mathcal{O} \quad \text{(Menge der Optimization Items)} $$ Definition der Standardfunktion wdefault: $$ w_{default}: \ \mathcal{O} \rightarrow \bigcup_{D\in\mathbb{D}} D, \\ \forall i \in \mathcal{O}: \ w_{default}(i) \in \delta(i) $$
Definition einer Optimization O: $$ O \ := \ (O, w_O),\\ O \subset \mathcal{O}, \\ w_O: \ O \rightarrow \bigcup_{D\in\mathbb{D}} D\\ \forall i \in \mathcal{O}: \ w_O(i) \in \delta(i) $$
Definition der Optimierungsfunktion Ω(Wdefault Menge der Standardfunktionen, WO Menge der Optimizationfunktionen): $$ \Omega: W_{default} \times W_O \rightarrow \{ f\ |\ f: \mathcal{O} \rightarrow \bigcup_{D\in\mathbb{D}} D \} \\ \Omega(w_{default}, w_O)(i)\mapsto \begin{cases} w_O(i) & |\ i \in dom(w_O) \\ w_{default}(i) & |\ i \not\in dom(w_O) \end{cases} $$
Trotz der Vagheit der Definition, die auch ihre Flexibilität garantiert, sollten bestimmte Items immer zu Data Report und Optimization gehören, da diese der Nachvollziehbarkeit und dem Management der Dateien dienen:
- ID zur eindeutigen Identifikation
- Zeitstempel (kann als ID verwendet werden)
- Name des Users
- Textuelle Beschreibung
- Optimierungsalgorithmus der Anfrage
Aus den bisher etablierten Eigenschaften des SPO lässt sich bereits der Ablauf einer typischen Pipeline Optimierung ableiten. Der User wählt
einen Optimierungsalgorithmus aus und optional einen bereits vorhandenen Data Report. Sollte kein Data Report angegeben werden, muss dieser
berechnet werden. Bei expliziter Angabe eines Reports, muss überprüft werden, ob dieser spezifisch für den ausgewählten Algorithmus erstellt wurde.
Falls nicht ist es weiterhin möglich, dass der vorhandene Bericht ein Oberreport des benötigten Reports darstellt. Zur Prüfung wird das Report Scheme
vom gewählten Algorithmus angefordert. Sollte der angegebene Report dennoch nicht geeignet sein, muss ebenfalls ein passender Data Report erstellt werden.
Sollte ein neuer Data Report angefertigt werden, können aufgrund der Möglichkeit der Parallelisierung weiter Optimierungsaufträge aufgegeben werden.
Die Analyseanfrage erzeugt einen spezifischen Data Report in Abhängigkeit vom Report Scheme. Auf Basis dieses Reports wird anschließend eine Optimierung
vom gewählten Optimierungsalgorithmus angefertigt, die dann auf eine Pipeline angewendet werden kann. Das UML Aktivitätendiagramm
(Abbildung 14) fasst diesen Ablauf zusammen.
Zusammen mit den bereits etablierten Komponenten des SPO und ihrer Funktion, den Dateien, die zum Austausch komplexer Daten verwendet werden
und dem Ablauf einer typischen Optimierung lässt sich letztere detaillierter Ausarbeiten. Bezüge zu den implementierten Funktionen werden in Klammern
dargestellt. Der User stellt eine Anfrage an den Optimization Manager über eine Optimierung (optimize) einer Pipeline
(operator), mittels eines bestimmten Algorithmus (algorithm) und auf Basis der Eingabedaten(data).
Aufgrund der Notwendigkeit einen Data Report anzufertigen, fordert Optimization Manager vom gewählten Optimierungsalgorithmus das benötigte Report
Scheme an (requiredReportScheme: reportScheme). Daraufhin stellt der Manager eine Anfrage an einen Data Analyzer über die Anfertigung
des benötigten Data Reports (requestDataReport). Dieser benötigt neben dem zuvor erhaltenen Report Scheme (reportScheme)
und den zu analysierenden Daten (data), eine Identifikationsmöglichkeit des anfragenden Optimization Managers (requester)
zur Notifikation und eine ID zur Identifikation des zu liefernden Data Reports. Die Berechnung des Reports verwendet die Inputdaten, das Report Scheme
und die zur Berechnung der einzelnen Items verwendete Analyseinfrastruktur. Nach Anfertigung des Reports (dataReport) wird dieser an
den anfragenden Manager ausgeliefert (notifyDataReportReady). Die Anfrage und Auslieferung eines Reports findet asynchron statt,
um die nötige zeitliche und infrastrukturelle Trennung gewährleisten zu können. Der erhaltene Data Report wird nun vom Optimization Manager dem gewählten
Optimierungsalgorithmus zur Verfügung gestellt und eine Optimierung auf dessen Basis angefordert (requestOptimization). Nach der
Anfertigung wird der Manager darüber informiert (notifyOptimizationReady). Auch dies findet aus genannten Gründen asynchron statt.
Die erzeugte Optimierung kann daraufhin dem anfangs gewählten Optimization Operator übergeben (acceptOptimization) und mittels der
Optimierungsinfrastruktur auf die Pipeline angewendet werden. Das UML Sequenzdiagramm (Abbildung 15) stellt den detaillierten
Ablauf zusammenfassend dar.
Auf Basis der gesammelten Konzeptionen lässt sich das UML Klassendiagramm (Abbildung 16) anfertigen. Dieses zeigt bereits ein großes Maß an Details und ist daher mit einem gewissen Abstand zu betrachten. Das Diagramm stellt die Komponenten als abstrakte Klassen dar. Die genaue Bedeutung kann, je nach Implementierungssprache, variieren. So könnten die Definitionen ebenfalls auch als Interfaces angesehen werden. Ebenfalls kann sich die konkrete Bedeutung bei den Komponenten unterschieden, da diese nicht notwendigerweise in derselben Sprache implementiert werden müssen. Bereits hier zeigen sich, je nach vorhandener Infrastruktur und gewünschter Implementierung, große Unterschiede. Besonders bei einer infrastrukturellen Trennung der Komponenten sind die Kommunikationsbeziehungen nicht als direkte Verbindung zwischen Klassen eines einheitlichen Programms anzusehen. Daher wird auf die detaillierte Darstellung der einzelnen Funktionen verzichtet. Optimization Operator und Data Analyzer sind prinzipiell in variabler Anzahl angelegt und müssen beim Manager an- und abgemeldet werden. Dementsprechend werden sie in geeigneten Datenstrukturen, wie Arrays oder Listen, gespeichert. Die Optimierungsfunktion ist überladen, um verschiedene mögliche Anwendungsfälle abzudecken, z.B. die Optimierung mit und ohne bereits vorhandenem Data Report. So werden auch die öffentlichen Funktionen zur Prüfung von Teilbeziehungen zwischen Reports und Schemes und der Spezifität von Reports zur Verfügung gestellt. Optimization Algorithms sind gezwungen ein Report Scheme zur Verfügung zu stellen.
Umsetzung bei MEVIS
Die für eine Umsetzung verwendete Infrastruktur beim Fraunhofer MEVIS basiert zu ein großen Teil auf der Anwendung MeVisLab. Diese stellt eine graphische Umgebung zum Laden und Darstellen vornehmlich medizinischer Bilddaten und der Erstellung von Prozessierungspipelines zur Verfügung. Die Verarbeitung erfolgt in Modulen mit definierten Input und Output, die zu komplexeren Verarbeitungsstrukturen verbunden werden können. Obwohl MeVisLab auch als Standalone-Anwendung zum Einsatz kommt, wird eine speziell für die Bildverarbeitung und das Training Neuronaler Netzwerke ausgestattete Serverstruktur zur Verfügung gestellt. Aufgrund der Effizienz dieser, gegenüber der lokalen Verwendung von MeVisLab, sollte diese ebenfalls für die Implementierung des SPO zum Einsatz kommen. Dabei ist durch die hohe Flexibilität von MeVisLab bezüglich des Hostsystems der lokale Einsatz nicht ausgeschlossen, lediglich als ineffizient anzusehen. Das Starten eines Trainings auf dem Server benötigt, neben den Trainingsdaten, drei Inputs. Erstens ein MeVisLab-Netzwerk, das den Rahmen der Pipeline bildet. Zweitens eine Architekturdatei zur Definition der Parameter des Neuronalen Netzwerks. Drittens eine Konfigurationsdatei als zusätzliche Möglichkeit zur Manipulation von Netzwerkparametern. Eine naheliegende Möglichkeit der Implementierung der Komponenten ist, sie als MeVisLab-Module zu konzipieren. Diese müssen noch vor dem Training gestartet werden und können so das Trainingsnetzwerk und die assoziierten Dateien anpassen. Ein weitere Möglichkeit wäre die Implementierung als separater Dienst der Serverstruktur. Dies hätte den Vorteil, die Analyse parallelisieren zu können, indem die Report Items als separate Tasks verteilt werden. Der SPO könnte durch eine Erweiterung des bestehenden QuantMed-Systems angesprochen werden, das momentan zum Starten von Traingjobs auf dem Rechencluster genutzt wird. Dies hat den Vorteil kein neues UI etablieren zu müssen. Die Pipelineoptimierung wäre lediglich eine neue Option und würde so bessere Useability garantieren. In diesem Falle sollte es leicht möglich sein, Optimierungsalgorithmen zur Auswahl des SPO hinzuzufügen, z.B. durch explizite Angabe eines Pfads, Hochladen neuer Algorithmen oder Zugriff auf einen standardisierten Ordner zur Ablage der Algorithmen und der assoziierten Dateien. Eine Implementierung in der beim Fraunhofer MEVIS weitläufig genutzten Skriptsprache Python kann den flexiblen Umgang mit den Optimierungsalgorithmen erleichtern. Die Berechnung der Report Items sollte aufgrund der allgemein besseren Performanz weiterhin in Instanzen von MeVisLab erfolgen. Die Anpassung der Pipeline Parameter erfordert eine Pipeline, die einer geeigneten Struktur entspricht und das Anwenden der Optimierungsfunktion Ω ermöglicht. Da beim Fraunhofer MEVIS nicht mit statischen Pipelines gearbeitet wird, sondern gerade die große Variabilität, die mittels MeVisLab erreicht werden kann einen großen Vorteil darstellt, muss diese Variabilität in den SPO aufgenommen werden. Zwei Varianten sind hier als sinnvoll zu erachten. Die Erste besteht in einer zusätzlichen Teilkomponente des Optimizers (vgl. Abbildung 13). Ähnlich dem Report Scheme wird jedem Optimierungsalgorithmus ein Pipeline Scheme zugeordnet, das eine Spezifikation der für den Algorithmus zulässigen Pipelines darstellt. Diese Variante ermöglicht die hohe Variabilität der Pipeline beizubehalten und gleichzeitig die Möglichkeiten der Trainingsdaten basierten Optimierung auszunutzen. Beim Test, der Entwicklung und vor allem dem Vergleich dieser Optimierungsalgorithmen kann diese hohe Variabilität der Pipelines allerdings auch die Beurteilung unnötig komplex werden lassen. Daher besteht die zweite Variante in der Implementierung einer wenig spezifischen Standardpipeline, die als Grundlage jedes Optimierungsalgorithmus dient und so zu einer besseren Vergleichbarkeit führt. Das im Abschnitt Standatisiertes Segmentierungs Modul beschriebene Modul kann als Basis für solch eine Standardpipeline dienen. Beide Ansätze schließen sich nicht aus, da eine Standardpipeline auch als von vielen Optimierungsalgorithmen gemeinsam genutztes Pipeline Scheme angesehen werden kann. Beide Ansätze haben ihre Berechtigung, je nachdem ob Beurteilung der Algorithmen oder bestmögliche Performanz der Segmentierung im Fokus stehen. Für die Implementierung des Data Schemes, des Data Reports und der Optimization bietet sich, aufgrund der bereits vorhandenen Schnittstellen und der ohnehin breiten Verwendung, Python an. Die Möglichkeiten der Kodierung der Daten sind vielfältig. Eine einfache, variable und dennoch für den User leicht verständliche soll hier vorgestellt werden. Items, egal ob Report oder Optimization, werden als Variablen dargestellt. Dies ermöglicht sie übersichtlicher aufzuschreiben, im Gegensatz zur Darstellung als Einträge eines Dictionaries. Da Python zu den interpretierten Sprachen gehört, können die Variablen dennoch problemlos ausgelesen und verwendet werden. Parametrisierten Items wird im Report Scheme ein Dictionary ihrer Parameter als Wert zugewiesen. Ein Tupel würde die Parameter unleserlicher kodieren, da kein Begriff zu ihrer Identifizierung vorhanden ist. Nicht parametrisierten Items wird None zugewiesen. Ein Data Report enthält immer sein zugrunde liegendes Scheme (vgl. Abschnitt Konzept). Daher wird den Variablen im Report ein 2-Tupel zugewiesen, das als erste Komponente die Parameter enthält und als zweite den Wert des Items. Die Optimization enthält lediglich die Items als Variablen denen ihr Wert zugewiesen ist. Folgend ein Beispiel für die Kodierung.
Report Scheme:
author = None
quantil = { "value" : 0.3 }
anisotropicity = None
...
Data Report:
author = "Ada Lovelace"
quantil = ({ "value" : 0.3 }, 397)
anisotropicity = (None, True)
...
Optimization:
networkDimensionality = "2D"
cnnLevels = 4
batchSize = 42
...
Diskussion
Die hier vorgestellte Softwarearchitektur des Segmentation Pipeline Optimizers stellt eine allgemeine Basis für die Umsetzung eines solchen Systems dar. Die gezielte Fokussierung auf eine flexible, abstrakte Grundstruktur erwies sich als vorteilhaft. Die wenigen, aber begründeten Grundannahmen auf denen sie basiert ermöglichen der Implementierung sehr viel Spielraum und maximiert so die Anzahl an Infrastrukturen für die sie in Frage kommt. Sie ermöglicht die zeitliche, infrastrukturelle und prozesshafte Trennung der Komponenten und sogar ihrer Teilaufgaben, z.B. der Berechnung einzelner Report Items im Data Analyzer. Auch die Multiplizitäten sind so gewählt, dass durch die Verwendung mehrerer Data Analyzer oder der internen Verteilung auf mehrfach vorhandene Subkomponenten im Data Analyzer, vor allem bei der Berechnung on-demand ein Hochskalieren der Analyseleistung leicht möglich ist. Hierfür ist keine Änderung des Grundkonzept notwendig. Trotz der Flexibilität ist die Architektur koherent genug, um eine klare Struktur vorzugeben, mit der Schnittstellen für die praktische Arbeit eindeutig spezifiziert werden können.
Die Flexibilität des Systems führt allerdings auch zu mehr Unklarheit bei einer konkreten Implementierung. Dies zeigte sich bereits bei der Ausarbeitung des abstrakt gehaltenen Klassendiagramms und noch viel stärker bei der skizzierten Umsetzung bei Fraunhofer MEVIS. Selbst die Definition der Kodierung des Report Schemes zeigt eine Fülle an Möglichkeiten. Diese müssen bei der Implementierung sehr genau abgewogen werden, um sich bezüglich der Useability, dem Anschluss an vorhandene Systeme und der Portabilität in die bestehende Infrastruktur und die üblichen Abläufe einzufügen.
Eine abschließende Ausarbeitung einer konkreten Umsetzung bei Fraunhofer MEVIS war im Rahmen dieser Ausarbeitung leider nicht möglich. Daher sind die erbrachten Konkretisierungen der Implementierung lediglich als Skizze anzusehen, die nur der beispielhaften Übertragung der abstrakt definierten Grundlagen auf die tatsächliche Anwendung dienen. Hier sind viele Varianten der Details denkbar, die anhand konkreter Eigenschaften der Infrastruktur und des Workflows definiert werden sollten.
Fazit
Der vom nnU-Net geführte Beweis, dass die automatische Optimierung einer Segmentation Pipeline zu einer signifikanten Performanzsteigerung führen kann, ist als wichtiger neuer Ansatz zu betrachten. Um so wichtiger ist die Aufgabe eine Forschungsumgebung für diesen Ansatz zu schaffen, die den Fokus auf die Optimierungsalgorithmen selbst erlaubt und sich gleichzeitig in eine bereits etablierte Forschungsinfrastruktur einfügt. Hier kann die vorgestellte Softwarestruktur als eine wichtige Basis für die Entwicklung einer solchen Umgebung dienen.
Fazit
Die Anforderungen, die im Abschnitt Ziele definiert wurden, konnten erreicht werden. Es wurden sieben Module erstellt, die es den Nutzern von MeVisLab erleichtern, ein trainiertes neuronales Netz zu analysieren. Außerdem wurde ein Konzept entworfen, das bei der Einführung des nnU-Net Konzepts zur automatischen Optimierung einer Segmentation Pipeline bei MEVIS helfen soll.
Ausblick
Die Visualisierung der Differenz durch das Confusion Matrix Modul zeigt die Fehlerbereiche Regional (Abbildung 1). Berechnet man diese Masken mit probabilistisch Netzen, kann man über den Durchschnitt verschiedener Prädiktionen die Fehlerbereiche als eine Art Unsicherheit des Netzes interpretieren (Uncertainty Sampling). Aus Sicht des Aktiven Lernens, sollte man diese Maße schon zwischen den Trainingsintervallen als Feedback bekommen. So könnte z.B. mit Hard Sample Mining das nächste Trainingsset aufgrund des Feedbacks ausgewählt werden. In SATORI werden bereits Label mit Maskierungs Tools gezeichnet. Ein Benutzer könnte damit anstelle von Label Masken, Regionen besonderer Priorität einzeichnen. Die ausgewählten Voxel sind Teil von Patches, die dann Teil des nächsten Trainingsintervalls werden.