Ein Bot lernt fahren... ========================= Eines der größten Probleme bei diesem Projekt war die Erstellung von geeigneten Trainingsdaten. In diesem Fall von Bildern, die verschiedene Fälle wie "geradeaus Fahren" oder "stehen bleiben" abbilden. Dabei besteht die Schwierigkeit, dass der Roboter einen geeigneten Untergrund benötigt. Dieser soll es ihm ermöglichen, die prägnantesten visuellen Merkmale der Straße zu erlernen. Bietet der Untergrund keinen ausreichenden Kontrast, so kann er keine Merkmale erlernen. Um diesem Anspruch gerecht zu werden, benutzen wir Lego-Straßen. Die Lego-Platten haben in der Mitte eine graue Fahrbahn, die außen durch einen Grünstreifen abgegrenzt wird. Mit diesem kontrastreichem Bild sollten ausreichend Merkmale erlernbar sein. Szenario 1: Binäre Klassifikation -------------------------------------- .. raw:: html
Download: Beispieldaten + Code
In diesem ersten Szenario möchten wir zwei Fälle unterscheiden:
- Der Bot erkennt eine leere Straße und fährt geradeaus.
.. image:: res/fw1.png
- Der Bot erkennt ein Hindernis und bleibt stehen (Kollisionsvermeidung).
.. image:: res/stop1.png
Wir importieren alle nötigen Module, definieren die Dimensionen der verwendeten Bilder
und verweisen auf die Pfade der Trainings- und Validierungsdaten:
.. code-block:: python
import os
import numpy as np
from time import time
from keras.callbacks import TensorBoard
from keras.models import Sequential
from keras.layers import Activation, Dropout, Flatten, Dense
from keras.preprocessing.image import ImageDataGenerator
from keras.layers import Convolution2D, MaxPooling2D, ZeroPadding2D
from keras import optimizers
from keras import applications
from keras.models import Model
# Dimensionen der Bilder
img_width, img_height = 160,120
# Pfadangaben der Trainings- und Validierungsdaten
train_data_dir = './data/train'
validation_data_dir = './data/validation'
Im nächsten Schritt werden die Bilder vorverarbeitet. Wir reduzieren die
Pixelwerte, die im RGB-Farbraum zwischen 0 und 255 liegen zu einem
Intervall von 0 bis 1 und legen die Batch Size fest. Wir werden später
untersuchen, ob die Größe der `Batch Size
Download: Beispieldaten + Code
Im zweiten Szenario möchten wir drei Fälle unterscheiden:
- Der Bot erkennt eine leere Straße und fährt geradeaus.
.. image:: res/fw1.png
- Der Bot erkennt eine Links- oder Rechtskurve und fährt in die entsprechende Richtung.
.. image:: res/left.png
.. image:: res/right.png
Für eine Multi-Klassifikation muss der bisherige Code ein wenig abgeändert werden:
- Wir setzen den class_mode beim Generator auf "categorical",
- die vorletzte Aktivierungsfunktion ist vom Typ "ReLu",
- die letzte Aktivierungsfunktion ist vom Typ "Softmax",
- wir setzten nb_classes = 3 und
- kompilieren das Modell mit der Kostenfunktion = "categorical_crossentropy".
Des Weiteren benutzen wir einen Stapel von drei convolutionellen Layern und
trainieren 100 Epochen.
.. code-block:: python
import os
import numpy as np
from time import time
from keras.callbacks import TensorBoard
from keras.models import Sequential
from keras.layers import Activation, Dropout, Flatten, Dense
from keras.preprocessing.image import ImageDataGenerator
from keras.layers import Convolution2D, MaxPooling2D, ZeroPadding2D
from keras import optimizers
from keras import applications
from keras.models import Model
from keras.utils.np_utils import to_categorical
img_width, img_height = 160,120
train_data_dir = './data/train'
validation_data_dir = './data/validation'
datagen = ImageDataGenerator(rescale=1./255)
batch_size = 128
train_generator = datagen.flow_from_directory(
train_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode='categorical')
validation_generator = datagen.flow_from_directory(
validation_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode='categorical')
model = Sequential()
model.add(Convolution2D(32, (3, 3), input_shape=(img_width, img_height,3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model = Sequential()
model.add(Convolution2D(32, (3, 3), input_shape=(img_width, img_height,3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model = Sequential()
model.add(Convolution2D(32, (3, 3), input_shape=(img_width, img_height,3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten())
model.add(Dense(64))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(3))
model.add(Activation('softmax'))
model.compile(loss='categorical_crossentropy',
optimizer='rmsprop',
metrics=['accuracy'])
nb_epochs = 100
nb_train_samples = 3000
nb_validation_samples = 600
nb_classes = 3
tb = TensorBoard(log_dir="logs/{}".format(time()))
model.fit_generator(
train_generator,
steps_per_epoch=nb_train_samples // batch_size,
epochs=nb_epochs,
validation_data=validation_generator,
validation_steps=nb_validation_samples // batch_size,
callbacks=[tb]
)
model.save('./data/models/beispiel2.1.h5')
**Ergebnisse**
Das Ergebnis hat uns überrascht:
Auch dieses Modell erlangt eine Genauigkeit von ca. 99%!
Für die drei Klassen haben wir jeweils 1000 Bilder
hinterlegt und jeweils 200 davon für die Validierung benutzt.
Die Berechnung dauerte hierbei stolze 27 Minuten.
Der Videobeweis ist auf der Startseite zu sehen.
.. image:: res/acc99.png
.. image:: res/vall_acc99.png
.. image:: res/loss99.png
.. image:: res/val_loss99.png
Fazit
----------------------------------------
In dieser Arbeit haben wir gezeigt, dass mit Hilfe von Convolutional Neural Networks
die Umsetzung eines autonomen Fahrzeugs möglich ist. Die größte Schwierigkeit war hierbei
nicht die Programmierleistung, sondern das Erzeugen von geeigneten Trainingsbildern.
Die Bilder müssen markante Unterschiede aufweisen, um erlernbar zu sein.
Des Weiteren ist die Wahl der für diesen Fall richtigen Aktivierungsfunktionen
und Kostenfunktionen entscheidend. Die Berechnungen für das autonome Fahren werden
aufgrund der Rechenzeit nicht auf dem Auto, sondern auf dem Desktop-Rechner ausgeführt.
Die Daten werden dazu über WLAN kommuniziert. Dennoch dauert die Berechnung
der Vorhersage eine gewisse Zeit, sodass das Auto für die im Video dargestellten drei Runden
ca. eine Stunde Fahrtzeit benötigt hat. Es ist erstaunlich, wie gut das Auto
die Strecke bewältigt und auch begangene Fehler korrigiert. Dabei können wir jedoch
nicht beurteilen, ob dies tatsächlich Fahrfehler sind oder ob wir diese Fehler
dem Auto "beigebracht" haben.
.. raw:: html