Trends Grundlagen Markt Magazin

iStock.com/Cecilie_Arcurs

Tools und Standards: Best Practices für den KI-Projektstart

Beginnen wir mit dem Thema Versionierung. Code Versionierung mithilfe von Git hat sich bereits als Standard durchgesetzt. In KI-Projekten macht das Sinn, da hier Code bei der Untersuchung der Daten anfällt oder für das Softwareprodukt geschrieben wird. Für die Zusammenarbeit im Team hat sich die Vorgehensweise von Git-flow etabliert. Grundsätzlich befinden sich bei Git verschiedene Code-Stände in sogenannten Branches. Git-flow schreibt nun Regeln für den Umgang mit Branches vor, die die Zusammenarbeit erleichtern. Vorteil dieses Vorgehens ist, dass viele Erfahrungswerte inklusive guter Dokumentation bestehen, Git-Flow sich bereits bewährt hat und weitere Helfer-Tools für die vereinfachte Arbeit mit Git-flow existieren. 

Der Kern des Git-flow-Vorgehens ist das Entwickeln jedes Teammitglieds in separaten Branches; den sog. Feature Branches. Diese werden dann bei Abschluss des entsprechenden Features in den Developer Branch eingefügt. Durch das Vorgehen können Code-Konflikte reduziert oder gegebenenfalls einfach beseitigt werden. Abseits der Code-Versionierung ist bei KI-Projekten auf die Versionierung der Experimente zu achten. Folgendes Szenario haben die meisten KI-Entwickler schon erlebt: Man trainiert mal schnell ein Machine-Learning-Modell, erhält gute Ergebnisse und experimentiert ein wenig weiter. Nach einigen Iterationen, einem Meeting oder sogar dem Wochenende dazwischen geht man in die nächste Iteration und ist gar nicht mehr so sicher, was man eigentlich schon ausprobiert hat. Und stellt dann fest, dass man zuvor eigentlich ein gutes Modell hatte, weiß aber nicht mehr genau, wie das Modell parametrisiert war. 

Viele beginnen dann mit eigens kreierten Excel-Tabellen. Hier gibt es unter dem Stichwort Experiment Tracking mittlerweile sehr gute Abhilfe. Dabei können durch die Integration von wenigen Codezeilen die Parameter zusammen mit den Ergebnissen des Experiments automatisiert gespeichert werden. Dies kann auch noch eine wichtige Lücke schließen, die die Code-Versionierung mit Git noch offenlässt: das regelmäßige Abspeichern des Notebook-Stands. Notebooks eignen sich sehr gut, um Machine-Learning-Modelle auszuprobieren und die Daten kennenzulernen.

Allerdings wird das Notebook typischerweise nicht bei jeder Änderung zwischendurch im Git gespeichert. Daher ist es sinnvoll, den kompletten Notebook-Stand mit jedem Experiment abzuspeichern. Zweckmäßig ist es dabei, sich auf ein Experiment Tracking Tool zu einigen und dessen Einrichtung vorzunehmen. Zuletzt kann man sich noch um die Daten-Versionierung kümmern. Dies ist nicht in allen Projekten notwendig, kann aber sinnvoll sein, wenn man mit großen Dateien arbeitet, die mehrmals mit unterschiedlichen Zwischenständen abgespeichert werden müssen. 


Coding Standards
Meist ist das Ziel eines KI-Projekts eine Software, die im optimalen Fall produktiv zum Einsatz kommt. Für die Software ist es sinnvoll, ein paar Standards zu etablieren. Der erste Effekt ist, dass der Code besser lesbar ist. Der Folgeeffekt ist, dass die Zusammenarbeit am Code erleichtert wird, Codeänderungen einfacher durchgeführt werden können und zu weniger Fehlern führen, die Software stabiler läuft und sich neue Mitarbeiter auch nach dem Abwandern der KI-Entwickler schnell einarbeiten können. Das Minimum an Standard bietet in Python das PEP 8. Viele der Vorschriften aus PEP 8 werden von Python-Entwicklern intuitiv eingehalten, wie beispielsweise das Kleinschreiben von Variablennamen und Großschreiben von Klassennamen.

Nichtsdestotrotz sollte dieser Standard anfangs als bindend fixiert werden. Eine weitere starke Empfehlung in Python sind Type Hints in Funktionsdefinitionen. Diese Type Hints – also Hinweise auf den Typ einer Variablen – können das Verständnis einer Funktion erheblich vereinfachen, und ihre Implementierung kostet kaum Zeit. Außerdem lassen die Type Hints eine automatisierte Überprüfung auf die Richtigkeit von Funktionsaufrufen vor Laufzeit zu. Damit können während des Programmierens Fehler entdeckt und beseitigt werden. Im optimalen Fall kann ein anderer Entwickler die Funktion verstehen, ohne den Code innerhalb der Funktion zu lesen. Dafür bedarf es oft noch eines zusätzlichen Kommentars, der direkt unter die Funktionsdefinition gesetzt werden sollte. Ein Beispiel liefert die Funktion aus Abbildung  » 1 .

Nun können andere Entwickler diese Funktion nutzen, ohne den Code im Detail durchzulesen. Wird am Ende des Projekts eine gut lesbare Dokumentation außerhalb des Codes benötigt, beispielsweise weil die Software Open Source gestellt wird, sollten zusätzliche Anforderungen an die Dokumentation festgesetzt werden. Hier hat sich das Tool Sphinx etabliert, das aus dem dokumentierten Code automatisch eine HTML-Seite oder ein PDF-Dokument erstellen kann.


Ordnerstruktur
Für ein koordiniertes Vorgehen ist letztlich auch eine gute Organisation der Ordnerstruktur notwendig, die von Anfang an ein paar Helfer-Dateien enthält. Nennen wir unser KI-Projekt Convolution. Dann gibt es einen Projektordner mit selbigem Namen, der alles Weitere enthält. Hier sollte es erneut einen Ordner mit dem Namen Convolution geben. Dieser enthält den gesamten Code, der später produktiv laufen soll. Dieser Ordner kann gegebenenfalls auch wieder mit Unterordnern strukturiert werden.

In vielen Fällen macht eine Konfigurationsdatei Sinn. In dieser werden Angaben abgespeichert, die sich gegebenenfalls später ändern können (wie zum Beispiel Pfad-Angaben oder Datenbankadressen) oder Einstellungen für das Programm, die abhängig von der Laufzeitumgebung sind. In manchen Fällen macht es auch Sinn, das Logging-Verhalten in einer separaten Datei zu beschreiben. Hier bieten sich .ini-Dateien an, die von der Python-Bibliothek logging verstanden werden. Dies ermöglicht unter anderem, das Logging-Verhalten auch während des Laufs der Applikation zu ändern. Die wichtigste Einstellung beim Logging ist das sogenannte Level. Hier unterscheidet man vier Level: Debug, Info, Warning und Error. Das Debug-Level ist beispielsweise sehr ausführlich und wird meist genutzt, um Fehler in der Applikation zu finden. Im Code können die einzelnen Logging-Nachrichten mit dem entsprechenden Level gekennzeichnet werden. Ist das Level, von dem man Nachrichten erhalten will, nun in einer Konfigurations-Datei angegeben (entweder die logging.ini oder die vorher angesprochene Konfigurationsdatei), kann man es zentral an einer Stelle für die ganze Applikation ändern.

Zurück zum Projektordner. Direkt neben dem Ordner für Code gibt es einen test-Ordner. Dieser enthält die gesamte Funktionalität zum automatisierten Testen des Codes. Manche schieben diese Ordner auch in den Code-Ordner. Funktional macht dies allerdings keinen Unterschied. Zusätzlich gibt es hier aber noch Abstimmungsbedarf zum Umfang der Tests. Manche streben eine 100-prozentige Abdeckung des Codes mit Tests an. Im Test Driven Development werden die Tests sogar vor der eigentlichen Funktion geschrieben. Beides geht mit einem Zeitinvestment einher. Allerdings auch mit einer höheren Qualität. Man kann dies also auch als den bekannten Konflikt aus dem Projektmanagement sehen, bei dem zwischen den Zielen „Kosten“, „Qualität“ und „Zeit“ ein Kompromiss gefunden werden muss. Hier steht man nun zwischen Qualität und Zeit. 

Es ist wichtig, sich dieses Trade-Offs von Anfang an bewusst zu sein und entsprechend abzuwägen. Eine anfängliche Festlegung auf Qualität kann ein wichtiges Signal an die Entwickler sein, die sich im Lauf des Projekts dann entsprechend Zeit nehmen können und nicht von der Entwicklung von neuen Features getrieben werden. Umgekehrt müssen Entwickler diese Zeit aber auch oft aktiv einfordern und erneut kommunizieren.

Gleichgestellt neben dem Code- und Test-Ordner sollte es noch einen Ordner scripts geben. Hier werden Codefragmente abgelegt, die während der Entwicklung angefallen sind und versioniert werden sollen, aber nicht produktiv laufen werden. Dazu zählen beispielsweise Skripte für Stresstests, Skripte zum Anlegen und Befüllen von Datenbank-Tabellen oder auch Jupyter Notebooks vom Experimentieren. Ebenfalls auf gleicher Ebene befindet sich die requirements.txt. Diese enthält die Namen der Python-Pakete, die für die Anwendung benötigt werden. Oft findet sich zusätzlich noch die genaue Version des Pakets neben dem Namen, um die Kompatibilität zu gewährleisten. Ein weiterer nützlicher Helfer in diesem Zusammenhang sind virtuelle Umgebungen. Diese erlauben trotz des einmaligen Installierens von Python mit mehreren und verschiedenen Umgebungen zu arbeiten, in denen dementsprechend auch unterschiedliche Python-Pakete und Versionen installiert sind. 

Die requirements.txt in Zusammenarbeit mit virtuellen Umgebungen kann nun eingesetzt werden, damit jeder im Team lokal mit der gleichen Umgebung arbeitet. Alle Pakete aus der requirements.txt lassen sich einfach mit dem Befehl „pip install -r requirements.txt“ installieren. Umgekehrt können alle Pakete der verwendeten Umgebung mit dem Befehl „pip freeze > requirements.txt“ in die Datei geschrieben werden. Auch dem Operations-Team kann die requirements.txt zur Sicherstellung einer automatisierten und funktionsfähigen Python Umgebung weiterhelfen. Weiterhin verwenden einige Tools für das automatisierte Deployment diese requirements.txt. Eine Übersicht der beschriebenen Struktur bietet Abbildung  » 2 .


Automatisierte Überprüfung der Standards
Als Entwickler automatisiert man ständig. Wieso also nicht auch die Einhaltung der Standards automatisieren? Dies kann mit Werkzeugen realisiert werden, die man typischerweise aus dem DevOps-Kontext kennt (z. B. Jenkins oder Gitlab CI Pipelines) und die zum Deployment von Applikationen dienen. Darüber hinaus können diese Tools aber auch Schritte auf der Strecke vom lokalen Code bis in das Code-Repository automatisieren. Diese Schritte überprüfen dann die Einhaltung der oben diskutierten Best Practices. Beispielsweise kann die Einhaltung von Code Standards (PEP 8) mit Pylint überprüft werden. Pylint ist darüber hinaus anpassbar an individuelle Regeln. Wird nun eine Regel oder ein Code-Standard nicht eingehalten, ist das Verschieben in das Code-Repository nicht erlaubt, bis die entsprechenden Änderungen vorgenommen wurden. Alternativ kann man sich auch über den Regelbruch per Mail informieren lassen und das Verschieben dennoch zulassen. Gleiches gilt für die Testabdeckung. Diese kann ebenfalls automatisch überprüft werden. Eine Durchführung der funktionalen Code-Tests kann ebenfalls hier schon stattfinden und bei Fehlschlagen das Verschieben in das Code Repository abgebrochen werden.


Fazit
Letztlich ist es schwierig zu entscheiden, was von diesem Blumenstrauß an Tools und Standards eingesetzt werden soll. Viel hilft nicht immer viel, und nicht alle angesprochenen Punkte eignen sich für jedes Projekt. Dennoch wünscht man sich als Entwickler oft ein paar mehr Standards, die die Qualität des Projekts heben können, aber potenziell auch mehr Zeit benötigen. Dafür bedarf es der Rückendeckung und des Verständnisses des Projektmanagements, aber auch des Muts der Entwickler, die Zeitinvestments zu verteidigen und Neues auszuprobieren. 
 



Autor

Nicolas Kuhaupt hat Mathematik in Deutschland und den USA studiert. Anschließend war er als Consultant im Bereich Big Data und als Research Data Scientist beim Fraunhofer Institut tätig. Seit 2020 ist er freiberuflicher Data Scientist.

 

Stichworte

Verwandte Artikel

Anzeige

Lexikoneinträge