Bildbasierte Detektion des Garagentores mit der Custom Vision API und TensorFlow

Einleitung

In diesem Artikel befassen wir uns erneut mit der Erkennung, ob das Garagentor offen oder geschlossen ist. Ursprünglich war geplant, im dritten Artikel den Klassifikator in eine API einzubauen. Die API sollte dann benutzt werden können, um beispielsweise vom Handy aus abfragen zu können, ob das Tor geschlossen ist. Allerdings wurde nun auf der diesjährigen Build-Konferenz von Microsoft eine neue API für das Maschinelle Sehen [CustomVision] vorgestellt. Damit ist es, im Gegensatz zu den Cognitive Services [AzureCognitive], möglich, einen eigenen Klassifikator zu trainieren. Dadurch können wir einen viel gezielteren Klassifikator trainieren als das mit Cognitive Services im letzten Artikel möglich war.

Neben der Klassifikation mit der Custom Vision API widmen wir uns in Kapitel TensorFlow der Klassifikation mittels TensorFlow [TensorFlow].

Custom Vision

Die Custom Vision API wurde dieses Jahr auf der Build Konferenz vorgestellt. Mit ihr ist es möglich einen eigenen Klassifikator zu trainieren. Wie man dazu vorgehen kann wollen wir im folgenden Abschnitt erörtern. Danach widmen wir uns der Evaluation.

Training

Um die API nutzen zu können muss man sich zunächst unter https://customvision.ai mit seinem Microsoft Account anmelden. Anschließend erstellt man ein erstes Projekt, in dem dann die Bilder hoch geladen werden können.

Für die Übertragung der Bilder gibt es aktuell zwei Möglichkeiten:

Übertragung der Bilder

Man kann über die Webseite einzelne oder auch mehrere Bilder hoch laden (siehe obiges Bild). Diese Bilder muss man dann im zweiten Schritt des Uploads mit Tags versehen. Tags sind in diesem Fall die Klassifikationsmöglichkeit, die trainiert wird. Bei der Vorhersage gibt die API anschließend die ihrer Meinung nach zu diesem Bild passenden Tags sowie eine Wahrscheinlichkeit zurück.

Prinzipiell ist es möglich mehrere Tags einem Bild zuzuordnen, in unserem Fall war das jedoch nicht nötig, da ein binäres Klassifikationsproblem vorliegt.

Leider ist es nicht möglich, als Bildquelle etwas anderes als das lokale Dateisystem zu verwenden. Da in unserem Fall die Bilder im Azure BlobStorage liegen und die zugehörigen Labels in Azure DocumentDB, konnten wir den Browser Upload nicht nutzen und entschieden uns für die zweite Variante.

Die Autoren der Custom Vision API bieten eine über Nuget verfügbare C# API an [NugetCustomVisionTraining,NugetCustomVisionPrediction]. Damit ist es möglich, die Bilder beispielsweise über ein Konsolenprogramm zu übertragen.

Bevor man anfangen kann benötigt man den Training Key, den man in den User Settings der Custom Vision Seite finden kann. Anschließend kann man sich eine Instanz der TrainingApi erstellen:

Über die Instanz kann man sich nun das erstellte Projekt abfragen in das man die Trainingsbilder übertragen möchte. Das Vorgehen hierfür ist allerdings etwas umständlich, was aber hoffentlich mit dem Preview Status der API zu tun hat.

Das erstellte Projekt sowie die beiden nötigen Tags erhält man über:

GetProject() erwartet als Parameter eine Guid. Leider ist die Guid für ein Projekt nicht auf der Webseite zu finden, lediglich der Name ist vorhanden. Nun kann man entweder erst einmal mit GetProjects() alle erstellten Projekte abfragen, um anschließend über den Namen zu filtern (also so, wie wir das für die beiden Tags gemacht haben) oder man gibt die Projekte mitsamt deren Ids aus und speichert sich dann die korrekte Guid in einer Variablen.

Anschließend kann über:

ein Bild mit den passenden Tags übertragen werden. Das geschieht, entgegen unserer Erwartung, nicht über das Projekt sondern über die trainingApi (die für die Id des Tags keine Guid, sondern einen String erwartet).

Nachdem die Bilder übertragen sind kann das Training gestartet werden. Das kann entweder auch im Konsolenprogramm geschehen 1:

Oder man nutzt die Webseite um das Training zu starten.

Evaluation

Für das Training, bei dem wir wie im vorherigen Kapitel beschrieben vorgingen, nutzten wir 100 Bilder. Die CustomVision API bestimmt für das Training automatisch Precision und Recall, die man im Reiter Performance einsehen kann. Wir erzielten durch das erste Training bereits eine Precision von 98,0% und einen Recall von ebenfalls 98,0%.

Obwohl wir dadurch bereits einen ersten Eindruck von der Güte unseres Klassifikators bekommen können, nutzen wir die übrigen Bilder, die wir im ersten Teil gespeichert hatten, für eine Evaluation. Dafür benötigten wir zunächst den Prediction Key, der ebenfalls in den Settings auf der Webseite zu finden ist.
Damit können wir eine Instanz der PredictionApi erzeugen:

Um nun ein Bild zu übertragen und von der API der Tags inklusive deren Unsicherheit vorhersagen zu lassen nutzen wir folgenden Code:

result ist eine Liste von Tags denen von der API eine Wahrscheinlichkeit zugeordnet wurde. Die Ergebnisse sammeln wir in der Liste predictions und speichern Sie zunächst in einer Datei.

Anschließend nutzen wir wieder LINQPad für die Auswertung. Wie im vorherigen Artikel gingen wir davon aus, dass das Garagentor geschlossen ist, wenn die Wahrscheinlichkeit für das DoorClosed-Tag bei über 85% liegt. Dadurch erhielten wir das in Tabelle 1 dargestellte Ergebnis.

Tabelle 1: Auswertung Vorhersagen. Tor wird als geschlossen angesehen, wenn die Wahrscheinlichkeit für das DoorClosed-Tag > 85% ist.

Vorhersage: OffenVorhersage:GeschlossenRecall
Offen8701.00
Geschlossen671940.74
Precision0.561.00

 

Die mittlere Dauer für eine Vorhersage beträgt bei geschlossenem Tor 2,73, bei offenem Tor 3,73 Sekunden.

Eine Sache machte uns bei diesem Ergebnis stutzig: Die Summe der Vorhersagen für Bilder vom geschlossenen Tor (67 + 194) ist größer als die Menge an Bildern von geschlossenen Toren die wir für die Evaluation genutzt haben. Eine schnelle Untersuchung ergab dann, dass bei manchen Bilder die Wahrscheinlichkeit für „DoorClosed“ sowie für „DoorOpened“ bei über 85% liegt (Ein Beispiel für ein so klassifiziertes Bild ist in Abbildung 3 zu finden).

Abbildung 3: Vorhersage sowohl offen als auch geschlossen.

Basierend auf dieser Erkenntnis führten wir eine zweite Auswertung durch. Dieses Mal entschieden wir uns schlicht für das Tag mit der höheren Wahrscheinlichkeit.
Dadurch erhielten wir folgendes Ergebnis:

Table 2: Auswertung Vorhersagen. Tor wird als geschlossen angesehen, wenn die Wahrscheinlichkeit für das DoorClosed-Tag größer der des DoorOpened-Tag ist.

Vorhersage: OffenVorhersage:GeschlossenRecall
Offen8701.00
Geschlossen51890.97
Precision0.951.00

 

Verbesserung des Klassifikators

Die CustomVision API bietet eine interessante Möglichkeit zur Verbesserung des Klassifikators. Unter dem Reiter Predictions werden die Bilder aufgelistet, für die die API eine Vorhersage getroffen hat. In der
Detailansicht lassen sich die Tags korrigieren und durch ein anschließendes erneutes Training kann der Klassifikator verbessert werden.

Wir nutzten einen Teil der Bilder die wir für die Evaluation übertragen hatten, korrigierten die Label und starteten ein erneutes Training. Dadurch erhielten wir eine Precision von über 99%.

Precision und Recall - Performance per Tag

TensorFlow

Bei TensorFlow handelt es sich um eine „plattformunabhängige Open-Source-Programmbibliothek für künstliche Intelligenz“ [Wikipedia] die vom Google Brain Team entwickelt wurde. TensorFlow ist aktuell nur mittels Python und C++ nutzbar, wir nutzen in diesem Kapitel die Python-Schnittstelle auf einem Windows 10 Notebook.

Installation

Wir gingen bei der Installation nach der Anleitung unter Installation TensorFlow vor. Dort findet man auch Installationsanleitungen für andere Betriebssysteme.

Bevor es zur eigentlichen Installation geht muss man sich entscheiden, ob man TensorFlow mit GPU-Unterstützung installieren, oder für die Berechnungen lediglich die CPU nutzen möchte. Durch die GPU-Unterstützung kann eine höhere Geschwindigkeit erzielt werden. Allerdings sind einige Anforderungen zu erfüllen, die auf unserem System nicht gegeben waren. Daher blieb uns nur die CPU-only Installation.

Nach der Installation von Python 3.5 und der anschließenden Installation von virtualenv 2  mittels 3:

Anschließend erstellen wir in einem geeigneten Ordner eine virtuelle Umgebung, aktivieren sie und installieren TensorFlow:

Training

Für das Training orientierten wir uns an TensorFlow For Poets. TensorFlow for Poets nutzt das Inception v3 Netzwerk zur Bildklassifikation, trainiert es aber erneut um eigene Klassen zu erkennen. Wir gehen ähnlich vor, nutzen aber keinen Docker Container und natürlich unsere eigenen Trainingsdaten.

Für das Training muss lediglich ein Python-Skript ausgeführt werden. Das Skript wiederum kann mit folgendem Aufruf in das aktuelle Verzeichnis kopiert werden:

Der Aufruf von:

startet dann das Training. --image-dir ist dabei der Pfad zu den Trainingsbildern. Für jede zu trainierende Klasse muss ein Unterordner erstellt werden, der Bilder der entsprechenden Klasse enthält. In unserem Fall sieht der Ordner train folgendermaßen aus:

Beim ersten Aufruf von retrain.py brach das Skript mit dem Fehler ab, dass keine Bilder für das Training gefunden werden konnten. Es stellte sich heraus, dass TensorFlow nicht mit Bildern im png Format zurecht kam. Dank der Bash On Windows konnte dieses Problem jedoch schnell behoben werden:

Anschließend klappte auch das Training, das nach knapp 2,5 Minuten beendet war. Um für das Training die selben Bedingungen wie für die Custom Vision API zu schaffen nutzten wir die selben 100 Bilder.

Evaluation

Die Evaluation fand wie bei der Evaluation der Custom Vision API mit den übrigen Bilder statt. Dazu haben wird das Script aus dem Abschnitt „Using the Retrained Model“ aus TensorFlow For Poets leicht angepasst angewandt:

Wir iterieren über unsere Testbilder (in diesem Fall die Bilder mit offenem Tor) und speichern die Ergebnisse zunächst in einer Liste. Diese schreiben wir anschließend wiederum in eine Datei, um sie später auswerten zu können.

Die Vorhersage bei geschlossenem Tor dauerte im Mittel 1,77, bei offenem Tor 2,16 Sekunden. Die Evaluation ergab folgende Konfusionsmatrix:

Vorhersage: OffenVorhersage:Geschlossenkeine VorhersageRecall
Offen86010.99
Geschlossen018590.95
keine Vorhersage0000
Precision1.001.000.00

Im Gegensatz zur Custom Vision API wurden keine Bilder sowohl als offen als auch als geschlossen bestimmt. Jedoch wurde für insgesamt 10 Bilder keine Aussage getroffen.

Zusammenfassung

In diesem Artikel haben wir zwei weitere Klassifikatoren erprobt. Zum einen die von Microsoft auf der diesjährigen Build-Konferenz vorgestellte Custom-Vision API, zum anderen TensorFlow. Während die Custom Vision API sehr einfach zu benutzen ist, bietet TensorFlow eine Fülle an Möglichkeiten um einen Klassifikator zu trainieren. Dadurch ist TensorFlow jedoch auch komplizierter in der Nutzung, hat jedoch wiederum den Vorteil, dass es auch auf dem lokalen Rechner oder in Offline-Szenarien verwendet werden kann.

Fußnoten

1

Code stammt von [CustomVisionCSharpTutorial].

2

bei virtualenv handelt es sich um ein Tool zur Erstellung von isolierten Python-Umgebungen

3

Wir nutzen hier den absoluten Pfad zur python 3.5 executable da auf unserem System auch Python 3.6 installiert ist, das aber von TensorFlow nicht unterstützt wird.