Überwachung von Data-Science-Workflows

Die Zeiten, in denen ein Data Science-Projekt nur aus lose gekoppelten Notebooks für die Datenverarbeitung und das Modelltraining bestand, die die Date Scientists gelegentlich auf ihren Laptops ausführten, sind längst vorbei. Mit zunehmender Reife haben sich die Projekte zu großen Softwareprojekten mit mehreren Beteiligten und Abhängigkeiten sowie unterschiedlichen Modulen mit zahlreichen Klassen und Funktionen entwickelt. Der Data-Science-Workflow, der in der Regel mit der Datenvorverarbeitung, dem Feature-Engineering, dem Modelltraining, dem Tuning, der Evaluierung und schließlich der Inferenz beginnt und als ML-Pipeline bezeichnet wird, wird modularisiert. Diese Modularisierung macht den Prozess skalierbarer und automatisierbar, ergo geeignet für die Ausführung in Container-Orchestrierungssystemen oder in der Cloud-Infrastruktur. Die Extraktion wertvoller modell- oder datenbezogener KPIs kann, wenn sie manuell erfolgt, eine arbeitsintensive Aufgabe sein, umso mehr, wenn sie mit zunehmenden und/oder automatisierten Wiederholungen verbunden ist. Diese Informationen sind wichtig für den Vergleich verschiedener Modelle und die Beobachtung von Trends wie «Distribution-Shift» in den Trainingsdaten. Sie können auch dazu verwendet werden, ungewöhnliche Werte zu erkennen, von unausgewogenen Klassen bis hin zur Löschung von Ausreißern – was auch immer als notwendig erachtet wird, um die Robustheit eines Modells zu gewährleisten. Bibliotheken wie MLFlow können verwendet werden, um all diese Arten von Metriken zu speichern. Außerdem hängt die Operationalisierung von ML-Pipelines stark von der Verfolgung laufbezogener Informationen zur effizienten Fehlerbehebung sowie zur Aufrechterhaltung oder Verbesserung des Ressourcenverbrauchs der Pipeline ab.

Dies gilt nicht nur für die Welt von Data Science. Die heutigen Microservice-basierten Architekturen tragen ebenfalls dazu bei, dass die Wartung und Verwaltung von bereitgestelltem Code eine einheitliche Überwachung erfordert. Dies kann die von einem DevOps-Team benötigten Betriebs- und Wartungsstunden aufgrund eines ganzheitlicheren Verständnisses der beteiligten Prozesse drastisch reduzieren und gleichzeitig fehlerbedingte Ausfallzeiten verringern.

Es ist wichtig zu verstehen, wie verschiedene Formen der Überwachung darauf abzielen, die oben genannten Implikationen anzugehen, und wie modell- und datenbezogene Metriken ebenfalls zu diesem Ziel beitragen können. Zwar hat sich MLFlow als Industriestandard für die Überwachung von ML-bezogenen Metriken etabliert, doch kann auch die Überwachung dieser Metriken zusammen mit allen betrieblichen Informationen interessant sein.

Protokolle vs. Metriken

Protokolle liefern eine ereignisbasierte Momentaufnahme – Metriken geben einen Überblick aus der Vogelperspektive

Ein Protokoll ist eine zu einem bestimmten Zeitpunkt geschriebene Aufzeichnung (z. B. stdout/stderr) eines Ereignisses, das diskontinuierlich und in nicht vordefinierten Intervallen auftritt. Je nach Anwendung enthalten die Protokolle Informationen wie Zeitstempel, Auslöser, Name, Beschreibung und/oder Ergebnis des Ereignisses. Bei den Ereignissen kann es sich um einfache Anfragen oder Benutzeranmeldungen handeln, die der Entwickler des zugrunde liegenden Codes als wichtig erachtet hat. Wenn Sie sich bei diesem Prozess an bewährte Verfahren halten, können Sie sich eine Menge Ärger und Zeit bei der Einrichtung nachgelagerter Überwachungswerkzeuge sparen. Die Verwendung dedizierter Protokollbibliotheken und das Schreiben aussagekräftiger Protokollnachrichten sind hier von Vorteil.

INFO[2021-01-06T17:44:13.368024402-08:00] starting *secrets.YamlSecrets               
INFO[2021-01-06T17:44:13.368679356-08:00] starting *config.YamlConfig                 
INFO[2021-01-06T17:44:13.369046236-08:00] starting *s3.DefaultService                 
INFO[2021-01-06T17:44:13.369518352-08:00] starting *lambda.DefaultService             
ERROR[2021-01-06T17:44:13.369694698-08:00] http server error   error="listen tcp 127.0.0.1:6060: bind: address already in use"

Abb. 1: Ereignisprotokolle in Textform

Obwohl die Datenmenge eines einzelnen Protokolls vernachlässigbar ist, können Protokollströme schnell exponentiell ansteigen. Dies führt dazu, dass die Speicherung jedes einzelnen Protokolls nicht gut skalierbar ist, insbesondere in Form von halbstrukturierten Textdaten. Für Debugging oder Auditing kann es jedoch unvermeidlich sein, Protokolle in unveränderter Form zu speichern. Archivspeicherlösungen oder Aufbewahrungsfristen können hier helfen.

In anderen Fällen können das Parsen und Extrahieren von Protokollen in andere Formate, wie z. B. Schlüssel-Wert-Paare, diesen Einschränkungen entgegenwirken. Auf diese Weise kann ein Großteil der Ereignisinformationen erhalten bleiben, während der Speicherbedarf deutlich geringer ist.

{
  time: "2021-01-06T17:44:13-08:00",
  mode: "reader",
  debug_http_error: "listen tcp 127.0.0.1:6061: bind: address already in use"
  servicePort: 8089,
  duration_ms: 180262
}

Abb. 2: Strukturierte Ereignisprotokolle

Eine andere Form der Verringerung dieses Fußabdrucks kann durch Stichprobenmethoden erfolgen, wobei Metriken die prominentesten Vertreter sind.

Eine Metrik ist ein numerisches Maß für ein bestimmtes Ziel (ein bestimmtes Ereignis), das gleichmäßig über Zeitintervalle verteilt ist. Mathematische Aggregationen wie Summen oder Durchschnittswerte sind gängige Transformationen, die solche Metriken datenmäßig relativ klein halten.

{
   time: "2022-01-06T17:44:13-08:00",
   Duration_ms: 60,
   sum_requests: 500,
   sum_hits_endpoint_1: 250,
   sum_hits_endpoint_2: 117,
   avg_duration: 113,
 }

Abb. 3: Metriken

Metriken eignen sich daher gut für die schrittweise Verringerung der Datenauflösung auf breitere Frequenzen wie tägliche, wöchentliche oder sogar längere Analysezeiträume. Außerdem lassen sich Metriken in der Regel besser über mehrere Anwendungen hinweg vereinheitlichen, da sie im Vergleich zu rohen Protokollnachrichten stark strukturierte Daten enthalten. Dies verringert zwar die zuvor genannten Probleme, geht aber auf Kosten der Granularität. Daher eignen sich Metriken perfekt für hochfrequente Ereignisse, bei denen die Informationen zu einem einzelnen Ereignis weniger wichtig sind. Die Überwachung von Rechenressourcen ist ein Beispiel dafür. Beide Ansätze haben ihre Berechtigung in jeder Überwachungskonfiguration, da die verschiedenen Anwendungsfälle zu den unterschiedlichen Zielen passen. Anhand eines konkreten Beispiels aus einem kleinen Unternehmen lassen sich die Hauptunterschiede verdeutlichen:

Der Gesamtsaldo eines Bankkontos kann im Laufe der Zeit aufgrund von Abhebungen und Einzahlungen (die zu jedem Zeitpunkt erfolgen können) schwanken. Wenn man nur daran interessiert ist, dass sich Geld auf dem Konto befindet, sollte es ausreichen, eine aggregierte Metrik regelmäßig zu verfolgen. Interessiert man sich jedoch für den Gesamtzufluss im Zusammenhang mit einem bestimmten Kunden, ist die Protokollierung jeder Transaktion unumgänglich.

Architektur und Tool-Stack

In den meisten modernen Cloud-Stacks, wie z. B. Azure Appservice, wird die Protokollierung der Infrastruktur und der Anfrageseite mit dem Dienst selbst ausgeliefert. Mit zunehmendem Volumen kann dies jedoch kostspielig werden. Die Definition der Anwendungsfälle, das Verständnis der Bereitstellungsumgebung und die Abstimmung mit der Protokollierungsarchitektur sind Teil der Aufgaben von DevOps-Teams.

Aus der Sicht eines Entwicklers gibt es eine Vielzahl von Open-Source-Tools, die wertvolle Überwachungslösungen liefern können, die nur einen gewissen Aufwand für die Orchestrierung erfordern. Schlankere Setups können nur aus einem Backend-Server wie einer Zeitreihendatenbank und einem Tool zur Visualisierung bestehen. Komplexere Systeme können mehrere Protokollierungssysteme mit mehreren dedizierten Protokollversendern, Alarmmanagern und anderen Zwischenkomponenten umfassen (siehe Abbildung). Einige dieser Werkzeuge können notwendig sein, um Protokolle überhaupt erst zugänglich zu machen oder um verschiedene Protokollströme zu vereinheitlichen. Das Verständnis der Funktionsweise und des Leistungsbereichs der einzelnen Komponenten ist daher von zentraler Bedeutung.

Abb. 4: Überwachungsablauf von Anwendungen, die in einem Kubernetes-Cluster bereitgestellt werden (verändert, aus https://logz.io/blog/fluentd-vs-fluent-bit/)

Datenbank & Entwurf

Protokolle, zumindest wenn sie nach den bewährten Verfahren mit einem Zeitstempel versehen sind, und Metriken sind in der Regel Zeitreihendaten, die in einer Zeitreihendatenbank gespeichert werden können. In Fällen, in denen Textprotokolle unverändert gespeichert werden, verwenden andere Architekturen dokumentenorientierte Speichertypen mit einer leistungsstarken Abfrage-Engine (wie ElasticSearch) als Ergänzung. Neben den speicherbezogenen Unterschieden wird die Backend-Infrastruktur in zwei verschiedene Paradigmen unterteilt: Push und Pull. Diese Paradigmen befassen sich mit der Frage, wer für die anfängliche Aufnahme der Daten verantwortlich ist (Client oder Backend).

Die Entscheidung für das eine oder andere Paradigma hängt vom Anwendungsfall oder der Art der Informationen ab, die persistiert werden sollen. Push-Dienste eignen sich beispielsweise gut für die Ereignisprotokollierung, bei der die Informationen zu einem einzelnen Ereignis wichtig sind. Allerdings sind sie dadurch auch anfälliger für Überlastung durch zu viele Anfragen, was die Robustheit beeinträchtigt. Andererseits sind Pull-Systeme perfekt geeignet, um periodische Informationen abzurufen, die mit der Zusammensetzung von Metriken übereinstimmen.

Dashboard & Warnmeldungen

Um die Daten besser zu verstehen und eventuelle Unregelmäßigkeiten zu erkennen, sind Dashboards sehr nützlich. Überwachungssysteme eignen sich vor allem für einfache, „weniger komplexe“ Abfragen, da die Leistung zählt. Der Zweck dieser Tools ist auf die zu bearbeitenden Probleme spezialisiert, und sie bieten einen begrenzteren Bestand als einige der bekannten Software wie PowerBI. Das macht sie jedoch nicht weniger leistungsfähig in ihrem Einsatzbereich. Tools wie Grafana, das sich hervorragend für den Umgang mit protokollbasierten Metrikdaten eignet, kann sich mit verschiedenen Datenbank-Backends verbinden und maßgeschneiderte Lösungen aus mehreren Quellen erstellen. Tools wie Kibana, die ihre Stärken bei textbasierten Protokoll-Analysen haben, bieten Anwendern ein umfangreiches Abfrage-Toolkit für die Ursachenanalyse und Diagnose. Es ist erwähnenswert, dass beide Tools ihren Anwendungsbereich erweitern, um beide Welten zu unterstützen.

Abb. 5 Grafana Beispiel Dashboard (https://grafana.com/grafana/)

Während sich die Überwachung hervorragend eignet, um Unregelmäßigkeiten zu erkennen (proaktiv) und fehlerhafte Systeme gezielt zu analysieren (reaktiv), können DevOps-Teams sofort handeln, wenn sie über Anwendungsausfälle informiert werden. Alert-Manager bieten die Möglichkeit, nach Ereignissen zu suchen und Alarme über alle möglichen Kommunikationskanäle auszulösen, z. B. über Messaging, Incident-Management-Programme oder per E-Mail.

Scraper, Aggregatoren & Verlader

Da nicht jeder Microservice einen Endpunkt zur Verfügung stellt, an dem Protokolle und protokollbasierte Metriken bewertet oder extrahiert werden können – denken Sie an die Unterschiede zwischen Push und Pull -, müssen Vermittler einspringen. Dienste wie Scraper extrahieren und formatieren Protokolle aus verschiedenen Quellen, Aggregatoren führen eine Art von kombinierten Aktionen (Generierung von Metriken) durch und Shipper können als Push-Dienst für Push-basierte Backends fungieren. Fluentd ist ein perfekter Kandidat, der all die genannten Fähigkeiten in sich vereint und dennoch einen kleinen Fußabdruck beibehält.

End-to-End-Überwachung

Es gibt kostenpflichtige Dienste, die versuchen, ein ganzheitliches System für jede Art von Anwendung, Architektur und unabhängig von Cloud-Anbietern bereitzustellen, was für DevOps-Teams ein entscheidender Vorteil sein kann. Aber auch schlankere Setups können kosteneffiziente und zuverlässige Arbeit leisten.

Wenn man die Notwendigkeit ausschließt, Volltextprotokolle zu sammeln, können viele Standardanwendungsfälle mit einer Zeitreihendatenbank als Backend realisiert werden. InfluxDB ist dafür gut geeignet und einfach aufzusetzen, mit ausgereifter Integrationsfähigkeit in Grafana. Grafana als Dashboard-Tool lässt sich gut mit dem Alter Manager Service von Prometheus kombinieren. Als Vermittler ist fluentd perfekt geeignet, um die textuellen Protokolle zu extrahieren und die notwendigen Transformationen durchzuführen. Da InfluxDB push-basiert ist, kümmert sich fluentd auch darum, dass die Daten in InfluxDB gelangen.

Aufbauend auf diesen Tools deckt die Beispielinfrastruktur alles ab, von der Data Science Pipeline bis zu den später eingesetzten Modell-APIs, mit Dashboards für jeden Anwendungsfall. Bevor ein neuer Trainingslauf für die Produktion freigegeben wird, bieten die eingangs erwähnten ML-Metriken einen guten Einstiegspunkt, um die Legitimität des Modells zu überprüfen. Einfache Nutzerstatistiken, wie die Gesamtzahl der Anfragen und die Anzahl der einzelnen Anfragen, geben einen guten Überblick über die Nutzung des Modells, sobald es eingesetzt wird. Durch die Verfolgung der Antwortzeiten, z. B. eines API-Aufrufs, lassen sich Engpässe leicht aufdecken.

Auf der Ressourcenebene werden die APIs zusammen mit jedem Pipelineschritt überwacht, um Unregelmäßigkeiten wie plötzliche Spitzen im Speicherverbrauch zu beobachten. Durch die Verfolgung der Ressourcen im Zeitverlauf kann auch festgestellt werden, ob die verwendeten VM-Typen über- oder unterausgelastet sind. Durch die Optimierung dieser Metriken lassen sich möglicherweise unnötige Kosten einsparen. Schließlich sollten vordefinierte Fehlerereignisse, wie eine nicht erreichbare API oder fehlgeschlagene Trainingsläufe, einen Alarm auslösen und eine E-Mail versenden.

Abb. 6: Eingesetzte Infrastruktur mit Protokoll-Streams und Monitoring-Stack. 

Die gesamte Architektur, bestehend aus der Überwachungsinfrastruktur, der Data Science Pipeline und den bereitgestellten APIs, kann in einem (verwalteten) Kubernetes-Cluster ausgeführt werden. Aus einer DevOps-Perspektive ist die Kenntnis von Kubernetes bereits die halbe Miete. Dieser Open-Source-Stack kann nach oben und unten skaliert werden und ist nicht an ein kostenpflichtiges Abonnementmodell gebunden, was große Flexibilität und Kosteneffizienz bietet. Außerdem ist das Onboarding neuer Protokoll-Streams, bereitgestellter Anwendungen oder mehrerer Pipelines mühelos möglich. Sogar einzelne Frameworks können ausgetauscht werden. Wenn zum Beispiel Grafana nicht mehr geeignet ist, verwenden Sie einfach ein anderes Visualisierungstool, das sich mit dem Backend integrieren lässt und den Anforderungen des Anwendungsfalls entspricht.

Fazit

Nicht erst seit Anwendungen modularisiert und in die Cloud verlagert wurden, sind Protokollierung und Monitoring zentrale Bestandteile moderner Infrastrukturen. Dennoch verschlimmern sie sicherlich die Probleme, die entstehen, wenn sie nicht richtig eingerichtet sind. Neben der zunehmenden Operationalisierung des ML-Workflows wächst auch die Notwendigkeit für Unternehmen, gut durchdachte Überwachungslösungen einzurichten, um Modelle, Daten und alles um sie herum im Blick zu behalten.

Es gibt zwar dedizierte Plattformen, die für diese Herausforderungen entwickelt wurden, aber die charmante Idee hinter der vorgestellten Infrastruktur ist, dass sie nur aus einem einzigen Einstiegspunkt für Data Science-, MLOps- und Devops-Teams besteht und in hohem Maße erweiterbar ist. Benedikt Müller Benedikt Müller

Schaffe Mehrwert für Deine Data Science Projekte

Data Science und datengetriebene Entscheidungen sind für viele Unternehmen zu einem zentralen Bestandteil ihres Tagesgeschäfts geworden, der in den kommenden Jahren nur noch an Wichtigkeit zunehmen wird. Bis Ende 2022 werden viele Unternehmen eine Cloud-Strategie eingeführt haben:

„70 % der Unternehmen werden bis 2022 über eine formale Cloud-Strategie verfügen, und diejenigen, die diese nicht einführen, werden es schwer haben.“
– Gartner-Forschung

Dadurch, dass sich Cloud-Technologien zu einem Grundbaustein in allen Arten von Unternehmen entwickeln, werden sie auch immer leichter verfügbar. Dies senkt die Einstiegshürde für die Entwicklung Cloud-nativer Anwendungen.

In diesem Blogeintrag werden wir uns damit beschäftigen, wie und warum wir Data Science Projekte am besten in der Cloud durchführen. Ich gebe einen Überblick über die erforderlichen Schritte, um ein Data Science Projekt in die Cloud zu verlagern, und gebe einige Best Practices aus meiner eigenen Erfahrung weiter, um häufige Fallstricke zu vermeiden.

Ich erörtere keine spezifischen Lösungsmuster für einzelne Cloud-Anbieter, stelle keine Vergleiche auf und gehe auch nicht im Detail auf Best Practices für Machine Learning und DevOps ein.

Data Science Projekte profitieren von der Nutzung öffentlicher Cloud-Dienste

Ein gängiger Ansatz für Data Science Projekte besteht darin, zunächst lokal Daten zu bearbeiten und Modelle auf Snapshot-basierten Daten zu trainieren und auszuwerten. Dies hilft in einem frühen Stadium Schritt zu halten, solange noch unklar ist, ob Machine Learning das identifizierte Problem überhaupt lösen kann. Nach der Erstellung einer ersten Modellversion, die den Anforderungen des Unternehmens entspricht, soll das Modell eingesetzt werden und somit Mehrwert schaffen.

Zum Einsatz eines Modells in Produktion gibt es normalerweise zwei Möglichkeiten: 1) Einsatz des Modells in einer on-premises Infrastruktur oder 2) Einsatz des Modells in einer Cloud-Umgebung bei einem Cloud-Anbieter Deiner Wahl. Die lokale Bereitstellung des Modells on-premises mag zunächst verlockend klingen, und es gibt Fälle, in denen dies eine umsetzbare Option ist. Allerdings können die Kosten für den Aufbau und die Wartung einer Data Science-spezifischen Infrastruktur recht hoch sein. Dies resultiert aus den unterschiedlichen Anforderungen, die von spezifischer Hardware über die Bewältigung von Spitzenbelastung während Trainingsphasen bis hin zu zusätzlichen, voneinander abhängigen Softwarekomponenten reichen.

Verschiedene Cloud-Konfigurationen bieten unterschiedliche Freiheitsgrade

Bei der Nutzung der Cloud wird zwischen «Infrastructure as a Service» (IaaS), «Container as a Service» (CaaS), «Platform as a Service» (PaaS) und «Software as a Service» (SaaS) unterschieden, wobei man in der Regel Flexibilität gegen Wartungsfreundlichkeit tauscht. Die folgende Abbildung veranschaulicht die Unterschiedlichen Abdeckungen auf den einzelnen Serviceebenen.

  • «On-Premises» musst Du dich um alles selbst kümmern: Bestellung und Einrichtung der erforderlichen Hardware, Einrichtung Deiner Datenpipeline und Entwicklung, Ausführung und Überwachung Deiner Anwendungen.
  • Bei «Infrastructure as a Service» kümmert sich der Anbieter um die Hardwarekomponenten und liefert eine virtuelle Maschine mit einer festen Version eines Betriebssystems (OS).
  • Bei «Containers as a Service» bietet der Anbieter eine Container-Plattform und eine Orchestrierungslösung an. Du kannst Container-Images aus einer öffentlichen Registry verwenden, diese anpassen oder eigene Container erstellen.
  • Bei «Platform as a Service»-Diensten musst Du in der Regel nur noch Deine Daten einbringen, um mit der Entwicklung Deiner Anwendung loszulegen. Falls es sich um eine serverlose Lösung handelt, sind auch keine Annahmen zur Servergröße nötig.
  • «Software as a Service»-Lösungen als höchstes Service-Level sind auf einen bestimmten Zweck zugeschnitten und beinhalten einen sehr geringen Aufwand für Einrichtung und Wartung. Dafür bieten sie aber nur eine stark begrenzte Flexibilität, denn neue Funktionen müssen in der Regel beim Anbieter angefordert werden.

Öffentliche Cloud-Dienste sind bereits auf die Bedürfnisse von Data Science Projekten zugeschnitten

Zu den Vorteilen der Public-Cloud gehören Skalierbarkeit, Entkopplung von Ressourcen und Pay-as-you-go-Modelle. Diese Vorteile sind bereits ein Plus für Data Science Anwendungen, z. B. für die Skalierung von Ressourcen für den Trainingsprozess. Darüber hinaus haben alle drei großen Cloud-Anbieter einen Teil ihres Servicekatalogs auf Data Science Anwendungen zugeschnitten, jeder von ihnen mit seinen eigenen Stärken und Schwächen.

Dazu gehören nicht nur spezielle Hardware wie GPUs, sondern auch integrierte Lösungen für ML-Operationen wie automatisierte Bereitstellungen, Modellregistrierungen und die Überwachung von Modellleistung und Datendrift. Viele neue Funktionen werden ständig entwickelt und zur Verfügung gestellt. Um mit diesen Innovationen und Funktionen on-premises Schritt zu halten, musst Du eine beträchtliche Anzahl von Ressourcen aufwenden, ohne dass sich dies direkt auf Dein Geschäft auswirkt.

Wenn Du an einer ausführlichen Diskussion über die Bedeutung der Cloud für den Erfolg von KI-Projekten interessiert bist, dann schau Dir doch dieses White Paper auf dem statworx Content Hub an.

Die Durchführung Deines Projekts in der Cloud erfolgt in nur 5 einfachen Schritten

Wenn Du mit der Nutzung der Cloud für Data Science Projekte beginnen möchtest, musst Du im Vorfeld einige wichtige Entscheidungen treffen und entsprechende Schritte unternehmen. Wir werden uns jeden dieser Schritte genauer ansehen.

1.    Auswahl der Cloud-Serviceebene

Bei der Wahl der Serviceebene sind die gängigsten Muster für Data-Science-Anwendungen CaaS oder PaaS. Der Grund dafür ist, dass «Infrastructure as a Service» hohe Kosten verursachen kann, die aus der Wartung virtueller Maschinen oder dem Aufbau von Skalierbarkeit über VMs hinweg resultieren. SaaS-Dienste hingegen sind bereits auf ein bestimmtes Geschäftsproblem zugeschnitten und sind einfach in Betrieb zu nehmen, anstatt ein eigenes Modell und eine eigene Anwendung zu entwickeln.

CaaS bietet den Hauptvorteil, dass Container auf jeder Containerplattform eines beliebigen Anbieters bereitgestellt werden können. Und wenn die Anwendung nicht nur aus dem Machine Learning Modell besteht, sondern zusätzliche Mikrodienste oder Front-End-Komponenten benötigt, können diese alle mit CaaS gehostet werden. Der Nachteil ist, dass, ähnlich wie bei einer On-Premises-Einführung, Container-Images für MLops-Tools wie Model Registry, Pipelines und Modell-Performance-Monitoring nicht standardmäßig verfügbar sind und mit der Anwendung erstellt und integriert werden müssen. Je größer die Anzahl der verwendeten Tools und Bibliotheken ist, desto höher ist die Wahrscheinlichkeit, dass künftige Versionen irgendwann Inkompatibilitäten aufweisen oder sogar überhaupt nicht mehr zusammenpassen.

PaaS-Dienste wie Azure Machine Learning, Google Vertex AI oder Amazon SageMaker hingegen haben all diese Funktionalitäten bereits integriert. Der Nachteil dieser Dienste ist, dass sie alle mit komplexen Kostenstrukturen einhergehen und spezifisch für den jeweiligen Cloud-Anbieter sind. Je nach Projektanforderungen können sich die PaaS-Dienste in einigen speziellen Fällen als zu restriktiv erweisen.

Beim Vergleich von CaaS und PaaS geht es meist um den Kompromiss zwischen Flexibilität und einem höheren Grad an Anbieterbindung. Eine stärkere Bindung an den Anbieter ist mit einem Aufpreis verbunden, der für die enthaltenen Funktionen, die größere Kompatibilität und die höhere Entwicklungsgeschwindigkeit zu entrichten ist. Eine höhere Flexibilität wiederum geht mit einem höheren Integrations- und Wartungsaufwand einher.

2.    Daten in der Cloud verfügbar machen

In der Regel besteht der erste Schritt zur Bereitstellung Deiner Daten darin, einen Schnappschuss der Daten in einen Cloud-Objektspeicher hochzuladen. Diese sind gut mit anderen Diensten integriert und können später mit geringem Aufwand durch eine geeignetere Datenspeicherlösung ersetzt werden. Sobald die Ergebnisse des Machine Learning Modells aus geschäftlicher Sicht geeignet sind, sollten Data Engineers einen Prozess einrichten, um Deine Daten automatisch auf dem neuesten Stand zu halten.

3.    Aufbau einer Pipeline für die Vorverarbeitung

Ein entscheidender Schritt bei jedem Data Science Projekt ist der Aufbau einer robusten Pipeline für die Datenvorverarbeitung. Dadurch wird sichergestellt, dass Deine Daten sauber und bereit für die Modellierung sind, was Dir auf lange Sicht Zeit und Mühe erspart. Ein bewährtes Verfahren ist die Einrichtung einer CICD-Pipeline (Continuous Integration and Continuous Delivery), um die Bereitstellung und das Testen Deiner Vorverarbeitung zu automatisieren und sie in Deinen DevOps-Zyklus einzubinden. Die Cloud hilft Dir, Deine Pipelines automatisch zu skalieren, um jede für das Training Deines Modells benötigte Datenmenge zu bewältigen.

4.    Training und Evaluierung des Modells

In dieser Phase wird die Preprocessing-Pipeline durch Hinzufügen von Modellierungskomponenten erweitert. Dazu gehört auch die Abstimmung von Hyperparametern, die wiederum von Cloud-Diensten durch die Skalierung von Ressourcen und die Speicherung der Ergebnisse der einzelnen Trainingsexperimente zum leichteren Vergleich unterstützt wird. Alle Cloud-Anbieter bieten einen automatisierten Dienst für Machine Learning an. Dieser kann entweder genutzt werden, um schnell die erste Version eines Modells zu erstellen und die Leistung mit den Daten über mehrere Modelltypen hinweg zu vergleichen. Auf diese Weise kannst Du schnell beurteilen, ob die Daten und die Vorverarbeitung ausreichen, um das Geschäftsproblem zu lösen. Außerdem kann das Ergebnis als Benchmark für Data Scientists verwendet werden. Das beste Modell sollte in einer Modellregistrierung gespeichert werden, damit es einsatzbereit und transparent ist.

Falls ein Modell bereits lokal oder on-premises trainiert wurde, ist es möglich, das Training zu überspringen und das Modell einfach in die Modellregistrierung zu laden.

5.   Bereitstellung des Modells für die Business Unit

Der letzte und wahrscheinlich wichtigste Schritt ist die Bereitstellung des Modells für Deine Business Unit, damit diese einen Nutzen daraus ziehen kann. Alle Cloud-Anbieter bieten Lösungen an, um das Modell mit geringem Aufwand skalierbar bereitzustellen. Schließlich werden alle Teile, die in den früheren Schritten von der automatischen Bereitstellung der neuesten Daten über die Anwendung der Vorverarbeitung und die Einspeisung der Daten in das bereitgestellte Modell erstellt wurden, zusammengeführt.

Jetzt haben wir die einzelnen Schritte für das Onboarding Deines Data Science Projekts durchlaufen. Mit diesen 5 Schritten bist Du auf dem besten Weg, Deinen Data-Science-Workflow in die Cloud zu verlagern. Um einige der üblichen Fallstricke zu vermeiden, möchte ich hier einige Erkenntnisse aus meinen persönlichen Erfahrungen weitergeben, die sich positiv auf den Erfolg Deines Projekts auswirken können.

Erleichtere Dir den Umstieg auf die Cloud mit diesen nützlichen Tipps

Beginne frühzeitig mit der Nutzung der Cloud.

Wenn Du früh damit beginnst, kann sich Dein Team mit den Funktionen der Plattform vertraut machen. Auf diese Weise kannst Du die Möglichkeiten der Plattform optimal nutzen und potenzielle Probleme und umfangreiche Umstrukturierungen vermeiden.

Stelle sicher, dass Deine Daten zugänglich sind.

Dies mag selbstverständlich erscheinen, aber es ist wichtig, dass Deine Daten beim Wechsel in die Cloud leicht zugänglich sind. Dies gilt insbesondere dann, wenn Du Deine Daten lokal generierst und anschliessend in die Cloud übertragen musst.

Erwäge den Einsatz von serverlosem Computing.

Serverless Computing ist eine großartige Option für Data Science Projekte, da es Dir ermöglicht, Deine Ressourcen nach Bedarf zu skalieren, ohne dass Du Server bereitstellen oder verwalten musst.

Vergiss nicht die Sicherheit.

Zwar bieten alle Cloud-Anbieter einige der modernsten IT-Sicherheitseinrichtungen an, doch einige davon sind bei der Konfiguration leicht zu übersehen und können Dein Projekt einem unnötigen Risiko aussetzen.

Überwache Deine Cloud-Kosten.

Bei der Optimierung von on-premises Lösungen geht es oft um die Spitzenauslastung von Ressourcen, da Hardware oder Lizenzen begrenzt sind. Mit Skalierbarkeit und Pay-as-you-go verschiebt sich dieses Paradigma stärker in Richtung Kostenoptimierung. Die Kostenoptimierung ist in der Regel nicht die erste Maßnahme, die man zu Beginn eines Projekts ergreift, aber wenn man die Kosten im Auge behält, können unangenehme Überraschungen vermeiden und die Cloud-Anwendung zu einem späteren Zeitpunkt noch kosteneffizienter gestalten werden.

Lass Deine Data Science Projekte mit der Cloud abheben

Wenn Du Dein nächstes Data Science Projekt in Angriff nimmst, ist die frühzeitige Nutzung der Cloud eine gute Option. Die Cloud ist skalierbar, flexibel und bietet eine Vielzahl von Diensten, mit denen Du das Beste aus Deinem Projekt herausholen kannst. Cloud-basierte Architekturen sind eine moderne Art der Anwendungsentwicklung, die in Zukunft noch mehr an Bedeutung gewinnen wird.

Wenn Du die vorgestellten Schritte befolgst, wirst Du auf diesem Weg unterstützt und kannst mit neusten Trends und Entwicklungen Schritt halten. Außerdem kannst Du mit meinen Tipps viele der üblichen Fallstricke vermeiden, die oft auf diesem Weg auftreten. Wenn Du also nach einer Möglichkeit suchst, das Beste aus Deinem Data Science Projekt herauszuholen, ist die Cloud definitiv eine Überlegung wert. Alexander Broska Alexander Broska Alexander Broska Alexander Broska

Be Safe!

Im Zeitalter der Open-Source-Softwareprojekte sind Angriffe auf verwundbare Software allgegenwärtig. Python ist die beliebteste Sprache für Data Science und Engineering und wird daher zunehmend zum Ziel von Angriffen durch bösartige Bibliotheken. Außerdem können öffentlich zugängliche Anwendungen durch Angriffe auf Schwachstellen im Quellcode ausgenutzt werden.

Aus diesem Grund ist es wichtig, dass Dein Code keine CVEs (Common Vulnerabilities and Exposures) enthält oder andere Bibliotheken verwendet, die bösartig sein könnten. Das gilt besonders, wenn es sich um öffentlich zugängliche Software handelt, z. B. eine Webanwendung. Bei statworx suchen wir nach Möglichkeiten, die Qualität unseres Codes durch den Einsatz automatischer Scan-Tools zu verbessern. Deshalb besprechen wir den Wert von zwei Code- und Paketscannern für Python.

Automatische Überprüfung

Es gibt zahlreiche Tools zum Scannen von Code und seinen Abhängigkeiten. Hier werde ich einen Überblick über die beliebtesten Tools geben, die speziell für Python entwickelt wurden. Solche Tools fallen in eine von zwei Kategorien:

  • Statische Anwendungssicherheitstests (SAST): suchen nach Schwachstellen im Code und verwundbaren Paketen
  • Dynamische Anwendungssicherheitstests (DAST): suchen nach Schwachstellen, die während der Laufzeit auftreten

Im Folgenden werde ich bandit und safety anhand einer kleinen, von mir entwickelten streamlit-Anwendung vergleichen. Beide Tools fallen in die Kategorie SAST, da sie die Anwendung nicht laufen lassen müssen, um ihre Prüfungen durchzuführen. Dynamische Anwendungstests sind komplizierter und werden vielleicht in einem späteren Beitrag behandelt.

Die Anwendung

Um den Zusammenhang zu verdeutlichen, hier eine kurze Beschreibung der Anwendung: Sie wurde entwickelt, um die Konvergenz (oder deren Fehlen) in den Stichprobenverteilungen von Zufallsvariablen zu visualisieren, die aus verschiedenen theoretischen Wahrscheinlichkeitsverteilungen gezogen wurden. Die Nutzer:innen können die Verteilung (z. B. Log-Normal) auswählen, die maximale Anzahl der Stichproben festlegen und verschiedene Stichprobenstatistiken (z. B. Mittelwert, Standardabweichung usw.) auswählen.

Bandit

Bandit ist ein quelloffener Python-Code-Scanner, der nach Schwachstellen im Deinem Code – und nur in Deinem Code – sucht. Er zerlegt den Code in seinen abstrakten Syntaxbaum und führt Plugins gegen diesen aus, um auf bekannte Schwachstellen zu prüfen. Neben anderen Tests prüft es einfachen SQL-Code, der eine Öffnung für SQL-Injektionen bieten könnte, im Code gespeicherte Passwörter und Hinweise auf häufige Angriffsmöglichkeiten wie die Verwendung der Bibliothek „Pickle“.

Bandit ist für die Verwendung mit CI/CD konzipiert und gibt einen Exit-Status von 1 aus, wenn es auf Probleme stößt, wodurch die Pipeline beendet wird. Es wird ein Bericht erstellt, der Informationen über die Anzahl der Probleme enthält, die nach Vertrauenswürdigkeit und Schweregrad in drei Stufen unterteilt sind: niedrig, mittel und hoch. In diesem Fall findet bandit keine offensichtlichen Sicherheitslücken in unserem Code.

Run started:2022-06-10 07:07:25.344619

Test results:
        No issues identified.

Code scanned:
        Total lines of code: 0
        Total lines skipped (#nosec): 0

Run metrics:
        Total issues (by severity):
                Undefined: 0
                Low: 0
                Medium: 0
                High: 0
        Total issues (by confidence):
                Undefined: 0
                Low: 0
                Medium: 0
                High: 0
Files skipped (0):

Umso wichtiger ist es, Bandit für die Verwendung in Deinem Projekt sorgfältig zu konfigurieren. Manchmal kann es eine Fehlermeldung auslösen, obwohl Du bereits weißt, dass dies zur Laufzeit kein Problem darstellen würde. Wenn Du zum Beispiel eine Reihe von Unit-Tests hast, die pytest verwenden und als Teil Deiner CI/CD-Pipeline laufen, wird Bandit normalerweise eine Fehlermeldung auslösen, da dieser Code die assert-Anweisung verwendet, die nicht für Code empfohlen wird, der nicht ohne das -O-Flag läuft.

Um dieses Verhalten zu vermeiden, kannst Du:

1. Scans gegen alle Dateien durchführen, aber den Test über die Befehlszeilenschnittstelle ausschließen.
2. eine Konfigurationsdatei yaml erstellen, um den Test auszuschließen.

Hier ist ein Beispiel:

# bandit_cfg.yml
skips: ["B101"] # skips the assert check

Dann können wir bandit wie folgt ausführen: bandit -c bandit_yml.cfg /path/to/python/files und die unnötigen Warnungen werden nicht auftauchen.

Safety

Entwickelt vom Team von pyup.io, läuft dieser Paketscanner gegen eine kuratierte Datenbank, die aus manuell überprüften Einträgen besteht, die auf öffentlich verfügbaren CVEs und Changelogs basieren. Das Paket ist für Python >= 3.5 verfügbar und kann kostenlos installiert werden. Standardmäßig verwendet es <a href="https://github.com/pyupio/safety-db">Safety DB</a>, die frei zugänglich ist. Pyup.io bietet auch bezahlten Zugang zu einer häufiger aktualisierten Datenbank.

Die Ausführung von safety check --full-report -r requirements.txt im Wurzelverzeichnis des Pakets gibt uns die folgende Ausgabe (aus Gründen der Lesbarkeit gekürzt):

+==============================================================================+
|                                                                              |
|                               /$$$$$$            /$$                         |
|                              /$$__  $$          | $$                         |
|           /$$$$$$$  /$$$$$$ | $$  \__//$$$$$$  /$$$$$$   /$$   /$$           |
|          /$$_____/ |____  $$| $$$$   /$$__  $$|_  $$_/  | $$  | $$           |
|         |  $$$$$$   /$$$$$$$| $$_/  | $$$$$$$$  | $$    | $$  | $$           |
|          \____  $$ /$$__  $$| $$    | $$_____/  | $$ /$$| $$  | $$           |
|          /$$$$$$$/|  $$$$$$$| $$    |  $$$$$$$  |  $$$$/|  $$$$$$$           |
|         |_______/  \_______/|__/     \_______/   \___/   \____  $$           |
|                                                          /$$  | $$           |
|                                                         |  $$$$$$/           |
|  by pyup.io                                              \______/            |
|                                                                              |
+==============================================================================+
| REPORT                                                                       |
| checked 110 packages, using free DB (updated once a month)                   |
+============================+===========+==========================+==========+
| package                    | installed | affected                 | ID       |
+============================+===========+==========================+==========+
| urllib3                    | 1.26.4    | <1.26.5                  | 43975    |
+==============================================================================+
| Urllib3 1.26.5 includes a fix for CVE-2021-33503: An issue was discovered in |
| urllib3 before 1.26.5. When provided with a URL containing many @ characters |
| in the authority component, the authority regular expression exhibits        |
| catastrophic backtracking, causing a denial of service if a URL were passed  |
| as a parameter or redirected to via an HTTP redirect.                        |
| https://github.com/advisories/GHSA-q2q7-5pp4-w6pg                            |
+==============================================================================+

Der Bericht enthält die Anzahl der überprüften Pakete, die Art der als Referenz verwendeten Datenbank und Informationen über jede gefundene Schwachstelle. In diesem Beispiel ist eine ältere Version des Pakets urllib3 von einer Schwachstelle betroffen, die technisch gesehen von einem Angreifer für einen Denial-of-Service-Angriff genutzt werden könnte.

Integration in den Workflow

Sowohl bandit als auch safety sind als GitHub Actions verfügbar. Die stabile Version von safety bietet auch Integrationen für TravisCI und GitLab CI/CD.

Natürlich kannst Du beide Pakete immer manuell von PyPI auf Deinem Runner installieren, wenn keine fertige Integration wie eine GitHub Actions verfügbar ist. Da beide Programme von der Kommandozeile aus verwendet werden können, kannst Du sie auch lokal in einen Pre-Commit-Hook integrieren, wenn die Verwendung auf Deiner CI/CD-Plattform nicht in Frage kommt.

Die CI/CD-Pipeline für die obige Anwendung wurde mit GitHub Actions erstellt. Nach der Installation der erforderlichen Pakete der Anwendung wird zuerst bandit und dann safety ausgeführt, um alle Pakete zu scannen. Wenn alle Pakete aktualisiert sind, werden die Schwachstellen-Scans bestanden und das Docker-Image wird erstellt.

Package check Code Check

Fazit

Ich würde dringend empfehlen, sowohl bandit als auch safety in Deiner CI/CD-Pipeline zu verwenden, da sie Sicherheitsüberprüfungen für Deinen Code und Deine Abhängigkeiten bieten. Bei modernen Anwendungen ist die manuelle Überprüfung jedes einzelnen Pakets, von dem Deine Anwendung abhängt, einfach nicht machbar, ganz zu schweigen von all den Abhängigkeiten, die diese Pakete haben! Daher ist automatisiertes Scannen unumgänglich, wenn Du ein gewisses Maß an Bewusstsein darüber haben willst, wie unsicher Dein Code ist.

Während bandit Deinen Code auf bekannte Exploits untersucht, prüft es keine der in Deinem Projekt verwendeten Bibliotheken. Hierfür benötigen Sie safety, da es die bekannten Sicherheitslücken in den Bibliotheken, von denen die Anwendung abhängt, aufzeigt. Zwar sind beide Frameworks nicht völlig idiotensicher, aber es ist immer noch besser, über einige CVEs informiert zu werden als über gar keine. Auf diese Weise kannst Du entweder Deinen anfälligen Code korrigieren oder eine anfällige Paketabhängigkeit auf eine sicherere Version aktualisieren.

Wenn Du Deinen Code sicher und Deine Abhängigkeiten vertrauenswürdig hältst, kannst Du potenziell verheerende Angriffe auf Deine Anwendung abwehren. Thomas Alcock Thomas Alcock Thomas Alcock Thomas Alcock Thomas Alcock Thomas Alcock Thomas Alcock Thomas Alcock Thomas Alcock Thomas Alcock Thomas Alcock Thomas Alcock Thomas Alcock

Bei all dem Hype um KI in den letzten Jahren darf man nicht außer Acht lassen, dass ein Großteil der Unternehmen bei der erfolgreichen Implementierung von KI-basierten Anwendungen noch hinterherhinken. Dies ist gerade in vielen Industrien, wie z.B. in produzierenden Gewerben, recht offensichtlich (McKinsey).

Eine von Accenture 2019 durchgeführte Studie zum Thema Implementierung von KI in Unternehmungen zeigt, dass über 80% aller Proof of Concepts (PoCs) es nicht in Produktion schaffen. Außerdem gaben nur 5% aller befragten Unternehmen an, eine unternehmensweite KI-Strategie implementiert zu haben.

Diese Erkenntnisse regen zum Nachdenken an: Was genau läuft schief und warum schafft künstliche Intelligenz anscheinend noch nicht die ganzheitliche Transition von erfolgreichen, akademischen Studien zu der realen Welt?

1. Was ist data-centric AI?

„Data-centric AI is the discipline of systematically engineering the data used to build an AI system.“
Zitat von Andrew Ng, data-centric AI Pionier

Der data-centric Ansatz fokussiert sich auf eine stärkere Daten-integrierenden KI (data-first) und weniger auf eine Konzentration auf Modelle (model-first), um die Schwierigkeiten von KI mit der „Realität“ zu bewältigen. Denn, die Trainingsdaten, die meist bei Unternehmen als Ausgangspunkt eines KI-Projekts stehen, haben relativ wenig gemeinsam mit den akribisch kurierten und weit verbreiteten Benchmark Datensets wie MNIST oder ImageNet.

Das Ziel dieses Artikels ist, data-centric im KI-Workflow und Projektkontext einzuordnen, Theorien sowie relevante Frameworks vorzustellen und aufzuzeigen, wie wir bei statworx eine data-first KI-Implementierung angehen.

2. Welche Gedankengänge stecken hinter data-centric?

Vereinfacht dargestellt bestehen KI-Systeme aus zwei entscheidenden Komponenten: Daten und Modell(-Code). Data-centric fokussiert sich mehr auf die Daten, model-centric auf das Modell – duh!

Bei einer stark model-centric lastigen KI werden Daten als ein extrinsischer, statischer Parameter behandelt. Der iterative Prozess eines Data Science Projekts startet praktisch erst nach dem Erhalt der Daten bei den Modell-spezifischen Schritten, wie Feature Engineering, aber vor allem exzessives Trainieren und Fine tunen verschiedener Modellarchitekturen. Dies macht meist das Gros der Zeit aus, das Data Scientists an einem Projekt aufwenden. Kleinere Daten-Aufbereitungsschritte werden meist nur einmalig, ad-hoc am Anfang eines Projekts angegangen.

Model Centric Grafik

Im Gegensatz dazu versucht data-centric (automatisierte) Datenprozesse als zentralen Teil jedes ML Projekts zu etablieren. Hierunter fallen alle Schritte die ausgehend von den Rohdaten nötig sind, um ein fertiges Trainingsset zu generieren. Durch diese Internalisierung soll eine methodische Überwachbarkeit für verbesserte Qualität sorgen.

Data Centric Grafik

Man kann dabei data-centric Überlegungen in drei übergeordnete Kategorien zusammenfassen. Diese beschreiben lose, welche Aufgabenbereiche bei einem data-centric Ansatz bedacht werden sollten. Im Folgenden wurde versucht, diese bekannte Buzzwords, die im Kontext von data-centric immer wieder auftauchen, thematisch einer Kategorie zuzuordnen.

2.1. Integration von SMEs in den Development Prozess als wichtiges Bindeglied zwischen Data- und Model-Knowledge.

Die Einbindung von Domain Knowledge ist ein integraler Bestandteil von data-centric. Dies hilft Projektteams besser zusammenwachsen zu lassen und so das Wissen der Expert:innen, auch Subject Matter Experts (SMEs) genannt, bestmöglich im KI-Prozess zu integrieren.

  • Data Profiling:
    Data Scientists sollten nicht als Alleinkämpfer:innen die Daten analysieren und nur ihre Befunde mit den SMEs teilen. Data Scientists können ihre statistischen und programmatischen Fähigkeiten gezielt einsetzen, um SMEs zu befähigen, die Daten eigenständig zu untersuchen und auszuwerten.
  • Human-in-the-loop Daten & Model Monitoring:
    Ähnlich wie beim Profiling soll hierbei durch das Bereitstellen eines Einstiegpunktes gewährleistet werden, das SMEs Zugang zu den relevanten Komponenten des KI-Systems erhalten. Von diesem zentralen Checkpoint können nicht nur Daten sondern auch Modell-relevante Metriken überwacht werden oder Beispiele visualisiert und gecheckt werden. Gleichzeit gewährt ein umfängliches Monitoring die Möglichkeit, nicht nur Fehler zu erkennen, sondern auch die Ursachen zu untersuchen und das möglichst ohne notwendige Programmierkenntnisse.

2.2. Datenqualitätsmanagement als agiler, automatisierter und iterativer Prozess über (Trainings-)Daten

Die Datenaufbereitung wird als Prozess verstanden, dessen kontinuierliche Verbesserung im Vordergrund eines Data Science Projekts stehen sollte. Das Modell, anders als bisher, sollte hingegen erstmal als (relativ) fixer Parameter behandelt werden.

  • Data Catalogue, Lineage & Validation:
    Die Dokumentation der Daten sollte ebenfalls keine extrinsische Aufgabe sein, die oft nur gegen Ende eines Projekts ad-hoc entsteht und bei jeder Änderung, z.B. eines Modellfeatures, wieder obsolet sein könnte. Änderungen sollen dynamisch reflektiert werden und so die Dokumentation automatisieren. Data Catalogue Frameworks bieten hier die Möglichkeit, Datensätze mit Meta-Informationen anzureichern.
    Data Lineage soll im Weiteren dabei unterstützen, bei diversen Inputdaten, verschiedenen Transformations- und Konsolidierungsschritten zwischen roh- und finalem Datenlayer den Überblick zu behalten. Je komplexer ein Datenmodell, desto eher kann ein Lineage Graph Auskunft über das Entstehen der finalen Spalten geben (Grafik unten), beispielsweise ob und wie Filterungen oder bestimmte join Logiken benutzt wurden. Die Validierung (neuer) Daten hilft schließlich eine konsistente Datengrundlage zu gewährleisten. Hier helfen die Kenntnisse aus dem Data Profiling um Validierungsregeln auszuarbeiten und im Prozess zu integrieren.

Lineage Graph

  • Data & Label Cleaning:
    Die Notwendigkeit der Datenaufbereitung ist selbsterklärend und als Best Practice ein fester Bestandteil in jedem KI-Projekt. Eine Label-Aufbereitung ist zwar nur bei Klassifikations-Algorithmen relevant, wird aber hier selten als wichtiger pre-processing Schritt mitbedacht. Aufbereitungen können aber mit Hilfe von Machine Learning automatisiert werden. Falsche Labels können es nämlich für Modelle erschweren, exakte patterns zu erlernen.
    Auch sollte man sich bewusst machen, dass solange sich die Trainingsdaten ändern, die Datenaufbereitung kein vollkommen abgeschlossener Prozess sein kann. Neue Daten bedeuten oft auch neue Cleaning-Schritte.
  • Data Drifts in Produktion:
    Eine weit verbreitete Schwachstelle von KI-Applikationen tritt meist dann auf, wenn sich Daten nicht so präsentieren, wie es beim Trainieren der Fall war, beispielweise im Zeitverlauf ändern (Data Drifts). Um die Güte von ML Modellen auch langfristig zu gewährleisten, müssen Daten in Produktion kontinuierlich überwacht werden. Hierdurch können Data Drifts frühzeitig ausfindig gemacht werden, um dann Modelle neu auszurichten, wenn z.B. bestimmte Inputvariablen von ihrer ursprünglichen Verteilung zu stark abweichen.
  • Data Versioning:
    GitHub ist seit Jahren der go to Standard für Code Versionierungen, um mehr Übersicht und Kontrolle zwischen Codeständen zu haben. Aber auch Daten können versioniert werden und so eine ganzheitliche Prozesskontrolle bieten. Ebenfalls können so Code- mit Datenständen verknüpft werden. Dies sorgt nicht nur für bessere Überwachbarkeit, sondern hilft auch dabei, automatisierte Prozesse anzustoßen.

Data/Code Versionierung Grafik

2.3. Generieren von Trainingsdatensätzen als programmatischer Task.

Gerade das Erzeugen von (gelabelten) Trainingsdaten ist einer der größten Roadblocker für viele KI-Projekte. Gerade bei komplexen Problemen, die große Datensätze benötigen, ist der initiale, manuelle Aufwand enorm.

  • Data Augmentation:
    Bei vielen datenintensiven Deep Learning Modellen wird diese Technik schon seit längerem eingesetzt, um mit bestehenden Daten, artifizielle Daten zu erzeugen. Bei Bilddaten ist dies recht anschaulich erklärbar. Hier werden beispielsweise durch Drehen eines Bildes verschiedene Perspektiven desselben Objektes erzeugt. Aber auch bei NLP und bei „tabularen“ Daten (Excel und Co.) gibt es Möglichkeiten neue Datenpunkte zu erzeugen.

Data Augmentation Grafik

  • Automated Data Labeling:
    Normalerweise ist Labeling ein sehr arbeitsintensiver Schritt, in dem Menschen Datenpunkte einer vordefinierten Kategorie zuordnen. Einerseits ist dadurch der initiale Aufwand (Kosten) sehr hoch, andererseits fehleranfällig und schwierig zu überwachen. Hier kann ML durch Konzepte wie semi- oder weak supervison Automatisierungshilfe leisten, was den manuellen Aufwand erheblich reduziert.
  • Data Selection:
    Arbeiten mit großen Datensätzen sind im lokalen Trainingskontext schwierig zu handhaben. Gerade dann, wenn diese nicht mehr in den Arbeitsspeicher des Laptops passen. Und selbst wenn, dann dauern Trainingsläufe meist sehr lange. Data Selection versucht die Größe durch ein aktives Subsampling (ob gelabelt oder ungelabelt) zu reduzieren. Aktiv werden hier die „besten“ Beispiele mit der höchsten Vielfalt und Repräsentativität ausgewählt, um die bestmögliche Charakterisierung des Inputs zu gewährleisten – und das automatisiert.

Selbstverständlich ist es nicht in jedem KI-Projekt sinnvoll, alle aufgeführten Frameworks zu bedenken. Es ist Aufgabe eines jedes Development Teams, die nötigen Tools und Schritte im data-centric Kontext zu analysieren und auf Relevanz und Übertragbarkeit zu prüfen. Hier spielen neben datenseitigen Überlegungen auch Business Faktoren eine Hauptrolle, da neue Tools meist auch mehr Projektkomplexität bedeuten.

3. Integration von data-centric bei statworx

Data-centric Überlegungen spielen bei unseren Projekten gerade in der Übergangsphase zwischen PoC und Produktivstellen des Modells vermehrt eine führende Rolle. Denn auch in einigen unserer Projekte ist es schon vorgekommen, dass man nach erfolgreichem PoC mit verschiedenen datenspezifischen Problemen zu kämpfen hatte; meist hervorgerufen durch unzureichende Dokumentation und Validierung der Inputdaten oder ungenügende Integration von SMEs im Datenprozess und Profiling.

Generell versuchen wir daher unseren Kunden die Wichtigkeit des Datenmanagements für die Langlebigkeit und Robustheit von KI-Produkten in Produktion aufzuzeigen und wie hilfreiche Komponenten innerhalb einer KI-Pipeline verknüpft sind.

Gerade unser Data Onboarding – ein Mix aus Profiling, Catalogue, Lineage und Validation, integriert in ein Orchestrations-Framework – ermöglicht uns mit den oben genannten Problemen besser umzugehen und so hochwertigere KI-Produkte bei unseren Kunden zu integrieren.

Zusätzlich hilft dieses Framework dem ganzen Unternehmen, bisher ungenutzte, undokumentierte Datenquellen für verschiedene Use Cases (nicht nur KI) verfügbar zu machen. Dabei ist die enge Zusammenarbeit mit den SMEs auf Kundenseite essenziell, um so effektive und robuste Datenqualitäts-Checks zu implementieren. Die resultierenden Datentöpfe und -prozesse sind somit gut verstanden, sodass Validierungs-Errors vom Kunden verstanden und behoben werden können, was so zu einem langlebigen Einsatz des Service beiträgt.

Data & AI Pipeline von statworx Grafik

In einer abgespeckten, kundenspezifischen Data Onboarding Integration haben wir mit Hilfe verschiedener Open und Closed Source Tools eine für den Kunden einfach skalierbare und leicht verständliche Plattform geschaffen.

So haben wir beispielsweise Validationchecks mit Great Expectations (GE), einem Open Source Framework, umgesetzt. Dieses Tool bietet neben Python-basierter Integration diverser Tests auch eine Reporting Oberfläche, die nach jedem Durchlauf einen einfach verständlichen Einstiegspunkt in die Resultate bietet.

Data Validation Grafik

Diese Architektur kann dann in verschiedenen Kontexten laufen, ob in der Cloud, mit einem Closed Source Software wie Azure Data Factory oder on premises mit Open Source Tools wie Airflow – und kann um weitere Tools jederzeit ergänzt werden.

4. Data-centric im Status Quo von KI

Sowohl model- als auch data-centric beschreiben Handlungsansätze, wie man an ein KI-Projekt herangehen kann.

Model-centric ist in den letzten Jahren recht erwachsen geworden und es haben sich dadurch einige Best Practices in verschiedenen Bereichen entwickelt, auf denen viele Frameworks aufbauen.

Dies hat auch damit zu tun, dass in der akademischen Welt der Fokus sehr stark auf Modellarchitekturen und deren Weiterentwicklung lag (und noch liegt) und diese stark mit führenden KI-Unternehmen korreliert. Gerade im Bereich Computer Vision und Natural Langue Processing konnten kommerzialisierte Meta-Modelle, trainiert auf gigantischen Datensets, die Tür zu erfolgreichen KI Use Cases öffnen. Diese riesigen Modelle können auf kleineren Datenmengen für Endanwendungen gefinetuned werden, bekannt unter Transfer Learning.

Diese Entwicklung hilft allerdings nur einem Teil der gescheiterten Projekte, da gerade im Kontext von industriellen Projekten fehlende Kompatibilität oder Starrheit der Use Cases die Anwendungen von Meta-Modellen erschwert. Die Nicht-Starrheit findet sich häufig in maschinenlastigen Produktionsindustrien, wo sich das Umfeld, in dem Daten produziert werden, stetig ändert und sogar der Austausch einer einzelnen Maschine große Auswirkungen auf ein produktives KI-Modell haben kann. Wenn diese Problematik nicht richtig im KI-Prozess bedacht wurde, entsteht hier ein schwer kalkulierbares Risiko, auch bekannt unter Technical Debt [Quelle: https://proceedings.neurips.cc/paper/2015/file/86df7dcfd896fcaf2674f757a2463eba-Paper.pdf].

Zu guter Letzt stellen die Distributionen bei einigen Use Cases ein inhärentes Problem für ML dar. Modelle haben grundsätzlich Schwierigkeiten mit edge cases, sehr seltene und ungewöhnliche Beobachtungspunkte (die long tails [Quelle: https://medium.com/codex/machine-learning-the-long-tail-paradox-1cc647d4ba4b] einer Verteilung). Beispielweise ist es nicht ungewöhnlich, dass bei Fault Detection das Verhältnis von fehlerhaften zu einwandfreien Bauteilen eins zu mehreren Tausend beträgt. Die Abstraktionsfähigkeit bei ungesehenen, abseits der Norm liegenden Fehlern ist hier meist schlecht.

5. Schluss – Paradigmenwechsel in Sicht?

Diese Probleme zu bewältigen, ist zwar Teil des Versprechens von data-centric, aber präsentiert sich im Moment noch eher unausgereift.

Das lässt sich auch an der Verfügbarkeit und Maturität von Open Source Frameworks darlegen. Zwar gibt es schon vereinzelte, produktionsfertige Anwendungen, aber keine, die die verschiedenen Teilbereiche von data-centric zu vereinheitlichen versucht. Dies führt unweigerlich zu längeren, aufwendigeren und komplexeren KI-Projekten, was für viele Unternehmen eine erhebliche Hürde darstellt. Außerdem sind kaum Datenmetriken vorhanden, die Unternehmen ein Feedback geben, was sie denn genau gerade „verbessern“. Und zweitens, viele der Tools (bsp. Data Catalogue) haben einen eher indirekten, verteilten Nutzen.

Einige Start-ups, die diese Probleme angehen wollen, sind in den letzten Jahren entstanden. Dadurch, dass diese aber (ausschließlich) paid tier Software vermarkten, ist es eher undurchsichtig, inwiefern diese Produkte wirklich die breite Masse an Problemen von verschiedenen Use Cases abdecken können.

Obwohl die Aufführungen oben zeigen, dass Unternehmen generell noch weit entfernt sind von einer ganzheitlichen Integration von data-centric, wurden robuste Daten Strategien in der letzten Zeit immer wichtiger (wie wir bei statworx an unseren Projekten sehen konnten).

Mit vermehrtem akademischem Research in Daten Produkte wird sich dieser Trend sicherlich noch verstärken. Nicht nur weil dadurch neue, robustere Frameworks entstehen, sondern auch weil durch Uni-Absolvent:innen den Unternehmen mehr Wissen in diesem Gebiet zufließt.

Bild-Quellen:

Model-centric arch: eigene
Data-centric arch: eigene
Data lineage: https://www.researchgate.net/figure/Data-lineage-visualization-example-in-DW-environment-using-Sankey-diagram_fig7_329364764
Historisierung Code/Data: https://ardigen.com/7155/
Data Augmentation: https://medium.com/secure-and-private-ai-writing-challenge/data-augmentation-increases-accuracy-of-your-model-but-how-aa1913468722
Data & AI pipeline: eigene
Validieren mit GE: https://greatexpectations.io/blog/ge-data-warehouse/

 

Benedikt Müller Benedikt Müller Benedikt Müller Benedikt Müller Benedikt Müller Benedikt Müller Benedikt Müller Benedikt Müller

Wir bei statworx arbeiten viel mit R und verwenden oft die gleichen kleinen Hilfsfunktionen in unseren Projekten. Diese Funktionen erleichtern unseren Arbeitsalltag, indem sie sich-wiederholende Codeteile reduzieren oder Übersichten über unsere Projekte erstellen.

Um diese Funktionen innerhalb unserer Teams und auch mit anderen zu teilen, habe ich angefangen, sie zu sammeln und habe dann daraus ein R-Paket namens helfRlein erstellt. Neben der gemeinsamen Nutzung wollte ich auch einige Anwendungsfälle haben, um meine Fähigkeiten zur Fehlersuche und Optimierung zu verbessern. Mit der Zeit wuchs das Paket und es kamen immer mehr Funktionen zusammen. Beim letzten Mal habe ich jede Funktion als Teil eines Adventskalenders vorgestellt. Zum Start unserer neuen Website habe ich alle Funktionen in diesem Kalender zusammengefasst und werde jede aktuelle Funktion aus dem Paket helfRlein vorstellen.

Die meisten Funktionen wurden entwickelt, als es ein Problem gab und man eine einfache Lösung dafür brauchte. Zum Beispiel war der angezeigte Text zu lang und musste gekürzt werden (siehe evenstrings). Andere Funktionen existieren nur, um sich-wiederholende Aufgaben zu reduzieren – wie das Einlesen mehrerer Dateien des selben Typs (siehe read_files). Daher könnten diese Funktionen auch für Euch nützlich sein!

Um alle Funktionen im Detail zu erkunden, könnt Ihr unser GitHub besuchen. Wenn Ihr irgendwelche Vorschläge habt, schickt mir bitte eine E-Mail oder öffnet ein Issue auf GitHub!

1. char_replace

Dieser kleine Helfer ersetzt Sonderzeichen (wie z. B. den Umlaut „ä“) durch ihre Standardentsprechung (in diesem Fall „ae“). Es ist auch möglich, alle Zeichen in Kleinbuchstaben umzuwandeln, Leerzeichen zu entfernen oder Leerzeichen und Bindestriche durch Unterstriche zu ersetzen.

Schauen wir uns ein kleines Beispiel mit verschiedenen Settings an:

x <- " Élizàldë-González Strasse"
char_replace(x, to_lower = TRUE)
[1] "elizalde-gonzalez strasse"
char_replace(x, to_lower = TRUE, to_underscore = TRUE)
[1] "elizalde_gonzalez_strasse"
char_replace(x, to_lower = FALSE, rm_space = TRUE, rm_dash = TRUE)
[1] "ElizaldeGonzalezStrasse"

2. checkdir

Dieser kleine Helfer prüft einen gegebenen Ordnerpfad auf Existenz und erstellt ihn bei Bedarf.

checkdir(path = "testfolder/subfolder")

Intern gibt es nur eine einfache if-Anweisung, die die R-Basisfunktionen file.exists() und dir.create(). kombiniert.

3. clean_gc

Dieser kleine Helfer gibt den Speicher von unbenutzten Objekten frei. Nun, im Grunde ruft es einfach gc() ein paar Mal auf. Ich habe das vor einiger Zeit für ein Projekt benutzt, bei dem ich mit riesigen Datendateien gearbeitet habe. Obwohl wir das Glück hatten, einen großen Server mit 500 GB RAM zu haben, stießen wir bald an seine Grenzen. Da wir in der Regel mehrere Prozesse parallelisieren, mussten wir jedes Bit und jedes Byte des Arbeitsspeichers nutzen, das wir bekommen konnten. Anstatt also viele Zeilen wie diese zu haben:

gc();gc();gc();gc()

… habe ich clean_gc() der Einfachheit halber geschrieben. Intern wird gc() so lange aufgerufen, wie es Speicher gibt, der freigegeben werden muss.

Some further thoughts

Es gibt einige Diskussionen über den Garbage Collector gc() und seine Nützlichkeit. Wenn Ihr mehr darüber erfahren wollt, schlage ich vor, dass Ihr Euch die memory section in Advanced R anseht. Ich weiß, dass R selbst bei Bedarf Speicher freigibt, aber ich bin mir nicht sicher, was passiert, wenn Ihr mehrere R-Prozesse habt. Können sie den Speicher von anderen Prozessen leeren? Wenn Ihr dazu etwas mehr wisst, lasst es mich wissen!

4. count_na

Dieser kleine Helfer zählt fehlende Werte innerhalb eines Vektors.

x <- c(NA, NA, 1, NaN, 0)
count_na(x)
3

Intern gibt es nur ein einfaches sum(is.na(x)), das die NA-Werte zählt. Wenn Ihr den Mittelwert statt der Summe wollt, könnt Ihr prop = TRUE setzen.

5. evenstrings

Dieser kleine Helfer zerlegt eine gegebene Zeichenkette in kleinere Teile mit einer festen Länge. Aber warum? Nun, ich brauchte diese Funktion beim Erstellen eines Plots mit einem langen Titel. Der Text war zu lang für eine Zeile und anstatt ihn einfach abzuschneiden oder über die Ränder laufen zu lassen, wollte ich ihn schön trennen.

Bei einer langen Zeichenkette wie…

long_title <- c("Contains the months: January, February, March, April, May, June, July, August, September, October, November, December")

…wollen wir sie nach split = "," mit einer maximalen Länge von char = 60 aufteilen.

short_title <- evenstrings(long_title, split = ",", char = 60)

Die Funktion hat zwei mögliche Ausgabeformate, die durch Setzen von newlines = TRUE oder FALSE gewählt werden können:

  • eine Zeichenkette mit Zeilentrennzeichen \n
  • ein Vektor mit jedem Unterteil.

Ein anderer Anwendungsfall könnte eine Nachricht sein, die mit cat() auf der Konsole ausgegeben wird:

cat(long_title)
Contains the months: January, February, March, April, May, June, July, August, September, October, November, December
cat(short_title)
Contains the months: January, February, March, April, May,
 June, July, August, September, October, November, December

Code for plot example

p1 <- ggplot(data.frame(x = 1:10, y = 1:10),
  aes(x = x, y = y)) +
  geom_point() +
  ggtitle(long_title)

p2 <- ggplot(data.frame(x = 1:10, y = 1:10),
  aes(x = x, y = y)) +
  geom_point() +
  ggtitle(short_title)

multiplot(p1, p2)

6. get_files

Dieser kleine Helfer macht das Gleiche wie die „Find in files „ Suche in RStudio. Sie gibt einen Vektor mit allen Dateien in einem bestimmten Ordner zurück, die das Suchmuster enthalten. In Eurem täglichen Arbeitsablauf würdet Ihr normalerweise die Tastenkombination SHIFT+CTRL+F verwenden. Mit get_files() könnt Ihr diese Funktionen in Euren Skripten nutzen.

7. get_network

Das Ziel dieses kleinen Helfers ist es, die Verbindungen zwischen R-Funktionen innerhalb eines Projekts als Flussdiagramm zu visualisieren. Dazu ist die Eingabe ein Verzeichnispfad zur Funktion oder eine Liste mit den Funktionen und die Ausgaben sind eine Adjazenzmatrix und ein Graph-Objekt. Als Beispiel verwenden wir diesen Ordner mit einigen Spielzeugfunktionen:

net <- get_network(dir = "flowchart/R_network_functions/", simplify = FALSE)
g1 <- net$igraph

Input

Es gibt fünf Parameter, um mit der Funktion zu interagieren:

  • ein Pfad dir, der durchsucht werden soll.
  • ein Zeichenvektor Variationen mit der Definitionszeichenfolge der Funktion – die Vorgabe ist c(" <- function", "<- function", "<-function").
  • ein „Muster“, eine Zeichenkette mit dem Dateisuffix – die Vorgabe ist "\\.R$".
  • ein boolesches simplify, das Funktionen ohne Verbindungen aus der Darstellung entfernt.
  • eine benannte Liste all_scripts, die eine Alternative zu dir ist. Diese Liste wird hauptsächlich nur zu Testzwecken verwendet.

Für eine normale Verwendung sollte es ausreichen, einen Pfad zum Projektordner anzugeben.

Output

Der gegebene Plot zeigt die Verbindungen der einzelnen Funktionen (Pfeile) und auch die relative Größe des Funktionscodes (Größe der Punkte). Wie bereits erwähnt, besteht die Ausgabe aus einer Adjazenzmatrix und einem Graph-Objekt. Die Matrix enthält die Anzahl der Aufrufe für jede Funktion. Das Graph-Objekt hat die folgenden Eigenschaften:

  • Die Namen der Funktionen werden als Label verwendet.
  • Die Anzahl der Zeilen jeder Funktion (ohne Kommentare und Leerzeilen) wird als Größe gespeichert.
  • Der Ordnername des ersten Ordners im Verzeichnis.
  • Eine Farbe, die dem Ordner entspricht.

Mit diesen Eigenschaften können Sie die Netzwerkdarstellung zum Beispiel wie folgt verbessern:

library(igraph)

# create plots ------------------------------------------------------------
l <- layout_with_fr(g1)
colrs <- rainbow(length(unique(V(g1)$color)))

plot(g1,
     edge.arrow.size = .1,
     edge.width = 5*E(g1)$weight/max(E(g1)$weight),
     vertex.shape = "none",
     vertex.label.color = colrs[V(g1)$color],
     vertex.label.color = "black",
     vertex.size = 20,
     vertex.color = colrs[V(g1)$color],
     edge.color = "steelblue1",
     layout = l)
legend(x = 0,
       unique(V(g1)$folder), pch = 21,
       pt.bg = colrs[unique(V(g1)$color)],
       pt.cex = 2, cex = .8, bty = "n", ncol = 1)
 

example-network-helfRlein

8. get_sequence

Dieser kleine Helfer gibt Indizes von wiederkehrenden Mustern zurück. Es funktioniert sowohl mit Zahlen als auch mit Zeichen. Alles, was es braucht, ist ein Vektor mit den Daten, ein Muster, nach dem gesucht werden soll, und eine Mindestanzahl von Vorkommen.

Lasst uns mit dem folgenden Code einige Zeitreihendaten erstellen.

library(data.table)

# random seed
set.seed(20181221)

# number of observations
n <- 100

# simulationg the data
ts_data <- data.table(DAY = 1:n, CHANGE = sample(c(-1, 0, 1), n, replace = TRUE))
ts_data[, VALUE := cumsum(CHANGE)]

Dies ist nichts anderes als ein Random Walk, da wir zwischen dem Abstieg (-1), dem Anstieg (1) und dem Verbleib auf demselben Niveau (0) wählen. Unsere Zeitreihendaten sehen folgendermaßen aus:

Angenommen, wir wollen die Datumsbereiche wissen, in denen es an mindestens vier aufeinanderfolgenden Tagen keine Veränderung gab.

ts_data[, get_sequence(x = CHANGE, pattern = 0, minsize = 4)]
     min max
[1,]  45  48
[2,]  65  69

Wir können auch die Frage beantworten, ob sich das Muster „down-up-down-up“ irgendwo wiederholt:

ts_data[, get_sequence(x = CHANGE, pattern = c(-1,1), minsize = 2)]
     min max
[1,]  88  91

Mit diesen beiden Eingaben können wir unseren Plot ein wenig aktualisieren, indem wir etwas geom_rect hinzufügen!

Code for the plot

rect <- data.table(
  rbind(ts_data[, get_sequence(x = CHANGE, pattern = c(0), minsize = 4)],
        ts_data[, get_sequence(x = CHANGE, pattern = c(-1,1), minsize = 2)]),
  GROUP = c("no change","no change","down-up"))

ggplot(ts_data, aes(x = DAY, y = VALUE)) +
  geom_line() +
  geom_rect(data = rect,
  inherit.aes = FALSE,
  aes(xmin = min - 1,
  xmax = max,
  ymin = -Inf,
  ymax = Inf,
  group = GROUP,
  fill = GROUP),
  color = "transparent",
  alpha = 0.5) +
  scale_fill_manual(values = statworx_palette(number = 2, basecolors = c(2,5))) +
  theme_minimal()

9. intersect2

Dieser kleine Helfer gibt den Schnittpunkt mehrerer Vektoren oder Listen zurück. Ich habe diese Funktion hier gefunden, fand sie recht nützlich und habe sie ein wenig angepasst.

intersect2(list(c(1:3), c(1:4)), list(c(1:2),c(1:3)), c(1:2))
[1] 1 2

Intern wird das Problem, die Schnittmenge zu finden, rekursiv gelöst, wenn ein Element eine Liste ist, und dann schrittweise mit dem nächsten Element.

10. multiplot

Dieses kleine Hilfsmittel kombiniert mehrere ggplots zu einem Plot. Dies ist eine Funktion aus dem R-cookbook.

Ein Vorteil gegenüber facets ist, dass man nicht alle Daten für alle Plots in einem Objekt benötigt. Auch kann man jeden einzelnen Plot frei erstellen – was manchmal auch ein Nachteil sein kann.

Mit dem Parameter layout könnt Ihr mehrere Plots mit unterschiedlichen Größen anordnen. Nehmen wir an, Ihr habt drei Plots und wollt sie wie folgt anordnen:

1    2    2
1    2    2
3    3    3

Bei multiplot läuft es auf Folgendes hinaus:

multiplot(plotlist = list(p1, p2, p3),
          layout = matrix(c(1,2,2,1,2,2,3,3,3), nrow = 3, byrow = TRUE))

Code for plot example

# star coordinates
c1  =   cos((2*pi)/5)   
c2  =   cos(pi/5)
s1  =   sin((2*pi)/5)
s2  =   sin((4*pi)/5)

data_star <- data.table(X = c(0, -s2, s1, -s1, s2),
                        Y = c(1, -c2, c1, c1, -c2))

p1 <- ggplot(data_star, aes(x = X, y = Y)) +
  geom_polygon(fill = "gold") +
  theme_void()

# tree
set.seed(24122018)
n <- 10000
lambda <- 2
data_tree <- data.table(X = c(rpois(n, lambda), rpois(n, 1.1*lambda)),
                        TYPE = rep(c("1", "2"), each = n))
data_tree <- data_tree[, list(COUNT = .N), by = c("TYPE", "X")]
data_tree[TYPE == "1", COUNT := -COUNT]

p2 <- ggplot(data_tree, aes(x = X, y = COUNT, fill = TYPE)) +
  geom_bar(stat = "identity") +
  scale_fill_manual(values = c("green", "darkgreen")) +
  coord_flip() +
  theme_minimal()

# gifts
data_gifts <- data.table(X = runif(5, min = 0, max = 10),
                         Y = runif(5, max = 0.5),
                         Z = sample(letters[1:5], 5, replace = FALSE))

p3 <- ggplot(data_gifts, aes(x = X, y = Y)) +
  geom_point(aes(color = Z), pch = 15, size = 10) +
  scale_color_brewer(palette = "Reds") +
  geom_point(pch = 12, size = 10, color = "gold") +
  xlim(0,8) +
  ylim(0.1,0.5) +
  theme_minimal() + 
  theme(legend.position="none") 


11. na_omitlist

Dieser kleine Helfer entfernt fehlende Werte aus einer Liste.

y <- list(NA, c(1, NA), list(c(5:6, NA), NA, "A"))

Es gibt zwei Möglichkeiten, die fehlenden Werte zu entfernen, entweder nur auf der ersten Ebene der Liste oder innerhalb jeder Unterebene.

na_omitlist(y, recursive = FALSE)
[[1]]
[1]  1 NA

[[2]]
[[2]][[1]]
[1]  5  6 NA

[[2]][[2]]
[1] NA

[[2]][[3]]
[1] "A"
na_omitlist(y, recursive = TRUE)
[[1]]
[1] 1

[[2]]
[[2]][[1]]
[1] 5 6

[[2]][[2]]
[1] "A"

12. %nin%

Dieser kleine Helfer ist eine reine Komfortfunktion. Sie ist einfach dasselbe wie der negierte %in%-Operator, wie Ihr unten sehen könnt. Aber meiner Meinung nach erhöht sie die Lesbarkeit des Codes.

all.equal( c(1,2,3,4) %nin% c(1,2,5),
          !c(1,2,3,4) %in%  c(1,2,5))
[1] TRUE

Dieser Operator hat es auch in einige andere Pakete geschafft – wie Ihr hier nachlesen könnt.

13. object_size_in_env

Dieser kleine Helfer zeigt eine Tabelle mit der Größe jedes Objekts in der vorgegebenen Umgebung an.

Wenn Ihr in einer Situation seid, in der Ihr viel gecodet habt und Eure Umgebung nun ziemlich unübersichtlich ist, hilft Euch object_size_in_env, die großen Fische in Bezug auf den Speicherverbrauch zu finden. Ich selbst bin ein paar Mal auf dieses Problem gestoßen, als ich mehrere Ausführungen meiner Modelle in einem Loop durchlaufen habe. Irgendwann wurden die Sitzungen ziemlich groß im Speicher und ich wusste nicht, warum! Mit Hilfe von object_size_in_env und etwas Degubbing konnte ich das Objekt ausfindig machen, das dieses Problem verursachte, und meinen Code entsprechend anpassen.

Zuerst wollen wir eine Umgebung mit einigen Variablen erstellen.

# building an environment
this_env <- new.env()
assign("Var1", 3, envir = this_env)
assign("Var2", 1:1000, envir = this_env)
assign("Var3", rep("test", 1000), envir = this_env)

Um die Größeninformationen unserer Objekte zu erhalten, wird intern format(object.size()) verwendet. Mit der Einheit kann das Ausgabeformat geändert werden (z.B. "B", "MB" oder "GB").

# checking the size
object_size_in_env(env = this_env, unit = "B")
   OBJECT SIZE UNIT
1:   Var3 8104    B
2:   Var2 4048    B
3:   Var1   56    B

14. print_fs

Dieser kleine Helfer gibt die Ordnerstruktur eines gegebenen Pfades zurück. Damit kann man z.B. eine schöne Übersicht in die Dokumentation eines Projektes oder in ein Git einbauen. Im Sinne der Automatisierung könnte diese Funktion nach einer größeren Änderung Teile in einer Log- oder News-Datei ändern.

Wenn wir uns das gleiche Beispiel anschauen, das wir für die Funktion get_network verwendet haben, erhalten wir folgendes:

print_fs("~/flowchart/", depth = 4)
1  flowchart                            
2   ¦--create_network.R                 
3   ¦--getnetwork.R                     
4   ¦--plots                            
5   ¦   ¦--example-network-helfRlein.png
6   ¦   °--improved-network.png         
7   ¦--R_network_functions              
8   ¦   ¦--dataprep                     
9   ¦   ¦   °--foo_01.R                 
10  ¦   ¦--method                       
11  ¦   ¦   °--foo_02.R                 
12  ¦   ¦--script_01.R                  
13  ¦   °--script_02.R                  
14  °--README.md 

Mit depth können wir einstellen, wie tief wir unsere Ordner durchforsten wollen.

15. read_files

Dieser kleine Helfer liest mehrere Dateien des selben Typs ein und fasst sie zu einer data.table zusammen. Welche Art von Dateilesefunktion verwendet werden soll, kann mit dem Argument FUN ausgewählt werden.

Wenn Sie eine Liste von Dateien haben, die alle mit der gleichen Funktion eingelesen werden sollen (z.B. read.csv), können Sie statt lapply und rbindlist nun dies verwenden:

read_files(files, FUN = readRDS)
read_files(files, FUN = readLines)
read_files(files, FUN = read.csv, sep = ";")

Intern verwendet es nur lapply und rbindlist, aber man muss es nicht ständig eingeben. Die read_files kombiniert die einzelnen Dateien nach ihren Spaltennamen und gibt eine data.table zurück. Warum data.table? Weil ich es mag. Aber lassen Sie uns nicht das Fass von data.table vs. dplyr aufmachen (zum Fass…).

16. save_rds_archive

Dieser kleine Helfer ist ein Wrapper um die Basis-R-Funktion saveRDS() und prüft, ob die Datei, die Ihr zu speichern versucht, bereits existiert. Wenn ja, wird die bestehende Datei umbenannt / archiviert (mit einem Zeitstempel), und die „aktualisierte“ Datei wird unter dem angegebenen Namen gespeichert. Das bedeutet, dass vorhandener Code, der davon abhängt, dass der Dateiname konstant bleibt (z.B. readRDS()-Aufrufe in anderen Skripten), weiterhin funktionieren wird, während eine archivierte Kopie der – ansonsten überschriebenen – Datei erhalten bleibt.

17. sci_palette

Dieser kleine Helfer liefert eine Reihe von Farben, die wir bei statworx häufig verwenden. Wenn Ihr Euch also – so wie ich – nicht an jeden Hex-Farbcode erinnern könnt, den Ihr braucht, könnte das helfen. Natürlich sind das unsere Farben, aber Ihr könnt es auch mit Eurer eigenen Farbpalette umschreiben. Aber der Hauptvorteil ist die Plot-Methode – so könnt Ihr die Farbe sehen, anstatt nur den Hex-Code zu lesen.

So seht Ihr, welcher Hexadezimalcode welcher Farbe entspricht und wofür Ihr ihn verwenden könnt.

sci_palette(scheme = "new")
Tech Blue       Black       White  Light Grey    Accent 1    Accent 2    Accent 3 
"#0000FF"   "#000000"   "#FFFFFF"   "#EBF0F2"   "#283440"   "#6C7D8C"   "#B6BDCC"   
Highlight 1 Highlight 2 Highlight 3 
"#00C800"   "#FFFF00"   "#FE0D6C" 
attr(,"class")
[1] "sci"

Wie bereits erwähnt, gibt es eine Methode plot(), die das folgende Bild ergibt.

plot(sci_palette(scheme = "new"))

18. statusbar

Dieser kleine Helfer gibt einen Fortschrittsbalken in der Konsole für Schleifen aus.

Es gibt zwei notwendige Parameter, um diese Funktion zu füttern:

  • run ist entweder der Iterator oder seine Nummer
  • max.run ist entweder alle möglichen Iteratoren in der Reihenfolge, in der sie verarbeitet werden, oder die maximale Anzahl von Iterationen.

So könnte es zum Beispiel run = 3 und max.run = 16 oder run = "a" und max.run = Buchstaben[1:16] sein.

Außerdem gibt es zwei optionale Parameter:

  • percent.max beeinflusst die Breite des Fortschrittsbalkens
  • info ist ein zusätzliches Zeichen, das am Ende der Zeile ausgegeben wird. Standardmäßig ist es run.

Ein kleiner Nachteil dieser Funktion ist, dass sie nicht mit parallelen Prozessen arbeitet. Wenn Ihr einen Fortschrittsbalken haben wollt, wenn Ihr apply Funktionen benutzt, schaut Euch pbapply an.

19. statworx_palette

Dieses kleine Hilfsmittel ist eine Ergänzung zu sci_palette(). Wir haben die Farben 1, 2, 3, 5 und 10 ausgewählt, um eine flexible Farbpalette zu erstellen. Wenn Sie 100 verschiedene Farben benötigen – sagen Sie nichts mehr!

Im Gegensatz zu sci_palette() ist der Rückgabewert ein Zeichenvektor. Zum Beispiel, wenn Sie 16 Farben wollen:

statworx_palette(16, scheme = "old")
[1] "#013848" "#004C63" "#00617E" "#00759A" "#0087AB" "#008F9C" "#00978E" "#009F7F"
[9] "#219E68" "#659448" "#A98B28" "#ED8208" "#F36F0F" "#E45A23" "#D54437" "#C62F4B"

Wenn wir nun diese Farben aufzeichnen, erhalten wir einen schönen regenbogenartigen Farbverlauf.

library(ggplot2)

ggplot(plot_data, aes(x = X, y = Y)) +
  geom_point(pch = 16, size = 15, color = statworx_palette(16, scheme = "old")) +
  theme_minimal()

Eine zusätzliche Funktion ist der Parameter reorder, der die Reihenfolge der Farben abtastet, so dass Nachbarn vielleicht etwas besser unterscheidbar sind. Auch wenn Sie die verwendeten Farben ändern wollen, können Sie dies mit basecolors tun.

ggplot(plot_data, aes(x = X, y = Y)) +
  geom_point(pch = 16, size = 15,
             color = statworx_palette(16, basecolors = c(4,8,10), scheme = "new")) +
  theme_minimal()


20. strsplit

Dieses kleine Hilfsmittel erweitert die R-Basisfunktion strsplit – daher der gleiche Name! Es ist nun möglich, before, after oder between ein bestimmtes Begrenzungszeichen zu trennen. Im Falle von between müsst ihr zwei Delimiter angeben.

Eine frühere Version dieser Funktion findet Ihr in diesem Blogbeitrag, wo ich die verwendeten regulären Ausdrücke beschreibe, falls Ihr daran interessiert seid.

Hier ist ein kleines Beispiel, wie man das neue strsplit benutzt.

text <- c("This sentence should be split between should and be.")

strsplit(x = text, split = " ")
strsplit(x = text, split = c("should", " be"), type = "between")
strsplit(x = text, split = "be", type = "before")
[[1]]
[1] "This"     "sentence" "should"   "be"       "split"    "between"  "should"   "and"     
[9] "be."

[[1]]
[1] "This sentence should"             " be split between should and be."

[[1]]
[1] "This sentence should " "be split "             "between should and "  
[4] "be."

21. to_na

Dieser kleine Helfer ist nur eine Komfortfunktion. Bei der Datenaufbereitung kann es vorkommen, dass Ihr einen Vektor mit unendlichen Werten wie Inf oder -Inf oder sogar NaN-Werten habt. Solche Werte können (müssen aber nicht!) Eure Auswertungen und Modelle durcheinanderbringen. Aber die meisten Funktionen haben die Tendenz, fehlende Werte zu behandeln. Daher entfernt diese kleine Hilfe solche Werte und ersetzt sie durch NA.

Ein kleines Beispiel, um Euch die Idee zu vermitteln:

test <- list(a = c("a", "b", NA),
             b = c(NaN, 1,2, -Inf),
             c = c(TRUE, FALSE, NaN, Inf))

lapply(test, to_na)
$a
[1] "a" "b" NA 

$b
[1] NA  1  2 NA

$c
[1]  TRUE FALSE    NA

Ein kleiner Tipp am Rande! Da es je nach den anderen Werten innerhalb eines Vektors verschiedene Arten von NA gibt, solltet Ihr das Format überprüfen, wenn Ihr to_na auf Gruppen oder Teilmengen anwendet.

test <- list(NA, c(NA, "a"), c(NA, 2.3), c(NA, 1L))
str(test)
List of 4
 $ : logi NA
 $ : chr [1:2] NA "a"
 $ : num [1:2] NA 2.3
 $ : int [1:2] NA 1

22. trim

Dieser kleine Helfer entfernt führende und nachfolgende Leerzeichen aus einer Zeichenkette. Mit R Version 3.5.1 wurde trimws eingeführt, das genau das Gleiche tut. Das zeigt nur, dass es keine schlechte Idee war, eine solche Funktion zu schreiben. ????

x <- c("  Hello world!", "  Hello world! ", "Hello world! ")
trim(x, lead = TRUE, trail = TRUE)
[1] "Hello world!" "Hello world!" "Hello world!"

Die Parameter lead und trail geben an, ob nur die führenden, die nachfolgenden oder beide Leerzeichen entfernt werden sollen.

Fazit

Ich hoffe, dass euch das helfRlein Package genauso die Arbeit erleichtert, wie uns hier bei statworx. Schreibt uns bei Fragen oder Input zum Package gerne eine Mail an: blog@statworx.com

Jakob Gepp Jakob Gepp Jakob Gepp Jakob Gepp Jakob Gepp Jakob Gepp

Ob bewusst oder unbewusst, Vorurteile in unserer Gesellschaft erschweren die Verwirklichung einer geschlechtergerechten Welt, die frei von Stereotypen und Diskriminierung ist. Leider schleichen sich diese geschlechtsspezifischen Vorurteile auch in die KI-Technologien ein, die sich in allen Bereichen unseres täglichen Lebens rasant weiterentwickeln und unsere Gesellschaft in nie gekanntem Maße verändern werden. Daher ist die Entwicklung fairer und unvoreingenommener KI-Systeme für eine vielfältige, gerechte und inklusive Zukunft unerlässlich. Es ist nicht nur wichtig, dass wir uns dieses Problems bewusst sind, sondern auch, dass wir jetzt handeln, bevor diese Technologien unsere geschlechtsspezifischen Vorurteile noch mehr verstärken, auch in Bereichen unseres Lebens, in denen wir sie bereits beseitigt haben.

Lösung beginnt mit Verständnis: Um an Lösungen zur Beseitigung geschlechtsspezifischer Vorurteile und aller anderen Formen von Vorurteilen in der KI zu arbeiten, müssen wir zunächst verstehen, was sie sind und woher sie kommen. Daher werde ich im Folgenden zunächst einige Beispiele für geschlechtsspezifische KI-Technologien vorstellen und Euch dann einen strukturierten Überblick über die verschiedenen Gründe für Vorurteile in der KI geben. In einem zweiten Schritt werde ich die notwendigen Maßnahmen für fairere und unvoreingenommenere KI-Systeme vorstellen.

Sexistische KI

Geschlechtsspezifische Vorurteile in der KI haben viele Gesichter und schwerwiegende Auswirkungen auf die Gleichstellung von Frauen. Während Youtube meinem ledigen Freund (männlich, 28) Werbung für die neuesten technischen Erfindungen oder die neuesten Automodelle zeigt, muss ich, ebenfalls ledig und 28, Werbung für Fruchtbarkeits- oder Schwangerschaftstests ertragen. Aber KI wird nicht nur eingesetzt, um Entscheidungen darüber zu treffen, welche Produkte wir kaufen oder welche Serien wir als nächstes sehen wollen. KI-Systeme werden auch eingesetzt, um zu entscheiden, ob Ihr ein Vorstellungsgespräch bekommt oder nicht, wie viel Ihr für Eure Autoversicherung zahlt, wie gut Eure Kreditwürdigkeit ist oder sogar, welche medizinische Behandlung Ihr bekommt. Und hier beginnt die Voreingenommenheit solcher Systeme wirklich gefährlich zu werden.

Im Jahr 2015 lernte das Rekrutierungstool von Amazon beispielsweise fälschlicherweise, dass Männer bessere Programmierer seien als Frauen. Daraufhin bewertete das Tool Bewerber:innen für Softwareentwicklerstellen und andere technische Stellen nicht geschlechtsneutral.

Im Jahr 2019 beantragte ein Paar dieselbe Kreditkarte. Obwohl die Ehefrau eine etwas bessere Kreditwürdigkeit und die gleichen Einnahmen, Ausgaben und Schulden wie ihr Ehemann hatte, setzte das Kreditkartenunternehmen ihr Kreditkartenlimit viel niedriger an, was der Kundendienst des Kreditkartenunternehmens nicht erklären konnte.

Wären diese sexistischen Entscheidungen von Menschen getroffen worden, wären wir empört. Zum Glück gibt es für uns Menschen Gesetze und Vorschriften gegen sexistisches Verhalten. Dennoch steht die künstliche Intelligenz mittlerweile über dem Gesetz, weil eine vermeintlich rationale Maschine die Entscheidung getroffen hat. Wie kann also eine vermeintlich rationale Maschine befangen, voreingenommen und rassistisch werden? Es gibt drei miteinander verknüpfte Gründe für Vorurteile in KI: Daten, Modelle und die AI Gemeinschaft.

Daten sind unser Schicksal

Erstens sind Daten ein Spiegel unserer Gesellschaft, mit all unseren Werten, Annahmen und leider auch Vorurteilen. Es gibt keine neutralen oder unbearbeiteten Daten. Daten werden immer von Menschen erzeugt, gemessen und gesammelt. Daten wurden schon immer durch kulturelle Vorgänge erzeugt und zu kulturellen Kategorien geformt. So werden beispielsweise die meisten demografischen Daten auf der Grundlage vereinfachter, binärer Frau-Mann-Kategorien etikettiert. Wenn die Geschlechterklassifizierung das Geschlecht auf diese Weise zusammenfasst, sind die Daten nicht in der Lage, Geschlechterfluidität und die eigene Geschlechtsidentität aufzuzeigen. Auch „Rasse“ ist ein soziales Konstrukt, ein Klassifizierungssystem, das wir Menschen vor langer Zeit erfunden haben, um physische Unterschiede zwischen Menschen zu definieren, und das immer noch in Daten vorhanden ist.

Der zugrundeliegende mathematische Algorithmus in KI-Systemen ist selbst nicht sexistisch. KI lernt aus Daten mit all ihren möglichen geschlechtsspezifischen Verzerrungen. Nehmen wir zum Beispiel an, ein Gesichtserkennungsmodell hat noch nie eine transsexuelle oder nicht-binäre Person gesehen, weil es kein solches Bild im Datensatz gab. In diesem Fall wird es eine transgender oder nicht-binäre Person nicht korrekt klassifizieren (Selection Bias).

Oder, wie im Fall von Google Translate, wird der Ausdruck „eine Ärztin“ in geschlechtsspezifisch flektierten Sprachen durchweg in die männliche Form übersetzt, weil das KI-System auf Tausenden von Online-Texten trainiert wurde, in denen die männliche Form von „Arzt“ aufgrund historischer und sozialer Umstände stärker verbreitet war (Historical Bias). Laut Invisible Women gibt es bei Big Data im Allgemeinen eine große Kluft zwischen den Geschlechtern, die zu Lasten der Frauen geht. Wenn wir also nicht darauf achten, mit welchen Daten wir diese Algorithmen füttern, werden sie den Gender Gap in den Daten übernehmen und Frauen systematisch diskriminieren.

Modelle brauchen Bildung

Zweitens sind unsere KI-Modelle leider nicht intelligent genug, um die Vorurteile in den Daten zu überwinden. Da die derzeitigen KI-Modelle nur Korrelationen und keine kausalen Strukturen analysieren, lernen sie blind, was in den Daten steht. Diesen Algorithmen wohnt ein systematischer Strukturkonservatismus inne, da sie darauf ausgelegt sind, bestimmte Muster in den Daten zu reproduzieren.

Um dies zu veranschaulichen, werde ich ein fiktives und sehr vereinfachtes Beispiel verwenden: Stellt euch einen sehr stereotypen Datensatz mit vielen Bildern von Frauen in Küchen und Männern in Autos vor. Anhand dieser Bilder soll ein Bildklassifikationsalgorithmus lernen, das Geschlecht einer Person auf einem Bild vorherzusagen. Aufgrund der Datenselektion gibt es in dem Datensatz eine hohe Korrelation zwischen Küchen und Frauen und zwischen Autos und Männern – eine höhere Korrelation als zwischen einigen charakteristischen Geschlechtsmerkmalen und dem jeweiligen Geschlecht. Da das Modell keine kausalen Strukturen erkennen kann (was geschlechtsspezifische Merkmale sind), lernt es also fälschlicherweise, dass eine Küche im Bild auch bedeutet, dass Frauen im Bild sind, und dasselbe gilt für Autos und Männer. Wenn also auf einem Bild eine Frau in einem Auto zu sehen ist, würde die KI die Person als Mann identifizieren und vice versa.

Dies ist jedoch nicht der einzige Grund, warum KI-Systeme die Vorurteile in Daten nicht überwinden können. Es liegt auch daran, dass wir den Systemen nicht „sagen“, dass sie darauf achten sollen. KI-Algorithmen lernen, indem sie ein bestimmtes, von den Entwicklern festgelegtes Ziel optimieren. In der Regel handelt es sich bei dieser Leistungsmessung um eine durchschnittliche Genauigkeitsmetrik, die keinerlei ethische oder faire Beschränkungen enthält. Das ist so, als ob ein Kind lernen soll, so viel Geld wie möglich zu bekommen, ohne zusätzliche Einschränkungen, wie z. B. die Konsequenzen von Diebstahl, Ausbeutung oder Betrug. Wenn wir wollen, dass KI-Systeme lernen, dass geschlechtsspezifische Vorurteile falsch sind, müssen wir dies in ihr Training und ihre Leistungsbewertung einbeziehen.

Der Gemeinschaft fehlt es an Diversität

Schließlich ist es die Entwickler:innen-Community, die direkt oder indirekt, bewusst oder unbewusst ihre eigenen geschlechtsspezifischen und anderen Vorurteile in KI-Technologien einbringt. Sie wählen die Daten aus, definieren das Optimierungsziel und gestalten die Nutzung von KI.

Auch wenn in einigen Fällen möglicherweise böswillige Absichten vorliegen, würde ich behaupten, dass Entwickler:innen ihre eigenen Vorurteile oft unbewusst in KI-Systeme einbringen. Wir alle erliegen unbewussten Vorurteilen, d. h. unbewussten Denkfehlern, die aus Problemen mit dem Gedächtnis, der Aufmerksamkeit und anderen mentalen Fehlern resultieren. Mit anderen Worten: Diese Verzerrungen resultieren aus dem Bestreben, die unglaublich komplexe Welt, in der wir leben, zu vereinfachen.

So fällt es unserem Gehirn beispielsweise leichter, stereotypes Denken anzuwenden, d. h. Vorstellungen über eine Person auf der Grundlage dessen zu entwickeln, wie Menschen aus einer ähnlichen Gruppe „typischerweise“ sein könnten (z. B. ein Mann eignet sich besser für die Position eines Geschäftsführers), als alle Informationen zu sammeln, um eine Person und ihre Eigenschaften vollständig zu verstehen. Oder, gemäß dem Affinitäts-Bias, mögen wir die Menschen am meisten, die so aussehen und denken wie wir, was ebenfalls eine vereinfachte Art ist, die Menschen um uns herum zu verstehen und zu kategorisieren.

Wir alle haben solche unbewussten Vorurteile, und da wir alle unterschiedliche Menschen sind, variieren diese Vorurteile von Person zu Person. Da jedoch die derzeitige Gemeinschaft der KI-Entwickler:innen zu über 80 % aus weißen, Cis-Männern besteht, sind die Werte, Ideen und Vorurteile, die sich in KI-Systeme einschleichen, sehr homogen und damit buchstäblich engstirnig. Angefangen bei der Definition von KI: Die Gründerväter der KI im Jahr 1956 waren allesamt weiße, männliche Ingenieure, eine sehr homogene Gruppe von Menschen, was zu einer engen Vorstellung davon führte, was Intelligenz ist, nämlich die Fähigkeit, Spiele wie Schach zu gewinnen. Aus der Psychologie wissen wir jedoch, dass es viele verschiedene Arten von Intelligenz gibt, z. B. emotionale oder soziale Intelligenz. Wenn heute ein Modell von einer sehr homogenen Gruppe von Menschen ohne besondere Aufmerksamkeit und Verfahren entwickelt und überprüft wird, sind sie aufgrund unbewusster Voreingenommenheit nicht in der Lage, Diskriminierung zu erkennen, die sich von ihnen selbst unterscheidet. In der Tat ist diese homogene Gemeinschaft tendenziell die Gruppe von Menschen, die in der KI kaum unter Voreingenommenheit leidet.

Stellen Sie sich vor, alle Kinder auf der Welt würden von 30-jährigen weißen Cis-Männern aufgezogen und erzogen. So sieht unsere KI heute aus. Sie wird von einer sehr homogenen Gruppe entworfen, entwickelt und bewertet und vermittelt so eine einseitige Perspektive auf Werte, Normen und Ideen. Die Entwickler:innen sind der Kern dieser Entwicklung. Sie bringen der KI bei, was richtig oder falsch, was gut oder schlecht ist.

Die Vorurteile in der Gesellschaft aufbrechen

Ein entscheidender Schritt auf dem Weg zu einer fairen und unvoreingenommenen KI ist also eine vielfältige und integrative KI-Entwicklungsgemeinschaft. Inzwischen gibt es einige technische Lösungen für die genannten Probleme der Daten- und Modellverzerrung (z. B. Datendiversifizierung oder Kausalmodellierung). Doch all diese Lösungen sind nutzlos, wenn die Entwickler:innen nicht von vornherein über Probleme mit Vorurteilen nachdenken. Unterschiedliche Menschen können die blinden Flecken und die Vorurteile der jeweils anderen besser überprüfen. **Viele Studien zeigen, dass die Vielfalt in Informatikteams entscheidend dazu beiträgt, Vorurteile in der KI zu verringern.

Außerdem müssen wir unsere Gesellschaft über KI, ihre Risiken und Chancen aufklären. Wir müssen die Ausbildung von KI-Entwickler:innen überdenken und umstrukturieren, denn sie brauchen ebenso viel ethisches Wissen wie technisches Wissen, um faire und unvoreingenommene KI-Systeme zu entwickeln. Wir müssen die breite Bevölkerung darüber aufklären, dass auch wir alle Teil dieses massiven Wandels durch KI werden können, um unsere Ideen und Werte in die Gestaltung und Entwicklung dieser Systeme einzubringen.

Wenn wir die Vorurteile der KI überwinden wollen, müssen wir letztlich auch die Vorurteile in unserer Gesellschaft überwinden. Vielfalt ist die Lösung für eine faire und unvoreingenommene KI, nicht nur in den KI-Entwicklungsteams, sondern in unserer gesamten Gesellschaft. KI wird von Menschen gemacht, von uns, von unserer Gesellschaft. Unsere Gesellschaft mit ihren Strukturen bringt Vorurteile in die KI: durch die Daten, die wir produzieren, die Ziele, die wir von den Maschinen erwarten, und die Gemeinschaft, die diese Systeme entwickelt. Im Kern sind Vorurteile in der KI kein technisches Problem – sie sind ein soziales Problem.

Positive Verstärkung von KI

Schließlich müssen wir uns fragen, ob wir wollen, dass die KI die heutige Gesellschaft widerspiegelt oder eine gleichberechtigtere Gesellschaft von morgen? Nehmen wir an, wir verwenden Machine Learning Modelle, um die Welt von heute abzubilden. In diesem Fall werden wir keinen sozialen Fortschritt erzielen. Wenn wir nicht handeln, könnten wir einige soziale Fortschritte, wie z. B. mehr Gleichberechtigung zwischen den Geschlechtern, verlieren, da die KI Vorurteile verstärkt und in unser Leben zurückbringt. Die KI soll zukunftsorientiert sein. Aber gleichzeitig basiert sie auf Daten, und Daten spiegeln unsere Geschichte und Gegenwart wider. So wie wir also die Voreingenommenheit in der Gesellschaft überwinden müssen, um die Voreingenommenheit in KI-Systemen zu überwinden, brauchen wir unvoreingenommene KI-Systeme für den sozialen Fortschritt in unserer Welt.

Nach all dem bin ich hoffnungsvoll und optimistisch. Durch diesen Verstärkungseffekt hat die KI das Bewusstsein für alte Fairness- und Diskriminierungsprobleme in unserer Gesellschaft auf einer viel breiteren Ebene geschärft. Vorurteile in KI zeigen uns einige der dringendsten gesellschaftlichen Herausforderungen. Ethische und philosophische Fragen werden immer wichtiger. Und weil KI diesen Verstärkungseffekt auf die Gesellschaft hat, können wir sie auch zum Positiven nutzen. Wir können diese Technologie für das Gute nutzen. Wenn wir alle zusammenarbeiten, haben wir die Chance, die Welt zu einem wesentlich vielfältigeren, inklusiveren und gleichberechtigteren Ort umzugestalten. Livia Eichenberger Livia Eichenberger

Warum sich Sorgen machen? KI und die Klimakrise

Nach dem neuesten Bericht des Weltklimarats (IPCC) im August 2021 „ist es eindeutig, dass menschlicher Einfluss die Atmosphäre, das Meer und das Land erwärmt hat“ [1]. Zudem schreitet der Klimawandel schneller voran als gedacht. Basierend auf den neuesten Berechnungen ist die globale Durchschnittstemperatur zwischen 2010 und 2019 im Vergleich zu dem Zeitraum zwischen 1850 und 1900 aufgrund des menschlichen Einflusses um 1.07°C gestiegen. Außerdem war die CO2 Konzentration in der Atmosphäre in dieser Zeit „höher als zu irgendeiner Zeit in mindestens 2 Millionen Jahren“ [1].

Dessen ungeachtet nehmen die globalen CO2 Emissionen weiter zu, auch wenn es 2020 einen kleinen Rückgang gab [2], der wahrscheinlich auf das Coronavirus und die damit zusammenhängenden ökonomischen Auswirkungen zurückzuführen ist. Im Jahr 2019 wurden weltweit insgesamt 36.7 Gigatonnen (Gt) CO2 ausgestoßen [2]. Eine Gt entspricht dabei einer Milliarden Tonnen. Um das 1.5 °C Ziel noch mit einer geschätzten Wahrscheinlichkeit von 80% zu erreichen, blieben Anfang 2020 nur noch 300 Gt übrig [1]. Da 2020 und 2021 bereits vorüber sind und unter Annahme von circa 35 Gt CO2 Emissionen für jedes Jahr, beträgt das verbleibende CO2 -Budget nur rund 230 Gt. Bleibt der jährliche Ausstoß konstant, wäre dieses in den nächsten sieben Jahren aufgebraucht.

Im Jahr 2019 verursachten China, die USA und Indien die größten CO2-Emissionen. Deutschland ist zwar nur für ungefähr 2% aller globalen CO2 Emissionen verantwortlich, liegt mit 0.7 Gt aber immer noch auf dem siebten Platz (siehe nachfolgende Grafik). Zusammen genommen sind die 10 Länder mit dem größten CO2-Ausstoß für circa zwei Drittel aller CO2-Emissionen weltweit verantwortlich [2]. Die meisten dieser Länder sind hoch industrialisiert, wodurch es sehr wahrscheinlich ist, dass sie künstliche Intelligenz (KI) in den nächsten Jahrzenten verstärkt nutzen werden, um Ihre eigene Wirtschaft zu stärken.

Mit KI den CO2-Ausstoß reduzieren

Was genau hat jetzt KI mit dem Ausstoß von CO2 zu tun? Die Antwort ist: Einiges! Prinzipiell ist die Anwendung von KI wie zwei Seiten derselben Medaille [3]. Auf der einen Seite hat KI großes Potenzial, CO2-Emissionen durch genauere Vorhersagen oder die Verbesserung von Prozessen in vielen Industrien zu reduzieren. Beispielsweise kann KI zur Vorhersage extremer Wetterereignisse, der Optimierung von Lieferketten oder der Überwachung von Mooren eingesetzt werden [4, 5].

Nach einer aktuellen Schätzung von Microsoft und PwC kann die Verwendung von KI im Umweltbereich den Ausstoß der weltweiten Treibhausgase um bis zu 4.4% im Jahr 2030 senken [6]. Absolut gesehen handelt es sich dabei um eine Reduzierung der weltweiten Treibhausgasemissionen von 0.9 bis 2.4 Gt CO2e. Dies entspricht dem, aufgrund aktueller Werte prognostizierten, Ausstoß von Australien, Kanada und Japan im Jahr 2030 zusammen [7]. Der Begriff Treibhausgase beinhaltet hier zusätzlich zu CO2 noch andere Gase wie Methan, die ebenfalls den Treibhauseffekt der Erde verstärken. Um all diese Gase einfach zu messen, werden sie oft als CO2-Äquivalente angeben und als CO2e abgekürzt.

Der CO2-Fußabdruck von KI

Obwohl KI großes Potenzial hat, CO2-Emissionen zu reduzieren, stößt die Anwendung von KI selbst CO2 aus. Dies ist die Kehrseite der Medaille. Im Vergleich zum Jahr 2012 ist die geschätzte Menge an Rechenaufwand für das Training von Deep Learning (DL) Modellen im Jahr 2018 um das 300.000-fache gestiegen (siehe nachfolgende Grafik, [8]). Die Erforschung, das Training und die Anwendung von KI-Modellen benötigen daher eine immer größere Menge an Strom, aber natürlich auch an Hardware. Beides setzt letztlich CO2-Emissionen frei und verstärkt somit den Klimawandel.

Anmerkung: Die Grafik wurde ursprünglich in [8] veröffentlicht.

Leider ist es mir nicht gelungen, eine Studie ausfindig zu machen, die den CO2-Fußabdruck von KI insgesamt schätzt. Allerdings gibt es diverse Studien, die den CO2– oder CO2e-Ausstoß von Natural Language Processing (NLP) Modellen schätzen. Diese sind in den vergangenen Jahren immer akkurater und somit populärer geworden [9]. Basierend auf der nachfolgenden Tabelle hat das abschließende Training von Googles BERT Modell ungefähr so viel CO2e freigesetzt, wie ein Passagier bei einer Flugreise von New York nach San Francisco. Das Training anderer Modelle, wie bspw. des Transformerbig-Modells, haben zwar wesentlich weniger CO2e-Emissionen verursacht, doch ist das abschließende Training von KI-Modellen nur der letzte Baustein beim Finden des besten Modells. Bevor ein Modell zum letzten Mal trainiert wird, sind häufig bereits viele verschiedene Modelle getestet worden, um so die besten Parameterwerte zu bestimmen. Diese neuronale Architektursuche hat beim Transformerbig-Modell entsprechend viele CO2e-Emissionen verursacht, insgesamt circa fünf Mal so viele wie ein durchschnittliches Auto in seiner gesamten Lebenszeit. Wirf jetzt mal einen Blick auf die CO2e-Emissionen des GPT-3 Modells und stell dir vor, wie hoch der CO2e-Ausstoß bei der dazugehörigen neuronalen Architektursuche gewesen sein muss.

Comparison of selected human and AI carbon emissions
Emissionen durch Menschen Emissionen durch KI
Beispiel CO2e Emissionen (Tonnen) Training von NLP Modellen CO2e Emissionen (Tonnen)
Ein Passagier bei Flugreise
New York San Francisco
0.90 Transformerbig 0.09
Durchschnittlicher Mensch
ein Jahr
5.00 BERTbase 0.65
Durchschnittlicher Amerikaner
ein Jahr
16.40 GPT-3 84.74
Durchschnittliches Auto während
Lebenszeit inkl. Benzin
57.15 Neuronale Architektursuche
für Transformerbig
284.02

Anmerkung: Alle Werte sind aus [9] entnommen, außer der Werte für GPT-3 [17].

Was du als Data Scientist tun kannst, um deinen CO2-Fußabdruck zu verringern

Insgesamt gibt es ganz unterschiedliche Möglichkeiten, wie du als Data Scientist den CO2-Fußabdruck beim Training und Anwendung von KI-Modellen reduzieren kannst. Aktuell sind im KI-Bereich Machine Learning (ML) und Deep Learning (DL) am populärsten, deswegen findest du nachfolgend verschiedene Ansätze, um den CO2-Fußabdruck dieser Art KI-Modelle zu messen und zu reduzieren.

1. Sei dir der negativen Auswirkungen bewusst und berichte darüber

Es mag einfach klingen, aber sich der negativen Konsequenzen bewusst zu sein, die sich durch die Suche, das Training sowie die Anwendung von ML und DL Modellen ergeben, ist der erste Schritt, deinen CO2-Fußabdruck zu reduzieren. Zu verstehen, wie sich KI negativ auf die Umwelt auswirkt, ist entscheidend, um bereit zu sein, den zusätzlichen Aufwand bei der Messung und systematische Erfassung von CO2-Emissionen zu betreiben. Dies widerrum ist nötig, um den Klimawandel zu bekämpfen [8, 9, 10]. Solltest du also den ersten Teil über KI und die Klimakrise übersprungen haben, gehh zurück und lies ihn. Es lohnt sich!

2. Miss den CO2-Ausstoß deines Codes

Um die CO2-Emissionen deiner ML und DL Modelle transparent darzulegen, müssen diese zuerst gemessen werden. Zurzeit gibt es leider noch kein standardisiertes Konzept, um alle Nachhaltigkeitsaspekte von KI zu messen. Eines wird allerdings gerade entwickelt [11]. Bis dieses fertiggestellt ist, kannst du bereits beginnen, den Energieverbrauch und die damit verbundenen CO2-Emissionen deiner KI-Modelle offen zu legen [12]. Mit TensorFlow und PyTorch sind die ausgereiftesten Pakete für die Berechnung von ML und DL Modellen wahrscheinlich in der Programmiersprache Python verfügbar. Obwohl Python nicht die effizienteste Programmiersprache ist [13], war es im September 2021 erneut die populärste im PYPL Index [14]. Dementsprechend gibt es sogar drei Python Pakete, die du nutzen kannst, um den CO2-Fußabdruck beim Training deiner Modelle zu messen:

  • CodeCarbon [15, 16]
  • CarbonTracker [17]
  • Experiment Impact Tracker [18]

Meiner Auffassung nach sind die beiden Pakete, CodeCarbon und CarbonTracker, am einfachsten anzuwenden. Außerdem lässt sich CodeCarbon problemlos mit TensorFlow und CarbonTracker mit PyTorch kombinieren. Aus diesen Gründen findest du für jedes der beiden Pakete nachfolgend ein Beispiel.

Um beide Pakete zu testen, habe ich den MNIST Datensatz verwendet und jeweils ein einfaches Multilayer Perceptron (MLP) mit zwei Hidden Layern und jeweils 256 Neuronen trainiert. Um sowohl eine CPU- als auch GPU-basierte Berechnung zu testen, habe ich das Modell mit TensorFlow und CodeCarbon auf meinem lokalen PC (15 Zoll MacBook Pro mit 6 Intel Core i7 CPUs aus dem Jahr 2018) und das mit PyTorch und CarbonTracker in einem Google Colab unter Verwendung einer Tesla K80 GPU trainiert. Beginnen wir mit den Ergebnissen für TensorFlow und CodeCarbon.

# benötigte Pakete importieren
import tensorflow as tf
from codecarbon import EmissionsTracker

# Modeltraining vorbereiten
mnist = tf.keras.datasets.mnist

(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0


model = tf.keras.models.Sequential(
    [
        tf.keras.layers.Flatten(input_shape=(28, 28)),
        tf.keras.layers.Dense(256, activation=“relu“),
        tf.keras.layers.Dense(256, activation=“relu“),
        tf.keras.layers.Dense(10, activation=“softmax“),
    ]
)

loss_fn = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)

model.compile(optimizer=“adam“, loss=loss_fn, metrics=[„accuracy“])

# Modell trainieren und CO2 Emissionen berechnen
tracker = EmissionsTracker()
tracker.start()
model.fit(x_train, y_train, epochs=10)
emissions: float = tracker.stop()
print(emissions)

Nach der Ausführung des Codes erstellt CodeCarbon automatisch eine CSV-Datei, welche verschiedene Ergebnisparameter beinhaltet, wie Berechnungszeit in Sekunden, totaler Stromverbrauch durch die verwendete Hardware in kWh und die damit verbundenen CO2-Emissionen in kg. Das Training meines Modells dauerte insgesamt 112.15 Sekunden, verbrauchte 0.00068 kWh und verursachte 0.00047 kg CO2-Emissionen.

Als Grundlage für die Berechnungen mit PyTorch und CarbonTracker habe ich dieses Google Colab Notebook verwendet. Um auch hier ein Multilayer Perceptron zu berechnen und die dabei entstehenden CO2-Emissionen zu messen, habe ich einige Details des Notebooks geändert. Als erstes habe ich in Schritt 2 („Define Network“) das Convolutional Neural Network in ein Multilayer Perceptron geändert (Den Namen der Klasse „CNN“ habe ich beibehalten, damit der restliche Code im Notebook noch funktioniert.):

 class CNN(nn.Module):
  """Ein einfaches MLP Modell."""

  @nn.compact
  def __call__(self, x):
    x = x.reshape((x.shape[0], -1))  # flach machen
    x = nn.Dense(features=256)(x)
    x = nn.relu(x)
    x = nn.Dense(features=256)(x)
    x = nn.relu(x)
    x = nn.Dense(features=10)(x)
    x = nn.log_softmax(x)
    return x

Als zweites habe ich die Installation und den Import von CarbonTracker sowie die Messung der CO2-Emissionen in Schritt 14 („Train and evaluate“) eingefügt:

 !pip install carbontracker

from carbontracker.tracker import CarbonTracker

tracker = CarbonTracker(epochs=num_epochs)
for epoch in range(1, num_epochs + 1):
  tracker.epoch_start()

  # Vewendung des separaten PRNG keys, um Bilddaten zu permutieren
  rng, input_rng = jax.random.split(rng)
  # Optimierung für Trainings Batches
  state = train_epoch(state, train_ds, batch_size, epoch, input_rng)
  # Evaluation für Testdatensatz nach jeder Epoche 
  test_loss, test_accuracy = eval_model(state.params, test_ds)
  print(' test epoch: %d, loss: %.2f, accuracy: %.2f' % (
      epoch, test_loss, test_accuracy * 100))
  
  tracker.epoch_end()

tracker.stop()

Nachdem das leicht geänderte Google Colab Notebook bis zum eigentlichen Training des Modells ausgeführt wurde, gab CarbonTracker nach der ersten Trainingsepoche das nachfolgende Ergebnis aus:

 train epoch: 1, loss: 0.2999, accuracy: 91.25
 test epoch: 1, loss: 0.22, accuracy: 93.42
CarbonTracker:
Actual consumption for 1 epoch(s):
       Time:  0:00:15
       Energy: 0.000397 kWh
       CO2eq: 0.116738 g
       This is equivalent to:
       0.000970 km travelled by car
CarbonTracker:
Predicted consumption for 10 epoch(s):
       Time:  0:02:30
       Energy: 0.003968 kWh
       CO2eq: 1.167384 g
       This is equivalent to:
       0.009696 km travelled by car

Wie erwartet hat die GPU mehr Strom verbraucht und somit auch mehr CO2-Emissionen verursacht. Der Stromverbrauch war um das 6-fache und die CO2-Emissionen um das 2,5-fache Mal höher im Vergleich zu der lokalen Berechnung mit CPUs. Logischerweise hängt beides mit der längeren Berechnungszeit zusammen. Diese betrug zweieinhalb Minuten für die GPU und nur etwas weniger als zwei Minuten für die CPUs. Insgesamt geben beide Pakete alle notwendigen Informationen an, um die CO2-Emissionen und damit zusammenhängende Informationen zu beurteilen und zu berichten.

3. Vergleiche die verschiedenen Regionen von Cloud-Anbietern

In den vergangenen Jahren hat das Training und die Anwendung von ML sowie DL Modellen in der Cloud im Vergleich zu lokalen Berechnungen immer mehr an Bedeutung gewonnen. Sicherlich ist einer der Gründe dafür der zunehmende Bedarf an Rechenleistung [8]. Zugriff auf GPUs in der Cloud ist für viele Unternehmen günstiger und schneller als der Bau eines eigenen Rechenzentrums. Natürlich benötigen auch Rechenzentren von Cloud-Anbietern Hardware und Strom für deren Betrieb. Es wird geschätzt, dass bereits circa 1% des weltweiten Strombedarfs auf Rechenzentren zurückgeht [19]. Da die Nutzung von Hardware, unabhängig vom Standort, immer CO2-Emissionen verursachen kann, ist es auch beim Training und der Anwendung von ML und DL Modellen in der Cloud wichtig, die CO2-Emissionen zu messen.

Aktuell ermöglichen zwei verschiedene Plattformen, die CO2e-Emissionen von Berechnungen in der Cloud zu ermitteln [20, 21]. Die guten Neuigkeiten dabei sind, dass die drei großen Cloud-Anbieter – AWS, Azure und GCP – in beiden Plattformen implementiert sind. Um zu beurteilen, welcher der drei Cloud-Anbieter und welche der verfügbaren europäischen Regionen die geringsten CO2e-Emissionen verursachen, habe ich die erste Plattform – ML CO2 Impact [20] – verwendet, um die CO2e-Emissionen für das abschließende Training von GPT-3 zu berechnen. Das finale Training von GPT-3 benötigte 310 GPUs (NVIDIA Tesla V100 PCIe), die ununterbrochen für 90 Tagen liefen [17]. Als Grundlage für die Berechnungen der CO2e-Emissionen der verschiedenen Cloud-Anbieter und deren Regionen, habe ich die verfügbare Option “Tesla V100-PCIE-16GB” als GPU gewählt. Die Ergebnisse der Berechnungen befinden sich in der nachfolgenden Tabelle.

Vergleich verschiedener Cloud-Anbieter und Regionen in Europa
Google Cloud Computing AWS Cloud Computing Microsoft Azure
Region CO2e Emissionen (Tonnen) Region CO2e Emissionen (Tonnen) Region CO2e Emissionen (Tonnen)
europe-west1 54.2 EU – Frankfurt 122.5 France Central 20.1
europe-west2 124.5 EU – Ireland 124.5 France South 20.1
europe-west3 122.5 EU – London 124.5 North Europe 124.5
europe-west4 114.5 EU – Paris 20.1 West Europe 114.5
europe-west6 4.0 EU – Stockholm 10.0 UK West 124.5
europe-north1 42.2 UK South 124.5

Zwei Ergebnisse in der Tabelle sind besonders auffällig. Erstens, die ausgewählte Region hat selbst innerhalb eines Cloud-Anbieters einen extrem großen Einfluss auf die geschätzten CO2e-Emissionen. Den größten Unterschied gab es bei GCP, mit einem Faktor von mehr als 30. Dieser große Unterschied ergibt sich auch durch die Region „europe-west6“, welche mit vier Tonnen die insgesamt geringsten CO2e-Emissionen verursacht. Interessanterweise ist ein Faktor der Größe 30 weit mehr als die Faktoren von 5 bis 10, welche in Studien beschrieben werden [12]. Neben den Unterschieden zwischen Regionen sind zweitens die Werte einiger Regionen exakt identisch. Dies spricht dafür, dass eine gewisse Vereinfachung bei den Berechnungen vorgenommen wurde. Die absoluten Werte sollten daher mit Vorsicht betrachtet werden, wobei die Unterschiede weiterhin bestehen bleiben, da allen Regionen die gleiche (vereinfachte) Art der Berechnung zu Grunde liegt.
Neben den reinen CO2e-Emissionen durch Rechenzentren, ist es für die Wahl eines Cloud-Anbieters ebenfalls wichtig, die Nachhaltigkeitsstrategie der Anbieter zu berücksichtigen. In diesem Bereich scheinen GCP und Azure im Vergleich zu AWS die besseren Strategien zu haben [22, 23]. Auch wenn kein Cloud-Anbieter bisher 100% erneuerbare Energien nutzt (siehe Tabelle 2 in [9]), haben GCP und Azure dies mit dem Ausgleich ihres CO2-Ausstoßes sowie Energiezertifikaten bereits in der Theorie erreicht. Aus ökologischer Sicht bevorzuge ich letztlich GCP, weil mich deren Strategie am meisten überzeugt hat. Zudem hat GCP seit 2021 bei der Auswahl der Regionen einen Hinweis eingefügt, welche den geringsten CO2-Ausstoß verursachen [24]. Für mich zeigen solche kleinen Hilfestellungen, welchen Stellenwert das Thema dort einnimmt.

4. Trainiere und nutze KI-Modelle mit Bedacht

Zu guter Letzt gibt es noch viele weitere Tipps und Tricks in Bezug auf das Training und den Einsatz von ML sowie DL Modellen, die dir helfen, deinen CO2-Fußabdruck als Data Scientist zu minimieren.

  • Sei sparsam! Neue Forschung, die DL Modelle mit aktuellen Ergebnissen aus den Neurowissenschaften kombiniert, kann die Berechnungszeit um das bis zu 100-fache reduzieren und dadurch extrem viel CO2 einsparen [25].
  • Verwende, wenn möglich, einfachere KI-Modelle, die eine vergleichbare Vorhersagegenauigkeit haben, aber weniger rechenintensiv sind. Beispielsweise gibt es das Modell DistilBERT, welches eine kleinere und schnellere Version von BERT ist, aber eine vergleichbare Genauigkeit besitzt [26].
  • Ziehe Transfer Learning und sogenannte Foundation Modelle [10| in Betracht, um die Vorhersagegenauigkeit zu maximieren und Berechnungszeit zu minimieren.
  • Ziehe Federated Learning in Betracht, um CO2-Emissionen zu minimieren [27].
  • Denke nicht nur an die Vorhersagegenauigkeit deiner Modelle. Effizienz ist ebenfalls ein wichtiges Kriterium. Wäge ab, ob eine 1% höhere Genauigkeit die zusätzlichen Umweltauswirkungen wert sind [9, 12].
  • Wenn der beste Bereich für die Hyperparameter deines Modells noch unbekannt sind, nutze eine zufällige oder Bayesianische Suche nach den Hyperparametern anstatt einer Rastersuche [9, 20].
  • Wenn dein Modell während der Anwendung regelmäßig neu trainiert wird, wähle das Trainingsintervall bewusst aus. Je nach Anwendungsfall reicht es womöglich aus, das Modell nur jeden Monat und nicht jede Woche neu zu trainieren.

Fazit

Es besteht kein Zweifel daran, dass Menschen und ihre Treibhausgasemissionen das Klima beeinflussen und unseren Planeten erwärmen. KI kann und sollte beim Problem des Klimawandels zur Lösung beitragen. Gleichzeitig müssen wir den CO2-Fußabdruck von KI im Auge behalten, um sicherzustellen, dass es Teil der Lösung und nicht Teil des Problems ist.

Du kannst als Data Scientist dabei einen großen Beitrag leisten. Informiere dich über die positiven Möglichkeiten und die negativen Auswirkungen von KI und kläre andere darüber auf. Außerdem kannst du die CO2-Emissionen deiner Modelle messen und transparent darstellen. Du solltest zudem deine Anstrengungen zur Minimierung des CO2-Fußabdrucks deiner Modelle beschreiben. Letztlich kannst du deinen Cloud-Anbieter bewusst wählen und beispielsweise prüfen, ob es für deinen Anwendungsfall einfachere Modelle gibt, die eine vergleichbare Vorhersagegenauigkeit bieten, aber mit weniger Emissionen.

Wir bei statworx haben vor kurzem die Initiative AI & Environment ins Leben gerufen, um genau solche Aspekte in unserer täglichen Arbeit als Data Scientists einzubauen. Wenn du mehr darüber erfahren möchtest, sprich uns einfach an!

Referenzen

  1. https://www.ipcc.ch/report/ar6/wg1/downloads/report/IPCC_AR6_WGI_SPM_final.pdf
  2. http://www.globalcarbonatlas.org/en/CO2-emissions
  3. https://doi.org/10.1007/s43681-021-00043-6
  4. https://arxiv.org/pdf/1906.05433.pdf
  5. Harnessing Artificial Intelligence
  6. https://www.pwc.co.uk/sustainability-climate-change/assets/pdf/how-ai-can-enable-a-sustainable-future.pdf
  7. https://climateactiontracker.org/
  8. https://arxiv.org/pdf/1907.10597.pdf
  9. https://arxiv.org/pdf/1906.02243.pdf
  10. https://arxiv.org/pdf/2108.07258.pdf
  11. https://algorithmwatch.org/de/sustain/
  12. https://arxiv.org/ftp/arxiv/papers/2104/2104.10350.pdf
  13. https://stefanos1316.github.io/my_curriculum_vitae/GKS17.pdf
  14. https://pypl.github.io/PYPL.html
  15. https://codecarbon.io/
  16. https://mlco2.github.io/codecarbon/index.html
  17. https://arxiv.org/pdf/2007.03051.pdf
  18. https://github.com/Breakend/experiment-impact-tracker
  19. https://www.iea.org/reports/data-centres-and-data-transmission-networks
  20. https://mlco2.github.io/impact/#co2eq
  21. http://www.green-algorithms.org/
  22. https://blog.container-solutions.com/the-green-cloud-how-climate-friendly-is-your-cloud-provider
  23. https://www.wired.com/story/amazon-google-microsoft-green-clouds-and-hyperscale-data-centers/
  24. https://cloud.google.com/blog/topics/sustainability/pick-the-google-cloud-region-with-the-lowest-co2)
  25. https://arxiv.org/abs/2112.13896
  26. https://arxiv.org/abs/1910.01108
  27. https://flower.dev/blog/2021-07-01-what-is-the-carbon-footprint-of-federated-learning

Alexander Niltop Alexander Niltop

Einleitung

Jeder Data-Science- und KI-Experte wird Ihnen sagen: Reale Data Science und KI-Initiativen bringen verschiedene Herausforderungen mit sich, auf die weder praktische Programmierwettbewerbe noch theoretische Vorlesungen vorbereiten können. Und manchmal – erschreckend oft [1, 2] – führen diese Probleme in der Praxis dazu, dass vielversprechende KI-Projekte oder ganze KI-Initiativen scheitern. Seit geraumer Zeit wird eine rege Diskussion über die eher technischen Fallstricke und mögliche Lösungen geführt. Zu den bekannteren Problemen gehören z. B. isolierte Daten, schlechte Datenqualität, zu unerfahrene oder unterbesetzte DS & KI-Teams, unzureichende Infrastruktur für das Training und die Bereitstellung von Modellen. Ein weiteres Problem ist, dass zu viele Lösungen aufgrund organisatorischer Probleme nie in die Produktion überführt werden.

Erst in letzter Zeit hat sich der Fokus des Diskurses mehr auf strategische Fragen verlagert. Meiner Meinung nach wird diesen Aspekten jedoch immer noch nicht die Aufmerksamkeit zuteil, die sie verdienen.

Deshalb möchte ich in diesem Beitrag meine Meinung zu den wichtigsten (nicht-technischen) Gründen für das Scheitern von DS & KI-Initiativen darlegen. Darüber hinaus werde ich Ihnen verschiedene Ansätze zur Lösung dieser Probleme vorstellen. Ich bin Data & Strategy Consultant bei STATWORX und ich bin sicher, dass dieser Artikel eher subjektiv ist. Er spiegelt meine persönlichen Erfahrungen mit den Problemen und Lösungen wider, auf die ich gestoßen bin. 

Problem Nr. 1: Mangelnde Verknüpfung von Projektumfang und tatsächlichem Business-Problem Problem 1

Ein Problem, das viel häufiger auftritt, als man denken würde, ist die Fehlanpassung der entwickelten Data Science und KI-Lösungen an die tatsächlichen Geschäftsbedürfnisse. Das fertige Produkt erfüllt vielleicht genau die Aufgabe, die das DS- und KI-Team lösen wollte, aber die Anwender:innen suchen eventuell nach einer Lösung für eine ähnliche, aber deutlich andere Aufgabe.

Zu wenig Austausch durch indirekte Kommunikationskanäle oder das Fehlen einer gemeinsamen Sprache und eines gemeinsamen Referenzrahmens führt oft zu grundlegenden Missverständnissen. Das Problem ist, dass ironischerweise nur eine extrem detaillierte, effektive Kommunikation solche subtilen Probleme aufdecken kann.

Die Einbeziehung zu weniger oder selektiver Perspektiven kann zu einem bösen Erwachen führen

In anderen Fällen unterscheiden sich einzelne Teilprozesse oder die Arbeitsweisen einzelner Nutzenden sehr stark. Oft sind sie so unterschiedlich, dass eine Lösung, die für einen der Anwender:innen/Prozesse von großem Nutzen ist, für alle anderen kaum Vorteile bringt (die Entwicklung von Lösungsvarianten ist zwar manchmal eine Option, aber bei weitem nicht so kosteneffizient).

Wenn Sie Glück haben, stellen Sie dies bereits zu Beginn eines Projekts bei der Erhebung der Anforderungen fest. Wenn man Pech hat, kommt das böse Erwachen erst beim breiteren Nutzertest oder gar bei der Einführung, wenn sich herausstellt, dass die Nutzer:innen oder Expert:innen, die die bisherige Entwicklung beeinflusst haben, keinen allgemeingültigen Input geliefert haben und das entwickelte Werkzeug daher nicht allgemein einsetzbar ist.

Wie Sie diesem Problem entgegenwirken können:

  • Führen Sie ein strukturiertes und gründliches Requirements Engineering durch. Nehmen Sie sich die Zeit, mit so vielen Expert:innen und Nutzer:innen wie möglich zu sprechen, und versuchen Sie, alle impliziten Annahmen so explizit wie möglich zu machen. Obwohl das Requirements Engineering aus dem Wasserfall-Paradigma stammt, kann es leicht für die agile Entwicklung angepasst werden. Die ermittelten Anforderungen dürfen einfach nicht als endgültige Produktmerkmale verstanden werden, sondern als Elemente für Ihr anfängliches Backlog, die ständig (neu) bewertet und (neu) priorisiert werden müssen.
  • Definieren Sie unbedingt Erfolgsmessungen. Tun Sie dies vor Projektbeginn, am besten in Form von objektiv quantifizierbaren KPIs und Benchmarks. Dies trägt wesentlich dazu bei, das Geschäftsproblem bzw. den Geschäftswert, der der angestrebten Lösung zugrunde liegt, zu ermitteln.
  • Erstellen Sie, wann immer möglich und so schnell wie möglich, Prototypen, Mock-ups oder sogar Storyboards. Präsentieren Sie diese Lösungsentwürfe so vielen Testnutzern wie möglich. Diese Methoden erleichtern das Einholen von offenem und präzisem Nutzerfeedback, das in die weitere Entwicklung einfließt. Achten Sie darauf, dass Sie eine für die Gesamtheit der Nutzer repräsentative Stichprobe einbeziehen.

Problem Nr. 2: Effizienz- und Ressourcenverluste durch nicht strukturierte Data Science- und KI-Maßnahmen Problem 2

Dezentralisierte Data Science- & KI-Teams entwickeln ihre Anwendungsfälle oft mit wenig bis gar keinem Austausch oder Abgleich zwischen den aktuellen Anwendungsfällen und Backlogs der Teams. Dies kann dazu führen, dass verschiedene Teams versehentlich und unbemerkt (Teile) der gleichen (oder sehr ähnlichen) Lösung entwickeln.

In den meisten Fällen wird, wenn eine solche Situation entdeckt wird, eine der redundanten DS & KI-Lösungen eingestellt oder es werden keine zukünftigen Mittel für die weitere Entwicklung oder Wartung bereitgestellt. So oder so, die redundante Entwicklung von Anwendungsfällen führt immer zu einer direkten Verschwendung von Zeit und anderen Ressourcen ohne oder mit nur minimalem Zusatznutzen.

Problematisch ist auch die fehlende Abstimmung des Use Case Portfolios eines Unternehmens auf die allgemeine Geschäfts- oder KI-Strategie. Dies kann hohe Opportunitätskosten verursachen: Anwendungsfälle, die nicht zur allgemeinen KI-Vision beitragen, können unnötigerweise wertvolle Ressourcen blockieren. Außerdem werden potenzielle Synergien zwischen strategisch wichtigeren Anwendungsfällen (Use Cases) möglicherweise nicht voll ausgeschöpft. Und schließlich könnte der Aufbau von Kompetenzen in Bereichen erfolgen, die von geringer oder gar keiner strategischen Bedeutung sind.

Wie Sie diesem Problem entgegenwirken können:

  • Kommunikation ist der Schlüssel. Deshalb sollte es immer eine Reihe von Möglichkeiten für die Data-Science-Expert:innen innerhalb eines Unternehmens geben, sich zu vernetzen und ihre Erfahrungen und Best Practices auszutauschen – insbesondere bei dezentralen DS & KI-Teams. Damit dies funktioniert, ist es wichtig, eine Arbeitsatmosphäre der Zusammenarbeit zu schaffen. Der freie Austausch von Erfolgen und Misserfolgen und damit die interne Verbreitung von Kompetenzen kann nur ohne Konkurrenzdenken gelingen.
  • Eine weitere Möglichkeit, das Problem zu entschärfen, ist die Einrichtung eines zentralen Ausschusses, der mit der Verwaltung des DS und KI Use Case Portfolios der Organisation betraut ist. Diesem Ausschuss sollten Vertreter:innen aller (dezentralen) Data Science und KI-Abteilungen sowie der Geschäftsleitung angehören. Gemeinsam überwacht der Ausschuss die Abstimmung von Use Cases und der KI-Strategie, um Redundanzen zu vermeiden und Synergien voll auszuschöpfen.

Problem Nr. 3: Unrealistisch hohe Erwartungen an den Erfolg von Data Science und KI Problem 3

Es mag paradox klingen, aber ein zu großer Optimismus in Bezug auf die Möglichkeiten und Fähigkeiten von Data Science und KI kann dem Erfolg abträglich sein. Denn zu optimistische Erwartungen führen oft dazu, dass die Anforderungen unterschätzt werden, wie z. B. die für die Entwicklung benötigte Zeit oder der Umfang und die Qualität der benötigten Datenbasis.

Gleichzeitig sind die Erwartungen in Bezug auf die Modellgenauigkeit oft zu hoch, ohne dass man die Grenzen des Modells und die grundlegenden Mechanismen von Machine Learning kennt. Diese Unerfahrenheit kann dazu führen, dass viele wichtige Tatsachen nicht erkannt werden, einschließlich, aber nicht beschränkt auf die folgenden Punkte: die unvermeidliche Extrapolation historischer Muster auf die Zukunft; die Tatsache, dass externe Paradigmenwechsel oder Schocks die Generalisierbarkeit und Leistung von Modellen gefährden; die Komplexität der Harmonisierung von Vorhersagen mathematisch nicht verwandter Modelle; die geringe Interpretierbarkeit naiver Modelle oder die Dynamik der Modellspezifikationen aufgrund von Umschulungen.

DS & KI sind einfach keine Wunderwaffe, und zu hohe Erwartungen können dazu führen, dass die Begeisterung in tiefe Ablehnung umschlägt. Die anfänglichen Erwartungen werden fast zwangsläufig nicht erfüllt und weichen daher oft einer tiefgreifenden und undifferenzierten Ablehnung von DS & KI. Dies kann in der Folge dazu führen, dass weniger auffällige, aber nützliche Anwendungsfälle keine Unterstützung mehr finden.

Wie Sie diesem Problem entgegenwirken können:

  • Versuchen Sie in Ihrer Kommunikation mit Stakeholdern stets realistische Perspektiven zu vermitteln. Achten Sie darauf, eindeutige Botschaften und objektive KPIs zu verwenden, um Erwartungen zu steuern und Bedenken so offen wie möglich anzusprechen.
  • Die Weiterbildung der Stakeholder und des Managements in den Grundlagen von Machine Learning und KI versetzt sie in die Lage, realistischere Einschätzungen und damit sinnvollere Entscheidungen zu treffen. Technisch fundiertes Wissen ist oft nicht notwendig. Konzeptuelles Fachwissen auf einem relativ hohen Abstraktionsniveau ist ausreichend (und glücklicherweise viel leichter zu erlangen).
  • Schließlich sollte, wann immer möglich, ein PoC vor einem vollwertigen Projekt durchgeführt werden. Dies ermöglicht es, empirische Hinweise auf die Durchführbarkeit des Use Cases zu sammeln und hilft bei der realistischen Einschätzung der erwarteten Leistung, die anhand relevanter (vordefinierter!) KPIs gemessen wird. Wichtig ist es auch, die Ergebnisse solcher Tests ernst zu nehmen. Bei einer negativen Prognose sollte nie einfach davon ausgegangen werden, dass sich mit mehr Zeit und Aufwand alle Probleme des PoC in Luft auflösen werden.

Problem Nr. 4: Ressentiments und grundsätzliche Ablehnung von Data Science und KI Problem 4

Eine unsichtbare, aber nicht zu unterschätzende Hürde liegt in den Köpfen der Menschen. Dies gilt sowohl für die Belegschaft als auch für das Management. Oft werden vielversprechende Data Science und KI-Initiativen aufgrund von tief verwurzelten, aber undifferenzierten Vorbehalten ausgebremst. Das richtige Mindset ist entscheidend.

Obwohl DS und KI in aller Munde sind, fehlt es in vielen Unternehmen noch an echtem Management-Engagement. Häufig werden zwar Lippenbekenntnisse zu DS & KI abgegeben und erhebliche Mittel investiert, aber die Vorbehalte gegenüber KI bleiben bestehen.

Begründet wird dies oft mit den inhärenten Verzerrungen und Unsicherheiten von KI-Modellen und ihrer geringen direkten Interpretierbarkeit. Hinzu kommt manchmal eine generelle Abneigung, Erkenntnisse zu akzeptieren, die nicht mit der eigenen Intuition übereinstimmen. Die Tatsache, dass die menschliche Intuition oft viel stärkeren – und im Gegensatz zu KI-Modellen nicht quantifizierbaren – Verzerrungen unterliegt, wird in der Regel ignoriert.

Data Science & KI-Initiativen brauchen die Akzeptanz und Unterstützung der Belegschaft

Dies führt dazu, dass (Entscheidungs-)Prozesse und Organisationsstrukturen (z.B. Rollen, Verantwortlichkeiten) nicht so angepasst werden, dass DS & KI-Lösungen ihren (vollen) Nutzen entfalten können. Dies wäre aber notwendig, denn Data Science & KI ist nicht einfach eine weitere Softwarelösung, die sich nahtlos in bestehende Strukturen integrieren lässt.

DS & KI ist eine disruptive Technologie, die unweigerlich ganze Branchen und Organisationen umgestalten wird. Unternehmen, die sich diesem Wandel verweigern, werden auf lange Sicht wahrscheinlich genau an diesem Paradigmenwechsel scheitern. Die Ablehnung des Wandels beginnt bei scheinbaren Kleinigkeiten, wie der Umstellung des Projektmanagements von der Wasserfallmethode auf eine agile, iterative Entwicklung. Ungeachtet der allgemein positiven Aufnahme bestimmter Veränderungsmaßnahmen wird manchmal eine völlig irrationale Ablehnung der Reform bestehender (noch) funktionierender Prozesse festgestellt. Dabei wäre genau das notwendig, um – zugegebenermaßen erst nach einer Phase der Neujustierung – langfristig wettbewerbsfähig zu sein.

Während Vision, Strategie und Strukturen von oben nach unten verändert werden müssen, kann das operative Tagesgeschäft nur von unten nach oben, durch die Mitarbeitenden, revolutioniert werden. Das Engagement des Managements und das beste Werkzeug der Welt sind nutzlos, wenn die Endnutzer:innen nicht in der Lage oder willens sind, es anzunehmen. Die allgemeine Unsicherheit über die langfristige KI-Roadmap und die Angst, durch Maschinen ersetzt zu werden, schüren Ängste, die dazu führen, dass DS & KI-Lösungen nicht in den Arbeitsalltag integriert werden. Dies ist natürlich mehr als problematisch, da nur die (richtige) Anwendung von KI-Lösungen einen Mehrwert schafft.

Wie Sie diesem Problem entgegenwirken können:

  • Es überrascht nicht, dass ein solides Change Management der beste Ansatz ist, um die KI-feindliche Denkweise zu entschärfen. Dies sollte nicht nur ein nachträglicher Gedanke, sondern ein integraler Bestandteil jeder DS & KI-Initiative und es sollten Verantwortlichkeiten für diese Aufgabe zugewiesen werden. Eine frühzeitige, umfassende, detaillierte und klare Kommunikation ist unerlässlich. Welche Schritte werden voraussichtlich wann und wie genau umgesetzt? Denken Sie daran, dass es schwer ist, einmal verlorenes Vertrauen wiederzugewinnen. Daher sollten alle Unklarheiten in der Planung angesprochen werden. Entscheidend ist es, bei allen Beteiligten ein Grundverständnis für die Sache zu schaffen und die Notwendigkeit der Veränderung zu verdeutlichen (z.B. weil sonst die Wettbewerbsfähigkeit gefährdet ist, Erfolgsgeschichten oder Misserfolge der Konkurrenz). Darüber hinaus ist der Dialog mit den Betroffenen von großer Bedeutung. Feedback sollte frühzeitig eingeholt und nach Möglichkeit umgesetzt werden. Bedenken sollten immer gehört und respektiert werden, auch wenn sie nicht berücksichtigt werden können. Falsche Versprechungen sind jedoch strikt zu vermeiden; stattdessen sollte man versuchen, die Vorteile von DS & KI in den Vordergrund zu stellen.
  • Neben der Einsicht in die Notwendigkeit von Veränderungen ist auch die grundsätzliche Fähigkeit zur Veränderung wichtig. Die Angst vor dem Unbekannten oder Unverständlichen ist uns Menschen inhärent. Daher kann Bildung – nur auf dem für die jeweilige Rolle notwendigen Abstraktions- und Tiefenniveau – einen großen Unterschied machen. Entsprechende Schulungsmaßnahmen sind keine einmalige Angelegenheit; der Aufbau von aktuellem Wissen und die Ausbildung im Bereich Data Science & KI müssen langfristig sichergestellt werden. Die allgemeine Datenkompetenz der Belegschaft muss ebenso sichergestellt werden, wie die Auf- oder Umschulung von technischen Expert:innen. Die Mitarbeitenden müssen eine realistische Chance erhalten, neue und attraktivere Beschäftigungsmöglichkeiten zu erhalten, indem sie sich weiterbilden und sich mit DS & KI beschäftigen. Das wahrscheinlichste Ergebnis sollte niemals sein, dass sie durch DS & KI ihren alten Arbeitsplatz (teilweise) verlieren, sondern muss als Chance und nicht als Gefahr wahrgenommen werden; Data Science & KI müssen Perspektiven schaffen und dürfen sie nicht verderben.
  • Übernehmen oder adaptieren Sie die Best Practices von DS & KI-Führungskräften in Bezug auf die Definition von Rollen- und Kompetenzprofilen, die Anpassung von Organisationsstrukturen und Wertschöpfungsprozessen. Bewährte Ansätze können als Blaupause für die Reformierung Ihrer Organisation dienen und so sicherstellen, dass Sie auch in Zukunft wettbewerbsfähig bleiben.

Schlussbemerkungen

Wie Sie vielleicht bemerkt haben, bietet dieser Blogbeitrag keine einfachen Lösungen. Das liegt daran, dass die Probleme, um die es hier geht, komplex und mehrdimensional sind. Dieser Artikel hat high-level Ansätze zur Entschärfung der angesprochenen Probleme geliefert, aber es muss betont werden, dass diese Probleme einen ganzheitlichen Lösungsansatz erfordern. Dies erfordert eine klare KI-Vision und eine daraus abgeleitete solide KI-Strategie, nach der die Vielzahl der notwendigen Maßnahmen koordiniert und gesteuert werden kann.

Deshalb muss ich betonen, dass wir das Stadium, in dem experimentelle und unstrukturierte Data Science und KI-Initiativen erfolgreich sein können, längst verlassen haben. DS & KI darf nicht als technisches Thema behandelt werden, das ausschließlich in Fachabteilungen stattfindet. Es ist an der Zeit, KI als strategisches Thema anzugehen. Wie bei der digitalen Revolution werden nur Organisationen, in denen KI das Tagesgeschäft und die allgemeine Geschäftsstrategie vollständig durchdringt und reformiert, langfristig erfolgreich sein. Wie oben beschrieben, birgt dies zweifelsohne viele Fallstricke, stellt aber auch eine unglaubliche Chance dar.

Wenn Sie bereit sind, diese Veränderungen zu integrieren, aber nicht wissen, wo Sie anfangen sollen, helfen wir von STATWORX Ihnen gerne. Besuchen Sie unsere Website und erfahren Sie mehr über unser Angebot im Bereich AI Strategy!

Quellen

[1] https://www.forbes.com/sites/forbestechcouncil/2020/10/14/why-do-most-ai-projects-fail/?sh=2f77da018aa3 [2] https://blogs.gartner.com/andrew_white/2019/01/03/our-top-data-and-analytics-predicts-for-2019/

Lea Waniek

Lea Waniek Lea Waniek

Dieser Artikel ist am 28. August 2021 in der Zeitung DIE WELT erschienen.

WELT_Menschzentrierte KI
 

Künstliche Intelligenz (KI) ist einer der zentralen Treiber der digitalen Transformation. Über die vergangene Dekade hinweg haben sich bahnbrechende Anwendungen der Technologie regelmäßig aneinandergereiht und sich dabei regelmäßig selbst überholt. Angetrieben durch den immer weiter voranschreitenden Erfolg von KI-Technologie diffundiert diese stetig in alle wesentlichen Bereiche des menschlichen Lebens hinein. Neben der Arbeitswelt schließt dies insbesondere auch das breitere gesellschaftliche Leben ein. Dabei sind sich KI-Experten alle einig, dass der aktuelle Entwicklungsstand von KI nur die Spitze eines riesigen Eisbergs ist, dessen Freilegung gerade erst begonnen hat. Die dadurch entstehenden Veränderungen werden eine neue Ära unserer Gesellschaft entstehen lassen, in der Menschen mit Maschinen Seite an Seite arbeiten und leben werden.

Mit der wachsenden Bedeutung von KI für die Gesellschaft nimmt auch die Sorge der Menschen zu, dass die Technologie, die ohnehin schon so viel verändert, in einigen Jahren dazu führen wird, dass Menschen „wie Roboter“ handeln. Während Künstliche Intelligenz heute noch als Werkzeug dient – so wie Maschinen oder Computer früher – wird sie sich in Zukunft zunehmend in die Gedanken und Handlungen der Menschen einbringen. Dazu wird sie das Verhalten von Personen und das Zusammenspiel mit anderen Menschen analysieren, um daraus abzulesen, welche Handlungsoptionen für ihre Nutzer in einem bestimmten Moment am besten sind.

Menschenzentrierte KI ist ein Teilbereich der KI-Forschung, der sich auf die Entwicklung von KI-Systemen konzentriert, die sich menschenähnlich verhalten. Im Gegensatz zur traditionellen KI-Forschung, die sich auf die Entwicklung von KI-Systemen konzentriert, die sich rational und ohne menschenähnliche Eigenschaften verhalten sollen, zielt die menschenzentrierte KI darauf ab, den Menschen und die menschliche Intelligenz zu studieren, um KI-Systeme mit ähnlichen Eigenschaften zu entwickeln.

Die menschenzentrierte KI ist durch den Wunsch motiviert, KI-Systeme zu schaffen, die mit Menschen auf natürliche Weise interagieren können. Rationale KI-Systeme können zwar intelligent handeln, verhalten sich aber nicht wie Menschen, was ein Hindernis für ihre Akzeptanz durch Menschen sein kann. Während sich die herkömmliche KI-Forschung auf die Überwindung dieser Barriere konzentriert hat, zielt die menschenzentrierte KI-Forschung darauf ab, KI-Systeme zu schaffen, die sich auf natürliche Weise verhalten, so dass sie für den Menschen besser nachvollziehbar und akzeptabel sind. Es ist wichtig, dass wir uns im Vorfeld vergewissern, dass die Technologie im Einklang mit unserer Menschlichkeit steht und den Menschen in der Arbeitswelt nicht nur unterstützt, sondern ihn auch nicht „überholt“. Eine solche menschenzentrierte KI kann dabei helfen, menschliche und nicht-menschliche Intelligenz in einem gesunden Verhältnis miteinander zu integrieren. Der Fokus liegt dabei auf den Bedürfnissen der Nutzer, die als die wichtigsten Zielgruppen der Technologie betrachtet werden.

Die zentrale Herausforderung der künstlichen Intelligenz ist daher nicht die Technologie selbst, sondern vielmehr der Umgang des Menschen mit dieser Technologie. Die technische Entwicklung wird in Zukunft weitergehen und damit immer intelligentere, autonome Systeme hervorbringen. Die Systeme und ihre Entscheidungsprozesse werden den Menschen zunehmend hinter sich lassen, „maschinelles Lernen“ wird das Gebot der Stunde sein. Dabei ist es wichtig, dass die Menschen die KI-Technologie als einen Schritt in eine bessere Zukunft begreifen und nicht als Bedrohung verkörpert. Die Entwicklung der KI ist ein Prozess, der nur durch den Dialog zwischen Menschen und Technologien bewältigt werden kann. Die unzureichende Aufklärung der Gesellschaft über die Technologie und die unzureichende Kommunikation zwischen den Nutzern und der Industrie spielen hierbei eine große Rolle. Dabei sollte der Mensch immer im Vordergrund stehen und nicht nur als ein Werkzeug der KI.

Genese

Der vorstehende Text wurde mithilfe der KI „GPT-3“ verfasst. Das Akronym GPT steht für „Generative Pretrained Transformer“ (in der Version 3), einer KI, die in 2020 durch das Amerikanische Forschungsunternehmen OpenAI entwickelt wurde. Bei GPT-3 handelt es sich um ein sogenanntes generatives Sprachmodell, das auf einer extrem großen Menge an diversen Texten aus dem Internet trainiert wurde.

Das Training von GPT-3 erfolgt mittels Deep Learning, einer Gruppe von Methoden aus dem maschinellen Lernen, die grobe Ähnlichkeiten zur Informationsverarbeitung und -weitergabe im menschlichen Gehirn aufweisen (Nervenzellen bzw. Neuronen geben die zu verarbeitenden Informationen an andere Neuronen und Hirnareale weiter). Im Rahmen des Modelltrainings passen sich die rund 175 Milliarden Parameter von GPT-3 an die zugrundeliegenden Trainingsdaten an und erlernen den Zusammenhang zwischen dem zuvor beobachteten Text eines Satzes/Abschnittes und dem nächsten, wahrscheinlich auftauchenden Wort. Hierdurch generiert die KI während des Lernvorgangs ein generelles und umfassendes Verständnis über die Verwendung von Worten im jeweiligen Kontext.

So geschah es auch in diesem Artikel. Als Ausgangsbasis der Textgenerierung dienten lediglich die ersten fünf Sätze des ersten Absatzes. Hierin wurde der Kontext definiert, in dem die KI operieren soll. Alle darauffolgenden Abschnitte wurden eigenständig durch die KI generiert und inhaltlich nicht modifiziert (Anmerkung: es wurden einzelne Absätze wiederholt erzeugt und anschließend zu einem Artikel zusammengefügt).

Der Schlüssel zum Erfolg liegt also in der geschickten Definition des Kontextes, der die KI im Prozess der Generierung anleitet. Bahnbrechend ist hierbei, dass die Kontextdefinition über natürliche Sprache funktioniert und nicht manuell in die KI „einprogrammiert“ werden muss. Die KI „versteht“ somit eigenständig den Kontext, in dem sie sich bewegen soll.

Wir hoffen, Ihnen mit diesem Beispiel einen Eindruck von der Mächtigkeit solcher KI-Systeme geben zu können. Es ist zu erwarten, dass bereits in naher Zukunft neue Versionen dieser und ähnlicher KI-Systeme entstehen, die in der Lage sein werden, noch bessere Ergebnisse erzeugen zu können.

Sebastian Heinz Sebastian Heinz

Einführung

Je komplexer ein beliebiges Data Science Projekt in Python wird, desto schwieriger wird es in der Regel, den Überblick darüber zu behalten, wie alle Module miteinander interagieren. Wenn man in einem Team an einem größeren Projekt arbeitet, wie es hier bei STATWORX oft der Fall ist, kann die Codebasis schnell so groß werden, dass die Komplexität abschreckend wirken kann. In einem typischen Szenario arbeitet jedes Teammitglied in seiner „Ecke“ des Projekts, so dass jeder nur über ein solides lokales Wissen über den Code des Projekts verfügt, aber möglicherweise nur eine vage Vorstellung von der Gesamtarchitektur des Projekts hat. Im Idealfall sollte jedoch jeder, der an dem Projekt beteiligt ist, einen guten globalen Überblick über das Projekt haben. Damit meine ich nicht, dass man wissen muss, wie jede Funktion intern funktioniert, sondern eher, dass man die Zuständigkeit der Hauptmodule kennt und weiß, wie sie miteinander verbunden sind.

Ein visuelles Hilfsmittel, um die globale Struktur kennenzulernen, kann ein Call Graph sein. Ein Call Graph ist ein gerichteter Graph, der anzeigt, welche Funktion welche Funktion aufruft. Er wird aus den Daten eines Python-Profilers wie cProfile erstellt.

Da sich ein solcher Graph in einem Projekt, an dem ich arbeite, als hilfreich erwiesen hat, habe ich ein Paket namens project_graph erstellt, das einen solchen Call Graph für ein beliebiges Python-Skript erstellt. Das Paket erstellt ein Profil des gegebenen Skripts über cProfile, konvertiert es in einen gefilterten Punktgraphen über gprof2dot und exportiert es schließlich als .png-Datei.

Warum sind Projektgrafiken nützlich?

Als erstes kleines Beispiel soll dieses einfache Modul dienen.

# test_script.py

import time
from tests.goodnight import sleep_five_seconds

def sleep_one_seconds():
    time.sleep(1)

def sleep_two_seconds():
    time.sleep(2)

for i in range(3):
    sleep_one_seconds()

sleep_two_seconds()

sleep_five_seconds()

Nach der Installation (siehe unten) wird durch Eingabe von project_graph test_script.py in die Kommandozeile die folgende png-Datei neben dem Skript platziert:

Das zu profilierende Skript dient immer als Ausgangspunkt und ist die Wurzel des Baums. Jedes Kästchen ist mit dem Namen einer Funktion, dem Gesamtprozentsatz der in der Funktion verbrachten Zeit und der Anzahl ihrer Aufrufe beschriftet. Die Zahl in Klammern gibt an, wieviel Zeit innerhalb einer Funktion verbracht wurde, jedoch ohne die Zeit in weiteren Unterfunktion zu berücksichtigen.

In diesem Fall wird die gesamte Zeit in der Funktion sleep des externen Moduls time verbracht, weshalb die Zahl 0,00% beträgt. In selbstgeschriebenen Funktionen wird nur selten viel Zeit verbracht, da die Arbeitslast eines Skripts in der Regel schnell auf sehr einfache Funktionen der Python-Implementierung selbst rausläuft. Neben den Pfeilen ist auch die Zeit angegeben, die eine Funktion an die andere weitergibt, zusammen mit der Anzahl der Aufrufe. Die Farben (ROT-GRÜN-BLAU, absteigend) und die Dicke der Pfeile zeigen die Relevanz der verschiedenen Stellen im Programm an.

Beachten Sie, dass sich die Prozentsätze der drei obigen Funktionen nicht zu 100 % aufaddieren. Der Grund dafür ist, dass der Graph so eingestellt ist, dass er nur selbst geschriebene Funktionen enthält. In diesem Fall hat das Importieren des Moduls time den Python-Interpreter dazu veranlasst, 0,04% der Zeit für eine Funktion des Moduls importlib aufzuwenden.

Auswertung mit externen Packages

Betrachten wir ein zweites Beispiel:

# test_script_2.py

import pandas as pd
from tests.goodnight import sleep_five_seconds

# some random madness
for i in range(1000):
   a_frame = pd.DataFrame([[1,2,3]])

sleep_five_seconds()

In diesem Skript wird ein Teil der Arbeit in einem externen Paket erledigt, das auf der Top-Ebene und nicht in einer benutzerdefinierten Funktion aufgerufen wird. Um dies im Graphen zu erfassen, können wir das externe Paket (pandas) mit der Flag -x hinzufügen. Die Initialisierung eines Pandas DataFrame wird jedoch in vielen Pandas-internen Funktionen durchgeführt. Offen gesagt, bin ich persönlich nicht an den inneren Verwicklungen von pandas interessiert, weshalb ich möchte, dass der Baum nicht zu tief in die Pandas-Mechanik „hineinwächst“. Diesem Umstand kann man Rechnung tragen, indem man nur Funktionen auftauchen lässt, die einen minimalen Prozentsatz der Laufzeit in ihnen verbringen. Genau dies kann mit der -m-Flag erreicht werden.

In Kombination ergibt project_graph -m 8 -x pandas test_script_2.py das folgende Ergebnis:

Project Graph Creation Example 02

Spaß(-Beispiele) beiseite, nun wollen wir uns ernsteren Dingen zuwenden. Ein echtes Data Science Projekt könnte wie dieses aussehen:

Project Graph Creation Example 03

Dieses Mal ist der Baum viel größer. Er ist sogar noch größer als in der Abbildung zu sehen, da viel mehr selbst geschriebene Funktionen aufgerufen werden. Sie werden jedoch aus Gründen der Übersichtlichkeit aus dem Baum entfernt, da Funktionen, für die weniger als 0,5 % der Gesamtzeit aufgewendet werden, herausgefiltert werden (dies ist die Standardeinstellung für die -m Flag). Beachten Sie, dass ein solches Diagramm auch bei der Suche nach Leistungsengpässen sehr vorteilhaft ist. Man sieht sofort, welche Funktionen den größten Teil der Arbeitslast tragen, wann sie aufgerufen werden und wie oft sie aufgerufen werden. Das kann Sie davor bewahren, Ihr Programm an den falschen Stellen zu optimieren und dabei den Elefanten im Raum zu übersehen.

Wie man project graph verwendet

Installation

Gehen Sie in Ihrer Projektumgebung wie folgt vor:

brew install graphviz

pip install git+https://github.com/fior-di-latte/project_graph.git

Verwendung

Wechseln Sie in der Projektumgebung in das aktuelle Arbeitsverzeichnis des Projekts (das ist wichtig!) und geben Sie für die Standardverwendung ein:

project_graph myscript.py

Wenn Ihr Skript einen argparser enthält, verwenden Sie (vergessen Sie nicht die Anführungsstriche!):

project_graph "myscript.py <arg1> <arg2> (...)"

Wenn Sie den gesamten Graphen sehen wollen, einschließlich aller externen Pakete, verwenden Sie:

project_graph -a myscript.py

Wenn Sie eine andere Sichtbarkeitsschwelle als 1% verwenden wollen, benutzen Sie:

project_graph -m <percent_value> myscript.py

Wenn Sie schließlich externe Pakete in den Graphen aufnehmen wollen, können Sie sie wie folgt angeben:

project_graph -x <package1> -x <package2> (...) myscript.py

Schluss & Hinweise

Dieses Paket hat einige Schwächen, von denen die meisten behoben werden können, z.B. durch Formatierung des Codes in einen funktionsbasierten Stil, durch Trimmen mit der -m-Flag oder durch Hinzufügen von Paketen mit der-x-Flag. Wenn etwas seltsam erscheint ist der erste Schritt wahrscheinlich die Verwendung der -a-Flag zur Fehlersuche. Wesentliche Einschränkungen sind die folgenden:

  • Es funktioniert nur auf Unix-Systemen.
  • Es zeigt keinen wahrheitsgetreuen Graphen an, wenn es mit Multiprocessing verwendet wird. Der Grund dafür ist, dass cProfile nicht mit Multiprocessing kompatibel ist. Wenn Multiprocessing verwendet wird, wird nur der Root-Prozess profiliert, was zu falschen Berechnungszeiten im Graphen führt. Wechseln Sie zu einer nicht-parallelen Version des Zielskripts.
  • Die Profilerstellung eines Skripts kann zu einem beträchtlichen Overhead bei der Berechnung führen. Es kann sinnvoll sein, die in Ihrem Skript geleistete Arbeit zu verringern (d. h. die Menge der Eingabedaten zu reduzieren). In diesem Fall kann die in den Funktionen verbrachte Zeit natürlich massiv verzerrt werden, wenn die Funktionen nicht linear skalieren.
  • Verschachtelte Funktionen werden im Diagramm nicht angezeigt. Insbesondere ein Dekorator verschachtelt implizit Ihre Funktion und versteckt sie daher. Das heißt, wenn Sie einen externen Dekorator verwenden, vergessen Sie nicht, das Paket des Dekorators über die-x Flag hinzuzufügen (zum Beispiel project_graph -x numba myscript.py).
  • Wenn Ihre selbst geschriebene Funktion ausschließlich von einer Funktion eines externen Pakets aufgerufen wird, müssen Sie das externe Paket manuell mit der -x Flag hinzufügen. Andernfalls wird Ihre Funktion nicht im Baum auftauchen, da ihr Parent eine externe Funktion ist und daher nicht berücksichtigt wird.

Sie können das kleine Paket gerne für Ihr eigenes Projekt verwenden, sei es für Leistungsanalysen, Code-Einführungen für neue Teammitglieder oder aus reiner Neugier. Was mich betrifft, so finde ich es sehr befriedigend, eine solche Visualisierung meiner Projekte zu sehen. Wenn Sie Probleme bei der Verwendung haben, zögern Sie nicht, mich auf Github zu kontaktieren (https://github.com/fior-di-latte/project_graph/).

PS: Wenn Sie nach einem ähnlichen Paket in R suchen, sehen Sie sich Jakobs Beitrag über Flussdiagramme von Funktionen an.

Felix Plagge Felix Plagge

Einführung

Je komplexer ein beliebiges Data Science Projekt in Python wird, desto schwieriger wird es in der Regel, den Überblick darüber zu behalten, wie alle Module miteinander interagieren. Wenn man in einem Team an einem größeren Projekt arbeitet, wie es hier bei STATWORX oft der Fall ist, kann die Codebasis schnell so groß werden, dass die Komplexität abschreckend wirken kann. In einem typischen Szenario arbeitet jedes Teammitglied in seiner „Ecke“ des Projekts, so dass jeder nur über ein solides lokales Wissen über den Code des Projekts verfügt, aber möglicherweise nur eine vage Vorstellung von der Gesamtarchitektur des Projekts hat. Im Idealfall sollte jedoch jeder, der an dem Projekt beteiligt ist, einen guten globalen Überblick über das Projekt haben. Damit meine ich nicht, dass man wissen muss, wie jede Funktion intern funktioniert, sondern eher, dass man die Zuständigkeit der Hauptmodule kennt und weiß, wie sie miteinander verbunden sind.

Ein visuelles Hilfsmittel, um die globale Struktur kennenzulernen, kann ein Call Graph sein. Ein Call Graph ist ein gerichteter Graph, der anzeigt, welche Funktion welche Funktion aufruft. Er wird aus den Daten eines Python-Profilers wie cProfile erstellt.

Da sich ein solcher Graph in einem Projekt, an dem ich arbeite, als hilfreich erwiesen hat, habe ich ein Paket namens project_graph erstellt, das einen solchen Call Graph für ein beliebiges Python-Skript erstellt. Das Paket erstellt ein Profil des gegebenen Skripts über cProfile, konvertiert es in einen gefilterten Punktgraphen über gprof2dot und exportiert es schließlich als .png-Datei.

Warum sind Projektgrafiken nützlich?

Als erstes kleines Beispiel soll dieses einfache Modul dienen.

# test_script.py

import time
from tests.goodnight import sleep_five_seconds

def sleep_one_seconds():
    time.sleep(1)

def sleep_two_seconds():
    time.sleep(2)

for i in range(3):
    sleep_one_seconds()

sleep_two_seconds()

sleep_five_seconds()

Nach der Installation (siehe unten) wird durch Eingabe von project_graph test_script.py in die Kommandozeile die folgende png-Datei neben dem Skript platziert:

Das zu profilierende Skript dient immer als Ausgangspunkt und ist die Wurzel des Baums. Jedes Kästchen ist mit dem Namen einer Funktion, dem Gesamtprozentsatz der in der Funktion verbrachten Zeit und der Anzahl ihrer Aufrufe beschriftet. Die Zahl in Klammern gibt an, wieviel Zeit innerhalb einer Funktion verbracht wurde, jedoch ohne die Zeit in weiteren Unterfunktion zu berücksichtigen.

In diesem Fall wird die gesamte Zeit in der Funktion sleep des externen Moduls time verbracht, weshalb die Zahl 0,00% beträgt. In selbstgeschriebenen Funktionen wird nur selten viel Zeit verbracht, da die Arbeitslast eines Skripts in der Regel schnell auf sehr einfache Funktionen der Python-Implementierung selbst rausläuft. Neben den Pfeilen ist auch die Zeit angegeben, die eine Funktion an die andere weitergibt, zusammen mit der Anzahl der Aufrufe. Die Farben (ROT-GRÜN-BLAU, absteigend) und die Dicke der Pfeile zeigen die Relevanz der verschiedenen Stellen im Programm an.

Beachten Sie, dass sich die Prozentsätze der drei obigen Funktionen nicht zu 100 % aufaddieren. Der Grund dafür ist, dass der Graph so eingestellt ist, dass er nur selbst geschriebene Funktionen enthält. In diesem Fall hat das Importieren des Moduls time den Python-Interpreter dazu veranlasst, 0,04% der Zeit für eine Funktion des Moduls importlib aufzuwenden.

Auswertung mit externen Packages

Betrachten wir ein zweites Beispiel:

# test_script_2.py

import pandas as pd
from tests.goodnight import sleep_five_seconds

# some random madness
for i in range(1000):
   a_frame = pd.DataFrame([[1,2,3]])

sleep_five_seconds()

In diesem Skript wird ein Teil der Arbeit in einem externen Paket erledigt, das auf der Top-Ebene und nicht in einer benutzerdefinierten Funktion aufgerufen wird. Um dies im Graphen zu erfassen, können wir das externe Paket (pandas) mit der Flag -x hinzufügen. Die Initialisierung eines Pandas DataFrame wird jedoch in vielen Pandas-internen Funktionen durchgeführt. Offen gesagt, bin ich persönlich nicht an den inneren Verwicklungen von pandas interessiert, weshalb ich möchte, dass der Baum nicht zu tief in die Pandas-Mechanik „hineinwächst“. Diesem Umstand kann man Rechnung tragen, indem man nur Funktionen auftauchen lässt, die einen minimalen Prozentsatz der Laufzeit in ihnen verbringen. Genau dies kann mit der -m-Flag erreicht werden.

In Kombination ergibt project_graph -m 8 -x pandas test_script_2.py das folgende Ergebnis:

Project Graph Creation Example 02

Spaß(-Beispiele) beiseite, nun wollen wir uns ernsteren Dingen zuwenden. Ein echtes Data Science Projekt könnte wie dieses aussehen:

Project Graph Creation Example 03

Dieses Mal ist der Baum viel größer. Er ist sogar noch größer als in der Abbildung zu sehen, da viel mehr selbst geschriebene Funktionen aufgerufen werden. Sie werden jedoch aus Gründen der Übersichtlichkeit aus dem Baum entfernt, da Funktionen, für die weniger als 0,5 % der Gesamtzeit aufgewendet werden, herausgefiltert werden (dies ist die Standardeinstellung für die -m Flag). Beachten Sie, dass ein solches Diagramm auch bei der Suche nach Leistungsengpässen sehr vorteilhaft ist. Man sieht sofort, welche Funktionen den größten Teil der Arbeitslast tragen, wann sie aufgerufen werden und wie oft sie aufgerufen werden. Das kann Sie davor bewahren, Ihr Programm an den falschen Stellen zu optimieren und dabei den Elefanten im Raum zu übersehen.

Wie man project graph verwendet

Installation

Gehen Sie in Ihrer Projektumgebung wie folgt vor:

brew install graphviz

pip install git+https://github.com/fior-di-latte/project_graph.git

Verwendung

Wechseln Sie in der Projektumgebung in das aktuelle Arbeitsverzeichnis des Projekts (das ist wichtig!) und geben Sie für die Standardverwendung ein:

project_graph myscript.py

Wenn Ihr Skript einen argparser enthält, verwenden Sie (vergessen Sie nicht die Anführungsstriche!):

project_graph "myscript.py <arg1> <arg2> (...)"

Wenn Sie den gesamten Graphen sehen wollen, einschließlich aller externen Pakete, verwenden Sie:

project_graph -a myscript.py

Wenn Sie eine andere Sichtbarkeitsschwelle als 1% verwenden wollen, benutzen Sie:

project_graph -m <percent_value> myscript.py

Wenn Sie schließlich externe Pakete in den Graphen aufnehmen wollen, können Sie sie wie folgt angeben:

project_graph -x <package1> -x <package2> (...) myscript.py

Schluss & Hinweise

Dieses Paket hat einige Schwächen, von denen die meisten behoben werden können, z.B. durch Formatierung des Codes in einen funktionsbasierten Stil, durch Trimmen mit der -m-Flag oder durch Hinzufügen von Paketen mit der-x-Flag. Wenn etwas seltsam erscheint ist der erste Schritt wahrscheinlich die Verwendung der -a-Flag zur Fehlersuche. Wesentliche Einschränkungen sind die folgenden:

Sie können das kleine Paket gerne für Ihr eigenes Projekt verwenden, sei es für Leistungsanalysen, Code-Einführungen für neue Teammitglieder oder aus reiner Neugier. Was mich betrifft, so finde ich es sehr befriedigend, eine solche Visualisierung meiner Projekte zu sehen. Wenn Sie Probleme bei der Verwendung haben, zögern Sie nicht, mich auf Github zu kontaktieren (https://github.com/fior-di-latte/project_graph/).

PS: Wenn Sie nach einem ähnlichen Paket in R suchen, sehen Sie sich Jakobs Beitrag über Flussdiagramme von Funktionen an.

Felix Plagge Felix Plagge