KAPITEL 3

Entwurfsmuster zur Problemdarstellung

Kapitel 2 hat sich mit Entwurfsmustern befasst, die die unzähligen Möglichkeiten, mit denen sich Eingaben in ML-Modelle darstellen lassen, katalogisieren. Dieses Kapitel zeigt verschiedene Arten von ML-Problemen und analysiert, wie die Modellarchitekturen je nach Problem variieren.

Die Eingabe- und die Ausgabetypen sind zwei Schlüsselfaktoren, die sich auf die Modellarchitektur auswirken. Zum Beispiel kann die Ausgabe in überwachten ML-Problemen variieren, je nachdem, ob ein Klassifizierungs- oder ein Regressionsproblem zu lösen ist. Für spezifische Arten von Eingabedaten existieren spezielle Schichten von neuronalen Netzen: Faltungsschichten für Bilder, Sprache, Text und andere Daten mit räumlich-zeitlicher Korrelation, rekurrente Netze für sequenzielle Daten usw. Eine umfangreiche Literatur ist um spezielle Techniken wie Max-Pooling, Attention usw. auf diesen Arten von Schichten entstanden. Darüber hinaus wurden spezielle Lösungsklassen für häufig auftretende Probleme entwickelt, wie Empfehlungen (zum Beispiel Matrixfaktorisierung) oder Zeitreihenvorhersage (zum Beispiel ARIMA). Schließlich ist es mit einer Gruppe einfacherer Modelle gemeinsam mit gängigen Idiomen möglich, komplexere Probleme zu lösen – zum Beispiel ist bei der Texterzeugung oftmals ein Klassifizierungsmodell beteiligt, dessen Ausgaben mit einem Beam-Search-Algorithmus nachbearbeitet werden.

Um unsere Diskussion zu beschränken und uns aus Bereichen aktiver Forschung herauszuhalten, ignorieren wir Muster und Idiome, die mit spezialisierten ML-Domänen verbunden sind. Stattdessen konzentrieren wir uns auf Regression und Klassifizierung und untersuchen Muster mit einer Problemdarstellung nur in diesen beiden Arten von ML-Modellen.

Das Entwurfsmuster Reframing übernimmt eine Lösung, die man intuitiv als Regressionsproblem auffassen würde, und stellt es als Klassifizierungsproblem dar (und umgekehrt). Das Entwurfsmuster Multilabel befasst sich mit dem Fall, dass Trainingsbeispiele zu mehr als einer Klasse gehören können. Das Entwurfsmuster Kaskade wird auf Situationen angewendet, in denen ein ML-Problem gewinnbringend in eine Reihe (oder Folge) von ML-Problemen zerlegt werden kann. Das Entwurfsmuster Ensemble löst ein Problem, indem mehrere Modelle trainiert und ihre Antworten zusammengefasst werden. Im Entwurfsmuster Neutrale Klasse geht es um den Umgang mit Situationen, in denen sich Experten nicht einig sind. Das Entwurfsmuster Rebalancing empfiehlt Ansätze dazu, wie mit stark verzerrten oder unausgewogenen Daten zu verfahren ist.

Entwurfsmuster 5: Reframing

Im Entwurfsmuster Reframing geht es darum, die Darstellung der Ausgabe eines ML-Problems zu ändern. Zum Beispiel könnten wir ein Problem, das wir intuitiv als Regressionsproblem einordnen, als Klassifizierungsproblem darstellen (und umgekehrt).

Problem

Wenn man eine ML-Lösung entwickelt, steckt man im ersten Schritt den Rahmen für das Problem ab. Handelt es sich um ein Problem des überwachten Lernens oder des unüberwachten Lernens? Welche Features gibt es? Wenn es ein überwachtes Problem ist, wie sehen die Labels aus? Wie groß darf der Fehler sein? Natürlich müssen die Antworten auf diese Fragen im Zusammenhang mit den Trainingsdaten, der gestellten Aufgabe und den Erfolgsmetriken betrachtet werden.

Nehmen wir zum Beispiel an, wir wollten ein ML-Modell erstellen, um zukünftige Niederschlagsmengen für einen bestimmten Ort vorherzusagen. Ganz allgemein gefragt: Wäre dies eine Regressions- oder eine Klassifizierungsaufgabe? Da wir ja versuchen, die Niederschlagsmenge (zum Beispiel 0,3 cm) vorherzusagen, ist es sinnvoll, diese Aufgabe als Problem einer Zeitreihenvorhersage zu betrachten: Welche Niederschlagsmenge sollten wir in einem bestimmten Gebiet in den nächsten 15 Minuten erwarten, wenn die aktuellen und historischen Klima- und Wettermuster gegeben sind? Da die Beschriftung (die Niederschlagsmenge) eine Realzahl ist, könnten wir alternativ auch ein Regressionsmodell erstellen. Wenn wir dann unser Modell entwickeln und trainieren, finden wir (was vielleicht nicht überrascht), dass eine Wettervorhersage schwerer ist, als es scheint. Unsere vorhergesagten Niederschlagsmengen liegen alle daneben, weil es – mit dem gleichen Satz an Features – manchmal 0,3 cm regnet und manchmal 0,5 cm. Was sollten wir tun, um unsere Vorhersagen zu verbessern? Sollten wir unserem Netz mehr Schichten spendieren? Oder mehr Features entwickeln? Helfen vielleicht mehr Daten? Brauchen wir vielleicht eine andere Verlustfunktion?

Jede dieser Anpassungen könnte unser Modell verbessern. Doch halt! Ist Regression die einzige Möglichkeit für diese Aufgabe? Vielleicht können wir unser Ziel des maschinellen Lernens in einer Weise neu formulieren, die die Performance unserer Aufgabe verbessert.

Lösung

Das Kernproblem ist hier, dass Niederschlag auch vom Zufall abhängt. Beim gleichen Satz von Features regnet es manchmal 0,3 cm und ein anderes Mal 0,5 cm. Doch selbst wenn ein Regressionsmodell in der Lage wäre, die beiden möglichen Mengen zu lernen, ist es darauf beschränkt, nur eine einzige Zahl vorherzusagen.

Anstatt zu versuchen, die Niederschlagsmenge als Regressionsaufgabe vorherzusagen, können wir unser Ziel als Klassifizierungsproblem neu formulieren. Dies lässt sich auf verschiedenen Wegen erreichen. Bei einem dieser Ansätze modelliert man eine diskrete Wahrscheinlichkeitsverteilung, wie Abbildung 3-1 zeigt. Die Niederschlagsmenge sagen wir nun nicht in Form einer Realzahl voraus, sondern modellieren die Ausgabe als Multiklassenklassifizierung, die die Wahrscheinlichkeit angibt, dass der Niederschlag in den nächsten 15 Minuten innerhalb eines bestimmten Bereichs von Niederschlagsmengen liegt.

image

Abbildung 3-1: Anstatt den Niederschlag als Regressionsausgabe vorherzusagen, können wir stattdessen mit einer Multiklassenklassifizierung eine diskrete Wahrscheinlichkeitsverteilung modellieren.

Sowohl der Regressionsansatz als auch dieser neu formulierte Klassifizierungsansatz liefern eine Vorhersage des Niederschlags für die nächsten 15 Minuten. Allerdings erlaubt der Klassifizierungsansatz dem Modell, die Wahrscheinlichkeitsverteilung der Niederschlagsmengen zu erfassen, anstatt den Mittelwert der Verteilung wählen zu müssen. Eine derartige Modellierung der Verteilung ist vorteilhaft, da der Niederschlag nicht die typische Glockenkurve einer Normalverteilung aufweist und stattdessen einer Tweedie-Verteilung (https://oreil.ly/C8JfK) folgt, die ein Überwiegen von Punkten bei null zulässt. Tatsächlich ist dies der Ansatz, der in einem Google-Research-Paper (https://oreil.ly/PGAEw) beschrieben wird. Damit werden Niederschlagsraten an einem bestimmten Ort mit einer kategorialen Verteilung von 512 Klassen vorhergesagt. Das Modellieren einer Verteilung kann ebenfalls vorteilhaft sein, wenn die Verteilung bimodal ist, oder sogar bei einer Normalverteilung, die eine große Varianz aufweist. Eine neuere Arbeit, die sämtliche Benchmarks bei der Vorhersage der Proteinfaltungsstruktur schlägt (https://oreil.ly/-Hi3k), sagt auch den Abstand zwischen Aminosäuren voraus, und zwar als 64-faches Klassifizierungsproblem, bei dem die Abstände in 64 Buckets klassifiziert werden.

Ein Problem wird man auch dann neu formulieren, wenn das Ziel im anderen Modelltyp besser zu erreichen ist. Nehmen Sie zum Beispiel an, Sie entwickeln ein Empfehlungssystem für Videos. Es liegt nahe, dieses Problem als Klassifizierungsproblem zu formulieren, und zwar als Vorhersage, ob ein Benutzer wahrscheinlich ein bestimmtes Video ansehen wird. Dieses Framing kann jedoch zu einem Empfehlungssystem führen, das Klickköder bevorzugt. Es wäre vielleicht besser, dieses Problem neu zu formulieren, und zwar als Regressionsproblem, das den Anteil des abgerufenen Videos vorhersagt.

Warum es funktioniert

Beim Entwickeln einer Lösung für maschinelles Lernen kann es hilfreich sein, den Kontext zu ändern und die Aufgabe eines Problems neu zu formulieren. Anstatt eine einzelne Realzahl zu lernen, lockern wir unser Vorhersageziel und sagen, dass es stattdessen eine diskrete Wahrscheinlichkeitsverteilung sein soll. Wir verlieren etwas Präzision infolge des Bucketings, gewinnen aber die Ausdruckskraft einer vollständigen Wahrscheinlichkeitsdichtefunktion (Probability Density Function, PDF). Die diskretisierten Vorhersagen, die das Klassifizierungsmodell liefert, sind souveräner beim Lernen eines komplexen Ziels als das starrere Regressionsmodell.

Dieses Klassifizierungs-Framing hat zusätzlich den Vorteil, dass wir die A-posteriori-Verteilung unserer vorhergesagten Werte erhalten, die nuanciertere Informationen liefert. Nehmen wir zum Beispiel an, dass die gelernte Verteilung bimodal ist. Indem wir eine Klassifizierung als diskrete Wahrscheinlichkeitsverteilung modellieren, ist das Modell in der Lage, die bimodale Struktur der Vorhersagen zu erfassen, wie Abbildung 3-2 veranschaulicht. Würde hingegen nur ein einzelner numerischer Wert vorhergesagt, gingen diese Informationen verloren. Je nach Anwendungsfall könnte das die Aufgabe leichter erlernbar und wesentlich nützlicher machen.

image

Abbildung 3-2: Durch die Umgestaltung einer Klassifizierungsaufgabe, um eine Wahrscheinlichkeitsverteilung zu modellieren, können Vorhersagen bimodale Ausgaben erfassen. Die Vorhersage ist nicht auf einen einzelnen Wert begrenzt wie in einer Regression.

Unsicherheit erfassen

Betrachten wir noch einmal den Geburtendatensatz und die Aufgabe, das Babygewicht vorherzusagen. Da das Babygewicht ein positiver reeller Wert ist, kommt intuitiv ein Regressionsproblem infrage. Für einen bestimmten Satz von Eingaben kann weight_pounds (das Label) aber viele verschiedene Werte annehmen. Die Verteilung der Babygewichte für einen bestimmten Satz von Eingabewerten (männliche Babys, die von 25-jährigen Müttern in der 38. Woche geboren wurden) folgt ungefähr einer Normalverteilung mit einem Zentrum bei etwa 7,5 Pfund. Im Repository zu diesem Buch (https://github.com/GoogleCloudPlatform/ml-design-patterns/03_problem_representation/reframing.ipynb) finden Sie den Code, mit dem Sie das Diagramm aus Abbildung 3-3 erzeugen können.

image

Abbildung 3-3: Bei einem bestimmten Satz von Eingaben (zum Beispiel männliche Babys, die von 25-jährigen Müttern in der 38. Woche geboren wurden) nimmt die Variable »weight_ pounds« einen Bereich von Werten an, die ungefähr einer Normalverteilung folgen, deren Zentrum bei 7,5 Pfund liegt.

Beachten Sie aber auch die Breite der Verteilung – selbst wenn die Verteilung einen Spitzenwert bei 7,5 Pfund hat, gibt es eine nicht triviale Wahrscheinlichkeit (tatsächlich 33 %), dass ein bestimmtes Baby weniger als 6,5 Pfund oder mehr als 8,5 Pfund wiegt! Die Breite dieser Verteilung weist auf den nicht reduzierbaren Fehler hin, der dem Problem innewohnt, das Babygewicht vorherzusagen. In der Tat ist der beste quadratische Fehler, den wir für dieses Problem bekommen können, wenn wir es als Regressionsproblem formulieren, die Standardabweichung der Verteilung, wie sie Abbildung 3-3 zeigt.

Als Regressionsproblem betrachtet, müssten wir das Vorhersageergebnis als 7,5 +/–1,0 (oder was auch immer die Standardabweichung ist) angeben. Die Breite der Verteilung variiert jedoch für verschiedene Kombinationen von Eingaben, und somit ist das Lernen der Breite ein weiteres Problem des maschinellen Lernens an sich. Zum Beispiel beträgt die Standardabweichung in der 36. Woche für Mütter desselben Alters 1,16 Pfund. Die später in der Musterdiskussion behandelte Quantilsregression versucht genau dies zu tun, aber parameterfrei.

image

Wäre die Verteilung multimodal (mit mehreren Spitzen), spräche noch viel mehr dafür, das Problem als Klassifizierungsproblem umzugestalten. Es ist jedoch hilfreich, zu erkennen, dass viele der Verteilungen, mit denen wir es bei großen Datensätzen zu tun haben, glockenförmig sind. Das hängt mit dem Gesetz der großen Zahlen zusammen und setzt voraus, dass wir sämtliche relevanten Eingaben erfassen. Es sind allerdings auch andere Verteilungen möglich. Je breiter die Glockenkurve ist und je mehr diese Breite bei verschiedenen Eingabewerten variiert, desto wichtiger ist es, die Unbestimmtheit zu erfassen, und desto mehr spricht dafür, das Regressionsproblem als ein Klassifizierungsproblem umzuformulieren.

Indem wir das Problem umformulieren, trainieren wir das Modell als Multiklassenklassifizierung, die eine diskrete Wahrscheinlichkeitsverteilung für die gegebenen Trainingsbeispiele lernt. Diese diskretisierten Vorhersagen sind flexibler in Bezug auf das Erfassen der Unsicherheit und besser als ein Regressionsmodell in der Lage, das komplexe Ziel zu approximieren. Zur Inferenzzeit sagt das Modell dann eine Auflistung von Wahrscheinlichkeiten voraus, die diesen potenziellen Ausgaben entsprechen. Wir bekommen also eine diskrete Wahrscheinlichkeitsdichtefunktion, die die relative Wahrscheinlichkeit eines bestimmten Gewichts angibt. Natürlich ist hier Vorsicht geboten – Klassifizierungsmodelle können weitgehend unkalibriert sein (wenn das Modell etwa allzu zuversichtlich und falsch ist).

Das Ziel ändern

In manchen Szenarios könnte es von Vorteil sein, eine Klassifizierungsaufgabe in eine Regressionsaufgabe umzuwandeln. Nehmen wir als Beispiel eine große Filmdatenbank mit Kundenbewertungen auf einer Skala von 1 bis 5 für sämtliche Filme, die der Benutzer gesehen und bewertet hat. Wir sollen nun ein ML-Model erstellen, das unsere Benutzer mit Empfehlungen versorgt.

Als Klassifizierungsaufgabe betrachtet, könnten wir ein Modell erstellen, das als Eingabe eine user_id zusammen mit den vorherigen Videoabrufen und -bewertungen dieses Benutzers übernimmt und vorhersagt, welcher Film aus unserer Datenbank als Nächstes empfohlen werden soll. Es ist jedoch möglich, dieses Problem als Regression umzuformulieren. Anstatt ein Modell mit einer kategorialen Ausgabe, die einem Film in unserer Datenbank entspricht, zu erstellen, könnte unser Modell stattdessen ein Multitask-Lernen durchführen. Dabei lernt das Modell eine Reihe wichtiger Eigenschaften (wie zum Beispiel Einkommen, Kundensegment usw.) von Benutzern, die wahrscheinlich einen bestimmten Film ansehen werden. Umgeformt als Regressionsaufgabe, sagt das Modell nun die Darstellung des Benutzerraums für einen bestimmten Film voraus. Um Empfehlungen auszusprechen, wählen wir den Satz von Filmen, der den bekannten Eigenschaften eines Benutzers am nächsten kommt. Anstatt das Modell wie in einer Klassifizierung die Wahrscheinlichkeit dafür ausgeben zu lassen, dass ein Benutzer einen Film mag, würden wir eine Gruppe von Filmen bekommen, die von Benutzern wie diesem Benutzer gesehen wurden.

Indem wir das Klassifizierungsproblem der Filmempfehlung in eine Regression von Benutzereigenschaften umwandeln, können wir nun unser Empfehlungsmodell leicht anpassen, um im Trend liegende Videos, klassische Filme oder Dokumentationen zu empfehlen, ohne jedes Mal ein eigenes Klassifizierungsmodell trainieren zu müssen.

Ein derartiges Modellkonzept ist auch nützlich, wenn die numerische Darstellung eine intuitive Interpretation zulässt. Zum Beispiel kann ein Breitengrad-Längengrad-Paar anstelle von Vorhersagen für Stadtgebiete verwendet werden. Nehmen wir an, wir wollten vorhersagen, welche Stadt den nächsten Virenausbruch erlebt oder in welchem New Yorker Stadtteil die Immobilienpreise in die Höhe schnellen werden. Es könnte einfacher sein, den Breiten- und Längengrad vorherzusagen und dann die Stadt oder den Stadtteil auszuwählen, die/der diesem Ort am nächsten liegt, als die Stadt oder den Stadtteil selbst vorherzusagen.

Kompromisse und Alternativen

Es gibt selten nur eine Möglichkeit, ein Problem zu formulieren, und es ist hilfreich, über alle Kompromisse oder Alternativen einer bestimmten Implementierung informiert zu sein. So ist zum Beispiel das Kategorisieren der Ausgabewerte (engl. Bucketizing) einer Regression ein Ansatz, um das Problem als Klassifizierungsaufgabe umzuformulieren. Ein anderer Ansatz ist Multitask-Lernen, das beide Aufgaben (Klassifizierung und Regression) in einem einzigen Modell mithilfe mehrerer Vorhersageköpfe kombiniert. Seien Sie sich aber bei jeder Reframing-Technik bewusst, dass es Datenbeschränkungen gibt oder dass das Risiko besteht, systematische Label-Abweichungen einzuführen.

Kategorisierte Ausgaben

Der typische Ansatz, eine Regressionsaufgabe als Klassifizierung umzuformulieren, besteht darin, die Ausgabewerte in Buckets einzuteilen. Wenn unser Modell zum Beispiel anzeigen soll, ob ein Baby nach der Geburt eine Intensivversorgung benötigt, könnten die in Tabelle 3-1 angegebenen Kategorien ausreichend sein.

Tabelle 3-1: Kategorisierte Ausgaben für das Babygewicht

Kategorie

Beschreibung

Hohes Geburtsgewicht

Mehr als 8,8 Pfund

Durchschnittliches Geburtsgewicht

Zwischen 5,5 und 8,8 Pfund

Niedriges Geburtsgewicht

Zwischen 3,31 und 5,5 Pfund

Sehr niedriges Geburtsgewicht

Weniger als 3,31 Pfund

Unser Regressionsmodell wird nun zu einer Multiklassenklassifizierung. Intuitiv ist es einfacher, einen von vier möglichen kategorialen Fällen vorherzusagen als einen einzelnen Wert aus dem Kontinuum der reellen Zahlen – genauso wie es einfacher wäre, eine binäre 0 gegenüber einer 1 als Ziel für is_underweight vorherzusagen statt einer aus vier getrennten Kategorien high_weight, avg_weight, low_weight oder very_low_weight. Mit kategorialen Ausgaben bekommt unser Modell weniger Anreize, willkürlich nahe an den tatsächlichen Ausgabewert heranzukommen, da wir im Wesentlichen das Ausgabe-Label in einen Wertebereich anstatt in eine einzelne Realzahl geändert haben.

Im Notebook zu diesem Abschnitt (https://github.com/GoogleCloudPlatform/ml-design-patterns/blob/master/03_problem_representation/reframing.ipynb) trainieren wir sowohl ein Regressions- als auch ein Multiklassenklassifizierungsmodell. Das Regressionsmodell erreicht einen RMSE von 1,3 auf dem Validierungsset, während das Klassifizierungsmodell eine Genauigkeit von 67% aufweist. Es ist schwierig, beide Modelle zu vergleichen, da die eine Bewertungsmetrik den RMSE verwendet und die andere die Genauigkeit. Letztlich ist der Anwendungsfall für die Entwurfsentscheidung maßgebend. Wenn medizinische Entscheidungen auf kategorisierten Werten basieren, sollte unser Modell eine Klassifizierung mit diesen Buckets sein. Wenn jedoch eine genauere Vorhersage des Babygewichts benötigt wird, ist es sinnvoll, das Regressionsmodell zu verwenden.

Andere Möglichkeiten, Unsicherheit zu erfassen

Es gibt noch andere Möglichkeiten, Unsicherheit in Regression zu erfassen. Ein einfacher Ansatz ist es, die Quantilsregression durchzuführen. Anstatt zum Beispiel nur den Mittelwert vorherzusagen, können wir das bedingte 10., 20., 30., …, 90. Perzentil für das vorauszusagende Ergebnis schätzen. Quantilsregression ist eine Erweiterung der linearen Regression. Reframing kann dagegen mit komplexeren ML-Modellen arbeiten.

Ein anderer, anspruchsvollerer Ansatz führt eine Regression mit einem Framework wie TensorFlow Probability (https://oreil.ly/AEtLG) durch. Allerdings müssen wir die Verteilung der Ausgabe explizit modellieren. Wenn wir zum Beispiel für die Ausgabe eine Normalverteilung erwarten, deren Mittelwert von den Eingaben abhängt, würde die Ausgabeschicht des Modells so aussehen:

tfp.layers.DistributionLambda(lambda t: tfd.Normal(loc=t, scale=1))

Wenn wir andererseits wissen, dass die Varianz mit dem Mittelwert zunimmt, könnten wir die Verteilung vielleicht mit der Lambda-Funktion modellieren. Beim Reframing hingegen brauchen wir die A-posteriori-Verteilung nicht zu modellieren.

image

Welches Modell des maschinellen Lernens auch trainiert wird, die Daten sind der Schlüssel. Komplexere Beziehungen verlangen typischerweise mehr Trainingsdatenbeispiele, um diese schwer fassbaren Muster zu finden. Deshalb ist es wichtig, zu überlegen, wie die Datenanforderungen für Regressions- oder Klassifizierungsmodelle aussehen. Für Klassifizierungsaufgaben besagt eine gängige Faustregel, dass für jede Label-Kategorie die 10-fache Anzahl an Modell-Features vorhanden sein sollte. Bei einem Regressionsmodell gilt als Faustregel das 50-Fache der Anzahl von Modell-Features. Natürlich sind diese Zahlen lediglich grobe Heuristik und keine genauen Werte. Es liegt aber auf der Hand, dass Regressionsaufgaben typischerweise mehr Trainingsbeispiele erfordern. Außerdem steigt dieser Bedarf an massiven Daten nur mit der Komplexität der Aufgabe. Somit könnten Datenbeschränkungen zu berücksichtigen sein, wenn es um die Art des verwendeten Modells oder – im Fall der Klassifizierung – die Anzahl der Label-Kategorien geht.

Genauigkeit von Vorhersagen

Stellt man sich das Reframing eines Regressionsmodells als Multiklassenklassifizierung vor, bestimmt die Breite der Klassen für das Ausgabe-Label die Genauigkeit des Klassifizierungsmodells. Wenn wir in unserem Beispiel mit den Babygewichten genauere Informationen von der diskreten Wahrscheinlichkeitsdichtefunktion benötigen, müssten wir die Anzahl der Klassen unseres kategorialen Modells erhöhen. Abbildung 3-4 zeigt, wie die diskreten Wahrscheinlichkeitsverteilungen bei vier und bei zehn Klassen aussähen.

image

Abbildung 3-4: Die Genauigkeit der Multiklassenklassifizierung wird durch die Breite der Klassen für die Labels gesteuert.

Die Schärfe der Wahrscheinlichkeitsdichtefunktion zeigt die Präzision der Aufgabe als Regression an. Eine schärfere Wahrscheinlichkeitsdichtefunktion weist auf eine kleinere Standardabweichung der Ausgabeverteilung hin, während eine breitere Funktion eine größere Standardabweichung und demzufolge mehr Varianz bedeutet. Bei einer sehr scharfen Dichtefunktion ist es besser, bei einem Regressionsmodell zu bleiben (siehe Abbildung 3-5).

image

Abbildung 3-5: Die Präzision der Regression zeigt sich an der Schärfe der Wahrscheinlichkeitsdichtefunktion für einen festen Satz von Eingabewerten.

Den Vorhersagebereich einschränken

Das Problem wird man auch dann neu formulieren, wenn es wichtig ist, den Bereich der Vorhersageausgabe einzuschränken. Nehmen wir zum Beispiel an, dass realistische Ausgabewerte für ein Regressionsproblem im Bereich [3, 20] liegen. Wenn wir ein Regressionsmodell trainieren, bei dem die Ausgabeschicht eine lineare Aktivierungsfunktion verwendet, besteht immer die Möglichkeit, dass die Modellvorhersagen außerhalb dieses Bereichs liegen. Um den Ausgabebereich zu beschränken, können Sie das Problem neu formulieren.

Machen Sie die Aktivierungsfunktion der vorletzten Schicht zu einer Sigmoid-Funktion (die typischerweise mit Klassifizierung assoziiert wird), sodass die Ausgabe im Bereich [0, 1] liegt, und lassen Sie die letzte Schicht diese Werte in den gewünschten Bereich skalieren:

MIN_Y = 3

MAX_Y = 20

input_size = 10

inputs = keras.layers.Input(shape=(input_size,))

h1 = keras.layers.Dense (20, 'relu')(inputs)

h2 = keras.layers.Dense (1, 'sigmoid')(h1) # 0-1 range

output = keras.layers.Lambda(

lambda y : (y*(MAX_Y-MIN_Y) + MIN_Y))(h2) # scaled

model = keras.Model(inputs, output)

Dieses Modell gibt jetzt Zahlen im Bereich [3, 20] aus, wovon Sie sich selbst überzeugen können (siehe das Notebook unter https://github.com/GoogleCloudPlatform/ml-design-patterns/blob/master/03_problem_representation/reframing.ipynb auf GitHub mit dem vollständigen Code). Da die Ausgabe von einer Sigmoid-Funktion kommt, wird das Modell weder das Minimum noch das Maximum des Bereichs treffen, sondern diesen Extremwerten nur sehr nahe kommen. Als wir das obige Modell mit einigen zufälligen Daten trainierten, lagen die Ergebniswerte im Bereich [3.03, 19.99].

Label-Bias

Empfehlungssysteme wie die Matrixfaktorisierung lassen sich im Kontext von neuronalen Netzen sowohl als Regression als auch als Klassifizierung neu formulieren. Dieser Kontextwechsel hat unter anderem den Vorteil, dass ein als Regressions- oder Klassifizierungsmodell konzipiertes neuronales Netz viel mehr zusätzliche Features als nur die bei der Matrixfaktorisierung gelernten Benutzer- und Objekteinbettungen einbeziehen kann. Es kann also eine reizvolle Alternative sein.

Allerdings ist es wichtig, die Art des Ziel-Labels zu berücksichtigen, wenn das Problem neu formuliert wird. Nehmen wir zum Beispiel an, wir hätten unser Empfehlungsmodell umformuliert in eine Klassifizierungsaufgabe, die die Wahrscheinlichkeit vorhersagt, dass ein Benutzer auf ein bestimmtes Video-Thumbnail klickt. Dies scheint eine vernünftige Umformung zu sein, denn wir wollen ja Inhalte bereitstellen, die ein Benutzer auswählen und ansehen wird. Doch Vorsicht! Diese Label-Änderung entspricht nicht wirklich unserer Vorhersageaufgabe. Durch die Optimierung auf Benutzerklicks wird unser Modell ungewollt Klickköder fördern und dem Benutzer nicht wirklich brauchbare Inhalte empfehlen.

Stattdessen wäre ein vorteilhafteres Label die Dauer, die das Video angesehen wurde, wodurch wir unsere Empfehlung in eine Regression umwandeln. Vielleicht können wir auch das Klassifizierungsziel modifizieren, um die Wahrscheinlichkeit vorherzusagen, dass sich ein Benutzer mindestens die Hälfte des Videoclips ansieht. Oft gibt es mehr als einen geeigneten Ansatz, und es ist wichtig, das Problem ganzheitlich zu betrachten, wenn man eine Lösung konzipiert.

image

Seien Sie vorsichtig, wenn Sie das Label und die Trainingsaufgabe Ihres ML-Modells ändern, da dies unbeabsichtigt Label-Bias in Ihre Lösung einbringen kann. Sehen Sie sich noch einmal das Beispiel der Videoempfehlung im Abschnitt »Warum es funktioniert« auf Seite 102 an.

Multitask-Lernen

Eine Alternative zum Reframing ist Multitask-Lernen. Anstatt zu versuchen, zwischen Regression und Klassifizierung auszuwählen, machen Sie beides! Allgemein gesagt, bezieht sich Multitask-Lernen auf jedes ML-Modell, in dem mehr als eine Verlustfunktion optimiert wird. Dies lässt sich auf viele verschiedene Arten erreichen, doch die beiden gebräuchlichsten Formen von Multitask-Lernen in neuronalen Netzen laufen über Hard-Parameter-Sharing und Soft-Parameter-Sharing.

Die gemeinsame Nutzung von Parametern bezieht sich auf Parameter des neuronalen Netzes, die zwischen den verschiedenen Ausgabeaufgaben wie Regression und Klassifizierung gemeinsam genutzt werden. Hard-Parameter-Sharing tritt auf, wenn die verdeckten Schichten des Modells von allen Ausgabeaufgaben gemeinsam genutzt werden. Beim Soft-Parameter-Sharing hat jedes Label sein eigenes neuronales Netz mit seinen eigenen Parametern, und die Parameter der verschiedenen Modelle werden durch eine Form der Regularisierung dazu gebracht, ähnlich zu sein. Abbildung 3-6 zeigt die typische Architektur für Hard-Parameter-Sharing und Soft-Parameter-Sharing.

image

Abbildung 3-6: Zwei gängige Implementierungen des Multitask-Lernens über Hard-Parameter-Sharing und Soft-Parameter-Sharing

In diesem Zusammenhang könnten wir zwei Köpfe für unser Modell vorsehen: einen, um eine Regressionsausgabe vorherzusagen, und einen anderen, um eine Klassifizierungsausgabe vorherzusagen. Zum Beispiel beschreibt das Paper unter https://oreil.ly/sIjsF, wie ein Computer-Vision-Modell mithilfe einer Klassifizierungsausgabe von Softmax-Wahrscheinlichkeiten zusammen mit einer Regressionsausgabe trainiert wird, um Bounding Boxes vorherzusagen. Es zeigt, dass dieser Ansatz eine bessere Performance erreicht als vergleichbare Arbeiten, die Netze getrennt nach Klassifizierungs- und Lokalisierungsaufgaben trainieren. Die Idee besteht hier darin, dass über Parameter-Sharing die Aufgaben gleichzeitig gelernt werden und Gradientenaktualisierungen der beiden Verlustfunktionen beide Ausgaben informieren. Insgesamt ergibt sich ein besser zu verallgemeinerndes Modell.

Entwurfsmuster 6: Multilabel

Das Entwurfsmuster Multilabel bezieht sich auf Probleme, bei denen wir einem bestimmten Trainingsbeispiel mehr als ein Label zuweisen können. Für neuronale Netze ist es bei diesem Design erforderlich, die Aktivierungsfunktion in der letzten Ausgabeschicht des Modells zu ändern und festzulegen, wie unsere Anwendung die Modellausgabe parsen soll. Das unterscheidet sich von Problemen der Multiklassenklassifizierung, bei denen einem einzelnen Beispiel genau ein Label aus einer Gruppe vieler (> 1) möglicher Klassen zugewiesen wird. Das Entwurfsmuster Multilabel wird auch als Multilabel-/Multiklassenklassifizierung bezeichnet, da mehr als ein Label aus einer Gruppe von mehr als einer möglichen Klasse ausgewählt wird. Bei der Besprechung dieses Musters werden wir uns hauptsächlich auf neuronale Netze konzentrieren.

Problem

Bei Modellvorhersageaufgaben ist häufig eine einzelne Klassifizierung auf ein bestimmtes Trainingsbeispiel anzuwenden. Diese Vorhersage wird bestimmt aus N möglichen Klassen, wobei N größer als 1 ist. In diesem Fall ist es üblich, Softmax als Aktivierungsfunktion für die Ausgabeschicht zu verwenden. Die Ausgabe unseres Modells ist bei Verwendung von Softmax ein Array mit N Elementen, bei dem die Summe aller Werte 1 ergibt. Jeder Wert gibt die Wahrscheinlichkeit an, dass ein bestimmtes Trainingsbeispiel mit der Klasse an diesem Index assoziiert ist.

Wenn unser Modell zum Beispiel Bilder als Katzen, Hunde oder Kaninchen klassifiziert, könnte die Softmax-Ausgabe für ein bestimmtes Bild [.89, .02, .09] lauten. Unser Modell sagt also voraus, dass es sich mit einer Wahrscheinlichkeit von 89% um eine Katze, mit 2% um einen Hund und mit 9% um ein Kaninchen handelt. Da jedes Bild in diesem Szenario nur ein mögliches Label haben kann, können wir den Wert von argmax (Index der höchsten Wahrscheinlichkeit) nehmen, um die von unserem Modell vorhergesagte Klasse zu bestimmen. Weniger häufig ist das Szenario, wenn jedem Trainingsbeispiel mehr als ein Label zugewiesen werden kann. Und das ist es, worum es bei diesem Muster geht.

Das Entwurfsmuster Multilabel existiert für Modelle, die auf allen Datenmodalitäten trainiert werden. Bei der Bildklassifizierung könnten wir in dem weiter oben gezeigten Beispiel mit Katze, Hund und Kaninchen stattdessen Trainingsbilder verwenden, die jeweils mehrere Tiere darstellen und daher mehrere Labels haben könnten. Für Textmodelle kann man sich Szenarios vorstellen, in denen Text mit mehreren Tags gelabelt werden kann. Am Beispiel des Datensatzes mit den Stack-Overflow-Fragen auf BigQuery könnten wir ein Modell erstellen, um die einer bestimmten Frage zugeordneten Tags vorherzusagen. So ließen sich der Frage »How do I plot a pandas DataFrame?« die Tags »Python«, »Pandas« und »Visualisierung« zuweisen. Ein weiteres Beispiel für eine Multilabel-Textklassifizierung ist ein Modell, das schädliche Kommentare identifiziert. Für dieses Modell könnten wir Kommentare mit mehreren Schädlichkeits-Labels markieren wollen. Ein Kommentar könnte demzufolge sowohl als »hasserfüllt« als auch als »obszön« gelabelt werden.

Dieses Entwurfsmuster kann auch auf tabellarische Datensätze angewendet werden. Stellen Sie sich einen Datensatz aus dem Gesundheitswesen mit verschiedenen physischen Eigenschaften – wie Größe, Gewicht, Alter, Blutdruck und mehr – für jede Patientin und jeden Patienten vor. Anhand dieser Daten könnte das Vorhandensein mehrerer Erkrankungen vorhergesagt werden. Beispielsweise könnte ein Patient sowohl das Risiko für eine Herzerkrankung als auch für Diabetes aufweisen.

Lösung

Um Modelle zu erstellen, die einem bestimmten Trainingsbeispiel mehr als ein Label zuweisen können, verwendet man in der letzten Ausgabeschicht die Sigmoid- Aktivierungsfunktion. Anstatt ein Array zu generieren, in dem sich alle Werte zu 1 summieren (wie in Softmax), ist jeder einzelne Wert in einem Sigmoid-Array eine Gleitkommazahl zwischen 0 und 1. Wenn also das Entwurfsmuster Multilabel implementiert wird, muss unser Label Multi-Hot-codiert sein. Die Länge des Multi-Hot-Arrays korrespondiert mit der Anzahl der Klassen in unserem Modell, und jede Ausgabe in diesem Label-Array wird ein Sigmoid-Wert sein.

Aufbauend auf dem obigen Bildbeispiel, nehmen wir an, dass unser Trainingsdatensatz Bilder mit mehr als einem Tier enthält. Die Sigmoid-Ausgabe für ein Bild, das eine Katze und einen Hund enthält, aber kein Kaninchen, könnte [.92, .85, .11] lauten. Diese Ausgabe bedeutet, dass das Modell mit einer Sicherheit von 92 % annimmt, dass das Bild eine Katze enthält, zu 85 % für einen Hund votiert und mit 11 % zu einem Kaninchen tendiert.

Eine Version dieses Modells für 28 × 28-Pixel-Bilder mit Sigmoid-Ausgabe könnte unter Verwendung der Sequential-API von Keras wie folgt aussehen:

model = keras.Sequential([

keras.layers.Flatten(input_shape=(28, 28)),

keras.layers.Dense(128, activation='relu'),

keras.layers.Dense(3, activation='sigmoid')

])

Die Ausgabe des Sigmoid-Modells hier und des Softmax-Beispiels im Abschnitt »Problem« oben unterscheidet sich vor allem darin, dass das Softmax-Array garantiert drei Werte enthält, die sich zu 1 summieren, während die Sigmoid-Ausgabe drei Werte enthält, die jeweils zwischen 0 und 1 liegen.

Aktivierung per Sigmoid oder Softmax

Die Sigmoid-Funktion ist eine nichtlineare, stetige und differenzierbare Aktivierungsfunktion, die die Ausgaben jedes Neurons in der vorherigen Schicht im ML-Modell übernimmt und den Wert dieser Ausgaben in einen Bereich zwischen 0 und 1 presst. Abbildung 3-7 zeigt, wie die Sigmoid-Funktion aussieht.

Während die Sigmoid-Funktion einen einzelnen Wert als Eingabe übernimmt und einen einzelnen Wert als Ausgabe liefert, übernimmt Softmax ein Array von Werten als Eingabe und transformiert ihn in ein Array von Wahrscheinlichkeiten, die sich zu 1 summieren. Die Eingabe der Softmax-Funktion könnte die Ausgabe von N Sigmoids sein.

image

Abbildung 3-7: Eine Sigmoid-Funktion

In einem Multiklassenklassifizierungsproblem, bei dem jedes Beispiel nur ein Label haben kann, verwenden Sie Softmax als letzte Schicht, um eine Wahrscheinlichkeitsverteilung zu erhalten. Im Entwurfsmuster Multilabel ist es akzeptabel, dass sich das Ausgabearray nicht zu 1 summiert, da wir die Wahrscheinlichkeit jedes einzelnen Labels auswerten.

Die folgenden Arrays sind Beispiele für Sigmoid- und Softmax-Ausgabearrays:

sigmoid = [.8, .9, .2, .5]

softmax = [.7, .1, .15, .05]

Kompromisse und Alternativen

Es sind mehrere Spezialfälle zu berücksichtigen, wenn Sie dem Entwurfsmuster Multilabel folgen und eine Sigmoid-Ausgabe verwenden. Als Nächstes untersuchen wir, wie Modelle zu strukturieren sind, die zwei mögliche Label-Klassen umfassen, wie Sigmoid-Ergebnisse interpretiert werden können und andere wichtige Betrachtungen für Multilabel-Modelle.

Sigmoid-Ausgabe für Modelle mit zwei Klassen

Es gibt zwei Arten von Modellen, bei denen die Ausgabe zu zwei möglichen Klassen gehört:

Abbildung 3-8 zeigt den Unterschied zwischen diesen Klassifizierungen.

image

Abbildung 3-8: Den Unterschied zwischen Multiklassen-, Multilabel- und binären Klassifizierungsproblemen verstehen

Der erste Fall (binäre Klassifizierung) ist insofern einzigartig, als es die einzige Art von Ein-Label-Klassifizierungsproblem ist, bei dem wir die Sigmoid-Funktion als Aktivierungsfunktion in Betracht ziehen würden. Für fast alle anderen Multiklassenklassifizierungsprobleme (zum Beispiel die Klassifizierung von Text in eine von fünf möglichen Kategorien) würden wir Softmax verwenden. Haben wir jedoch nur zwei Klassen, ist Softmax überflüssig. Nehmen wir zum Beispiel ein Modell, das vorhersagt, ob eine bestimmte Transaktion betrügerisch ist oder nicht. Hätten wir in diesem Beispiel eine Softmax-Ausgabe verwendet, würde eine betrügerische Modellvorhersage folgendermaßen aussehen:

[.02, .98]

In diesem Beispiel entspricht der erste Index »nicht betrügerisch«, und der zweite Index steht für »betrügerisch«. Dies ist redundant, da wir dies ebenso mit einem einzelnen Skalarwert darstellen und somit eine Sigmoid-Ausgabe verwenden könnten. Die gleiche Vorhersage ließe sich einfach als .98 darstellen. Da jeder Eingabe nur eine einzelne Klasse zugewiesen werden kann, können wir von dieser Ausgabe mit .98 ableiten, dass das Modell eine 98%ige Chance für einen Betrug und eine 2%ige Chance für eine ordnungsgemäße Transaktion vorhergesagt hat.

Für binäre Klassifizierungsmodelle ist es demzufolge optimal, eine Ausgabe der Gestalt 1 mit einer Sigmoid-Aktivierungsfunktion zu verwenden. Modelle mit einem einzelnen Ausgabeknoten sind ebenfalls effizienter, da sie weniger trainierbare Parameter haben und wahrscheinlich schneller trainiert werden können. Die Ausgabeschicht eines binären Klassifizierungsmodells würde so aussehen:

keras.layers.Dense(1, activation='sigmoid')

Für den zweiten Fall, in dem ein Trainingsbeispiel zu beiden möglichen Klassen gehören könnte und in das Entwurfsmuster Multilabel passt, werden wir ebenfalls Sigmoid verwenden, dieses Mal mit einer Ausgabe, die zwei Elemente umfasst:

keras.layers.Dense(2, activation='sigmoid')

Welche Verlustfunktion sollten wir verwenden?

Da wir nun wissen, wann wir die Sigmoid-Aktivierungsfunktion in unserem Modell verwenden sollten, stellt sich die Frage, wie wir die dazugehörende Verlustfunktion auswählen. Für den Fall der binären Klassifizierung, in dem unser Modell eine Ausgabe mit einem Element hat, verwenden wir den binären Kreuzentropieverlust. In Keras stellen wir eine Verlustfunktion bereit, wenn wir unser Modell kompilieren:

model.compile(loss='binary_crossentropy', optimizer='adam',

metrics=['accuracy'])

Interessanterweise verwenden wir die binäre Kreuzentropieverlustfunktion auch für Multilabel-Modelle mit Sigmoid-Ausgabe. Wie Abbildung 3-9 zeigt, hängt das damit zusammen, dass ein Multilabel-Problem mit drei Klassen praktisch aus drei kleineren binären Klassifizierungsproblemen besteht.

image

Abbildung 3-9: Um das Multilabel-Muster zu verstehen, kann man das Problem in drei kleinere binäre Klassifizierungsaufgaben zerlegen.

Sigmoid-Ergebnisse parsen

Um das vorhergesagte Label für ein Modell mit Softmax-Ausgabe zu extrahieren, können wir einfach den Wert von argmax (höchster Wertindex) des Ausgabearrays nehmen, um die vorhergesagte Klasse zu erhalten. Das Parsing von Sigmoid-Ausgaben ist nicht ganz so einfach. Anstatt die Klasse mit der höchsten vorhergesagten Wahrscheinlichkeit zu nehmen, müssen wir die Wahrscheinlichkeit jeder Klasse in unserer Ausgabeschicht bewerten und den Wahrscheinlichkeitsschwellenwert für unseren Anwendungsfall berücksichtigen. Beide Entscheidungen sind weitgehend von der Endbenutzeranwendung unseres Modells abhängig.

image

Mit Schwellenwert ist die Wahrscheinlichkeit gemeint, mit der wir eine Eingabe mit großer Sicherheit einer bestimmten Klasse zuordnen können. Bei einem Modell, das verschiedene Arten von Tieren auf Bildern klassifizieren soll, könnten wir durchaus zufrieden sein, zu sagen, dass ein Bild eine Katze zeigt, selbst wenn das Modell nur eine 80%ige Sicherheit aufweist, dass das Bild eine Katze enthält. Wenn wir hingegen ein Modell erstellen, das Vorhersagen im Gesundheitswesen trifft, werden wir sicherlich verlangen, dass es mit einer näher an 99 % liegenden Sicherheit bestätigt, ob ein bestimmter medizinischer Zustand vorliegt oder nicht. Obwohl wir Schwellenwerte für jede Art von Klassifizierungsmodell berücksichtigen müssen, sind sie besonders für das Entwurfsmuster Multilabel relevant, da wir Schwellenwerte für jede Klasse bestimmen müssen und diese unterschiedlich sein können.

Als konkretes Beispiel nehmen wir den Stack-Overflow-Datensatz in BigQuery. Das Modell dafür soll für einen gegebenen Titel die Tags vorhersagen, die einer Stack-Overflow-Frage zugeordnet sind. Der Einfachheit halber beschränken wir unseren Datensatz auf Fragen, die nur fünf Tags enthalten:

SELECT

title,

REPLACE(tags, "|", ",") as tags

FROM

`bigquery-public-data.stackoverflow.posts_questions`

WHERE

REGEXP_CONTAINS(tags,

r"(?:keras|tensorflow|matplotlib|pandas|scikit-learn)")

Die Ausgabeschicht unseres Modells sieht folgendermaßen aus (der vollständige Code für diesen Abschnitt ist im GitHub-Repository unter https://github.com/GoogleCloudPlatform/ml-design-patterns/blob/master/03_problem_representation/multilabel.ipynb verfügbar):

keras.layers.Dense(5, activation='sigmoid')

Als Eingabebeispiel nehmen wir die Stack-Overflow-Frage: »What is the definition of a non-trainable parameter?« (Wie lautet die Definition eines nicht trainierbaren Parameters?) Unter der Annahme, dass unsere Ausgabeindizes mit der Reihenfolge der Tags in unserer Frage übereinstimmen, könnte eine Ausgabe für diese Frage wie folgt aussehen:

[.95, .83, .02, .08, .65]

Unser Modell ist zu 95 % zuversichtlich, dass diese Frage mit keras getaggt werden sollte, und zu 83 %, dass ihr das Tag tensorflow zuzuordnen ist. Wenn wir Modellvorhersagen auswerten, müssen wir jedes Element im Ausgabearray durchlaufen und festlegen, wie wir diese Ergebnisse für die Endbenutzer anzeigen wollen. Bei einem Schwellenwert von 80 % für alle Tags würden wir Keras und TensorFlow zusammen mit dieser Frage anzeigen. Vielleicht möchten wir alternativ die Benutzer ermutigen, möglichst viele Tags hinzuzufügen, und Optionen für jedes Tag mit einer Vorhersagesicherheit über 50 % anzeigen.

Für derartige Beispiele, bei denen das Ziel vor allem darin besteht, mögliche Tags vorzuschlagen, und weniger Wert darauf gelegt wird, das Tag genau richtig zu erhalten, lautet eine typische Faustregel, n_specific_tag / n_total_examples als Schwellenwert für jede Klasse zu verwenden. Dabei ist n_specific_tag die Anzahl der Beispiele mit einem Tag im Datensatz (zum Beispiel pandas), und n_total_examples gibt die Gesamtzahl der Beispiele im Trainingsset über alle Beispiele an. Damit wird sichergestellt, dass das Modell besser abschneidet, als ein bestimmtes Label aufgrund seines Vorkommens im Trainingsdatensatz zu erraten.

image

Für eine präzisere Herangehensweise an die Schwellenwertfestlegung sollten Sie S-Cut in Betracht ziehen oder Ihr Modell nach dem F-Maß optimieren. Details zu beidem finden Sie im Paper unter https://oreil.ly/oyR57. Oftmals ist es auch hilfreich, die Wahrscheinlichkeiten pro Label zu kalibrieren, insbesondere wenn es Tausende von Labels gibt und Sie die K besten von ihnen betrachten möchten (wie es bei Such- und Rangfolgeproblemen üblich ist).

Wie Sie gesehen haben, sind Multilabel-Modelle flexibler in Bezug darauf, wie wir Vorhersagen parsen. Zudem sind wir gefordert, genau über die Ausgabe für jede Klasse nachzudenken.

Überlegungen zu Datensätzen

Bei Klassifizierungsaufgaben mit einzelnen Labels können wir sicherstellen, dass unser Datensatz ausgewogen ist, indem wir eine relativ gleiche Anzahl von Trainingsbeispielen für jede Klasse anstreben. Beim Entwurfsmuster Multilabel ist es nuancierter, einen ausgewogenen Datensatz zu erstellen.

Im Beispiel mit dem Stack-Overflow-Datensatz gibt es wahrscheinlich viele Fragen, die sowohl mit tensorflow als auch mit keras getaggt sind. Aber es gibt sicherlich auch Fragen zu Keras, die nichts mit TensorFlow zu tun haben. Analog dazu könnten Fragen auftauchen über das Plotten von Daten, die sowohl mit matplotlib als auch mit pandas getaggt sind, und Fragen zur Datenvorverarbeitung, die sowohl mit pandas als auch mit scikit-learn ausgezeichnet sind. Damit unser Modell lernen kann, was für jedes Tag einzigartig ist, müssen wir sicherstellen, dass der Trainingsdatensatz aus verschiedenen Kombinationen der einzelnen Tags besteht. Wenn die Mehrheit der matplotlib-Fragen in unserem Datensatz auch mit dem Tag pandas versehen ist, wird das Modell nicht lernen, matplotlib als eigenständigen Begriff zu klassifizieren. Um dies zu berücksichtigen, sollten Sie sich die verschiedenen Beziehungen zwischen den Labels klarmachen, die im Modell vorhanden sein können, und die Anzahl der Trainingsbeispiele zählen, die zu jeder sich überlappenden Kombination von Labels gehören.

Wenn wir die Beziehung zwischen Labels in unserem Datensatz untersuchen, können wir auch auf hierarchische Labels stoßen. So enthält der beliebte Datensatz ImageNet (https://oreil.ly/0VXtc) zur Bildklassifizierung Tausende von gelabelten Bildern. Er wird oft als Ausgangspunkt für das Transfer Learning auf Bildmodelle angewendet. Alle in ImageNet verwendeten Labels sind hierarchisch, d. h., alle Bilder haben mindestens ein Label, und viele Bilder haben spezifischere Labels, die Teil einer Hierarchie sind. Eine Label-Hierarchie in ImageNet sieht zum Beispiel so aus:

animalinvertebratearthropodarachnidspider

Je nach Größe und Art des Datensatzes gibt es zwei gängige Ansätze für den Umgang mit hierarchischen Labels:

Der flache Ansatz ist unkomplizierter, als dem Entwurfsmuster Kaskade zu folgen, da er nur ein Modell erfordert. Allerdings kann das dazu führen, dass Informationen über detailliertere Label-Klassen verloren gehen, da es naturgemäß in unserem Datensatz mehr Trainingsbeispiele mit den Labels auf höherer Ebene geben wird.

Eingaben mit sich überlappenden Labels

Das Entwurfsmuster Multilabel ist ebenfalls nützlich, wenn sich gelegentlich die Labels bei Eingabedaten überlappen. Nehmen wir als Beispiel ein Bildmodell, das Kleidungsstücke für einen Katalog klassifizieren soll. Wenn mehrere Personen jedes Bild im Trainingsdatensatz labeln, kann der eine Label-Ersteller ein Bild eines Rocks (engl. Skirt) als »Maxi skirt« labeln, während ein anderer ihn als »Pleated skirt« (Faltenrock) identifiziert. Beide sind korrekt. Wenn wir aber ein Multiklassenklassifizierungsmodell auf diesen Daten erstellen und ihm mehrere Beispiele desselben Bilds mit unterschiedlichen Labels übergeben, werden wir wahrscheinlich auf Situationen stoßen, in denen das Modell bei Vorhersagen ähnliche Bilder mit unterschiedlichen Labels versieht. Im Idealfall möchten wir ein Modell, das dieses Bild sowohl mit »Maxi skirt« als auch mit »Pleated skirt« labelt, wie Abbildung 3-10 zeigt, anstatt manchmal nur eines dieser Labels vorherzusagen.

Hier kommt uns das Entwurfsmuster Multilabel zu Hilfe, indem es uns erlaubt, einem Bild beide sich überlappenden Labels zuzuordnen. In Fällen mit sich überlappenden Labels, in denen wir mehrere Label-Ersteller haben, die jedes Bild in unserem Trainingsdatensatz bewerten, können wir die maximale Anzahl von Labels wählen, die die Label-Ersteller einem bestimmten Bild zuweisen sollen. Dann nehmen wir die am häufigsten gewählten Tags, um sie während des Trainings mit einem Bild zu verknüpfen.

image

Abbildung 3-10: Die Eingaben von mehreren Label-Erstellern verwenden, um sich überlappende Labels zu erzeugen, wenn mehrere Beschreibungen eines Artikels korrekt sind

Der Schwellenwert für »die am häufigsten gewählten Tags« hängt von unserer Vorhersageaufgabe und der Anzahl der vorhandenen menschlichen Label-Ersteller ab. Wenn zum Beispiel 5 Label-Ersteller jedes Bild bewerten und es für jedes Bild 20 mögliche Tags gibt, sollten wir die Label-Ersteller dazu anhalten, jedem Bild 3 Tags zuzuordnen. Aus dieser Liste von 15 Label-»Stimmen« pro Bild könnten wir dann 2 bis 3 mit den meisten Stimmen von den Label-Erstellern auswählen. Bei der Auswertung dieses Modells müssen wir die durchschnittliche Vorhersagekonfidenz berücksichtigen, die das Modell für jedes Label zurückgibt, und diese verwenden, um unseren Datensatz und die Label-Qualität iterativ zu verbessern.

Einer gegen alle

Mit der Multilabel-Klassifizierung kann man auch eine andere Technik anwenden, die mehrere binäre Klassifizierer statt eines Multilabel-Modells trainiert. Dieser Ansatz wird einer gegen alle genannt. Im Stack-Overflow-Beispiel, in dem wir Fragen mit den Tags tensorflow, python und pandas versehen wollen, würden wir einen individuellen Klassifizierer für jedes dieser drei Tags trainieren: Python oder nicht, TensorFlow oder nicht usw. Dann würden wir einen Konfidenzschwellenwert wählen und die ursprüngliche Eingangsfrage mit Tags von jedem binären Klassifizierer über einem bestimmten Schwellenwert versehen.

Das Verfahren einer gegen alle hat den Vorteil, dass wir es mit Modellarchitekturen verwenden können, die nur für eine binäre Klassifizierung konzipiert sind, wie etwa SVMs. Es kann auch bei seltenen Kategorien helfen, da das Modell nur eine einzige Klassifizierungsaufgabe auf einmal für jede Eingabe durchführen muss und es möglich ist, das Entwurfsmuster Rebalancing anzuwenden. Der Nachteil dieses Ansatzes ist die zusätzliche Komplexität, die durch das Training vieler verschiedener Klassifizierer entsteht. Wir müssen unsere Anwendung so aufbauen, dass sie Vorhersagen von jedem dieser Modelle generiert, anstatt nur mit einem Modell auszukommen.

Alles in allem sollten Sie das Entwurfsmuster Multilabel verwenden, wenn Ihre Daten unter eines der folgenden Klassifizierungsszenarios fallen:

Wenn Sie ein Multilabel-Modell implementieren, stellen Sie sicher, dass Kombinationen aus sich überlappenden Labels ausreichend gut im Datensatz repräsentiert sind, und überlegen Sie sich die Schwellenwerte, die Sie für jedes mögliche Label in Ihrem Modell akzeptieren wollen. Eine Ausgabeschicht mit Sigmoid-Aktivierungsfunktion ist der gängigste Ansatz, um Modelle zu erstellen, die Multilabel-Klassifizierung beherrschen. Darüber hinaus kann die Sigmoid-Ausgabe auch auf binäre Klassifizierungsaufgaben angewendet werden, bei denen ein Trainingsbeispiel nur eines von zwei möglichen Labels haben kann.

Entwurfsmuster 7: Ensemble

Das Entwurfsmuster Ensemble bezieht sich auf Techniken des maschinellen Lernens, die mehrere ML-Modelle kombinieren und ihre Ergebnisse für Vorhersagen zusammenfassen. Ensembles können wirksame Instrumente sein, um die Performance zu verbessern und Vorhersagen zu treffen, die besser als jedes einzelne Modell sind.

Problem

Angenommen, wir hätten unser Vorhersagemodell für Babygewichte trainiert, indem wir ein spezielles Feature Engineering durchgeführt und zusätzliche Schichten in unser neuronales Netz eingefügt haben, sodass der Fehler mit unserem Trainingsdatensatz nahezu null ist. »Ausgezeichnet!«, werden Sie sagen. Wenn wir jedoch unser Modell in der Produktion im Krankenhaus einsetzen oder die Performance auf dem reservierten Testset bewerten wollen, sind unsere Vorhersagen alle falsch. Was ist passiert? Und vor allem, wie können wir es korrigieren?

Kein ML-Modell ist perfekt. Um besser zu verstehen, wo und wie unser Modell falsch ist, kann man den Fehler eines ML-Modells in drei Teile gliedern: den nicht reduzierbaren Fehler, den Fehler aufgrund von Bias und den Fehler infolge von Varianz. Der nicht reduzierbare Fehler ist der Fehler, der dem Modell inhärent ist und sich aus dem Rauschen im Datensatz, der Problemformulierung oder aus schlechten Trainingsbeispielen wie Messfehlern oder Störfaktoren ergibt. Wie der Name schon sagt, können wir kaum etwas gegen nicht reduzierbare Fehler ausrichten.

Die beiden anderen Fehler, der Bias und die Varianz, gehören zu den reduzierbaren Fehlern. Hier können wir die Performance unseres Modells beeinflussen. Kurz gesagt, ist der Bias die Unfähigkeit des Modells, genügend über die Beziehung zwischen den Features und den Labels des Modells zu lernen, während die Varianz die Unfähigkeit des Modells erfasst, auf neue, noch nicht gesehene Beispiele zu verallgemeinern. Ein Modell mit hohem Bias vereinfacht die Beziehung zu stark und wird als unterangepasst (engl. underfit) bezeichnet. Bei zu hoher Varianz hat das Modell zu viel über die Trainingsdaten gelernt und ist überangepasst (engl. overfit). Natürlich strebt man bei jedem ML-Modell einen niedrigen Bias und eine niedrige Varianz an, doch ist es in der Praxis schwer, beide Ziele zu erreichen. Man spricht auch vom Bias-Varianz-Kompromiss. Wir können eben nicht alles auf einmal haben. Zum Beispiel verringert eine steigende Modellkomplexität den Bias, erhöht aber die Varianz, während eine geringere Modellkomplexität die Varianz senkt, aber mehr Bias mit sich bringt.

Neuere Arbeiten (https://oreil.ly/PxUvs) deuten darauf hin, dass dieses Verhalten bei modernen Techniken des maschinellen Lernens, zum Beispiel bei großen neuronalen Netzen mit hoher Kapazität, nur bis zu einem gewissen Punkt gültig ist. In Experimenten hat man beobachtet, dass es einen »Interpolationsschwellenwert« gibt, über dem Modelle mit sehr hoher Kapazität in der Lage sind, sowohl einen Trainingsfehler von null als auch einen geringen Fehler bei nicht gesehenen Daten zu erreichen. Natürlich brauchen wir wesentlich größere Datensätze, um Overfitting bei Modellen mit hoher Kapazität zu vermeiden.

Gibt es eine Möglichkeit, um diesen Bias-Varianz-Kompromiss bei kleineren und mittelgroßen Problemen abzuschwächen?

Lösung

Ensemble-Methoden sind Metaalgorithmen, die mehrere ML-Modelle als Technik kombinieren, um den Bias und/oder die Varianz zu verringern und die Modellperformance zu verbessern. Prinzipiell hilft die Kombination mehrerer Modelle, die Ergebnisse des maschinellen Lernens zu verbessern. Indem wir mehrere Modelle mit unterschiedlichen Bias-Werten erzeugen und ihre Ausgaben zusammenfassen, hoffen wir, ein Modell mit besserer Performance zu bekommen. Dieser Abschnitt erläutert einige häufig verwendete Ensemble-Methoden, einschließlich Bagging, Boosting und Stacking.

Bagging

Bagging (von Bootstrap aggregating) ist eine Art parallele Ensemble-Methode und wird verwendet, um hoher Varianz in ML-Modellen zu begegnen. Der Bootstrap-Teil des Baggings bezieht sich auf die Datensätze, mit denen die Ensemble-Mitglieder trainiert werden. Wenn es k Teilmodelle gibt, werden k separate Datensätze für das Training jedes Teilmodells des Ensembles verwendet. Jeder Datensatz wird durch Zufallsstichproben (mit Ersetzung) aus dem ursprünglichen Trainingsdatensatz gebildet. Es gibt also eine hohe Wahrscheinlichkeit, dass in jedem der k Datensätze einige Trainingsbeispiele fehlen, doch wahrscheinlich wird auch jeder Datensatz sich wiederholende Trainingsbeispiele enthalten. Die Ausgaben der verschiedenen Ensemble-Modellmitglieder werden dann aggregiert – entweder gemittelt, wie bei einer Regressionsaufgabe, oder durch Mehrheitsabstimmung im Fall der Klassifizierung.

Ein gutes Beispiel für eine Bagging-Ensemble-Methode ist der Random Forest: Mehrere Entscheidungsbäume werden auf zufällig erhobenen Teilmengen der gesamten Trainingsdaten trainiert, und dann werden die Baumvorhersagen aggregiert, um eine Vorhersage zu erzeugen, wie Abbildung 3-11 zeigt.

image

Abbildung 3-11: Bagging eignet sich gut, um die Varianz in der Ausgabe von ML-Modellen zu verringern.

Bekannte Bibliotheken für maschinelles Lernen verfügen über Implementierungen von Bagging-Methoden. Zum Beispiel implementiert der folgende Code eine Random-Forest-Regression in scikit-learn, um das Babygewicht aus unserem Geburtendatensatz vorherzusagen:

from sklearn.ensemble import RandomForestRegressor

# Das Modell mit 50 Bäumen erzeugen.

RF_model = RandomForestRegressor(n_estimators=50,

max_features='sqrt',

n_jobs=-1, verbose = 1)

# An Trainingsdaten anpassen.

RF_model.fit(X_train, Y_train)

Die Modellmittelung wie beim Bagging ist eine leistungsfähige und zuverlässige Methode, um die Modellvarianz zu verringern. Wie Sie noch sehen werden, kombinieren verschiedene Ensemble-Methoden mehrere Teilmodelle auf unterschiedliche Arten, manchmal mit unterschiedlichen Modellen, unterschiedlichen Algorithmen oder sogar unterschiedlichen Zielfunktionen. Beim Bagging sind Modell und Algorithmen gleich. Zum Beispiel sind beim Random Forest alle Teilmodelle kurze Entscheidungsbäume.

Boosting

Eine andere Ensemble-Technik ist Boosting. Im Gegensatz zum Bagging konstruiert Boosting jedoch letztlich ein Ensemble-Modell mit mehr Kapazität als die einzelnen Mitgliedsmodelle. Deshalb ist Boosting ein effektiveres Instrument, um den Bias zu verringern, als die Varianz zu verringern. Boosting liegt die Idee zugrunde, iterativ ein Ensemble von Modellen zu erstellen, wobei sich jedes Folgemodell darauf konzentriert, die Beispiele zu lernen, die das vorherige Modell falsch erkannt hat. Kurz gesagt, verbessert Boosting iterativ eine Sequenz von schwachen Klassifikatoren, indem es einen gewichteten Mittelwert nimmt, um letztlich einen starken Klassifikator zu liefern.

Zu Beginn des Boosting-Verfahrens wird ein einfaches Basismodell f_0 ausgewählt. Bei einer Regressionsaufgabe könnte das Basismodell einfach der durchschnittliche Zielwert sein: f_0 = np.mean(Y_train). Für den ersten Iterationsschritt werden die Residuen delta_1 gemessen und über ein separates Modell approximiert. Das Residuenmodell kann beliebig gestaltet sein, in der Regel ist es nicht sehr anspruchsvoll. Oftmals kommt ein schwacher Klassifikator wie zum Beispiel ein Entscheidungsbaum infrage. Die vom Residuenmodell gelieferte Approximation wird dann der aktuellen Vorhersage hinzugefügt, und der Vorgang setzt sich fort.

Nach vielen Iterationen laufen die Residuen gegen null, und die Vorhersage wird immer besser in der Modellierung des ursprünglichen Trainingsdatensatzes. Beachten Sie, dass in Abbildung 3-12 die Residuen für jedes Element des Datensatzes mit jeder weiteren Iteration abnehmen.

image

Abbildung 3-12: Boosting konvertiert schwache Klassifikatoren zu starken Klassifikatoren, indem es die Modellvorhersage iterativ verbessert.

Zu den bekannteren Boosting-Algorithmen gehören AdaBoost, Gradient Boosting Machines und XGBoost. Diese sind auch in bekannten ML-Frameworks wie scikit-learn oder TensorFlow implementiert.

Die Implementierung in scikit-learn ist ebenfalls recht einfach:

from sklearn.ensemble import GradientBoostingRegressor

# Den Gradient-Boosting-Regressor erzeugen.

GB_model = GradientBoostingRegressor(n_estimators=1,

max_depth=1,

learning_rate=1,

criterion='mse')

# An Trainingsdaten anpassen.

GB_model.fit(X_train, Y_train)

Stacking

Stacking ist eine Ensemble-Methode, die die Ausgaben einer Sammlung von Modellen für eine Vorhersage kombiniert. Die anfänglichen Modelle, bei denen es sich in der Regel um verschiedene Modelltypen handelt, werden bis zur Fertigstellung auf dem gesamten Trainingsdatensatz trainiert. Dann wird ein sekundäres Metamodell trainiert, das die Ausgaben des anfänglichen Modells als Features verwendet. Dieses zweite Metamodell lernt, wie die Ausgaben des anfänglichen Modells am besten zu kombinieren sind, um den Trainingsfehler zu verringern. Es kann ein beliebiges Modell für maschinelles Lernen sein.

Um ein Stacking-Ensemble zu implementieren, trainieren wir zuerst alle Mitglieder des Ensembles auf dem Trainingsdatensatz. Der folgende Code ruft die Funktion fit_model auf, die als Argumente ein Modell und die Trainingsdatensatzeingaben X_train und das Label Y_train übernimmt. Somit ist members eine Liste, die alle trainierten Modelle in unserem Ensemble enthält (den vollständigen Code für dieses Beispiel finden Sie im Code-Repository für dieses Buch unter https://github.com/GoogleCloudPlatform/ml-design-patterns/blob/master/03_problem_representation/ensemble_methods.ipynb):

members = [model_1, model_2, model_3]

# Modelle anpassen und speichern.

n_members = len(members)

for i in range(n_members):

# Modell anpassen.

model = fit_model(members[i])

# Modell speichern.

filename = 'models/model_' + str(i + 1) + '.h5'

model.save(filename, save_format='tf')

print('Saved {}\n'.format(filename))

Diese Teilmodelle werden als individuelle Eingaben in ein größeres Stacking-Ensemble-Modell eingebunden. Da diese Eingabemodelle zusammen mit dem sekundären Ensemble-Modell trainiert werden, fixieren wir die Gewichte dieser Eingabemodelle. Hierzu setzen wir für die Ensemble-Mitgliedermodelle layer.trainable auf False:

for i in range(n_members):

model = members[i]

for layer in model.layers:

# Nicht trainierbar machen.

layer.trainable = False

# Umbenennen, um das Problem 'einzigartiger Schichtenname' zu vermeiden.

layer._name = 'ensemble_' + str(i+1) + '_' + layer.name

Um das Ensemble-Modell zu erstellen, fügen wir die Komponenten mithilfe der funktionalen API von Keras zusammen:

member_inputs = [model.input for model in members]

# Ausgabe von jedem Modell zusammenführen und verketten.

member_outputs = [model.output for model in members]

merge = layers.concatenate(member_outputs)

hidden = layers.Dense(10, activation='relu')(merge)

ensemble_output = layers.Dense(1, activation='relu')(hidden)

ensemble_model = Model(inputs=member_inputs, outputs=ensemble_output)

# Graphen des Ensembles plotten.

tf.keras.utils.plot_model(ensemble_model, show_shapes=True,

to_file='ensemble_graph.png')

# Kompilieren.

ensemble_model.compile(loss='mse', optimizer='adam', metrics=['mse'])

In diesem Beispiel ist das sekundäre Modell ein dichtes neuronales Netz mit zwei verdeckten Schichten. Durch das Training lernt dieses Netz, wie sich die Ergebnisse der Ensemble-Mitglieder am besten zu Vorhersagen kombinieren lassen.

Warum es funktioniert

Modellmittelungsmethoden wie Bagging funktionieren, weil die einzelnen Modelle, die das Ensemble-Modell umfasst, in der Regel nicht alle die gleichen Fehler auf dem Testset machen. In einer idealen Situation liegt jedes einzelne Modell um einen zufälligen Betrag daneben. Wenn also die Ergebnisse der Modelle gemittelt werden, heben sich die zufälligen Fehler auf, und die Vorhersage kommt der richtigen Antwort näher. Kurz gesagt – es ist die »Weisheit der Vielen«.

Boosting funktioniert gut, weil das Modell bei jedem Iterationsschritt mehr und mehr entsprechend den Residuen bestraft wird. Mit jeder Iteration wird das Ensemble-Modell dazu angehalten, diese schwer vorherzusagenden Beispiele immer besser vorherzusagen. Stacking funktioniert, weil es das Beste von Bagging und Boosting kombiniert. Das sekundäre Modell kann man sich als anspruchsvollere Version der Modellmittelung vorstellen.

Bagging

Genauer gesagt nehmen wir an, dass wir k neuronale Netze als Regressionsmodelle trainiert haben und ihre Ergebnisse mitteln, um ein Ensemble-Modell zu erstellen. Wenn jedes Modell für jedes Beispiel einen Fehler error_i liefert, wobei error_i aus einer multivariaten Normalverteilung mit dem Mittelwert null, der Varianz var und der Kovarianz cov gezogen wird, ergibt sich für den Ensemble-Prädiktor folgender Fehler:

ensemble_error = 1./k * np.sum([error_1, error_2,...,error_k])

Wenn die Fehler error_i perfekt korreliert sind, sodass cov = var ist, verringert sich der mittlere quadratische Fehler des Ensemble-Modells auf var. In diesem Fall hilft Modellmittelung überhaupt nicht. Sind die Fehler error_i im anderen Extremfall perfekt unkorreliert, dann ist cov = 0, und der mittlere quadratische Fehler des Ensemble-Modells ist var/k. Der erwartete quadratische Fehler nimmt also linear mit der Anzahl k von Modellen im Ensemble ab.1 Zusammenfassend lässt sich sagen, dass das Ensemble im Durchschnitt mindestens so gut abschneidet wie jedes der einzelnen Modelle im Ensemble. Und wenn die Modelle im Ensemble unabhängige Fehler machen (zum Beispiel cov = 0), ist die Performance des Ensembles deutlich besser. Letztlich ist die Modellvielfalt der Schlüssel zum Erfolg beim Bagging.

Das erklärt auch, warum Bagging bei stabileren Klassifikatoren wie k-nächste-Nachbarn (kNN), naivem Bayes, linearen Modellen oder Support Vector Machines (SVMs) typischerweise weniger effektiv ist, da die Größe des Trainingssets durch Bootstrapping verringert wird. Selbst bei Verwendung derselben Trainingsdaten können neuronale Netze aufgrund von zufälligen Gewichtsinitialisierungen, zufälliger Mini-Batch-Auswahl oder unterschiedlichen Hyperparametern zu unterschiedlichen Lösungen kommen, wodurch Modelle entstehen, deren Fehler partiell unabhängig sind. Daher kann die Modellmittelung sogar für neuronale Netze vorteilhaft sein, die auf demselben Datensatz trainiert werden. Tatsächlich wird unter anderem empfohlen, mehrere Modelle zu trainieren und deren Vorhersagen zu aggregieren, um die hohe Varianz von neuronalen Netzen zu kompensieren.

Boosting

Der Boosting-Algorithmus verbessert iterativ das Modell, um den Vorhersagefehler zu verringern. Jeder neue schwache Klassifikator korrigiert Fehler der vorherigen Vorhersage, indem er die Residuen delta_i jedes Schritts modelliert. Die endgültige Vorhersage ist die Summe der Ausgaben aus dem Basisklassifikator und jedem der nachfolgenden schwachen Klassifikatoren, wie Abbildung 3-13 zeigt.

image

Abbildung 3-13: Boosting erstellt iterativ eine starken Klassifikator aus einer Sequenz von schwachen Klassifikatoren, die den Restfehler der vorherigen Iteration modellieren.

Somit wird das resultierende Ensemble-Modell sukzessive immer komplexer und erhält mehr Kapazität als jedes seiner Mitglieder. Dies erklärt auch, warum Boosting besonders gut geeignet ist, um einen hohen Bias zu bekämpfen. Wie bereits erläutert, hängt der Bias mit der Tendenz des Modells zur Unteranpassung zusammen. Indem die schwer vorherzusagenden Beispiele iterativ in den Mittelpunkt gerückt werden, senkt Boosting wirksam den Bias des resultierenden Modells.

Stacking

Stacking kann man als Erweiterung einer einfachen Modellmittelung betrachten, bei der wir k Modelle bis zur Fertigstellung auf dem Trainingsdatensatz trainieren und dann die Ergebnisse mitteln, um eine Vorhersage zu bestimmen. Eine einfache Modellmittelung ähnelt dem Bagging, wobei aber die Modelle im Ensemble von verschiedenen Typen sein können, während sie beim Bagging vom gleichen Typ sind. Allgemein könnten wir die Mittelwertbildung dahin gehend modifizieren, dass wir mit einem gewichteten Mittelwert zum Beispiel einem Modell in unserem Ensemble mehr Gewicht geben als den anderen, wie Abbildung 3-14 zeigt.

image

Abbildung 3-14: Die einfachste Form der Modellmittelung bildet aus den Ausgaben von zwei oder mehr verschiedenen ML-Modellen einen Mittelwert. Alternativ könnte man den Mittelwert durch einen gewichteten Mittelwert ersetzen, wobei die Gewichtung abhängig von der relativen Genauigkeit der Modelle erfolgen könnte.

Im Prinzip ist Stacking eine erweiterte Version der Modellmittelung, bei der wir anstelle eines Mittelwerts oder gewichteten Mittelwerts ein zweites ML-Modell auf den Ausgaben trainieren. Dieses zweite Modell soll lernen, wie sich die Ergebnisse der Modelle in unserem Ensemble am besten zu einer Vorhersage kombinieren lassen (siehe Abbildung 3-15). Diese Technik vereint mehrere Vorteile. Einerseits verringert sie die Varianz wie bei Bagging-Techniken, geht andererseits aber auch gegen einen hohen Bias an.

image

Abbildung 3-15: Stacking ist eine Ensemble-Lerntechnik, die die Ausgaben mehrerer verschiedener ML-Modelle als Eingabe eines sekundären ML-Modells kombiniert, das dann die Vorhersagen trifft.

Kompromisse und Alternativen

Ensemble-Methoden sind im modernen maschinellen Lernen recht populär geworden und haben eine große Rolle gespielt beim Gewinnen bekannter Herausforderungen, wobei hier vor allem der Netflix Prize (https://oreil.ly/ybZ28) zu nennen ist. Zudem gibt es eine Menge theoretischer Beweise, die den Erfolg bei diesen realen Herausforderungen untermauern.

Erhöhte Trainings- und Entwurfszeit

Ein Nachteil beim Ensemble-Lernen ist der erhöhte Zeitaufwand für Training und Entwurf. Zum Beispiel erfordert die Auswahl der Mitgliedermodelle bei einem gestapelten Ensemble-Modell wahrscheinlich ein gewisses Maß an Know-how und wirft zudem seine eigenen Fragen auf: Ist es besser, die gleichen Architekturen wiederzuverwenden oder die Vielfalt zu fördern? Wenn wir verschiedene Architekturen verwenden, welche sollten es dann sein? Und wie viele? Anstatt ein einzelnes ML-Modell zu entwickeln (was schon für sich eine Menge Arbeit bedeuten kann!), entwickeln wir nun k Modelle. Wir haben zusätzlich viel Overhead in unsere Modellentwicklung eingeführt, ganz zu schweigen von der Wartung, der Inferenzkomplexität und der Ressourcennutzung, wenn das Ensemble-Modell in Produktion gehen soll. Dies kann schnell unpraktisch werden, wenn die Anzahl der Modelle im Ensemble zunimmt.

Beliebte Bibliotheken für maschinelles Lernen wie scikit-learn und TensorFlow bieten einfach anzuwendende Implementierungen für viele gängige Bagging- und Boosting-Methoden, beispielsweise Random Forest, AdaBoost, Gradient Boosting und XGBoost. Allerdings sollten Sie sorgfältig abwägen, ob sich der erhöhte Overhead, der mit einer Ensemble-Methode verbunden ist, wirklich lohnt. Vergleichen Sie immer die Genauigkeit und den Ressourcenverbrauch mit einem linearen oder DNN-Modell. Das Destillieren (siehe »Entwurfsmuster 11: Nützliche Überanpassung« auf Seite 165) eines Ensembles von neuronalen Netzen kann oftmals die Komplexität verringern und die Performance verbessern.

Dropout als Bagging

Techniken wie Dropout bieten eine leistungsfähige und effektive Alternative. Dropout ist als Regularisierungstechnik im Deep Learning bekannt, kann aber auch als Annäherung an Bagging verstanden werden. In einem neuronalen Netz bewirkt Dropout, dass Neuronen des Netzes zufällig (mit einer vorgegebenen Wahrscheinlichkeit) »abgeschaltet« werden, und zwar für jeden Mini-Batch des Trainings, wodurch praktisch ein per Bagging erzeugtes Ensemble von exponentiell vielen neuronalen Netzen bewertet wird. Davon abgesehen ist das Training eines neuronalen Netzes mit Dropout nicht genau dasselbe wie Bagging. Es gibt zwei bemerkenswerte Unterschiede. Erstens sind die Modelle beim Bagging unabhängig, während die Modelle beim Training mit Dropout Parameter gemeinsam nutzen. Zweitens werden die Modelle beim Bagging bis zur Konvergenz auf ihrem jeweiligen Trainingsset trainiert. Beim Training mit Dropout würden die Modelle der Ensemble-Mitglieder nur für einen einzelnen Trainingsschritt trainiert, weil in jeder Iteration der Trainingsschleife verschiedene Knoten ausgeschaltet werden.

Geringere Modellinterpretierbarkeit

Die Modellinterpretierbarkeit ist ein weiterer Punkt, den man im Hinterkopf behalten sollte. Bereits im Deep Learning kann es schwierig sein, effektiv zu erklären, warum unser Modell gerade die Vorhersagen trifft, die es trifft. Dieses Problem verschärft sich noch bei Ensemble-Modellen. Vergleichen Sie zum Beispiel Entscheidungsbäume und den Random Forest. Ein Entscheidungsbaum lernt letztlich Grenzwerte für alle Features, die eine einzelne Instanz zur endgültigen Vorhersage des Modells führen. In diesem Sinne ist es einfach zu erklären, warum ein Entscheidungsbaum die Entscheidungen trifft, wie sie getroffen wurden. Der Random Forest, der ein Ensemble aus vielen Entscheidungsbäumen ist, verliert diese Ebene der lokalen Interpretierbarkeit.

Das richtige Tool für das Problem auswählen

Ebenfalls wichtig ist es, den Bias-Varianz-Kompromiss im Auge zu behalten. Manche Ensemble-Techniken sind im Umgang mit hohen Bias- oder Varianzwerten besser als andere (siehe Tabelle 3-2). Insbesondere bietet sich Boosting bei zu hohen Bias-Werten an, während sich Bagging eignet, um hohe Varianzen in den Griff zu bekommen. Und wie wir schon im Abschnitt »Bagging« auf Seite 121 festgestellt haben, lässt sich die Varianz nicht verringern, wenn man zwei Modelle kombiniert, deren Fehler stark miteinander korreliert sind. Kurz gesagt, wird die falsche Ensemble-Methode für unser Problem die Performance nicht unbedingt verbessern, sondern nur unnötigen Overhead hinzufügen.

Tabelle 3-2: Eine Zusammenfassung zum Bias-Varianz-Kompromiss

Problem

Ensemble-Lösung

Hoher Bias (Unteranpassung)

Boosting

Hohe Varianz (Überanpassung)

Bagging

Andere Ensemble-Methoden

Wir haben einige der gebräuchlicheren Ensemble-Techniken beim maschinellen Lernen erörtert. Die weiter oben besprochene Liste ist keineswegs erschöpfend, und es gibt verschiedene Algorithmen, die zu diesen breit gefassten Kategorien passen. Es gibt auch andere Ensemble-Techniken, darunter viele, die einen bayesschen Ansatz beinhalten oder die eine Suche mit neuronaler Architektur und Reinforcement Learning kombinieren, wie zum Beispiel AdaNet- oder AutoML-Techniken von Google. Kurz gesagt, das Entwurfsmuster Ensemble umfasst Techniken, die mehrere ML-Modelle kombinieren, um die Modellperformance insgesamt zu verbessern. Zudem kann dieses Entwurfsmuster besonders nützlich sein, wenn es um häufig vorkommende Trainingsprobleme wie hoher Bias oder hohe Varianz geht.

Entwurfsmuster 8: Kaskade

Das Entwurfsmuster Kaskade ist für Situationen gedacht, in denen sich ein ML-Problem gewinnbringend in eine Folge von ML-Problemen zerlegen lässt. Eine derartige Kaskade erfordert oft einen sorgfältigen Entwurf des ML-Experiments.

Problem

Was passiert, wenn wir einen Wert sowohl bei üblichen als auch bei ungewöhnlichen Aktivitäten vorhersagen müssen? Das Modell wird lernen, die ungewöhnliche Aktivität zu ignorieren, weil sie selten ist. Wenn die ungewöhnliche Aktivität auch mit abnormalen Werten verbunden ist, leidet die Trainierbarkeit.

Nehmen wir zum Beispiel an, wir wollten ein Modell trainieren, um die Wahrscheinlichkeit vorherzusagen, dass ein Kunde einen gekauften Artikel zurückgibt. Wenn wir ein einzelnes Modell trainieren, geht das Rückgabeverhalten der Wiederverkäufer verloren, weil es Millionen von Einkäufern für den Einzelhandel (und Einzelhandelstransaktionen) gibt, aber nur wenige Tausend Wiederverkäufer. Zum Zeitpunkt eines Kaufs wissen wir nicht wirklich, ob es sich um einen Einzelhändler oder einen Wiederverkäufer handelt. Indem wir andere Marktplätze überwachen, haben wir aber herausgefunden, wann bei uns gekaufte Artikel anschließend weiterverkauft werden. Unser Datensatz hat deshalb ein Label, das einen Kauf als von einem Wiederverkäufer ausgeführt kennzeichnet.

Um dieses Problem zu lösen, könnte man die Instanzen der Wiederverkäufer beim Trainieren des Modells übergewichten. Das ist aber suboptimal, weil wir den häufigeren Anwendungsfall »Einzelhändler« so korrekt wie möglich bekommen müssen. Wir sind nicht gewillt, eine geringere Genauigkeit im Anwendungsfall »Einzelhändler« gegen eine höhere Genauigkeit im Anwendungsfall »Wiederverkäufer« einzutauschen. Allerdings verhalten sich Einzelhändler und Wiederverkäufer sehr unterschiedlich. Denn während zum Beispiel Einzelhändler die Artikel innerhalb von etwa einer Woche zurückgeben, geben Wiederverkäufer Artikel nur zurück, wenn sie sie nicht verkaufen können, und so können die Retouren erst Monate später stattfinden. Die geschäftliche Entscheidung, Waren zu bevorraten, sieht für wahrscheinliche Rückgaben bei Einzelhändlern anders aus als bei Wiederverkäufern. Demzufolge ist es notwendig, beide Arten von Retouren so genau wie möglich zu erfassen. Es wird nicht funktionieren, einfach die Instanzen von Wiederverkäufern höher zu gewichten.

Es liegt nahe, dieses Problem mithilfe des Entwurfsmusters Kaskade anzugehen. Wir gliedern das Problem in vier Teile:

  1. Vorhersagen, ob eine bestimmte Transaktion von einem Wiederverkäufer stammt.
  2. Ein Modell auf Verkäufe an Einzelhändler trainieren.
  3. Das zweite Modell auf Verkäufe an Wiederverkäufer trainieren.
  4. In der Produktion die Ausgaben der drei separaten Modelle kombinieren, um die Rückgabewahrscheinlichkeit für jeden gekauften Artikel und die Wahrscheinlichkeit, dass die Transaktion von einem Wiederverkäufer stammt, vorherzusagen.

Dies ermöglicht unterschiedliche Entscheidungen zu Artikeln, die je nach Käufertyp wahrscheinlich zurückgegeben werden, und gewährleistet, dass die Modelle in den Schritten 2 und 3 in ihrem Segment der Trainingsdaten so genau wie möglich sind. Jedes dieser Modelle ist relativ einfach zu trainieren. Das erste ist einfach ein Klassifikator, und wenn die ungewöhnliche Aktivität äußerst selten ist, können wir dem mit dem Muster Rebalancing begegnen. Die beiden nächsten Modelle sind im Wesentlichen Klassifizierungsmodelle, die auf verschiedenen Segmenten der Trainingsdaten trainiert werden. Die Kombination ist deterministisch, da wir das auszuführende Modell danach auswählen, ob die Aktivität zu einem Wiederverkäufer gehört.

Das Problem tritt während der Vorhersage auf. Zur Vorhersagezeit haben wir keine echten Labels, sondern nur die Ausgabe des ersten Klassifizierungsmodells. Anhand der Ausgabe des ersten Modells müssen wir bestimmen, welche der beiden Verkaufsmodelle wir aufrufen. Das Problem besteht darin, dass wir auf Labels trainieren, aber zur Inferenzzeit Entscheidungen basierend auf Vorhersagen treffen müssen. Und Vorhersagen sind mit Fehlern behaftet. Das zweite und das dritte Modell müssen also Vorhersagen auf der Basis von Daten treffen, die sie während des Trainings vielleicht nie gesehen haben.

Als extremes Beispiel nehmen wir an, dass die Adresse, die Wiederverkäufer angeben, immer in einem Gewerbegebiet der Stadt liegt, während Einzelhändler überall zu finden sein können. Wenn das erste (Klassifizierungs-)Modell einen Fehler macht und ein Einzelhändler fälschlicherweise als Wiederverkäufer identifiziert wird, enthält das Vokabular des aufgerufenen Modells für die Abbruchvorhersage nicht das Gebiet, in dem der Kunde wohnt.

Wie trainiert man eine Kaskade von Modellen, bei der die Ausgabe des einen Modells eine Eingabe in das folgende Modell ist oder die Auswahl des folgenden Modells bestimmt?

Lösung

Jedes Problem des maschinellen Lernens, bei dem die Ausgabe des einen Modells eine Eingabe für das folgende Modell ist oder die Auswahl der nachfolgenden Modelle bestimmt, wird als Kaskade bezeichnet. Beim Training einer Kaskade von ML-Modellen ist besondere Vorsicht geboten.

Um zum Beispiel ein ML-Problem zu lösen, das manchmal ungewöhnliche Umstände beinhaltet, kann man es als Kaskade von vier ML-Problemen behandeln:

  1. ein Klassifizierungsmodell, um den Umstand zu identifizieren
  2. ein Modell, das auf ungewöhnliche Umstände trainiert wird
  3. ein separates Modell, das auf typische Umstände trainiert wird
  4. ein Modell, um die Ausgabe der beiden separaten Modelle zu kombinieren, da die Ausgabe eine probabilistische Kombination der beiden Ausgaben ist

Auf den ersten Blick scheint dieses Muster ein Spezialfall des Entwurfsmusters Ensemble zu sein. Dass es als separates Muster gilt, ist auf die spezielle Versuchsplanung zurückzuführen, die beim Ablaufen einer Kaskade erforderlich ist.

Als Beispiel nehmen wir an, dass wir zur Abschätzung der Kosten für die Lagerung von Fahrrädern an Bahnhöfen die Entfernung zwischen Verleih- und Rückgabestationen für Fahrräder in San Francisco vorhersagen möchten. Mit anderen Worten, das Modell soll die Entfernung vorhersagen, über die wir die Fahrräder zurück zur Verleihstation transportieren müssen. Zu den gegebenen Features gehören die Tageszeit, zu der der Verleih beginnt, der Ort, an dem das Fahrrad ausgeliehen wird, die Aussage, ob der Mieter ein Abonnent ist oder nicht, usw. Das Problem ist, dass das Ausleihen von mehr als vier Stunden ein extrem anderes Mieterverhalten bedeutet als kürzere Ausleihen und dass der Lagerungsalgorithmus beide Ausgaben benötigt (die Wahrscheinlichkeit, dass die Ausleihe länger als vier Stunden dauert, und die wahrscheinliche Entfernung, über die das Fahrrad transportiert werden muss). Allerdings ist nur bei einem sehr kleinen Teil der Ausleihen mit solch ungewöhnlichen Ausflügen zu rechnen.

Dieses Problem lässt sich zum Beispiel dadurch lösen, dass ein Klassifizierungsmodell trainiert wird, das zunächst die Fahrten danach klassifiziert, ob sie lang ('Long') oder typisch ('Typical') sind (den vollständigen Code finden Sie im Repository zu diesem Buch unter https://github.com/GoogleCloudPlatform/ml-design-patterns/blob/master/03_problem_representation/cascade.ipynb):

CREATE OR REPLACE MODEL mlpatterns.classify_trips

TRANSFORM(

trip_type,

EXTRACT (HOUR FROM start_date) AS start_hour,

EXTRACT (DAYOFWEEK FROM start_date) AS day_of_week,

start_station_name,

subscriber_type,

...

)

OPTIONS(model_type='logistic_reg',

auto_class_weights=True,

input_label_cols=['trip_type']) AS

SELECT

start_date, start_station_name, subscriber_type, ...

IF(duration_sec > 3600*4, 'Long', 'Typical') AS trip_type

FROM `bigquery-public-data.san_francisco_bikeshare.bikeshare_trips`

Es mag verlockend erscheinen, einfach den Trainingsdatensatz in zwei Teile zu teilen, basierend auf der tatsächlichen Reise, und die nächsten beiden Modelle zu trainieren, eines für die Long-Ausleihen und das andere für die Typical-Ausleihen. Das Problem besteht hier darin, dass das eben diskutierte Klassifizierungsmodell Fehler haben wird. In der Tat zeigt die Auswertung des Modells auf einem reservierten Teil der San-Francisco-Fahrraddaten, dass die Genauigkeit des Modells nur etwa 75 % beträgt (siehe Abbildung 3-16). Unter diesen Umständen wird das Trainieren eines Modells auf einer perfekten Teilung der Daten nichts bringen.

image

Abbildung 3-16: Die Genauigkeit eines Klassifizierungsmodells, um atypisches Verhalten vorherzusagen, liegt höchstwahrscheinlich nicht bei 100 %.

Stattdessen müssen wir nach dem Training dieses Klassifizierungsmodells die Vorhersagen dieses Modells verwenden, um den Trainingsdatensatz für die nächste Gruppe von Modellen zu erzeugen. Zum Beispiel könnten wir den Trainingsdatensatz für das Modell erzeugen, um die Entfernung von typischen Ausleihen vorherzusagen:

CREATE OR REPLACE TABLE mlpatterns.Typical_trips AS

SELECT

* EXCEPT(predicted_trip_type_probs, predicted_trip_type)

FROM

ML.PREDICT(MODEL mlpatterns.classify_trips,

(SELECT

start_date, start_station_name, subscriber_type, ...,

ST_Distance(start_station_geom, end_station_geom) AS distance

FROM `bigquery-public-data.san_francisco_bikeshare.bikeshare_trips`)

)

WHERE predicted_trip_type = 'Typical' AND distance IS NOT NULL

Dann sollten wir mit diesem Datensatz das Modell trainieren, um Entfernungen vorherzusagen:

CREATE OR REPLACE MODEL mlpatterns.predict_distance_Typical

TRANSFORM(

distance,

EXTRACT (HOUR FROM start_date) AS start_hour,

EXTRACT (DAYOFWEEK FROM start_date) AS day_of_week,

start_station_name,

subscriber_type,

...

)

OPTIONS(model_type='linear_reg', input_label_cols=['distance']) AS

SELECT

*

FROM

mlpatterns.Typical_trips

Schließlich sollten wir bei Auswertung, Vorhersage usw. berücksichtigen, dass wir drei trainierte Modelle verwenden müssen und nicht nur eines. Das ist es nämlich, was wir als Entwurfsmuster Kaskade bezeichnen.

In der Praxis kann es schwierig werden, einen geradlinigen Kaskade-Workflow zu realisieren. Anstatt die Modelle einzeln zu trainieren, ist es besser, den gesamten Workflow nach dem Muster Workflow-Pipelines (siehe Kapitel 6) zu automatisieren, wie Abbildung 3-17 zeigt. Dabei ist sicherzustellen, dass die Trainingsdatensätze für die beiden nachgelagerten Modelle bei jeder Ausführung des Experiments basierend auf den Vorhersagen vorgelagerter Modelle erzeugt werden.

Obwohl wir das Kaskade-Muster eingeführt haben als Möglichkeit, einen Wert sowohl bei gewöhnlicher als auch bei ungewöhnlicher Aktivität vorherzusagen, kommt die Lösung des Kaskade-Musters auch mit allgemeineren Situationen zurecht. Mit dem Pipeline-Framework können wir jede Situation behandeln, in der sich ein ML-Problem gewinnbringend in eine Folge (oder Kaskade) von ML-Problemen zerlegen lässt. Immer dann, wenn es erforderlich ist, die Ausgabe eines ML-Modells als Eingabe in ein anderes Modell einzuspeisen, muss das zweite Modell auf den Vorhersagen des ersten Modells trainiert werden. In allen derartigen Situationen ist ein formales Framework für Pipeline-Experimente hilfreich.

image

Abbildung 3-17: Eine Pipeline, um die Kaskade von Modellen als einzelner Job zu trainieren

Ein derartiges Framework ist Kubeflow Pipelines. Da es mit Containern arbeitet, kann man die zugrunde liegenden ML-Modelle und den Verbindungscode in nahezu jeder Programmier- oder Skriptsprache schreiben. Hier stützen wir uns auf die BigQuery-Clientbibliothek und hüllen die obigen BigQuery-SQL-Modelle in Python-Funktionen ein. Wir könnten auch TensorFlow oder scikit-learn, ja selbst R verwenden, um einzelne Komponenten zu implementieren.

Mithilfe von Kubeflow Pipelines lässt sich der Pipeline-Code recht einfach ausdrücken, wie das folgende Codefragment zeigt (den vollständigen Code finden Sie unter https://github.com/GoogleCloudPlatform/ml-design-patterns/blob/master/03_problem_representation/cascade.ipynb im Code-Repository zu diesem Buch):

@dsl.pipeline(

name='Cascade pipeline on SF bikeshare',

description='Cascade pipeline on SF bikeshare'

)

def cascade_pipeline(

project_id = PROJECT_ID

):

ddlop = comp.func_to_container_op(run_bigquery_ddl,

packages_to_install=['google-cloud-bigquery'])

c1 = train_classification_model(ddlop, PROJECT_ID)

c1_model_name = c1.outputs['created_table']

c2a_input = create_training_data(ddlop,

PROJECT_ID, c1_model_name, 'Typical')

c2b_input = create_training_data(ddlop,

PROJECT_ID, c1_model_name, 'Long')

c3a_model = train_distance_model(ddlop,

PROJECT_ID, c2a_input.outputs['created_table'], 'Typical')

c3b_model = train_distance_model(ddlop,

PROJECT_ID, c2b_input.outputs['created_table'], 'Long')

...

Mit dem Pipelines-Framework ist es möglich, die gesamte Pipeline zur Ausführung zu bestätigen und verschiedene Läufe des Experiments zu verfolgen.

image

Wenn wir TFX als Pipeline-Framework verwenden (TFX lässt sich auf Kubeflow Pipelines ausführen), ist es nicht notwendig, die vorgelagerten Modelle bereitzustellen, um deren ausgegebene Vorhersagen in nachgelagerten Modellen zu verwenden. Stattdessen können wir die TensorFlow-Transform-Methode tft.apply_saved_model als Teil unserer Vorverarbeitungsoperationen aufrufen. Das Entwurfsmuster Transformation lernen Sie in Kapitel 6 näher kennen.

Für verkettete ML-Modelle ist es unbedingt zu empfehlen, ein Pipeline-Experiment-Framework zu verwenden. Ein derartiges Framework stellt sicher, dass nachgelagerte Modelle erneut trainiert werden, wenn sich vorgelagerte Modelle ändern, und dass wir über einen Verlauf aller vorherigen Trainingsläufe verfügen.

Kompromisse und Alternativen

Das Entwurfsmuster Kaskade sollten Sie nicht überstrapazieren – im Gegensatz zu vielen anderen Entwurfsmustern, die wir in diesem Buch beschreiben, gehört Kaskade nicht unbedingt zu den Best Practices. Es verkompliziert Ihre ML-Workflows und kann sogar zu einer schlechteren Performance führen. Beachten Sie, dass ein Pipeline-Experiment-Framework zweifellos zu den Best Practices zählt, doch Sie sollten möglichst versuchen, eine Pipeline auf ein einzelnes ML-Problem (Erfassung, Aufbereitung, Datenvalidierung, Transformation, Training, Bewertung und Bereitstellung) zu begrenzen. Vermeiden Sie es, in derselben Pipeline mehrere ML-Modelle einzureihen, wie es beim Kaskade-Muster der Fall ist.

Deterministische Eingaben

Ein ML-Problem aufzuteilen, ist in der Regel eine schlechte Idee, da ein ML-Modell Kombinationen aus mehreren Faktoren lernen kann/sollte, zum Beispiel:

Das Entwurfsmuster Kaskade richtet sich an ein ungewöhnliches Szenario, für das wir keine kategoriale Eingabe haben und für das Extremwerte aus mehreren Eingaben gelernt werden müssen.

Einzelnes Modell

Das Entwurfsmuster Kaskade sollte nicht für allgemeine Szenarios verwendet werden, bei denen ein einzelnes Modell genügt. Nehmen wir zum Beispiel an, wir wollten die Kaufneigung eines Kunden lernen. Man könnte denken, dass wir verschiedene Modelle lernen müssen, zum einen für Menschen, die Preisvergleiche anstellen, zum anderen für Menschen, die genau das nicht tun. Wir wissen nicht wirklich, wer Preise vergleicht, aber wir können eine fundierte Vermutung anstellen, basierend auf der Anzahl der Besuche, wie lange der Artikel im Einkaufswagen gelegen hat usw. Für dieses Problem ist das Entwurfsmuster Kaskade nicht erforderlich, da es so häufig vorkommt (ein Großteil der Kunden stellt Preisvergleiche an), dass das ML-Modell in der Lage sein sollte, dieses Verhalten im Laufe des Trainings implizit zu lernen. Für häufige Szenarios trainieren Sie ein einzelnes Modell.

Interne Konsistenz

Das Kaskade-Entwurfsmuster wird benötigt, wenn wir interne Konsistenz unter den Vorhersagen mehrerer Modelle aufrechterhalten müssen. Beachten Sie, dass wir versuchen, mehr als nur die ungewöhnliche Aktivität vorherzusagen. Wir versuchen, Retouren vorherzusagen, wobei wir berücksichtigen, dass es auch eine gewisse Wiederverkäuferaktivität geben wird. Wenn die Aufgabe nur darin besteht, vorherzusagen, ob ein Verkauf von einem Wiederverkäufer stammt oder nicht, würden wir das Muster Rebalancing verwenden. Das Muster Kaskade wird eingesetzt, weil die Ausgabe des unausgewogenen Labels als Eingabe für nachfolgende Modelle benötigt wird und auch selbst nützlich ist.

Analog dazu nehmen wir an, dass wir das Modell trainieren wollen, um die Kaufneigung eines Kunden bei einem rabattierten Angebot vorherzusagen. Ob wir das rabattierte Angebot machen oder nicht und wie groß der Rabatt ist, hängt oft davon ab, ob dieser Kunde Preisvergleiche anstellt oder nicht. Deshalb benötigen wir interne Konsistenz zwischen den beiden Modellen (dem Modell für Preisvergleiche und dem Modell für die Kaufbereitschaft). In diesem Fall könnte das Kaskade-Entwurfsmuster erforderlich sein.

Vortrainierte Modelle

Das Entwurfsmuster Kaskade wird auch benötigt, wenn wir die Ausgabe eines bereits trainierten Modells als Eingabe in unser Modell wiederverwenden möchten. Nehmen wir zum Beispiel an, wir wollten ein Modell erstellen, um autorisierte Besucher eines Gebäudes zu erkennen, damit wir das Tor automatisch öffnen können. Eine der Eingaben in unser Modell könnte das Nummernschild des Fahrzeugs sein. Anstatt das Sicherheitsfoto direkt im Modell zu verwenden, dürfte es einfacher sein, die Ausgabe eines Modells für optische Zeichenerkennung (Optical Character Recognition, OCR) einzusetzen. OCR-Systeme weisen jedoch Fehler auf. Deshalb sollten wir unser Modell nicht mit perfekten Nummernschilddaten trainieren, sondern auf den tatsächlichen Ausgaben des OCR-Systems. Da sich verschiedene OCR-Modelle unterschiedlich verhalten und unterschiedliche Fehler erzeugen, ist es notwendig, das Modell neu zu trainieren, wenn wir den Anbieter unseres OCR-Systems wechseln.

image

Ein vortrainiertes Modell verwendet man häufig als ersten Schritt in einer Pipeline für ein Objekterkennungsmodell. Darauf folgt dann ein Modell für die feinkörnige Bildklassifizierung. Zum Beispiel könnte das Objekterkennungsmodell alle Handtaschen im Bild finden, ein Zwischenschritt würde das Bild auf die Begrenzungsrahmen der erkannten Objekte beschneiden, und das nachfolgende Modell könnte die Art der Handtasche identifizieren. Wir empfehlen, eine Kaskade zu verwenden, damit sich die gesamte Pipeline neu trainieren lässt, wenn das Objekterkennungsmodell aktualisiert wird (etwa mit einer neuen Version der API).

Reframing statt Kaskade

In unserem Beispielproblem wollen wir die Wahrscheinlichkeit vorhersagen, dass ein Artikel zurückgegeben wird. Es handelt sich also um ein Klassifizierungsproblem. Nehmen wir stattdessen an, dass wir die stündlichen Verkaufsbeträge vorhersagen möchten. Die meiste Zeit werden wir nur Einzelhändler bedienen, doch hin und wieder (vielleicht vier- oder fünfmal im Jahr) haben wir es mit einem Großhändler zu tun.

Rein gedanklich ist dies ein Regressionsproblem, um tägliche Verkaufsbeträge vorherzusagen, wobei wir einen Störfaktor in Form von Großhändlern haben. Ein besserer Ansatz wäre es, das Regressionsproblem neu zu formulieren, und zwar als Klassifizierungsproblem von verschiedenen Verkaufsbeträgen. Obwohl dabei ein Klassifizierungsmodell für jeden Bucket von Verkaufsbeträgen trainiert wird, fällt die Notwendigkeit weg, Einzelhändler gegenüber Großhändlern richtig zu klassifizieren.

Regression in seltenen Situationen

Das Entwurfsmuster Kaskade kann bei Regressionsaufgaben hilfreich sein, wenn einige Werte viel häufiger vorkommen als andere. Vielleicht möchten wir die Niederschlagsmenge aus einem Satellitenbild vorhersagen. Es könnte sein, dass 99 % der Pixel keinen Regen zeigen. In einem derartigen Fall kann es hilfreich sein, ein gestapeltes Klassifizierungsmodell mit einem nachfolgenden Regressionsmodell zu erzeugen:

  1. Zuerst vorhersagen, ob es regnen wird oder nicht.
  2. Für Pixel, bei denen laut Modell Regen unwahrscheinlich ist, eine Regenmenge von null vorhersagen.
  3. Ein Regressionsmodell trainieren, um die Regenmenge für Pixel vorherzusagen, bei denen das Modell Regen als wahrscheinlich vorhersagt.

Denken Sie unbedingt daran, dass das Klassifizierungsmodell nicht perfekt ist. Das Regressionsmodell muss also auf den Pixeln trainiert werden, die das Klassifizierungsmodell als wahrscheinlich für Regen vorhersagt (und nicht nur auf Pixeln, die Regen im gelabelten Datensatz entsprechen). Ergänzende Lösungen zu diesem Problem finden Sie auch in »Entwurfsmuster 10: Rebalancing« auf Seite 144 und in »Entwurfsmuster 5: Reframing« auf Seite 100.