Tutorials

In zwei Tutorials wird in anhand von Beispielen gezeigt, wie die Daten des autonomen Shuttles verarbeitet werden können. Die Tutorials sollen zum praktischen Ausprobieren anleiten und durch das Aufzeigen der technischen Möglichkeiten zu neuen Ideen inspirieren.


TensorFlow

Basierend auf

TensorFlow Detection API Tutorial

Einführung und Benutzung TensorFlow Object Detection

Generell ist TensorFlow dafür geeignet auf Bildern oder Videos Objekte, anhand bereits vorhandener, verfügbarer und trainierter Modelle oder selbst trainierten bzw. modifizierten Modellen, zu erkennen.

TensorFlow wurde in der Programmiersprache Python entwickelt und dementsprechend handelt es sich bei den benötigten Bibliotheken um Python Abhängigkeiten. Überdies ist die Installations Anleitung für Linux Ubuntu 16.04 verfasst worden, bei einer Installation unter Windows mag es also Unterschiede geben. Die angegebenen Links, auf denen das Tutorial basiert, enthalten aber auch wertvolle Hinweise für eine Windows-Umgebung.

Da Python fester Bestandteil der Ubuntu Installation ist, erfolgt hier keine Anleitung für die Installation von Python.

Zur einfachen und komfortablen Installation von Python Bibliotheken installieren wir das Pythonpaketmanagementtool pipq

Installation von pip unter Ubuntu 16.04
pip
sudo apt-get update && sudo apt-get -y upgrade
sudo apt-get install python-pip

Im Terminal folgende Eingabe

pip -V

sollte zu diesem Ergebnis führen (die Version kann abweichen)

pip 8.1.1 from /usr/lib/python2.7/dist-packages (python 2.7)

Anschließend werden unten stehende Python Bibliotheken mit den folgenden Befehlen installiert.

Python Bibliotheken
pip install tensorflow
pip install pillow
pip install lxml
pip install jupyter
pip install matplotlib
Github

Als nächstes benötigen wir folgendes github repository

TensorFlow Github Repository

Hierbei gibt es 2 Varianten der Installation bzw. des Downloads

1. Im Terminal folgenden Befehl ausführen

git clone https://github.com/tensorflow/models.git

oder

2. Dem Link folgen, “Clone or download” klicken und “Download Zip” auswählen sowie anschließend entpacken

Weitere Abhängigkeiten

Navigation in das nun vorhandene Verzeichnis

cd models

und folgende Befehle ausführen

protoc object_detection/protos/*.proto –python_out=.
export PYTHONPATH=$PYTHONPATH:`pwd`:`pwd`/slim

Falls es bezüglich des protoc Befehls zu einer Fehlermeldung kommt, mit

protoc –version

die Version anzeigen lassen. Diese Anleitung bezieht sich auf Version 3.4.0. Unter https://github.com/google/protobuf/releases kann protoc 3.4.0 für python heruntergeladen werden. Anschließend entpacken und im selbigen Verzeichnis folgende Befehle ausführen.

sudo ./configure
sudo make check
sudo make install
Jupyter Notebook
cd models/research/object_detection

und folgenden Befehl ausführen

jupyter notebook

Nun sollte man sich in der Jupyter Notebook App befinden. Hier wählen wir die Datei object_detection_tutorial.ipynb aus. Danach sollten wir in der Lage sein über die Navigationsleiste “Cell” anzuklicken und “run all” auszuwählen. Anschließend sollte unter anderem folgendes Ergebnis zu sehen sein.

Tensor flow default
TensorFlow Test image
Eigene Bilder für Objekterkennung nutzen

Es gibt einen schnellen und direkten Weg eigene Bilder der Objekterkennung zu unterziehen. Die beiden Beispielbilder liegen im Verzeichnis "models/research/object_detection/test_images" diese kann man löschen und eigene Bilder unter Verwendung des gleichen Dateinamens und -Endung (image1.jpg, image2.jpg) nutzen. Falls man mehr als 2 Bilder auf einmal nutzen möchte, müssen wir den den Python Code leicht verändern.

Ausgangszeile
TEST_IMAGE_PATHS = [ os.path.join(PATH_TO_TEST_IMAGES_DIR, 'image{}.jpg'.format(i)) for i in range(1, 3) ]

Um Bilder der Objekterkennung zu unterziehen verändern wir der Einfachheit halber nur die "for Schleife" und erweitern sie um ein Element. Der Dateiname des 3. Bildes muss dementsprechend image3.jpg lauten.

TEST_IMAGE_PATHS = [ os.path.join(PATH_TO_TEST_IMAGES_DIR, 'image{}.jpg'.format(i)) for i in range(1, 4) ]

Ergebnis Anwendung TensorFlow auf eigene Bilder

Tensor flow test
Auf COCO (ssd_mobilenet_v1_coco_2017_11_17) Basis trainierter TensorFlow angewendet auf original Aufnahmen des autonomen Shuttles

Anwendung des TensorFlow auf eigene Videos

Um die Objekterkennung auch für Video Dateien nutzen zu können, wird eine weitere Abhängigkeit benötigt.

sudo apt-get install python-opencv

Als nächstes Erstellen wir das Verzeichnis

/models/research/object_detection/test_videos

analog zu test_images. In dieses Verzeichnis platzieren wir ein Video mit Dateinamen test.mp4

Die folgenden Änderungen im Code werden am besten in einem neuen Notebook festgehalten, dazu object_detection_tutorial.ipynb unter einem neuen Namen, wie z.B. object_detection_tutorial_video.ipynb abspeichern und die folgenden Änderungen einfügen.

Hier der komplette Code
Imports
import numpy as np
import os
import six.moves.urllib as urllib
import sys
import tarfile
import tensorflow as tf
import zipfile
import cv2

from collections import defaultdict
from io import StringIO
from matplotlib import pyplot as plt
from PIL import Image

os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
cap = cv2.VideoCapture('test_videos/test.mp4')
Environment Setup
# This is needed to display the images.
%matplotlib notebook

# This is needed since the notebook is stored in the object_detection folder.
sys.path.append("..")
Object detection imports
from utils import label_map_util
from utils import visualization_utils as vis_util
Model preparation
# What model to download.
MODEL_NAME = 'ssd_mobilenet_v1_coco_2017_11_17'
MODEL_FILE = MODEL_NAME + '.tar.gz'
DOWNLOAD_BASE = 'http://download.tensorflow.org/models/object_detection/'

# Path to frozen detection graph. This is the actual model that is used for the object detection.
PATH_TO_CKPT = MODEL_NAME + '/frozen_inference_graph.pb'

# List of the strings that is used to add correct label for each box.
PATH_TO_LABELS = os.path.join('data', 'mscoco_label_map.pbtxt')

NUM_CLASSES = 90
Download Model
opener = urllib.request.URLopener()
opener.retrieve(DOWNLOAD_BASE + MODEL_FILE, MODEL_FILE)
tar_file = tarfile.open(MODEL_FILE)
for file in tar_file.getmembers():
  file_name = os.path.basename(file.name)
  if 'frozen_inference_graph.pb' in file_name:
    tar_file.extract(file, os.getcwd())
Load a (frozen) Tensorflow model into memory.
detection_graph = tf.Graph()
with detection_graph.as_default():
  od_graph_def = tf.GraphDef()
  with tf.gfile.GFile(PATH_TO_CKPT, 'rb') as fid:
    serialized_graph = fid.read()
    od_graph_def.ParseFromString(serialized_graph)
    tf.import_graph_def(od_graph_def, name='')
Loading label map
label_map = label_map_util.load_labelmap(PATH_TO_LABELS)
categories = label_map_util.convert_label_map_to_categories(label_map, max_num_classes=NUM_CLASSES, use_display_name=True)
category_index = label_map_util.create_category_index(categories)
Helper code
def load_image_into_numpy_array(image):
  (im_width, im_height) = image.size
  return np.array(image.getdata()).reshape(
      (im_height, im_width, 3)).astype(np.uint8)
Detection
PATH_TO_TEST_IMAGES_DIR = 'test_images'
TEST_IMAGE_PATHS = [ os.path.join(PATH_TO_TEST_IMAGES_DIR, 'image{}.jpg'.format(i)) for i in range(1, 3) ]

# Size, in inches, of the output images.
IMAGE_SIZE = (12, 8)

with detection_graph.as_default():
  with tf.Session(graph=detection_graph) as sess:
    while True:
      ret, image_np = cap.read()
      # Expand dimensions since the model expects images to have shape: [1, None, None, 3]
      image_np_expanded = np.expand_dims(image_np, axis=0)
      image_tensor = detection_graph.get_tensor_by_name('image_tensor:0')
      # Each box represents a part of the image where a particular object was detected.
      boxes = detection_graph.get_tensor_by_name('detection_boxes:0')
      # Each score represent how level of confidence for each of the objects.
      # Score is shown on the result image, together with the class label.
      scores = detection_graph.get_tensor_by_name('detection_scores:0')
      classes = detection_graph.get_tensor_by_name('detection_classes:0')
      num_detections = detection_graph.get_tensor_by_name('num_detections:0')
      # Actual detection.
      (boxes, scores, classes, num_detections) = sess.run(
          [boxes, scores, classes, num_detections],
          feed_dict={image_tensor: image_np_expanded})
      # Visualization of the results of a detection.
      vis_util.visualize_boxes_and_labels_on_image_array(
          image_np,
          np.squeeze(boxes),
          np.squeeze(classes).astype(np.int32),
          np.squeeze(scores),
          category_index,
          use_normalized_coordinates=True,
          line_thickness=8)

      cv2.imshow('window',cv2.resize(image_np,(800, 600)))
      if cv2.waitKey(25) & 0xFF == ord('q'):
          cv2.destroyAllWindows()
          break

Videobeispiel

Maschinelles Lernen

Dieses Tutorial ist eine Einführung in das Paradigma des maschinellen Lernens. Zu Beginn wird der Begriff in der Vielzahl von Buzzwords verortet und das Innovative an dem Ansatz hervorgehoben. In dem praktischen Teil des Tutorials betrachten wir den Entscheidungsbaum-Algorithmus und seine Implementierung in R. Überdies ist die Installationsanleitung für Linux Ubuntu 16.04 verfasst worden, bei einer Installation unter Windows mag es also Unterschiede geben.

Ein neues Paradigma

Maschinelles Lernen ist Teil des übergeordneten Forschungsgebiets der künstlichen Intelligenz (KI). Mit KI kann eine Maschine gemeint sein, die sich wie ein Mensch verhält und auf eine verändernde Umwelt selbständig reagieren kann. KI kann aber auch kleiner gedacht werden, so dass mit KI Methoden gemeint sind, die einzelne Probleme z.B. aus dem Bereich der Mustererkennung lösen. Maschinelles Lernen ist in dieser sogenannten schwachen KI ein Ansatz, um der Notwendigkeit des Lernens von intelligenten Systemen gerecht zu werden.

Das Ziel von maschinellen Lernen ist Objekte aufgrund von deren charakteristischen Eigenschaften zu erkennen. Das Wissen über die für ein Objekt charakteristischen Eigenschaften lernt der Algorithmus aus einem Datensatz in einer sogenannten "Trainingsphase". In dieser Trainingsphase werden die erklärenden Attribute der Trainingsdaten mit statistischen Methoden analysiert. In den Trainingsdaten wird nach Mustern gesucht, die typisch für die Ausprägungen des gesuchten Attributs sind. Die Ausprägungen des Attributs können sowohl numerisch (z. B. Vorhersage des Wetters: Temperatur, Luftdruck) oder aus klar abgegrenzten Klassen (z. B. Bilderkennung: Mensch, Straßenschild) bestehen.

Tensor flow test
Bilderkennung von den Objektklassen "Mensch" und "Auto" aus den original Aufnahmen des autonomen Shuttles.

Im Tensor Flow Tutorial wird ein Algorithmus aus dem Bereich des maschinellen Lernens für die Erkennung von Menschen in Videos eingesetzt. In der Trainingsphase wurde der Algorithmus mit einer sehr großen Anzahl von Bildern (Trainingsdaten) trainiert, die Menschen aus unterschiedlichsten Perspektiven und Belichtungssituationen zeigen. Der Algorithmus hat die für die Objektklasse "Menschen" typischen Muster aus den einzelnen Pixeln analysiert. Diese Muster wurden von dem Algorithmus in einem mathematischen Modell abgebildet. Dieses Modell wird bei der Erkennung (Klassifikation) von Menschen in unbekannten Bildern angewendet.

Neben der Bilderkennung kann maschinelles Lernen auch für nicht grafische Daten eingesetzt werden. In diesem Tutorial werden wir deswegen einen Algorithmus darauf trainieren unterschiedliche Blumenarten auf Grund von numerischen Attributen zu identifizieren.

Die Vorteile

Der Einsatz des maschinellen Lernens bringt zwei Vorteile mit sich:


  1. Die maschinelle Analyse der Daten und die anschließende automatische Modellierung, ist der Analyse und Programmierung eines menschlichen Entwicklers deutlich überlegen. Die Muster in den Daten werden detaillierter identifiziert und die Regeln, die in dem Modell abgebildet werden, sind viel komplexer.
  2. Die Modellierung und die Programmierung werden automatisiert. Auf diese Weise lassen sich Aufwand und Kosten sparen. Der initiale Aufwand für die Vorbereitung der Trainingsdaten ist jedoch nicht zu unterschätzen.

R

Die Implementierung werden wir in diesem Tutorial in R umsetzen. R ist sowohl eine Programmiersprache als auch ein Framework. Im Sinne einer Programmiersprache ist für R eine Syntax definiert. R ist gleichzeitig auch ein Framework, das nach der Installation von R bereits in eine Art Programmiergerüst angelegt ist. Dieser Rahmen bietet fertig Methoden und Datenstrukturen aus denen spezifische Anwendungen geschaffen werden können. R wurde speziell für die Manipulation, statistische Berechnung und Visualisierung von Daten entwickelt. Für verschiedenste Zwecke steht eine große Anzahl von Zusatzpaketen zur Verfügung. Auf diese Weise können vorgefertigte Methoden unkompliziert eingebunden werden. Gerade im Bereich maschinelles Lernen kann auf eine Vielzahl von Bibliotheken zurückgegriffen werden.

Um die aktuellste R-Version zu installieren, sollten die Pakete von einem CRAN-Mirror und nicht von Ubuntu geladen werden. Eine ausführliche Installationsanleitung für weitere Ubuntuversionen kann hier gefunden werden. Folgend sind die Befehle für Ubuntu 16.04 Xenial aufgeführt.


CRAN Mirror zur Datei /etc/apt/sources.list hinzufügen
deb https://cran.uni-muenster.de//bin/linux/ubuntu xenial/

Der Server der Uni Münster kann auch durch einen anderen Server aus dieser Liste ersetzt werden.


R installieren
sudo apt-get update
sudo apt-get install r-base
sudo apt-get install r-base-dev

R kann in der Shell ausgeführt werden, jedoch empfehlen wir die Nutzung der Entwicklungsumgebung RStudio. Hier kann RStudio heruntergeladen und installiert werden.


Libraries installieren

Zusätzlich zu R benötigen wir drei Bibliotheken, die wir zunächst installieren und laden müssen. Die folgenden Befehle werden in der Konsole von Rstudio ausgeführt.

install.packages("caret")
install.packages("ellipse")
install.packages("rpart")
library(caret)
library(ellipse)
library(rpart)

Das Ziel

Das Ziel dieses Tutorials ist es einen Algorithmus auf die Identifikation von drei Blumenarten zu trainieren. Die Attribute die für die Identifikation betrachtet werden, sind die Länge und Breite der Blüten- und Kelchblätter der Blumenarten. Das Beispiel der Blumenarten wurde gewählt, da es sich um einen simplen Datensatz handelt, der signifikante Attribute in Bezug auf die Unterscheidung der Blumenarten enthält.

Die Daten

Bei dem bereits angesprochenen Datensatz handelt es sich um die „iris“-Daten, die als Beispieldaten in R vorhanden sind. Durch folgende Befehle werden die Daten in die Entwicklungsumgebung geladen:

data(iris)
data <- iris

Mit der str()-Methode wird die Datenstruktur des Datensatzes angezeigt.

str(data)

Str
Ausgabe der str()-Methode.

Der Datensatz besteht aus 150 Objekten, wobei jedes Objekt die Messwerte einer einzelnen Pflanze repräsentiert. Weiterhin sind 5 Attribute vorhanden. Die ersten Vier beschreiben die Länge und Breite der Blüten- und Kelchblätter. Das Attribut „Species“ ordnet jedem Objekt eine Pflanzenart zu.

summary(data$species)
Sum
Ausgabe der sum()-Methode.

Durch die summary-Methode wird die Verteilung bzw. das Vorkommen der Blumenarten in den Daten beschrieben. Es ist erkennbar, dass eine Gleichverteilung in Bezug auf alle Arten vorliegt. Die Verteilung des Attributes in welches später Klassifiziert werden soll, ist insofern relevant, da der verwendete Algorithmus sensibel gegenüber einer Ungleichverteilung wäre.

Die letzte Frage, die im Vorfeld des Trainings geklärt werden sollte ist, ob relevante Muster in den Daten in Bezug auf das gesuchte Attribute vorliegen. Dies kann am einfachsten durch das grafische Anzeigen der Daten überprüft werden.

featurePlot(x=data[,1:4], y=data[,5], plot = "ellipse")

Der Befehl erzeugt einen Scatter-Plot der die einzelnen Objekte als Punkte visualisiert. In der Abbildung ist erkennbar, dass die Blumenarten, die hier als einzelne farbige Cluster dargestellt werden, durch die Attribute klar unterschieden werden können.

Scatter
Darstellung der einzelnen Blumenarten als farbige Cluster in Bezug zu den verschiedenen Attributkombinationen.

Am Ende dieses Tutorials soll der trainierte Algorithmus mit Daten validiert werden, die dem Algorithmus bis dahin unbekannt sind. Aus diesem Grund werden folgend die Daten in zwei Teile untergliedert. Für das Training des Algorithmus werden 80% der Daten verwendet. Für das spätere Validieren werden 20% der Daten als Testdaten zurückgestellt.

dataPartitions <- createDataPartition(data$Species, p=0.80, list=FALSE)
testData<- data[-dataPartitions,]
trainingData <- data[dataPartitions,]

Der Algorithmus

In diesem Tutorial wird ein Entscheidungsbaum Algorithmus verwendet. Dieser Algorithmus gehört zu den Methoden des maschinellen Lernens. Entscheidungsbäume sind ein hierarchisches Modell, welches grafisch als Baumdiagramm dargestellt werden kann. In der Baumstruktur der Entscheidungsbäume werden Regeln zur Klassifikation von Objekten abgebildet. Ein Entscheidungsbaum besteht aus einzelnen Entscheidungsknoten und den Zweigen die davon abgehen. An jedem Knoten wird ein Test in Bezug auf ein Attribut des zu klassifizierenden Datums durchgeführt. In Abhängigkeit des Ergebnisses wird ein Zweig ausgewählt, der das Datum zum nächsten Entscheidungs- oder Blattknoten führt. Der Klassifikationsprozess beginnt bei der Wurzel des Baums, die den ersten Entscheidungsknoten darstellt. Der Prozess wird fortgeführt, bis ein Blattknoten erreicht ist. Ein Blattknoten repräsentiert eine bestimmte Klasse. Wenn ein Objekt einen Blattknoten erreicht, wird dieses Objekt mit der entsprechenden Klasse klassifiziert. Entscheidungsbäume sind durch ihre Wenn-Dann-Struktur leicht lesbar und im Gegensatz zu anderen Klassifikationsmethoden unkompliziert nachvollziehbar. Die Struktur der Verzweigungen und die Grenzwerte der einzelne Tests an den Entscheidungsknoten, entstehen durch das Bestreben des Algorithmus, die Menge aller Daten in zwei möglichst homogene Fragmente aufzuteilen. Mit homogen ist eine klare Abgrenzung der Trainingsdaten in Bezug auf die gesuchten Klassen gemeint. In dem Fall, dass nach einem Entscheidungsknoten die Instanzen in zwei Stichproben aufgeteilt wurden, in denen alle Instanzen der gleichen Klasse angehören, würde man davon sprechen, dass die Aufteilung rein ist. Wenn die Aufteilung nach einem Entscheidungsknoten rein ist, kann ein Blattknoten hinzugefügt werden, da die Klassifikation damit abgeschlossen ist.

Das in diesem Abschnitt bislang theoretisch erläuterte Vorgehen des Entscheidungsbaum-Algorithmus wird nun konkret implementiert.

tree <- rpart(trainingData$Species~., trainingData)

Mit der rpart()-Methode wird ein Entscheidungsbaum aus den Trainingsdaten in Bezug auf die Klassifikation des Attributs „Species“ berechnet. Der berechnete Entscheidungsbaum kann als Baumdiagramm visualisiert werden.

plot(tree)
text(tree)
Tree
Die Abbildung zeigt ein Baumdiagramm, welches die Regeln, die aus der Analyse der Trainingsdaten entstanden sind, visualisiert.

Die Abbildung zeigt die Struktur des Entscheidungsbaums. Aus den Fallunterscheidungen kann abgelesen werden, wie der Algorithmus die einzelnen Objekte in Klassen einteilt. In der oberen Fallunterscheidung wird das Attribut Petal.Length betrachtet. Alle Objekte dessen Petal.Length kleiner 2.45 ist, werden als Setosa Blumen klassifiziert. Für alle Objekte mit einer Petal.Length größer als 2.45 wird eine erneute Fallunterscheidung in Bezug auf die Klassen Versicolor und Virginica durchgeführt.

Das Klassifikationsergebnis

Um die Klassifikationsgenauigkeit des trainierten Entscheidungsbaums beurteilen zu können, wird der Algorithmus auf die Klassifikation der Testdaten angewendet. Diese bedeutet, dass der Algorithmus jedem Objekte eine Blumenart zuordnet, die auf Grundlage der Analyse von den Attributen Petal.Length, Petal.Width, Sepal.Length und Sepal.Width am wahrscheinlichsten ist.

predictions <- predict(tree, testData, type = "class")

Durch die Betrachtung der Konfusionsmatrix lässt sich die Klassifikationsgenauigkeit des Algorithmus beurteilen. Die Klassennamen am Ende der Zeilen bezeichnen die tatächliche Klasse der Objekte und die Klassennamen am Ende der Spalten bezeichnen die vom Algorithmus vorhergesagten.

confusionMatrix(predictions, testData$Species)
Conf1
Das Klassifikationsergebnis als Konfusionsmatrix dargestellt.

Aus dieser Abbildung wird deutlich, dass für die Klassen Setosa und Virginica alle Objekte richtig klassifiziert wurden. Drei Objekte die tatsächlich der Klasse Versicolor angehören wurden vom Algorithmus fälschlicherweise in die Klasse Virginica eingeteilt. Die Leistung der Klassifikators lässt sich auch in Form von Gütemaßen beurteilen.

Conf2
Die Gütemaße Sensitivity und Precision werden für jede Klasse einzeln dargestellt.

Die Sensitivity gibt die Anzahl der vom Algorithmus korrekt mit Klasse x klassifizierten Wege, von allen tatsächlichen Wegen der Klasse x an. Die Precision den Anteil der mit Klasse x klassifizierten Wege, die tatsächlich der Klasse x angehören.