SDA SE Wiki

Software Engineering for Smart Data Analytics & Smart Data Analytics for Software Engineering

User Tools

Site Tools


Projektgruppe Angewandte Softwaretechnologie

Dr. Günter Kniesel-Wünsche, Lars Reimann

Motivation: Schwächen in bekannten APIs

Die drei in der Praxis störendsten Probleme im Design von scikit-learn, derer wir uns in der PG annehmen wollen, bestehen darin, dass viele Funktionsparameter

  • überflüssig sind und somit verwirrend,
  • ihr Typ zu primitiv ist, um im Compiler eine sinnvolle statische Fehlerbehandlung durchführen zu können,
  • oder sie nur dann gebraucht werden, wenn ein anderer Parameter einen bestimmten Wert hat, was besonders verwirrend ist.

Im Folgenden wird für jede Kategorie ein konkretes Beispiel des Problems und eine mögliche Lösung vorgestellt. Ziel der PG wird es sein, die Lösungen in einem verbesserten API umzusetzen und dies neue API mit so geringem Aufwand wie nur möglich (d.h. so weit wie möglich automatisiert) zu erstellen.

Ein solches verbessertes API ist keine akademische Übung sondern hat eine sehr große Auswirkung in der Praxis. Alles was Fehlern vorbeugt oder sie frühzeitig (schon bei der Compilierung) erkennt, ist im Rahmen von maschinellem Lernen ein unschätzbarer Vorteil, denn manche Algorithmen laufen Stunden oder Tage. Dann wegen eines Tippfehlers (s.u.) neu anfangen zu müssen ist extrem ineffektiv und äusserst frustrierend.

Zu viele Parameter / Überflüssige Parameter

Das Hicksche Gesetz 1) besagt, dass die Zeit, die eine Person zur Entscheidungsfindung benötigt, logarithmisch mit der Zahl der Wahlmöglichkeiten steigt. Daraus lässt sich schließen, dass die Zahl der Parameter einer Funktion auf ein Minimum reduziert werden sollte.

Bei scikit-learn wird dieser Grundsatz häufig nicht eingehalten. Dies ist zum Teil der Tatsache geschuldet, dass es bei ML-Algorithmen inhärent viele Einstellungsmöglichkeiten gibt, die man ausprobieren muss um gute Ergebnisse zu erreichen. Dennoch gibt es noch viel Verbesserungpotential, denn viele parameter sind nicht inhärent aus dem jeweiligen mathematischen Modell motiviert, sondern

  • selten gebrauchte default-werte,
  • nur für logging, debugging, etc. relevant,
  • teilweise von anderen Paremetern abhängig

Die letzten beiden Problemkategorien werden im Folgenden am Beispiel des SVC-Modell erläutert, das insgesamt 15 Parameter (!) hat. Davon sind hier exemplarisch zwei gezeigt:

Der Parameter 'linear' setzt den sogenannten Kernel dieses Modells, ist also eine notwendige Einstellung mit ML-Bezug. Der Parameter verbose=True hingegen aktiviert lediglich Debugging-Ausgaben, was nicht für ML spezifisch ist. Sinnvoller wäre Debugging global an- bzw. abzuschalten und für eine geeignete Gruppierung der Ausgaben zu sorgen, so dass weiterhin sichtbar wäre, welche Ausgaben von SVC erzeugt werden (ohne dass man den verbose Parameter hier benötigt).

Mit weiteren Parametern der Funktion kann man ähnliche Überlegungen anstellen.

String statt Aufzählungstyp

Ein weiteres häufiges Problem in scikit-learn ist, dass Strings als Parameter verwendet werden, obwohl nur eine endliche Anzahl von Argumenten erlaubt ist. Das wird deutlich, wenn man sich die Dokumentation des oben schon besprochenen essentiellen Parameters kernel von SVC-Modell ansieht:

Die Dokumentation beschreibt den Typ des Kernel-Parameters als String, schränkt aber die legalen Werte auf die fünf Zeichenketten 'linear', 'poly', 'rbf', 'sigmoid' und 'precomputed' ein. Dies ist aus mehreren Gründen problematisch:

  • Die legalen / illegalen Werte sind nicht aus der Typangabe erkennbar
  • Tippfehler (z. B. 'linaer') werden nicht direkt erkannt
  • Die IDE kann keine Auto-Vervollständigung anbieten
  • Der Zweck des String-Arguments ist ohne Blick in die Dokumentation nicht ersichtlich, wenn keine benannten Argumente verwendet werden.

Die Lösung liegt auf der Hand: Python verfügt mittlerweile über Enum-Klassen, die genau für diesen Zweck hinzugefügt wurden. Damit lässt sich das Beispiel entsprechend umschreiben:

Dies löst die oben beschriebenen Probleme und erzwingt insbesondere durch den Präfix Kernel. selbstdokumentierenden Code, denn im Gegensatz zu den optionalen Argumentnamen muss der Präfix verwendet werden.

Abhängigkeiten zwischen Parametern

Anhand des SVC-Modells zeigen wir noch ein letztes Problem, bei dem es darum geht, dass Abhängigkeiten zwischen Parametern nur durch die Dokumentation ausgedrückt werden und somit nicht erzwungen werden können:

Hier verwenden wir zusätzlich zum Kernel-Parameter noch den Degree-Parameter, der den Grad des Polynoms setzt, den der Kernel poly nutzt. Dieser Parameter ist allerdings auch nur sinnvoll, wenn der poly Kernel verwendet wird und dann sollte er auf jeden Fall gesetzt werden.

Dies lässt sich dadurch erreichen, dass wir statt einzelner primitiver Parameter ein ganzes Parameterobjekt übergeben:

Dies ist im Wesentlichen eine Erweiterung der Enum-Idee die bereits unser vorheriges Problem gelöst hat. Dort ist für lineare Kernel ein einziger Wert, Kernel.linear, ausreichend. Für polynomielle Kernel ist dies nicht möglich, da ein Polynom beliebige Grade haben kann. Um beides zu modellieren müssen die möglichen Werte eine Klassenhierarchie bilden, die einerseits Singletons umfasst, wie etwa Kernel.linear, und andererseits Klassen mit öffentlichem Konstruktor, z.B. Kernel.poly(degree). Durch den Konstruktor-Parameter degree lassen sich die unendlichen Möglichkeiten für den Grad des Polynoms modellieren. Gleichzeitig wird klar, dass der Grad nur für Kernel der Art poly benötigt wird (da der Paremeter degree nur bei einem polynomiellen Kernel gesetzt werden kann). Indem wir diesem Parameter keinen Standardwert geben, erzwingen wir außerdem, dass er bei einem polynomiellen Kernel auch immer gesetzt werden muss.

Als positiven Nebeneffekt reduzieren wir die Zahl der Parameter des SVC-Modells und tragen so zur Lösung des ersten beschriebenen Problems bei.

1)
W. E. Hick (1952): On the rate of gain of information, Quarterly Journal of Experimental Psychology, 4:1, 11-26
teaching/projectgroups/ast/2021/motivation.txt · Last modified: 2021/03/17 19:18 by Günter Kniesel

SEWiki, © 2021