Hobbys und maschinenbasiertes Lernen: 1.000 Bilder - und nur zwei Vögel drauf

Hier wird das Techie-Herz erwärmt: Diese Serie ist für alle von euch, die sich jeden Tag eine kleine Auszeit von der Weltlage wünschen. Es gibt täglich eine Geschichte für euch aus unserem Archiv - auf jeden Fall geeignet für ein wenig fröhlichen Eskapismus. Viel Spaß!
Als IT-Sachverständiger erhalte ich im Freundes- und Bekanntenkreis oft Supportanfragen wie Druckerinstallationen und Lizenzverlängerungen - an sich wichtige Tätigkeiten, aber doch eher unspannend. Neugierig wurde ich allerdings, als ein Freund mich fragte: "Glaubst du, du könntest mir ein Skript schreiben, das ein paar Hundert JPEGs sortiert?" Er hatte sich bei einem bekannten Youtube-Kanal(öffnet im neuen Fenster) mit dem Ornithologie-Fieber infiziert und sich im Garten eine Vogelbeobachtungsstelle eingerichtet. Hier begannen seine Probleme - und meine.
Seine Beobachtungsstelle besteht aus einem Futterautomaten und einer günstigen Wildkamera, um die Gäste an der Futterstelle abzulichten. Nur: Der Bewegungssensor der Kamera war entweder zu wenig sensibel eingestellt, was wenig oder gar keine Fotos bedeutete - oder zu sensibel, was wiederum eine Unmenge an Bildern erzeugte, wovon natürlich nur ein sehr kleiner Teil tatsächlich die Gäste an der Futterstelle zeigte.
"Über tausend Bilder, über eine Stunde durchsehen und dann sind nur auf zwei Bildern Vögel zu sehen?!" Das war der Grund, mich anzurufen und mich um besagtes Skript zu bitten. Die Anforderungen waren sehr einfach: Die Ursprungsbilder werden in einem Ordner abgelegt, das Skript soll diese Bilder kategorisieren und dann in nach der Kategorie benannte Unterordner verschieben. Nicht kategorisierbare Bilder sollen in ein eigenes Unterverzeichnis verschoben werden.
Klingt doch einfach, oder?
Die Umsetzung dieser Anforderungen erfordert den Einsatz von maschinenbasiertem Lernen (MBL), konkret Bilderkennungstechnologie. Bis dato hatte ich mich mit maschinenbasiertem Lernen nur rudimentär befasst, jetzt hatte ich endlich einen Anlass, mich intensiver mit MBL und Python in der Praxis auseinanderzusetzen.

Das Projekt selbst wollte ich aus Zeitgründen hands-on angehen, das heißt: kurz in die Dokumentation einlesen (statt stundenlang Grundlagen wälzen), schnell ersten Code entwickeln und die aufkommenden Probleme sozusagen unterwegs lösen.
Zur Kategorisierung der Bilder setzte ich ImageAI(öffnet im neuen Fenster) ein. Es ist Open Source und eine weit verbreitete Python-Bibliothek zur Bilderkennung. Sie unterstützt vortrainierte Modelle, die laut Dokumentation mehr als 1.000 verschiedene Objekte erkennen können soll. Sollte mal ein Objekt nicht erkannt werden, besteht die Möglichkeit, das eingesetzte Modell weiter zu trainieren. Beste Voraussetzungen also, um dieses Projekt schnell und erfolgreich abzuschließen.
Plötzlich wurde die Performance ein großes Thema
Python ist bereits in Version 3.7 auf meiner Linux Box installiert, ImageAI und die dafür benötigten Python-Module sind dank dieser Anleitung(öffnet im neuen Fenster) sehr schnell installiert, es konnte also direkt losgehen. Mit Hilfe dieses Tutorials(öffnet im neuen Fenster) war der erste Prototyp des Skripts schnell programmiert und erste Tests (mit Bildern aus der Google-Bildersuche) waren vielversprechend.
Ich sendete meinem Freund also einen Link mit der Bitte, mir die Fotos seiner Wildkamera hochzuladen, und bekam als Antwort: "Könnte ich dir auch einen USB-Stick vorbeibringen?" Bei der Übergabe stellte ich fest, dass auf dem USB-Stick über 5.000 Fotos gespeichert waren (Zitat: "Und das sind nur die von letzter Woche." )
Mein Skript sollte also nicht nur ein paar Hundert, sondern ein paar Tausend Bilder kategorisieren. Performance wurde ein großes Thema und eines, das ich nicht vorab auf dem Radar hatte. Irgendwie war ich mir plötzlich nicht mehr so sicher, ob das Projekt tatsächlich so simpel war, wie ich es mit zunächst vorgestellt hatte - aber noch war ich voller Zuversicht.
Konfrontiert mit Echtdaten zeigte ImageAI beziehungsweise das implementierte Modell (zunächst Retinanet) Schwächen. Während die Fotos aus der Google-Bildersuche sehr eindeutige, korrekte Ergebnisse lieferten (bei konfigurierter 80-Prozent-Wahrscheinlichkeit, das heißt: ImageAI kategorisiert Bilder nur, wenn die Objekterkennung ein Objekt mit mehr als 80-prozentiger Sicherheit erkennt), wurden die Fotos der Wildkamera bei gleichen Settings entweder gar nicht oder falsch kategorisiert.
Einzig "leere" Fotos beziehungsweise Fotos, auf denen Personen zu sehen waren, wurden zuverlässig korrekt kategorisiert. Das galt allerdings wiederum nur für Fotos, die bei Tageslicht aufgenommen wurden. Nachtfotos wurden durchgehend falsch oder gar nicht kategorisiert.
Reduzierte man die Erkennungsschwelle, zum Beispiel auf 60 Prozent, wurden die vermeintlichen Kategorien der erkannten Objekte etwas abenteuerlich. So wurden Nager, die sich an der Futterstelle zu schaffen machten, mal als "Clock" oder "Bird" kategorisiert oder ein Ast als "Frisbee".
Lange Laufzeit, Kernel zerschossen - alles viel komplizierter als gedacht
Mein erster Problemlösungsansatz war, ImageAI und die zugehörigen Bibliotheken auf die neueste Version upzugraden und Python auf Version 3.8 zu heben. Um im nächsten Schritt die Performance zu erhöhen, wollte ich ImageAI auf meiner GPU laufen lassen. Bis dato lief es auf der CPU und benötigte mehrere Sekunden pro Bild, was sich bei dieser Menge an Bildern natürlich stark auf die Gesamtlaufzeit auswirkte.
Ich installierte dazu die entsprechenden Nvidia-Treiber und zerschoss mir damit umgehend meinen Kernel. Wie genau ich dieses Kunststück vollbracht habe, ist mir auch im Nachhinein nicht ganz klar. Auf jeden Fall kann ich den Unmut der Open-Source-Community über Nvidia gut nachvollziehen, denn weitere Installationsversuche blieben ebenso erfolglos. Möglicherweise liegt es daran, dass ich nicht den aktuellsten Kernel einsetze, ich habe dieses Thema jedoch nicht weiterverfolgt.
Optimierungen im Skript, zum Beispiel die Nutzung anderer vortrainierter Modelle, brachten kleine Verbesserungen in der Laufzeit, jedoch keine positive Änderung bei der Kategorisierung. Auch eine qualitativ hochwertigere Wildkamera bewirkte keine spürbaren Verbesserungen bei der Erkennung von Vögeln in den Bildern.
Als einzig sinnvoller Lösungsweg blieb uns nun noch das individuelle Training des eingesetzten Modells. An diesem Punkt wurde mir klar, dass die Komplexität des Projekts bereits jenseits meiner ursprünglichen Vorstellungen lag.
Dann trainieren wir doch einfach das Modell
Die Programmierung des technischen Ablaufs des Trainings war mit wesentlich weniger Aufwand verbunden als die Aufbereitung des entsprechenden Trainingsmaterials. Der Trainingserfolg hängt nicht nur von der Menge, sondern insbesondere von der Qualität der Aufbereitung des Trainingsmaterials ab.
Ich denke, dass wir wahrscheinlich über ausreichend Bilder verfügen, um ein entsprechendes Training erfolgreich durchführen zu können. Leider fehlte uns jedoch die Zeit, um die Berge an Fotos entsprechend exakt mit Annotations zu beschreiben. Daher legten wir das Projekt an dieser Stelle vorläufig auf Eis.
War das Projekt erfolgreich?
Die Erwartungshaltung meines Freundes hinsichtlich der "automagischen" Sortierung seiner Wildkamerabilder konnte ich nicht erfüllen. Ich habe jedoch tieferen Einblick erhalten, wie maschinenbasiertes Lernen funktioniert und worauf es hierbei ankommt, nämlich einfach gesagt:
Wer maschinenbasiertes Lernen einsetzen möchte, muss der Maschine auch beibringen, was von ihr erwartet wird. Sonst wird das nix.
Die vortrainierten Modelle liefern unerwartet schnelle und gute Ergebnisse, solange die vorgelegten Bilder nicht zu speziell sind. Sinkt die Erkennungsrate unter die erhofften Werte, so muss man das Modell auf den eigenen Anwendungsfall hin trainieren. Das benötigt Zeit und Aufwand.
Marcus Toth beschäftigt sich seit mehr als 25 Jahren mit freier Open-Source-Software und freut sich über Rückmeldungen von Leuten, die ein ähnliches Projekt umgesetzt haben und wie es ihnen damit ergangen ist.
Update:
Der Artikel wurde auf seine Aktualität überprüft.



