— Dies ist Teil2 der Tutorials zu Neuronalen Netzen – hier ist Teil1: Neuronale Netze einfach erklärt —
Nach der Einführung in die Thematik der Neuronalen Netze nun ein einfaches Deep Learning Beispiel mit der wichtigsten Bibliothek, welche für das Thema Machine Learning mit Neuronalen Netzen derzeit genutzt wird: Tensorflow!
Deep Learning ist hauptsächlich (bis auf Forschungsthemen) Supervised Learning, d.h. man zeigt dem Netzwerk also für bestimmte Eingangswerte die richtige Lösung (z.B. Klassifikation von Bildern oder Gruppen), das Netzwerk lernt Schritt für Schritt besser zu werden. Für viele Ingenieurs-Problemstellungen ist die zu schätzende Ausgangsgröße keine einzelne Klasse oder Kategorie (z.B. Auto, Haus, Boot) sondern ein kontinuierlicher Wert, z.B. ein Preis oder eine Kraft oder Fläche o.ä.
Neuronale Netze sind ein universeller Approximator: Wenn es einen Zusammenhang zwischen Ein- und Ausgangsgröße gibt, ist es sehr wahrscheinlich, dass ein (handwerklich korrekt aufgesetztes) Neuronales Netz diesen finden wird. Achtung: Es findet Korrelationen! Ob diese Korrelationen auch einen kausalen Zusammenhang haben oder nicht muss der Experte entscheiden.
Für dieses Tutorial knüpfen wir an Michael Nielsons Tutorial an und versuchen die folgende Funktion \(f(x)\) von einem Netzwerk schätzen zu lassen.
\[f(x)=0.2+0.4x^2+0.3x \cdot \sin(15x)+0.05 \cdot \cos(50x)\]
Ein typisches Regressionsproblem, daher nun ein Tensorflow Tutorial zum DNNRegressor, welches sich prinzipiell auch für höherdimensionale bzw. kompliziertere Fragestellungen nutzen lässt.
If you are looking for a very simple way to check, if two objects touch each other in Blender, maybe this might be a solution. The field of collision detection is very popular in game development and these guys have a lot of special algorithms for fast and/or exact collision between circles & circles, rectangles & circles, triangles & circles and so on…
Most of these are based on the Seperating Axis Theorem, which is simply the mathematical solution of the question: Is it possible to look ‘between’ the two objects from any direction? If so, they are not colliding. Things get much simpler, if you just check the bounding boxes of two objects. In case of a cube, the bounding box is exactly the object itself. To check if two cubes touch each other, you have to check a collision between two bounding boxes. To make it even easier, one of the boxes is axis aligned (not rotated). We are talking about AABB (axis aligned bounding box) 3D collision check in Python. For visualization, we are using Blender. In Blender, you can run Python scripts.
Es fehlt eindeutig an deutschsprachigen Beginner-Tutorials zum Thema Neuronale Netze. Es gibt ausgesprochen gute – ich meine wirklich herausragend gut! – Tutorials zum Thema, welche man diesem hier unbedingt vorziehen sollte. Bitteschön:
Doch was soll ich sagen, diese Tutorials sind umfangreich und gleich die große Kanone. Wenn man nur Spatzen haben möchte, dann hilft es vielleicht, ein einfaches Tutorial zum Einstieg zu nutzen, in dem großzügig auf Ausnahmen, Feinheiten und Randbedingungen verzichtet wird. Das versuche ich mit dem folgenden Beitrag.
Neuronale Netze ([engl.] Neural Networks) sind schon ziemlich alt und in der Wissenschaft schon lange Thema. Seit einigen Jahren erleben sie in praktischen (medienwirksamen und leicht verständlichen) Anwendungsfällen allerdings eine unglaubliche Renissance. Ein wichtiger Grundstein war sicherlich, dass NVIDIA Ende der 2000er Jahre mit ihren CUDA Grafikkarten eine unglaubliche Rechenpower zur Verfügung stellte. Warum? Neuronale Netzwerke lernen im Grunde mit simplen Multiplikationen bzw. Faltungen, welche sich prima parallel abarbeiten lassen. Hat man mehr Prozessorkerne, hat man in überschaubarer Zeit bessere Lernkurven. Eine Quad-Core CPU stellt dabei keine relevante Anzahl Kerne dar. Das wäre, wie mit einem 50ccm Roller zu einem DTM Rennen zu kommen.
Keine Chance also, auf dem heimischen Laptop ein auch nur ansatzweise konkurrenzfähiges Neuronales Netzwerk in überschaubarer Zeit (heißt: Wochen/Monate) zu trainieren!
Am beeindruckendsten finde ich, sind derzeit folgende Neuronalen Netze (welche noch kombiniert mit so genannten Reinforcement Learning Algorithmen funktionieren und die Q-Values lernen):
Not bad, right? Steigen wir ein.
Alle Begrifflichkeiten zu erläutern würde zu weit führen, aber die Wichtigsten im Überblick:
Spricht man über ein Neuronales Netz, so ist natürlich die Frage, was ein Neuron ist. Angelehnt an die Biologie ist ein Neuron ein ‘Ding’, welches auf einen Reiz mehr oder weniger reagiert, d.h. diesen Reiz ‘durch lässt’. Je nachdem wie stark es aktiviert ist, lässt es mehr oder weniger Reiz durch.
Dabei werden Eingangswerte \(x_0, x_1, x_2, …\) mit Gewichten \(w_0, w_1, w_2, …\) multipliziert, alle Produkte summiert, noch ein Offset \(b\) hinzu addiert und alles geht als Eingang in die Aktivierungsfunktion \(f\). Resultat ist der Ausgang des Neurons, die Aktivierung. Diese kann auch wieder Mehrdimensional sein, denn wenn danach noch ein Layer folgt, so benötigt man ja für die nächste Ebene wieder Eingänge.
Spricht man nun davon, dass ein Neuron ‘aktiviert’ wird (d.h. das Netzwerk lernt), so muss man eine mathematische Funktion \(f\) hinterlegen, die diese Aktivierung modelliert. Typisch und oft genutzt ist die Sigmoid Funktion oder auch der Tangens Hyperbolicus. Großer Beliebtheit erfreut sich die ReLu (Rectifier Linear Unit) Funktion, welche eine simple \(f(x)=max(0, x)\) Funktion ist. Alle 3 sind nachfolgend dargestellt. Alle 3 sind nichtlinear, was deren Sinn ist.
Sie geben für einen Input (in der Abbildung beispielhaft -6…+6) je nach Aktivierung einen Output. Der funktionelle Zusammenhang ist nichtlinear. Je nachdem wie stark das Neuron aktiviert ist, gibt es ein Signal unterschiedlich stark weiter. Zu Beginn des Lernprozesses, muss jedes Neuron initialisiert werden.
Wie man an den Aktivierungsfunktionen sehen kann, ist es von elementarer Bedeutung, ob ein Neuron mit 0 oder -1 oder +1 aktiviert ist. Je nach Aktivierungsfunktion lässt es ein Signal gar nicht oder teilweise oder stark durch. Zu Beginn weiß das Neuronale Netz noch gar nichts, man muss es aber initialisieren. Wenn man ein Netzwerk mit 100 Neuronen hat, sollte man 100 verschiedene Aktivierungen initialisieren.
Die Initialisierung kann im einfachsten Fall gleichverteilt erfolgen. Aber auch normalverteilt oder mit etwas ausgeklügelterer Logik. Auf keinen Fall jedoch alle mit exakt der gleichen Zahl (z.B. 0,0). Das würde dazu führen, dass jedes Neuron exakt gleich ist und beim Lernen ergäbe sich durch die Mathematik hinter dem Lernprozess, dass Fehler bzw. Korrekturen auf jedes Neuron gleich angewendet werden. Das Neuronale Netzwerk würde so nicht schlauer werden, denn es hätte ja dann nur 100 identisch dumme Neuronen.
Das Wichtigste am Lernen ist, dass man weiß, wann etwas richtig oder falsch war. Möchte man z.B. etwas vom Neuronalen Netz klassifziert haben (Ziffern, Buchstaben, Tiere, …), so gibt es nur ein richtig oder falsch. Eine Zielfunktion für ein Klassifizierungsproblem würde im einfachsten Fall nur die korrekt erkannten Dinge zählen. Umso mehr korrekt erkannt wurde, umso besser gelernt. Mit etwas mehr drüber nachdenken kommt man auf die Idee Softmax als Zielfunktion zu nehmen.
Es gibt aber auch Anwendungsfälle, da soll das Neuronale Netzwerk einen Wert schätzen und keine Klasse. Diese Anwendungsfälle nennt man Regressionsprobleme. Dafür ist eine andere Zielfunktion notwendig. Im einfachsten Fall berechnet man, wieviel das Netzwerk und die korrekte Funktion auseinander liegen. Diese Zielfunktionen werden L1 oder L2 Norm genannt, wobei bei letzterer der Fehler quadriert wird. In einigen Anwendungsfällen empfiehlt sich auch die Cross-Entropy als Loss Function.
Eine Zielfunktion kann aber z.B. auch ein Punktestand in einem Spiel (umso mehr, umso besser), die Anzahl an geschlagenen Figuren (umso mehr, umso besser), die erreichte Distanz (umso weiter, umso besser) oder die Entfernung zu einem Hindernis (umso dichter/weiter, umso besser). Je nach Anwendungsfall, welches das Netzwerk lösen soll.
Kommen wir nun zum elementaren und kompliziertesten Teil: Das Lernen! Nicht nur bei Kindern ist das kompliziert, auch bei Neuronalen Netzen muss man da clever sein, um ihnen etwas beizubringen. Die Neuronen sind im ersten Schritt ja initialisiert mit zufälligen Aktivierungen. Das Netzwerk berechnet die Ausgabegröße und wird von der Zielfunktion (Loss) gnadenlos bestraft. Der Fehler den es gemacht hat, wird über so genannte Backpropagation auf die jeweiligen Neuronen zurück verteilt, die ihn verursacht haben.
Nun könnte man auf die Idee kommen, dass man die verschiedenen Neuronen einfach nach und nach einzeln durch geht und mit verschiedenen Aktivierungen (z.B. -6…6) probiert (Bruteforce), bis das Netzwerk die beste Zielfunktion ausgibt. Glückwunsch, so viel Rechenpower hat selbst Google nicht, das für halbwegs reale Anwendungsfälle durch zu spielen.
Eine etwas bessere Idee ist, zu schauen, ob der Fehler größer oder kleiner wird, wenn man die Aktivierung erhöht. Mathematisch gesehen wird die Steigung der Fehlerfunktion bestimmt. Idealer Weise gibt es eine Richtung in die man optimieren kann, sodass die Fehlerfunktion minimiert wird.
Diese Suche nach der idealen Aktivierung bedeutet mathematisch das Finden von Minimalwerten im Fehlerraum. Gibt es nur zwei Parameter, so kann man eine Fehlerfunktion wunderschön visualisieren. Dabei können verschiedene mathematische Suchen implementiert werden. Der Klassiker ist sicherlich die Stochastic Gradient Descent (SGD) Methode, welche numerisch einen Anstieg der Funktion bestimmt und in die abfallende Richtung optimiert. Es gibt andere Verfahren wie Nesterov Momentum, Adagrad und Adadelta oder Rmsprop. Alle haben Vor- und Nachteile sowie Parameter, welche einzustellen sind.
Der Fehler \(e\), den das Netzwerk bei einer Schätzung des Ausgangswertes macht, wird zurück an das Netzwerk gegeben. Dabei wird dieser anteilig auf das Neuron verteilt, welches maßgeblich am Fehler \(e\) beteiligt war. Das mathematische Verfahren ist die Backpropagation. Man kann es sich bildlich so vorstellen:
Das funktioniert auch, wenn man mehr als einen Layer hat.
Ein Neuronales Netzwerk besteht aus mehreren Neuronen. Dabei gibt es verschiedene Architekturen. Es gibt aber immer einen Input- und ein Output-Layer (im GIF oberhalb orange und grün). Bei der Bezeichnung des Netzwerkes wird der Input Layer nicht mit gezählt.
Ein 3-Layer Neuronales Netzwerk hat
usw. Die Layer sind nacheinander (Sequentiell) angeordnet und verbunden. Ab einer gewissen Anzahl an Layern (10…20) spricht man von Deep Neural Networks.
Wenn jedes Neuron mit jedem Neuron des nächsten Layers verbunden ist, dann spricht man von ‘Fully Connected Layer’ (auch ‘Dense-Layer’). Es gibt dann so viele Gewichte \(w\), wie es Verbindungen gibt.
Soll das Netzwerk irgendwelche Informationen aus Bildern (oder Videospielen, YouTube Videos, Kamera, …) lernen, werden zur Extraktion von Features Layer eingesetzt, welche eine Faltungsoperation ausführen. Faltung (oder Englisch: Convolution, die Netzwerke heißen dann Convolutional Neuronal Network oder kurz ConvNets), ist eine relativ simple Funktion, welche in einem gleitenden Fenster das Produkt von zwei Funktionen berechnet. Es zeigt sich aber, dass dieses Vorgehen so mächtig ist, dass ein Layer damit relevante Erkennungsmerkmale für viele reale Gegenstände aus dem Bild heraus arbeitet..
Nun kommen wir zum eigentlichen Teil. Ein Gewicht \(w\) ist eigentlich das Elementare in einem neuronalen Netzwerk, denn es sagt, wie stark ein Neuron mit einem anderen verbunden ist. Der Ausgangswert eines Neurons, multipliziert mit dem Gewicht \(w\) und addiertem Offset \(b\), ergibt den Eingangswert für die Aktivierungsfunktion des Neurons! Mathematisch beschrieben, sieht das so aus:
\[out=f\left(\sum_iw_ix_i + b\right)\]
Wobei \(w_i\)=Gewicht, \(x_i\)=Eingangswert (bzw. Ausgangswert des Neurons des vorhergehenden Layers), \(b\)=Offset des Layers und \(f\)=Aktivierungsfunktion (z.B. Sigmoid). Der Index \(i\) bezieht sich darauf, wieviel Verbindungen auf das Neuron kommen. Besteht der Layer aus 10 Neuronen, wäre \(i=10\). Der Offset \(b\) ist ohne Index, dieser ist pro Layer für jedes Neuron konstant.
Im Code liegt die Wahrheit, hier ist also welcher, Quelle: CS231n
# forward-pass of a 3-layer neural network: f = lambda x: 1.0/(1.0 + np.exp(-x)) # activation function (use sigmoid) x = np.random.randn(3, 1) # random input vector of three numbers (3x1) h1 = f(np.dot(W1, x) + b1) # calculate first hidden layer activations (4x1) h2 = f(np.dot(W2, h1) + b2) # calculate second hidden layer activations (4x1) out = np.dot(W3, h2) + b3 # output neuron (1x1)
Im Code oberhalb sind die Variablen \(W1, W2, W3, b1, b2, b3\) das, was das Neuronale Netzwerk ‘lernen’ muss (wobei die Dimension von \(W_i\) und \(b_i\) von der Dimension der Eingangsdaten abhängt). D.h. die Backpropagation muss den Fehler so auf die \(W_i\) und \(b\) verteilen, dass der Fehler zwischen \(out\) und dem korrekten Wert minimal wird.
Die `numpy dot` Funktion bedeutet elementweise Multiplikation von Matrix-Elementen, denn was in der Formel als Summe dargestellt ist, kann natürlich effizient als elementweise Matrixmultiplikation in einem Rutsch ausgeführt werden. Es ist keine zeitaufwendige Schleife für die Summe notwendig.
Ein Neural Network ist im Prinzip eine wiederholte Matrixmultiplikation mit eingearbeiteter Aktivierungsfunktion.
Nun haben wir alles beisammen, was man benötigt, um ein Neuronales Netzwerk aufzusetzen.
Wie im ersten Teil erwähnt, bringt es nichts auf dem heimischen Laptop ein Netzwerk aufzusetzen, was Super Mario spielen lernt. Es ist prinzipiell möglich, doch die Lernzeit ist so lang, dass bis zum Erreichen eines respektablen Erfolges viele Sommer vergehen werden.
Wir nehmen ein sehr einfaches Beispiel.
Ein Neuronales Netz ist per Definition ein universeller Approximator. Das bedeutet, dass es bereits mit einem Hidden Layer prinzipiell (und mit gewissem Fehler) jede Funktion nachahmen kann. Voraussetzung ist, dass es genügend Neuronen in dem Layer gibt und diese eine nichtlineare Aktivierungsfunktion haben.
Wir könnten den Code prinzipiell selbst in Python aufsetzen [siehe z.B. hier], doch das ist uneffizient und nicht sehr clever.
Besser ist es, eine Bibliothek zu verwenden, die das perfekt macht. Da kann man endlos durch probieren: What is the best deep learning library at the current stage for working on large data?
Das Feld der Neuronalen Netze ist so populär, dass ca. täglich neue Bibliotheken und Wrapper für C++, Lua, Python oder Java auf Github erscheinen, welche mehr oder weniger Beta sind und mehr oder weniger Dokumentation besitzen. Auch die Big Player wie facebook oder Google veröffentlichen ihre Bibliotheken. Wer die Wahl hat, hat die Qual.
Als Anfänger sollte man darauf achten, dass man nicht erst 2 Wochen mit dem Setup für GPU und AWS Cloud zubringt, bevor man überhaupt das 1. mal anfängt rumzuspielen. Daher empfehle ich: Python > Theano > Keras!
Man kann natürlich gleich mit realen Fragestellungen beginnen, doch da lässt sich schwerlich verstehen, worum es im Kern geht. Daher als Beispiel eine gaaaaaanz einfache Sache: Es gibt eine Funktion \(f(x)\), welche dem Netzwerk nicht bekannt ist. Es soll ein neuronales Netzwerk \(g(x)\) aufgesetzt und angelernt werden, was diese Funktion approximiert.
Michael Nielsen hat dazu eine schöne Spielwiese programmiert: A visual proof that neural nets can compute any function.
Wie bekommen wir das nun mit Python, Theano und Keras aufgesetzt?
# Import Keras and Numpy Stuff we need from keras.models import Sequential from keras.layers.core import Dense, Activation from keras.optimizers import Adadelta import numpy as np f = lambda x: 0.2+0.4*x**2+0.3*x*np.sin(15*x)+0.05*np.cos(50*x) x = np.linspace(0, 1, 101) y = f(x)
Der Eingangsvektor \(x\) (kann auch eine Matrix sein, z.B. wenn mit mehreren Trainingsdaten gleichzeitig gelernt werden soll) des Neuronalen Netzwerkes besteht nun einfach aus 100 Zahlen zwischen 0…1. Der Vektor hat die Dimensionen [1, 100]:
\[x=\left[0, 0.01, 0.02, …, 1.0\right]\]
Damit die schöne Matrixstruktur und einfachen Multiplikationen funktionieren, wird der Vektor auf die Dimension [100, 1] umgestellt (also 100 lang, nicht breit). Pro Spalte in \(x\) sollte ein Trainingsdatensatz, pro Zeile ein Wert des Trainingsdatensatzes sein. Da wir nur einen Trainingsdatensatz mit 100 Werten haben, hat unser \(x\) die Form [100, 1].
X = x.reshape((-1, 1)) print(np.shape(X)) # (100, 1) print(np.shape(y)) # (100, )
Jetzt bauen wir das Neuronale Netzwerk mit Keras auf.
model = Sequential() # Sequentielles Netz, d.h. Layer nach Layer... model.add(Dense(input_dim=1, output_dim=300, init="uniform")) model.add(Activation("relu")) model.add(Dense(output_dim=1, init="uniform"))
Was haben wir jetzt aufgesetzt? Ein Dense Layer ist ein Fully Connected Layer, d.h. jedes Neuron soll mit jedem des nächsten verbunden werden. Input hat die Dimension 1. Unser Inputvektor \(x\) hat die Form [100, 1]. Wie bereits beschrieben, bedeutet die Länge 100, dass wir 100 Werte haben, welche aber die Dimension 1 haben. Die Output Dimension wurde mit 300 initialisiert, das bedeutet, dass das Netzwerk 300 Neuronen bekommt im 1. Layer. Die Initialisierung soll ‘uniform’, d.h. gleichverteilt erfolgen.
Als Aktivierungsfunktion wird die ReLu Funktion hinzugefügt.
Anschließend, als Output-Layer wieder ein Fully-Connected Layer mit einer Output Dimension, d.h. das Netzwerk soll keine Klassifizierung o.ä. machen, sondern eine reale Zahl ausgeben. Diese müssen wir nun irgendwie mit dem Sollwert, d.h. der Funktion \(f(x)\) vergleichen und dem Netzwerk eine Loss-Funktion mitteilen.
model.compile(loss='mean_squared_error', optimizer=Adadelta())
In Keras wird das aufgesetzte Modell mit Loss Funktion (in dem Fall der mittlere quadratische Fehler oder auch L2 Norm genannt) und Optimizer (in dem Fall Adadelta) gleich kompiliert, d.h. wenn möglich als optimierter GPU Code im Hintergrund erzeugt.
Nun ist alles aufgesetzt und in Code gegossen. Nun kann man es lernen lassen.
model.fit(X, y, batch_size=15, nb_epoch=10000)
Das Lernen erfolgt mit jeweils 15 der 100 Werte aus dem Eingangsvektor \(x\). Die Fehlerfunktion wird 10.000x die gemachten mittleren quadratischen Fehler via Backpropagation auf die Gewichte \(w\) und \(b\) zurück verteilen. Je nach Initialisierung und Loss Funktion und Aktivierungsfunktion und gewählter Hyperparameter, lernt das Netzwerk schneller oder langsamer.
Hier kann man für einfachere Funktionen beim Lernen zusehen.
Die Loss Funktion sieht beispielsweise so aus (logarithmische y-Achse).
Nach 10.000 Lernvorgängen (auf einem MBP 2.9GHz, Intel Core i5 dauert das knapp 1 Minute), hat das Netzwerk die Funktion \(g(x)\) gefunden, welche \(f(x)\) approximiert.
g=model.predict(X)
Gar nicht schlecht für 1 Minute lernen mit einem Layer mit 300 Neuronen, oder? Allerdings nicht perfekt. Vor allem der erste Teil der Funktion ist relativ schlecht approximiert. Da könnte man nun anfangen zu optimieren. Ist die Schrittweite zu groß, die Loss Funktion die richtige, die Lerndauer zu kurz, …
Bei einer Lerndauer von nur 1 Minute kann man viel rum probieren und mal schnell wieder neu anlernen. Bei einem sehr komplexen Netzwerk, mit 10 Layern und mehreren Millionen Neuronen, dauert das Lernen, selbst in Rechenzentren, einige Tage. Da ist ein gewisses KnowHow notwendig, um in die richtige Richtung zu optimieren.
Ach übrigens: Für kommerzielle Anfragen gibt es auch die Möglichkeit mich zum Thema zu konsultieren: Hire me!
— Im Teil 2 des Deep Learning Tutorials wird dieses Beispiel mit Tensorflow noch mal aufgegriffen! —
Artificial Neural Networks sind aus der modernen Machine Learning Welt nicht mehr weg zu denken. Von der Sortierung der facebook Timeline, Siris Spracherkennung oder auch Fahrspur- und Kollisionserkennung in kamerabasierten Fahrerassistenzsystemen – überall helfen sie uns im Alltag.
Sofern man eine Zielfunktion aufstellen kann, ist das Lernen parallel und relativ schnell (weil der Rechner schnell prüfen kann ob es stimmt und wie groß der Fehler war) möglich. In eng eingegrenzten Szenarien (z.B. Go spielen, Atari spiele spielen, …) können sie menschliche Fähigkeiten durchaus nachahmen oder sogar besser werden als der beste Mensch in der Disziplin.
Doch ein Neuronales Netz, was Atari spielt, kann keine Sprache verstehen. Es sind keine universellen Profis. Allerdings sind die derzeit bestehenden Netzwerke auch noch wesentlich kleiner als das menschliche Gehirn. Die Biochemie im menschlichen Gehirn ist auch wesentlich komplexer als eine einfache ReLu oder Sigmoid Funktion mit ein paar Gewichten. Dennoch: Es gibt nicht wenige Gelehrte dieser Tage, die die Gefahr kommen sehen.
Ein schöner Beitrag dazu: The AI Revolution.
Haben wir damals in Science Fiction Filmen (Minority Report) noch über die Vorhersage von Verbrechen geschmunzelt, so ist es heute Realität.
Haben wir damals in Science Fiction Filmen (Terminator) noch über Skynet gelacht, einem Neuronalen Netz, was alle Informationen sammelt, so haben Firmen wie Google, facebook oder Geheimdienste wohl im Ansatz vergleichbare Architekturen aufgebaut.
Wann wird also der Moment gekommen sein, in dem die SciFi Vision beginnt und eine allumfassendes KI auf die Idee kommt, sich selbst zu trainieren und eigene Zielfunktionen aufzustellen? Eventuell sogar mit einem End-to-End trainierten Neuronalen Netz, welches auch gleich die Stellsignale für Elektromotoren mit lernt und physisch in Erscheinung tritt?
Hope we’re not just the biological boot loader for digital superintelligence. Unfortunately, that is increasingly probable
— Elon Musk (@elonmusk) 3. August 2014
Ein interessantes Interview zum Thema: Jürgen Schmidhuber – Intelligente Roboter werden vom Leben fasziniert sein.
Bald werden eben die klügsten Bestandteile der Zivilisation nicht mehr die Menschen sein. – Jürgen Schmidhuber
A lot of data is recorded in time domain, which means you will have a datapoint in the form of
timestamp: value
A useful approach to get insights into the data is, to decompose the timeseries. That usually means, you seperate your data into
This famous library from R (`decompose`) is available in Python via statsmodel since version 0.6. Yeah! Let’s take a look into it with the parking lot data of city of Dresden.
Mit Abstand am häufigsten gelesen hier im Blog, sind die Beiträge zum Kalman Filter (Teil 1 & Teil 2 & EKF). In den Kommentaren und Emails, die ich dazu bekomme, zeigt sich allerdings, dass da mit Kanonen auf Spatzen geschossen wird. Einige Probleme, die der Algorithmus lösen soll, sind gar nicht so kompliziert, dass man einen Kalman Filter oder Extended Kalman Filter aufsetzen muss.
Ich möchte in diesem Beitrag den kleinen Bruder vom Kalman Filter, den Alpha-Beta-Filter, vorstellen. Dieser ist zwar im Grunde ein Kalman-Filter, allerdings mit einigen Vereinfachungen, sodass er leichter zu implementieren ist.
Die Rotation eines Körpers im Raum ist ein Thema, welches einen Ingenieur in vielen Einsatzbereichen tangiert. Es gibt auch schon unzählige Webseiten dazu und auch die Wikipedia lässt sich zum Thema Drehmatrix oder Eulersche-Winkel ausführlich aus.
Doch so richtig gepasst hat bisher keine Beschreibung. Deshalb an dieser Stelle noch einmal eine ausführliche und einfache Beschreibung der 3D Rotation eines Körpers/Vektors mit Euler-Winkeln nach ZYX-Konvention im DIN70000 Koordinatensystem des Fahrzeugs.
Continue Reading
Dieser Beitrag wurde aus dem IPython Notebook konvertiert, ich bitte um etwas Nachsicht bezüglich der Formatierung.
Da die Beiträge zum Kalman Filter (Teil1 und Teil2) sowie der Beitrag zum Extended Kalman Filter die am Häufigsten gelesenen des Motorblogs sind, habe ich zum Extended Kalman Filter noch mal einen etwas detaillierteren Screencast aufgezeichnet, welcher recht ausführlich erläutert, wie dieser aufgesetzt wird und arbeitet.
Extended Kalman Filter with CTRV Vehicle Model in Python from Paul Balzer on Vimeo.
Als Ingenieur ist man von der Informatik meilenweit entfernt. Im Studium wird man manchmal an Mathworks Matlab herangeführt, versteht es aber im Allgemeinen erstmal nicht. In Fleisch und Blut geht es ohnehin nie über, weil es nahezu unbeschränkte Möglichkeiten bietet, das Studium aber nur eine kurze Zeit dauert.
Während man die ersten Semester Diagramme und Protokolle lieber mit Excel erstellt, reduziert sich die Zeit, in welcher man sich mit Matlab beschäftigen kann, noch weiter. In den letzten Semestern, vielleicht erst in der Diplomarbeit, merkt man dann aber, dass es echt gut ist! Warum nicht eher?
Kommt man aus dem Uni-Umfeld heraus, wird es leider sehr teuer mit Matlab! Eine Standard Einzelplatz Lizenz ohne eine einzige Toolbox kostet 2.000€ Netto. Nur um ein paar Diagramme zu erstellen?
Ich habe mir daher vor einiger Zeit Python angesehen, welches nach einiger Zeit zunehmend Spaß macht! Da es zu Beginn relativ schwer war, einen Einstieg zu finden, möchte ich mein Setup mal vorstellen.
Das Herz der Angelegenheit und bei Linux, Unix und MacOS schon von Haus aus an Board. Für Windows muss man es manuell nachinstallieren. Generell ist die einfachste Variante Anaconda zu installieren, weil dort so ziemlich alle Pakete (Plug-Ins) dabei sind, die wichtig werden für die tägliche Arbeit.
In der Kommandozeile oder im Terminal kann man nun Python nutzen.
Python an sich ist nun schon mächtig, aber immernoch ein zahnloser Tiger, so lange es ohne Zusatzpakete auskommen muss. Zum installieren der Pakete kann man auf Paketmanager zurückgreifen, die die Arbeit in den meisten Fällen übernehmen. Hat man Anaconda installiert, sind die meisten Pakete schon dabei.
Der Paketmanager, welcher nachfolgend die Arbeit der Installation/Upgrades übernimmt, ist PIP. Die Installation von PIP erfolgt betriebssystemabhängig. Am einfachsten mit der get-pip.py, welche dort herunter geladen werden kann. Da wir ja Python installiert haben, können wir einfach:
python get-pip.py
eingeben, dann müsste alles automatisch funktionieren. Da es nun für jedes Betriebssystem immer ein paar Unterschiede gibt, möchte ich aus diesem Beitrag kein Installationstutorial machen, sondern einfach nur zeigen, was meiner Meinung nach am besten geeignet ist, ohne Support.
Das wichtigste Paket, wenn man in großen Schritten Richtung Matlab gehen möchte: Scipy. Es enthält viele elementare Pakete, wie z.b.
Ich habe einige Python IDEs ausprobiert, aber bin nun bei IPython hängen geblieben. IPython kommt mit Scipy mit und ist sehr umfangreich. Gestartet wird die Arbeitsumgebung über die Kommandozeile mit
ipython notebook --script
Der Befehl notebook startet einen lokalen Server, welcher über den Browser unter localhost angesprochen werden kann. Auf der ‘Webseite’ ist es dann möglich so genannte Notebooks zu öffnen, welche ähnlich wie MATLAB .m Files zu nutzen sind. Der Schalter –script sorgt dafür, dass immer parallel eine .py (also eine Python Datei) gespeichert wird, wenn man das Notebook (.ipynb) speichert.
Der große Unterschied zu MATLAB ist nun, dass man bei Python immer erst mal sagen muss, welche Plug-Ins man nutzen möchte im aktuellen Projekt (ähnlich der ‘path’ Umgebung in MATLAB). Möchte man beispielsweise ein Plot erstellen, so ist vorher mitzuteilen, dass die mit Scipy gelieferte Bibliothek Pyplot zu verwenden ist.
import matplotlib.pyplot as plt
Danach stehen alle Funktionen von Matplotlib unter dem Objektnamen plt zur Verfügung.
Ein Plot lässt sich beispielsweise erstellen mit
x=range(5) y=range(5) plt.plot(x,y) plt.show()
Diese Bibliothek ist sehr mächtig, wie die Beispiele zeigen!
import numpy as np import matplotlib.pyplot as plt import random import time n = 1100000 m=0.0 v=0.0 elapsed=[] vals=[] for i in xrange(0,n,1000): # Python reagiert auf Einrückungen (Leerzeichen oder <tab>) # Alles was eingerückt ist, gehört zur Schleife! #print 'Berechne für ' + str(i) + ' Werte.' values = np.random.sample(i) start = time.clock() m = np.mean(values) v = np.var(values) elapsed.append((time.clock() - start)) vals.append(i) fig = plt.figure(figsize=(12,5)) plt.plot(vals,elapsed, 'ro') plt.xlabel(u'Anzahl Werte') plt.grid() plt.ylabel(u'Berechnungszeit [s]') plt.title(u'Berechnungsdauer für var() und mean()') plt.savefig('Berechnungsdauer.png',dpi=72) plt.close() print('Done.')Download IPython Notebook
Zwar gibt es für MATLAB unzählige Toolboxen und auch das Matlab Central, wo Zusatzfunktionen herunter geladen werden können, aber der große Vorteil an Python ist: Es ist kostenfrei!
Ein Blick auf die kompilierten Windows Versionen der Pakete zeigt, dass man überhaupt nicht überblicken kann, was alles möglich ist. Die Pakete die ich bisher genutzt habe, sind folgende:
Möchte man das Plot jetzt auch noch mal in “schön” haben, so bietet sich Bokeh an. Es muss natürlich importiert werden
from bokeh.plotting import *
aber anschließend geht es sogar einfacher und ansehnlicher als mit Matplotlib:
scatter(vals, elapsed, title='Berechnungsdauer') show()
Weiterführend ist der Kurs “Introduction to scientific computing with Python” von J.R. Johansson empfohlen! Hier insbesondere der Teil 4: matplotlib – 2D and 3D plotting in Python.
Der Nachteil ist ganz eindeutig, dass viele viele viele verschiedene Menschen die Zusatzpakete erstellen und jeder so seine eigene Art hat, dies umzusetzen. Das führt dazu, dass zum einen die Webseiten, wo die Pakete zu bekommen sind, nicht einheitlich aussehen und teilweise wirklich schlecht gepflegt werden (Installationshinweise usw..) und zum anderen auch die Art, wie man die Pakete nutzen kann, verschieden ist.
Bei MATLAB ist alles zentral durch Mathworks organisiert, d.h. man kann sich drauf verlassen, dass es eine ordentliche Hilfe gibt, dass die Funktion genau so funktioniert wie dort dargestellt und das es vom Syntax her eindeutig ist.
Bei einigen Python Paketen ist es eher ein Rätselraten, wie man das nun so benutzt, dass es macht was man möchte. Da wird http://stackoverflow.com/ schnell der beste Freund!
Nachdem wir im Teil 1 den Kern des Kalman Filters geklärt haben, widmen wir uns nun dem komplizierteren Teil. Die im Teil 1 genannte Vorgehensweise mit dem multiplizieren bzw. addieren der Mittelwerte und Varianzen funktioniert so nur im eindimensionalen Fall. \(\)
Das heißt, wenn der Zustand, den man messen möchte, mit nur einer Variablen vollständig beschrieben werden kann. Das Beispiel, welches eingangs genannt wurde, die Position eines Fahrzeugs im Tunnel zu bestimmen, kann aber nicht mehr mit einer Variablen vollständig beschrieben werden. Zwar interessiert nur die Position, aber diese ist genau genommen ja schon 2-Dimensional in der Ebene (\(x\) & \(y\)). Außerdem kann nur die Geschwindigkeit (\(\dot x\) & \(\dot y\)) gemessen werden, nicht die Position direkt. Dies führt zu einem 4D-Kalman-Filter, mit folgenden Zustandsvariablen:
$$x=\begin{bmatrix}
x \\
y \\
\dot x \\
\dot y
\end{bmatrix}=\begin{matrix}\text{Position X} \\ \text{Position Y} \\ \text{Geschwindigkeit in X} \\ \text{Geschwindigkeit in Y}
\end{matrix}$$
Herr Kalman hatte sich nun überlegt, wie man es schafft, trotz verrauschter Messung einzelner Sensoren, eine optimale Schätzung aller Zustände zu berechnen.
Durch meine berufliche Betätigung bin ich auf mehr oder weniger sinnvolle Anleitungen zur Inbetriebnahme der Open Computer Vision Bibliotheken mit Python unter Windows 7 gestoßen. Ich möchte eine schnelle und einfache Art noch mal festhalten, damit nicht jeder so viel Zeit in diese Sache investieren muss.
Obwohl ich ein 64bit Windows nutze, sind die 32bit Versionen der nachfolgenden Software zu nutzen, da OpenCV und 64bit keine richtigen Freunde sind.
Nach der Installation aller Pakete muss Python noch der Zugriff auf OpenCV ermöglicht werden. Dazu im Installationsverzeichnis von OpenCV im Unterordner \build\python\2.7 die Dateien cv.py und cv2.pyd in den Python-Ordner \Lib\site-packages\ kopieren.
Wenn alles erfolgreich verlief, so kann man im Python mit import cv die komplette Computervision Biblitothek importieren und nutzen.