Vielen Dank an NeuroForge für das spannende Praktikum!

Durch das Projekt konnte ich meine Fähigkeiten mit u.a. in Tensorflow & Software Engineering weiterentwicklen und bekam einen tollen Einblick in euren Tagesbetrieb.

Jakob Fleischmann

Von der Idee zum MvP

Jakob Fleischmann ist Praktikant für Forschung im Bereich Künstlicher Intelligenz bei NeuroForge und hat im Rahmen seines Praktikums einen Einblick in die tägliche Arbeitswelt bei NeuroForge erhalten. Im Zuge dessen konnte er das Konzept eines Minimal viable Products (MvP) beispielhaft am tagesaktuellen Corona-Geschehen umsetzen und ein System zur Einhaltung der Maskenpflicht entwickeln. Wir haben uns Jakob einfach mal geschnappt und ihn zu seinem Projekt befragt.

Jakob, was hat dich dazu bewegt im Rahmen deines Praktikums neuronale Netze einzusetzen um die Einhaltung der Maskenpflicht mit Hilfe der Software zu überprüfen?

Aufgrund der aktuellen Corona-Pandemie hat sich das Tragen eines Mund-Nasen-Schutzes etabliert bzw. ist an vielen öffentlichen Orten wie Geschäften oder im Personennahverkehr zur Pflicht geworden. Durch die Erlasse der Regierung stehen Betriebe vor der Herausforderung sicherzustellen, dass sich Mitarbeitende und Kundschaft an die Sicherheitsvorgaben halten. Mit diesem Projekt möchte ich zeigen, dass sich KI perfekt eignet bei dieser Aufgabe zu unterstützen, Strafen zu vermeiden und die Gesundheit aller zu schützen.

Welchen Ansatz hast du für das Projekt gewählt und warum hast du dich dafür entschieden?

Ich habe mich auf schnelle Ergebnisse und damit auch eine schnelle Evaluation konzentriert. In Zeiten von Krisen zählt ja auch Geschwindigkeit. Mir war ebenfalls wichtig zeit- und ressourceneffizient zu arbeiten. Spannend war der innovative Ansatz natürlich sowieso. Während der ersten Schritte ist uns aufgefallen, dass es bereits sehr große Trainingsdatensätze zur Erkennung von Personen gibt. Die Idee war also nur noch fix ein paar zusätzliche Maskenbilder aufzunehmen.

Meine gewählte Netzarchitektur, Faster R-CNN, gibt natürlich auch da schon einiges vor. Wenn wir ein so trainiertes Faster R-CNN verwenden, bleibt lediglich die Aufgabe, für eine einzelne Person zu entscheiden, ob eine Maske getragen wird oder nicht. Hierfür ist ein klassisches CNN prädestiniert. Die Kombination macht dann das gute Ergebnis

Convolutional Neuronal Networks fallen ja in den Bereich Künstlicher Intelligenz, nämlich des Deep Learning. Du verwendest hier zusätzlich noch eine Regionserkennung. Wie hast du das gemacht?

Mir war nicht nur wichtig, eine Maske auf dem Bild zu erkennen, sondern auch, einen echten Vorteil auf Bilder zu bekommen, auf denen sich mehrere Personen befinden. Deshalb war natürlich ein RPN (Region Proposal Network) die erste Wahl. Als Vorlage dafür habe ich ein Konzept von “Faster R-CNN” verwendet und mich in der Implementierung an FurkanOM orientiert.

Du hast also 2 unterschiedliche Ansätze für eine Lösung verwendet. Warum hast du dich dafür entschieden?

Für den MvP war es mir vor allem wichtig die Machbarkeit des Projekts und damit das Potential von künstlicher Intelligenz zu demonstrieren. Ich wollte vor aufwändiger Datenaufnahme und dem sogenannten “Labeln” herausfinden, wie ich clever die Umsetzung prototypisieren kann. Wir sind dann im Team schnell zur Idee gekommen, möglichst bestehende Datensätze dafür zu verwenden. Also wurde das Projekt “aufgespalten”. Dazu haben wir die PascalVOC 2007 und 2012 Datensätze verwendet und unser Netz zuerst nur auf die allgemeine Personenerkennung trainiert. Wir haben aus den Datensätzen also nur die Bilder mit zugehörigen Metainformationen extrahiert, die eine Person beinhalten.

def filter_by_label_id(data_set, label_id): 
    """Filter for dataset. Passes just entries that involve persons
    inputs: 
            train_data 
    outputs:
            tensorflow bool vector
    """
    labels = data_set['labels']
    right_label_or_not = (labels == label_id)
    right_label_or_not = tf.dtypes.cast(right_label_or_not, tf.int32)
    right_label_or_not = tf.reduce_sum(right_label_or_not)
    right_label_or_not = tf.dtypes.cast(right_label_or_not, tf.bool)
    return right_label_or_not
def main():
    ......
    train_data, train_info = data_utils.get_dataset("voc/2007", "train+validation")
    val_data, _ = data_utils.get_dataset("voc/2007", "test")

    label_id = data_utils.get_label_id_for_label(label_name, train_info)

    if with_voc_2012:
        voc_2012_data, _ = data_utils.get_dataset("voc/2012", "train+validation")
        train_data = train_data.concatenate(voc_2012_data)

    train_data = train_data.filter(lambda data_set: data_utils.filter_by_label_id(data_set, label_id)) 
    train_total_items = data_utils.get_total_item_size(train_data)

    val_data = val_data.filter(lambda data_set: data_utils.filter_by_label_id(data_set, label_id))
    val_total_items = data_utils.get_total_item_size(val_data)
    ......

Alle unbenötigten Informationen wurden verworfen und somit also nicht in das Training der künstlichen Intelligenz aufgenommen. Beim anschließend notwendigen Preprocessing entfernten wir sämtliche Informationen bezüglich der für uns irrelevanten 19 Klassen.

def preprocessing(image_data, final_height, final_width, label_id, apply_augmentation=False, evaluate=False):
    """Image resizing operation handled before batch operations
       and discard information on all labels except label with label_id
    inputs:
        image_data = tensorflow dataset image_data
        final_height = final image height after resizing
        final_width = final image width after resizing
    outputs:
        img = (final_height, final_width, channels)
        gt_boxes = (gt_box_size, [y1, x1, y2, x2])
        gt_labels = (gt_box_size)
    """
    img = image_data["image"]
    gt_boxes = image_data["objects"]["bbox"]
    gt_labels = tf.cast(image_data["objects"]["label"] + 1, tf.int32) # add 1 for background

    # delete gt_boxe and gt_label entrys that do not belong to label_id
    person_or_not = gt_labels == (label_id + 1) # + 1 since the lable background is added
    gt_boxes = gt_boxes[person_or_not]
    gt_labels = gt_labels[person_or_not]
    gt_labels = gt_labels - label_id # since just one lable is used it is identified with 1

    if evaluate:
        not_diff = tf.logical_not(image_data["objects"]["is_difficult"])
        gt_boxes = gt_boxes[not_diff]
        gt_labels = gt_labels[not_diff]
    img = tf.image.convert_image_dtype(img, tf.float32)
    img = tf.image.resize(img, (final_height, final_width))
    if apply_augmentation:
        img, gt_boxes = randomly_apply_operation(flip_horizontally, img, gt_boxes)
    return img, gt_boxes, gt_labels

Für mein Faster-RCNN Backbone habe ich als fertige Architektur auf das MobileNetV2 gesetzt. Im Vergleich mit z.B. VGG-16 hat sich im Training und in der Evaluation gezeigt, dass wir schnellere und zuverlässigere Trainingserfolge erzielen konnten.

Als letzte Aufgabe musste ich noch die ausgeschnittenen Personen mit Hilfe meines eigenen Convolutional Neuronal Network klassifizieren. Mit Hilfe von gestapelten Convolutional, Pooling und Dense Layers sowie Batch Normalization erhalten wir am Ende eine Aussage darüber, ob die Person auf dem Eingabebild eine Maske trägt oder nicht. Die Architektur habe ich hier illustriert.

Warum hast du dich dafür entschieden ein zusätzliches CNN für diesen MvP zu verwenden und nicht komplett auf Faster R-CNN zu setzen?

Im Rahmen dieses MvPs wurde schnell klar, dass wir nicht nur feststellen wollen, ob auf dem Bild eine Maske getragen wird oder nicht, sondern unseren Maskentest auch für mehrere Personen im selben Bild durchführen zu können. Um Faster-RCNN diese zusätzlichen Informationen beizubringen, wäre eigentlich zeitaufwändiges, händisches Markieren von Personen mit Maske notwendig gewesen. Für die Bewertung der Machbarkeit des Szenarios hat sich der oben beschriebene, aufgetrennte Ansatz als schneller und einfacher herausgestellt.

Für eine Weiterentwicklung und eine stabliere Anwendung im Produktivbetrieb würde ich natürlich den Ansatz mit Markieren und Labeln auf einem extra angefertigtem Datensatz empfehlen. Vor allem nachdem der MvP schon sehr gute Ergebnisse erzielen konnte.

Welches Potential siehst du in diesem Projekt? Wie würdest du jetzt weiter vorgehen?

Das Projekt hat aus meiner Sicht vor allem das Potential des iterativen Entwicklungsprozesses demonstriert. Die Entwicklung hat neben dem Wissentransfer auch mein Bewusstein für die Problemstellung und mögliche auftauchende Fragen geschult. Natürlich haben wir das Ergebnis der künstlichen Intelligenz am Ende nachvollzogen. Eine Visualisierung des Prozess hängt hier an.

Vielen Dank für deine Arbeit, Jakob!

Immer wieder schön zu sehen, wie innovative Ansätze schnell und einfach erste Ergebnisse liefern.

Jonas Szalanczi


Quellen:

https://github.com/neuroforgede/intern_mask_detection
http://host.robots.ox.ac.uk/pascal/VOC/voc2007/index.html
http://host.robots.ox.ac.uk/pascal/VOC/voc2012/index.html
https://github.com/FurkanOM/tf-faster-rcnn
Faster-RCNN: https://arxiv.org/abs/1506.01497
MobileNetV2: https://arxiv.org/abs/1801.04381
Kaggle Dataset: https://www.kaggle.com/andrewmvd/face-mask-detection/notebooks