Fehler-Rückführung mit der Backpropagation

Dies ist Artikel 4 von 6 der Artikelserie –Einstieg in Deep Learning.

Das Gradienten(abstiegs)verfahren ist der Schlüssel zum Training einzelner Neuronen bzw. deren Gewichtungen zu den Neuronen der vorherigen Schicht. Wer dieses Prinzip verstanden hat, hat bereits die halbe Miete zum Verständnis des Trainings von künstlichen neuronalen Netzen.

Der Gradientenabstieg wird häufig fälschlicherweise mit der Backpropagation gleichgesetzt, jedoch ist das nicht ganz richtig, denn die Backpropagation ist mehr als die Anwendung des Gradientenabstiegs.

Bevor wir die Backpropagation erläutern, nochmal kurz zurück zur Forward-Propagation, die die eigentliche Prädiktion über ein künstliches neuronales Netz darstellt:

Forward-Propagation

Abbildung 1: Ein simples kleines künstliches neuronales Netz mit zwei Schichten (+ Eingabeschicht) und zwei Neuronen pro Schicht.

In einem kleinen künstlichen neuronalen Netz, wie es in der Abbildung 1 dargestellt ist, und das alle Neuronen über die Sigmoid-Funktion aktiviert, wird jedes Neuron eine Nettoeingabe z berechnen…

z = w^{T} \cdot x

… und diese Nettoeingabe in die Sigmoid-Funktion einspeisen…

\phi(z) = sigmoid(z) = \frac{1}{1 + e^{-z}}

… die dann das einzelne Neuron aktiviert. Die Aktivierung erfolgt also in der mittleren Schicht (N-Schicht) wie folgt:

N_{j} = \frac{1}{1 + e^{- \sum (w_{ij} \cdot x_{i}) }}

Die beiden Aktivierungsausgaben N werden dann als Berechnungsgrundlage für die Ausgaben der Ausgabeschicht o verwendet. Auch die Ausgabe-Neuronen berechnen ihre jeweilige Nettoeingabe z und aktivieren über Sigmoid(z).

Ausgabe eines Ausgabeknotens als Funktion der Eingänge und der Verknüpfungsgewichte für ein dreischichtiges neuronales Netz, mit nur zwei Knoten je Schicht, kann also wie folgt zusammen gefasst werden:

O_{k} = \frac{1}{1 + e^{- \sum (w_{jk} \cdot \frac{1}{1 + e^{- \sum (w_{ij} \cdot x_{i}) }}) }}

Abbildung 2: Forward-Propagation. Aktivierung via Sigmoid-Funktion.

Sollte dies die erste Forward-Propagation gewesen sein, wird der Output noch nicht auf den Input abgestimmt sein. Diese Abstimmung erfolgt in Form der Gewichtsanpassung im Training des neuronalen Netzes, über die zuvor erwähnte Gradientenmethode. Die Gradientenmethode ist jedoch von einem Fehler abhängig. Diesen Fehler zu bestimmen und durch das Netz zurück zu führen, das ist die Backpropagation.

Back-Propagation

Um die Gewichte entgegen des Fehlers anpassen zu können, benötigen wir einen möglichst exakten Fehler als Eingabe. Der Fehler berechnet sich an der Ausgabeschicht über eine Fehlerfunktion (Loss Function), beispielsweise über den MSE (Mean Squared Error) oder über die sogenannte Kreuzentropie (Cross Entropy). Lassen wir es in diesem Beispiel einfach bei einem simplen Vergleich zwischen dem realen Wert (Sollwert o_{real}) und der Prädiktion (Ausgabe o) bleiben:

e_{o} = o_{real} - o

Der Fehler e ist also einfach der Unterschied zwischen dem Ziel-Wert und der Prädiktion. Jedes Training ist eine Wiederholung von Prädiktion (Forward) und Gewichtsanpassung (Back). Im ersten Schritt werden üblicherweise die Gewichtungen zufällig gesetzt, jede Gewichtung unterschiedlich nach Zufallszahl. So ist die Wahrscheinlichkeit, gleich zu Beginn die “richtigen” Gewichtungen gefunden zu haben auch bei kleinen neuronalen Netzen verschwindend gering. Der Fehler wird also groß sein und kann über den Gradientenabstieg durch Gewichtsanpassung verkleinert werden.

In diesem Beispiel berechnen wir die Fehler e_{1} und e_{2} und passen danach die Gewichte w_{j,k} (w_{1,1} & w_{2,1} und w_{1,2} & w_{2,2}) der Schicht zwischen dem Hidden-Layer N und dem Output-Layer o an.

Abbildung 3: Anpassung der Gewichtungen basierend auf dem Fehler in der Ausgabe-Schicht.

Die Frage ist nun, wie die Gewichte zwischen dem Input-Layer X und dem Hidden-Layer N anzupassen sind. Es stellt sich die Frage, welchen Einfluss diese auf die Fehler in der Ausgabe-Schicht haben?

Um diese Gewichtungen anpassen zu können, benötigen wir den Fehler-Anteil der beiden Neuronen N_{1} und N_{2}. Dieser Anteil am Fehler der jeweiligen Neuronen ergibt sich direkt aus den Gewichtungen w_{j,k} zum Output-Layer:

e_{N_{1}} = e_{o1} \cdot \frac{w_{1,1}}{w_{1,1} + w_{1,2}} + e_{o2} \cdot \frac{w_{1,2}}{w_{1,1} + w_{1,2}}

e_{N_{2}} = e_{o1} \cdot \frac{w_{2,1}}{w_{2,1} + w_{2,2}} + e_{o2} \cdot \frac{w_{2,2}}{w_{2,1} + w_{2,2}}

Wenn man das nun generalisiert:

    \[ e_{N} = \left(\begin{array}{rr} \frac{w_{1,1}}{w_{1,1} + w_{1,2}} & \frac{w_{1,2}}{w_{1,1} + w_{1,2}} \\ \frac{w_{2,1}}{w_{2,1} + w_{2,2}} & \frac{w_{2,2}}{w_{2,1} + w_{2,2}} \end{array}\right) \cdot \left(\begin{array}{c} e_{1} \\ e_{2} \end{array}\right) \qquad \]

Dabei ist es recht aufwändig, die Gewichtungen stets ins Verhältnis zu setzen. Diese Berechnung können wir verkürzen, indem ganz einfach direkt nur die Gewichtungen ohne Relativierung zur Kalkulation des Fehleranteils benutzt werden. Die Relationen bleiben dabei erhalten!

    \[ e_{N} = \left(\begin{array}{rr} w_{1,1} & w_{1,2} \\ w_{2,1} & w_{2,2} \end{array}\right) \cdot \left(\begin{array}{c} e_{1} \\ e_{2} \end{array}\right) \qquad \]

Oder folglich in Kurzform: e_{N} = w^{T} \cdot e_{o}

Abbildung 4: Vollständige Gewichtsanpassung auf Basis der Fehler in der Ausgabeschicht und der Fehleranteile in der verborgenden Schicht.

Und nun können, basierend auf den Fehleranteilen der verborgenden Schicht N, die Gewichtungen w_{i,j} zwischen der Eingabe-Schicht I und der verborgenden Schicht N angepasst werden, entgegen dieser Fehler e_{N}.

Die Backpropagation besteht demnach aus zwei Schritten:

  1. Fehler-Berechnung durch Abgleich der Soll-Werte mit den Prädiktionen in der Ausgabeschicht und durch Fehler-Rückführung zu den Neuronen der verborgenden Schichten (Hidden-Layer)
  2. Anpassung der Gewichte entgegen des Gradientenanstiegs der Fehlerfunktion (Loss Function)

Buchempfehlungen

Die folgenden zwei Bücher haben mir sehr beim Verständnis und beim Verständlichmachen der Backpropagation in künstlichen neuronalen Netzen geholfen.

Neuronale Netze selbst programmieren: Ein verständlicher Einstieg mit Python Deep Learning. Das umfassende Handbuch: Grundlagen, aktuelle Verfahren und Algorithmen, neue Forschungsansätze (mitp Professional)

Training eines Neurons mit dem Gradientenverfahren

Dies ist Artikel 3 von 6 der Artikelserie –Einstieg in Deep Learning.

Das Training von neuronalen Netzen erfolgt nach der Forward-Propagation über zwei Schritte:

  1. Fehler-Rückführung über aller aktiver Neuronen aller Netz-Schichten, so dass jedes Neuron “seinen” Einfluss auf den Ausgabefehler kennt.
  2. Anpassung der Gewichte entgegen den Gradienten der Fehlerfunktion

Beide Schritte werden in der Regel zusammen als Backpropagation bezeichnet. Machen wir erstmal einen Schritt vor und betrachten wir, wie ein Neuron seine Gewichtsverbindungen zu seinen Vorgängern anpasst.

Gradientenabstiegsverfahren

Der Gradientenabstieg ist ein generalisierbarer Algorithmus zur Optimierung, der in vielen Verfahren des maschinellen Lernens zur Anwendung kommt, jedoch ganz besonders als sogenannte Backpropagation im Deep Learning den Erfolg der künstlichen neuronalen Netze erst möglich machen konnte.

Der Gradientenabstieg lässt sich vom Prinzip her leicht erklären: Angenommen, man stünde im Gebirge im dichten Nebel. Das Tal, und somit der Weg nach Hause, ist vom Nebel verdeckt. Wohin laufen wir? Wir können das Ziel zwar nicht sehen, tasten uns jedoch so heran, dass unser Gehirn den Gradienten (den Unterschied der Höhen beider Füße) berechnet, somit die Steigung des Bodens kennt und sich entgegen dieser Steigung unser Weg fortsetzt.

Konkret funktioniert der Gradientenabstieg so: Wir starten bei einem zufälligen Theta \theta (Random Initialization). Wir berechnen die Ausgabe (Forwardpropogation) und vergleichen sie über eine Verlustfunktion (z. B. über die Funktion Mean Squared Error) mit dem tatsächlich korrekten Wert. Auf Grund der zufälligen Initialisierung haben wir eine nahe zu garantierte Falschheit der Ergebnisse und somit einen Verlust. Für die Verlustfunktion berechnen wir den Gradienten für gegebene Eingabewerte. Voraussetzung dafür ist, dass die Funktion ableitbar ist. Wir bewegen uns entgegen des Gradienten in Richtung Minimum der Verlustfunktion. Ist dieses Minimum (fast) gefunden, spricht man auch davon, dass der Lernalgorithmus konvergiert.

Das Gradientenabstiegsverfahren ist eine Möglichkeit der Gradientenverfahren, denn wollten wir maximieren, würden wir uns entlang des Gradienten bewegen, was in anderen Anwendungen sinnvoll ist.

Ob als “Cost Function” oder als “Loss Function” bezeichnet, in jedem Fall ist es eine “Error Function”, aber auf die Benennung kommen wir später zu sprechen. Jedenfalls versuchen wir die Fehlerrate zu senken! Leider sind diese Funktionen in der Praxis selten so einfach konvex (zwei Berge mit einem Tal dazwischen).

 

Aber Achtung: Denn befinden wir uns nur zwischen zwei Bergen, finden wir das Tal mit Sicherheit über den Gradienten. Befinden wir uns jedoch in einem richtigen Gebirge mit vielen Bergen und Tälern, gilt es, das richtige Tal zu finden. Bei der Optimierung der Gewichtungen von künstlichen neuronalen Netzen wollen wir die besten Gewichtungen finden, die uns zu den geringsten Ausgaben der Verlustfunktion führen. Wir suchen also das globale Minimum unter den vielen (lokalen) Minima.

Programmier-Beispiel in Python

Nachfolgend ein Beispiel des Gradientenverfahrens zur Berechnung einer Regression. Wir importieren numpy und matplotlib.pyplot und erzeugen uns künstliche Datenpunkte:

import numpy as np
import matplotlib.pyplot as plt


X = 2 * np.random.rand(1000, 1)
y = 5 + 2 * X + np.random.randn(1000, 1)

plt.figure(figsize = (15, 15))
plt.plot(X, y, "b.")
plt.axis([0, 2, 0, 15])
plt.show()

Nun wollen wir einen Lernalgorithmus über das Gradientenverfahren erstellen. Im Grunde haben wir hier es bereits mit einem linear aktivierten Neuron zutun:

Bei der linearen Regression, die wir durchführen wollen, nehmen wir zwei-dimensionale Daten (wobei wir die Regression prinzipiell auch mit x-Dimensionen durchführen können, dann hätte unser Neuron weitere Eingänge). Wir empfangen einen Bias (w_0) der stets mit einer Eingangskonstante multipliziert und somit als Wert erhalten bleibt. Der Bias ist das Alpha \alpha in einer Schulmathe-tauglichen Formel wie y = \beta \cdot x + \alpha.

Beta \beta ist die Steigung, der Gradient, der Funktion.

Sowohl \alpha als auch \beta sind uns unbekannt, versuchen wir jedoch über die Betrachtung unserer Prädiktion durch Berechnung der Formel \^y = \beta \cdot x + \alpha und den darauffolgenden Abgleich mit dem tatsächlichen y herauszufinden. Anfangs behaupten wir beispielsweise einfach, sowohl \beta als auch \alpha seien 0.00. Folglich wird \^y = \beta \cdot x + \alpha ebenfalls gleich 0.00 sein und die Fehlerfunktion (Loss Function) wird maximal sein. Dies war der erste Durchlauf des Trainings, die sogenannte erste Epoche!

Die Epochen (Durchläufe) und dazugehörige Fehlergrößen. Wenn die Fehler sinken und mit weiteren Epochen nicht mehr wesentlich besser werden, heißt es, das der Lernalogorithmus konvergiert.

Als Fehlerfunktion verwenden wir bei der Regression die MSE-Funktion (Mean Squared Error):

MSE = \sum(\^y_i - y_i)^2

Um diese Funktion wird sich nun alles drehen, denn diese beschreibt den Fehler und gibt uns auch die Auskunft darüber, ob wie stark und in welche Richtung sie ansteigt, so dass wir uns entgegen der Steigung bewegen können. Wer die Regeln der Ableitung im Kopf hat, weiß, dass die Ableitung der Formel leichter wird, wenn wir sie vorher auf halbe Werte runterskalieren. Da die Proportionen dabei erhalten bleiben und uns quadrierte Fehlerwerte unserem menschlichen Verstand sowieso nicht so viel sagen (unser Gehirn denkt nunmal nicht exponential), stört das nicht:

MSE = \frac{\frac{1}{2} \cdot \sum(\^y_i - y_i)^2}{n}

MSE = \frac{\frac{1}{2} \cdot \sum(w^T \cdot x_i - y_i)^2}{n}

Wenn die Mathematik der partiellen Ableitung (Ableitung einer Funktion nach jedem Gradienten) abhanden gekommen ist, bitte nochmal folgende Regeln nachschlagen, um die nachfolgende Ableitung verstehen zu können:

  • Allgemeine partielle Ableitung
  • Kettenregel

Ableitung der MSD-Funktion nach dem einen Gewicht w bzw. partiell nach jedem vorhandenen w_j:

\frac{\partial}{\partial w_j}MSE = \frac{\partial}{\partial w} \frac{1}{2} \cdot \sum(\^y - y_i)^2

\frac{\partial}{\partial w_j}MSE = \frac{\partial}{\partial w} \frac{1}{2} \cdot \sum(w^T \cdot x_i - y_i)^2

\frac{\partial}{\partial w_j}MSE = \frac{2}{n} \cdot \sum(w^T \cdot x_i - y_i) \cdot x_{ij}

Woher wir das x_{ij} am Ende her haben? Das ergibt sie aus der Kettenregel: Die äußere Funktion wurde abgeleitet, so wurde aus \frac{1}{2} \cdot \sum(w^T \cdot x_i - y_i)^2 dann \frac{2}{n} \cdot \sum(w^T \cdot x_i - y_i). Jedoch muss im Sinne eben dieser Kettenregel auch die innere Funktion abgeleitet werden. Da wir nach w_j ableiten, bleibt nur x_ij erhalten.

Damit können wir arbeiten! So kompliziert ist die Formel nun auch wieder nicht: \frac{2}{n} \cdot \sum(w^T \cdot x_i - y_i) \cdot x_{ij}

Mit dieser Formel können wir unsere Gewichte an den Fehler anpassen: (f\nabla ist der Gradient der Funktion!)

w_j = w_j - \nabla MSE(w_j)

Initialisieren der Gewichtungen

Die Gewichtungen \alpha und \beta müssen anfänglich mit Werten initialisiert werden. In der Regression bietet es sich an, die Gewichte anfänglich mit 0.00 zu initialisieren.

Bei vielen neuronalen Netzen, mit nicht-linearen Aktivierungsfunktionen, ist das jedoch eher ungünstig und zufällige Werte sind initial besser. Gut erprobt sind normal-verteilte Zufallswerte.

Lernrate

Nur eine Kleinigkeit haben wir bisher vergessen: Wir brauchen einen Faktor, mit dem wir anpassen. Hier wäre der Faktor 1. Das ist in der Regel viel zu groß. Dieser Faktor wird geläufig als Lernrate (Learning Rate) \eta (eta) bezeichnet:

w_j = w_j - \eta \cdot \nabla MSE(w_j)

Die Lernrate \eta ist ein Knackpunkt und der erste Parameter des Lernalgorithmus, den es anzupassen gilt, wenn das Training nicht konvergiert.

Die Lernrate \eta darf nicht zu groß klein gewählt werden, da das Training sonst zu viele Epochen benötigt. Ungeduldige erhöhen die Lernrate möglicherweise aber so sehr, dass der Lernalgorithmus im Minimum der Fehlerfunktion vorbeiläuft und diesen stets überspringt. Hier würde der Algorithmus also sozusagen konvergieren, weil nicht mehr besser werden, aber das resultierende Modell wäre weit vom Optimum entfernt.

Beginnen wir mit der Implementierung als Python-Klasse:

class LinearRegressionGD(object):
    
    def __init__(self, eta = 0.0001, n_iter = 50):
        
        self.eta = eta                  # Lernrate
        self.n_iter = n_iter            # Epochen
        
    def fit(self, X, y):
        
        self.w_ = np.zeros(1 + X.shape[1]) # <- 1 für den Bias + alle weiteren Columns für die Steigungen
                                           # In diesem Beispiel self.w_ = [0.0, 0.] = [Alpha, Beta]
                                           # Dabei initialisieren wir Alpha und Beta mit 0.00-Werten
        
        self.cost_ = []                    # Cost Function (der Verlauf der Loss Function MSE)
        
        for i in range(self.n_iter):       # Für jede Epoche...
            
            output = self.predict(X)       # Die Funktion x * Beta + Alpha ausrechnen  
                                           # Batch-Verfahren, denn wir trainieren jede Epoche mit allen X-Werten

            errors = y.flatten() - output  # y_predicted - y_real

            mse = ((errors ** 2).sum() / 2.0) / len(X)  # Loss Function MSE
            
            self.cost_.append(mse)                      # Loss Function wird Teil der Cost Function
            
            self.w_[1:] += self.eta * X.T.dot(errors)   # Anpassen des Gewichts Beta (und falls es sie gäbe: aller weiteren Gewichte)
            self.w_[0] += self.eta * errors.sum()      # Anpassen des Gewichts Alpha
            
            
            #print(output)
            #print(errors)
            #print("Beta  -> ", self.w_[1:])
            #print("Alpha -> ", self.w_[0])                   
            
        return self
        
    def predict(self, X):
        return np.dot(X, self.w_[1:]) + self.w_[0]      # y = x * Beta + Alpha

Die Klasse sollte so funktionieren, bevor wir sie verwenden, sollten wir die Input-Werte standardisieren:

x_std = (X - X.mean()) / X.std()
y_std = (y - y.mean()) / y.std()

Bei diesem Beispiel mit künstlich erzeugten Werten ist das Standardisieren bzw. das Fehlen des Standardisierens zwar nicht kritisch, aber man sollte es sich zur Gewohnheit machen. Testweise es einfach mal weglassen 🙂

Kommen wir nun zum Einsatz der Klasse, die die Regression via Gradientenabstieg absolvieren soll:

lrGD = LinearRegressionGD()  # Instanziieren
lrGD.fit(x_std, y_std)       # Trainieren (das ".fit()" entspricht dem Wording von scikit-learn, ".train()" wäre mir sonst lieber 🙂

Was tut diese Instanz der Klasse LinearRegressionGD nun eigentlich?

Bildlich gesprochen, legt sie eine Gerade auf den Boden des Koordinatensystems, denn die Gewichtungen werden mit 0.00 initialisiert, y ist also gleich 0.00, egal welche Werte in x enthalten sind. Der Fehler ist dann aber sehr groß (sollte maximal sein, im Vergleich zu zukünftigen Epochen). Die Gewichte werden also angepasst, die Gerade somit besser in die Punktwolke platziert. Mit jeder Epoche wird die Gerade erneut in die Punktwolke gelegt, der Gesamtfehler (über alle x, da wir es hier mit dem Batch-Verfahren zutun haben) berechnet, die Werte angepasst… bis die vorgegebene Zahl an Epochen abgelaufen ist.

Schauen wir uns das Ergebnis des Trainings an:

plt.figure(figsize = (15, 15))
plt.plot(x_std, y_std, "b.")                                # Scatter, wie zuvor!
plt.plot(x_std, lrGD.predict(x_std), "r-", linewidth = 5)   # Regressionsgerade als Linie
plt.show()

Die Linie sieht passend aus, oder? Da wir hier nicht zu sehr in die Theorie der Regressionsanalyse abdriften möchten, lassen wir das testen und prüfen der Akkuratesse mal aus, hier möchte ich auf meinen Artikel Regressionsanalyse in Python mit Scikit-Learn verweisen.

Prüfen sollten wir hingegen mal, wie schnell der Lernalgorithmus mit der vorgegebenen Lernrate eta konvergiert:

plt.figure(figsize = (15, 15))
plt.plot(range(1, lrGD.n_iter + 1), lrGD.cost_)
plt.xlabel('Epochen')
plt.ylabel('Summe quadrierter Abweichungen')
plt.show()

Hier die Verlaufskurve der Cost Function:

Die Kurve zeigt uns, dass spätestens nach 40 Epochen kaum noch Verbesserung (im Sinne der Gesamtfehler-Minimierung) erreicht wird.

Wichtige Hinweise

Natürlich war das nun nur ein erster kleiner Einstieg und wer es verstanden hat, hat viel gewonnen. Denn erst dann kann man sich vorstellen, wie ein einzelnen Neuron eines künstlichen neuronalen Netzes grundsätzlich trainiert werden kann.

Folgendes sollte noch beachtet werden:

  • Lernrate \eta:
    Die Lernrate ist ein wichtiger Parameter. Wer das Programmier-Beispiel bei sich zum Laufen gebracht hat, einfach mal die Lernrate auf Werte zwischen 10.00 und 0.00000001 setzen, schauen was passiert 🙂
  • Globale Minima vs lokale Minima:
    Diese lineare zwei-dimensionale Regression ist ziemlich einfach. Neuronale Netze sind hingegen komplexer und haben nicht einfach nur eine simple konvexe Fehlerfunktion. Hier gibt es mehrere Hügel und Täler in der Fehlerfunktion und die Gefahr ist groß, in einem lokalen, nicht aber in einem globalen Minimum zu landen.
  • Stochastisches Gradientenverfahren:
    Wir haben hier das sogenannte Batch-Verfahren verwendet. Dieses ist grundsätzlich besser als die stochastische Methode. Denn beim Batch verwenden wir den gesamten Stapel an x-Werten für die Fehlerbestimmung. Allerdings ist dies bei großen Daten zu rechen- und speicherintensiv. Dann werden kleinere Unter-Stapel (Sub-Batches) zufällig aus den x-Werten ausgewählt, der Fehler daraus bestimmt (was nicht ganz so akkurat ist, wie als würden wir den Fehler über alle x berechnen) und der Gradient bestimmt. Dies ist schon Rechen- und Speicherkapazität, erfordert aber meistens mehr Epochen.

Buchempfehlung

Die folgenden zwei Bücher haben mir bei der Erstellung dieses Beispiels geholfen und kann ich als hilfreiche und deutlich weiterführende Lektüre empfehlen:

 

Machine Learning mit Python und Scikit-Learn und TensorFlow: Das umfassende Praxis-Handbuch für Data Science, Predictive Analytics und Deep Learning (mitp Professional) Hands-On Machine Learning with Scikit-Learn and TensorFlow: Concepts, Tools, and Techniques for Building Intelligent Systems

 

Über die Integration symbolischer Inferenz in tiefe neuronale Netze

Tiefe neuronale Netze waren in den letzten Jahren eine enorme Erfolgsgeschichte. Viele Fortschritte im Bereich der KI, wie das Erkennen von Objekten, die fließende Übersetzung natürlicher Sprache oder das Spielen von GO auf Weltklasseniveau, basieren auf tiefen neuronalen Netzen. Über die Grenzen dieses Ansatzes gab es jedoch nur wenige Berichte. Eine dieser Einschränkungen ist die Unfähigkeit, aus einer kleinen Anzahl von Beispielen zu lernen. Tiefe neuronale Netze erfordern in der Regel eine Vielzahl von Trainingsbeispielen, während der Mensch aus nur einem einzigen Beispiel lernen kann. Wenn Sie eine Katze einem Kind zeigen, das noch nie zuvor eine gesehen hat, kann es eine weitere Katze anhand dieser einzigen Instanz erkennen. Tiefe neuronale Netze hingegen benötigen Hunderttausende von Bildern, um zu erlernen, wie eine Katze aussieht. Eine weitere Einschränkung ist die Unfähigkeit, Rückschlüsse aus bereits erlerntem Allgemeinwissen zu ziehen. Beim Lesen eines Textes neigen Menschen dazu, weitreichende Rückschlüsse auf mögliche Interpretationen des Textes zu ziehen. Der Mensch ist dazu in der Lage, weil er Wissen aus sehr unterschiedlichen Bereichen abrufen und auf den Text anwenden kann.

Diese Einschränkungen deuten darauf hin, dass in tiefen neuronalen Netzen noch etwas Grundsätzliches fehlt. Dieses Etwas ist die Fähigkeit, symbolische Bezüge zu Entitäten in der realen Welt herzustellen und sie in Beziehung zueinander zu setzen. Symbolische Inferenz in Form von formaler Logik ist seit Jahrzehnten der Kern der klassischen KI, hat sich jedoch als spröde und komplex in der Anwendung erwiesen. Gibt es dennoch keine Möglichkeit, tiefe neuronale Netze so zu verbessern, dass sie in der Lage sind, symbolische Informationen zu verarbeiten? Tiefe neuronale Netzwerke wurden von biologischen neuronalen Netzwerken wie dem menschlichen Gehirn inspiriert. Im Wesentlichen sind sie ein vereinfachtes Modell der Neuronen und Synapsen, die die Grundbausteine des Gehirns ausmachen. Eine solche Vereinfachung ist, dass statt mit zeitlich begrenzten Aktionspotenzialen nur mit einem Aktivierungswert gearbeitet wird. Aber was ist, wenn es nicht nur wichtig ist, ob ein Neuron aktiviert wird, sondern auch, wann genau. Was wäre, wenn der Zeitpunkt, zu dem ein Neuron feuert, einen relationalen Kontext herstellt, auf den sich diese Aktivierung bezieht? Nehmen wir zum Beispiel ein Neuron, das für ein bestimmtes Wort steht. Wäre es nicht sinnvoll, wenn dieses Neuron jedes Mal ausgelöst würde, wenn das Wort in einem Text erscheint? In diesem Fall würde das Timing der Aktionspotenziale eine wichtige Rolle spielen. Und nicht nur das Timing einer einzelnen Aktivierung, sondern auch das Timing aller eingehenden Aktionspotenziale eines Neurons relativ zueinander wäre wichtig. Dieses zeitliche Muster kann verwendet werden, um eine Beziehung zwischen diesen Eingangsaktivierungen herzustellen. Wenn beispielsweise ein Neuron, das ein bestimmtes Wort repräsentiert, eine Eingabesynapse für jeden Buchstaben in diesem Wort hat, ist es wichtig, dass das Wort Neuron nur dann ausgelöst wird, wenn die Buchstabenneuronen in der richtigen Reihenfolge zueinander abgefeuert wurden. Konzeptionell könnten diese zeitlichen Unterschiede als Relationen zwischen den Eingangssynapsen eines Neurons modelliert werden. Diese Relationen definieren auch den Zeitpunkt, zu dem das Neuron selbst im Verhältnis zu seinen Eingangsaktivierungen feuert. Aus praktischen Gründen kann es sinnvoll sein, der Aktivierung eines Neurons mehrere Slots zuzuordnen, wie z.B. den Anfang und das Ende eines Wortes. Andernfalls müssten Anfang und Ende eines Wortes als zwei getrennte Neuronen modelliert werden. Diese Relationen sind ein sehr mächtiges Konzept. Sie ermöglichen es, die hierarchische Struktur von Texten einfach zu erfassen oder verschiedene Bereiche innerhalb eines Textes miteinander in Beziehung zu setzen. In diesem Fall kann sich ein Neuron auf eine sehr lokale Information beziehen, wie z.B. einen Buchstaben, oder auf eine sehr weitreichende Information, wie z.B. das Thema eines Textes.

Eine weitere Vereinfachung im Hinblick auf biologische neuronale Netze besteht darin, dass mit Hilfe einer Aktivierungsfunktion die Feuerrate eines einzelnen Neurons angenähert wird. Zu diesem Zweck nutzen klassische neuronale Netze die Sigmoidfunktion. Die Sigmoidfunktion ist jedoch symmetrisch bezüglich großer positiver oder negativer Eingangswerte, was es sehr schwierig macht, ausssagenlogische Operationen mit Neuronen mit der Sigmoidfunktion zu modellieren. Spiking-Netzwerke hingegen haben einen klaren Schwellenwert und ignorieren alle Eingangssignale, die unterhalb dieses Schwellenwerts bleiben. Daher ist die ReLU-Funktion oder eine andere asymmetrische Funktion eine deutlich bessere Annäherung für die Feuerrate. Diese Asymmetrie ist auch für Neuronen unerlässlich, die relationale Informationen verarbeiten. Das Neuron, das ein bestimmtes Wort repräsentiert, muss nämlich für alle Zeitpunkte, an denen das Wort nicht vorkommt, völlig inaktiv bleiben.

Ebenfalls vernachlässigt wird in tiefen neuronalen Netzwerken die Tatsache, dass verschiedene Arten von Neuronen in der Großhirnrinde vorkommen. Zwei wichtige Typen sind die bedornte Pyramidenzelle, die in erster Linie eine exzitatorische Charakteristik aufweist, und die nicht bedornte Sternzelle, die eine hemmende aufweist. Die inhibitorischen Neuronen sind besonders, weil sie es ermöglichen, negative Rückkopplungsschleifen aufzubauen. Solche Rückkopplungsschleifen finden sich normalerweise nicht in einem tiefen neuronalen Netzwerk, da sie einen inneren Zustand in das Netzwerk einbringen. Betrachten wir das folgende Netzwerk mit einem hemmenden Neuron und zwei exzitatorischen Neuronen, die zwei verschiedene Bedeutungen des Wortes “August” darstellen.

Beide Bedeutungen schließen sich gegenseitig aus, so dass das Netzwerk nun zwei stabile Zustände aufweist. Diese Zustände können von weiteren Eingangssynapsen der beiden exzitatorischen Neuronen abhängen. Wenn beispielsweise das nächste Wort nach dem Wort ‘August’ ein potenzieller Nachname ist, könnte eine entsprechende Eingabesynapse für das Entitätsneuron August-(Vorname) das Gewicht dieses Zustands erhöhen. Es ist nun wahrscheinlicher, dass das Wort “August” als Vorname und nicht als Monat eingestuft wird. Aber bedenken Sie, dass beide Zustände evaluiert werden müssen. In größeren Netzwerken können viele Neuronen durch negative oder positive Rückkopplungsschleifen verbunden sein, was zu einer großen Anzahl von stabilen Zuständen im Netzwerk führen kann.

Aus diesem Grund ist ein effizienter Optimierungsprozess erforderlich, der den besten Zustand in Bezug auf eine Zielfunktion ermittelt. Diese Zielfunktion könnte darin bestehen, die Notwendigkeit der Unterdrückung stark aktivierter Neuronen zu minimieren. Diese Zustände haben jedoch den enormen Vorteil, dass sie es erlauben, unterschiedliche Interpretationen eines bestimmten Textes zu berücksichtigen. Es ist eine Art Denkprozess, in dem verschiedene Interpretationen bewertet werden und die jeweils stärkste als Ergebnis geliefert wird. Glücklicherweise lässt sich die Suche nach einem optimalen Lösungszustand recht gut optimieren.

Der Grund, warum wir in diesen Rückkopplungsschleifen hemmende Neuronen benötigen, ist, dass sonst alle gegenseitig unterdrückenden Neuronen vollständig miteinander verbunden sein müssten. Das würde zu einer quadratisch zunehmenden Anzahl von Synapsen führen.

Durch die negativen Rückkopplungsschleifen, d.h. durch einfaches Verbinden einer negativen Synapse mit einem ihrer Vorläuferneuronen, haben wir plötzlich den Bereich der nichtmonotonen Logik betreten. Die nichtmonotone Logik ist ein Teilgebiet der formalen Logik, in dem Implikationen nicht nur zu einem Modell hinzugefügt, sondern auch entfernt werden. Es wird davon ausgegangen, dass eine nichtmonotone Logik erforderlich ist, um Schlussfolgerungen für viele Common Sense Aufgaben ziehen zu können. Eines der Hauptprobleme der nichtmonotonen Logik ist, dass sie oft nicht entscheiden kann, welche Schlussfolgerungen sie ziehen soll und welche eben nicht. Einige skeptische oder leichtgläubige Schlussfolgerungen sollten nur gezogen werden, wenn keine anderen Schlussfolgerungen wahrscheinlicher sind. Hier kommt die gewichtete Natur neuronaler Netze zum Tragen. In neuronalen Netzen können nämlich eher wahrscheinliche Zustände weniger wahrscheinliche Zustände unterdrücken.

Beispielimplementierung innerhalb des Aika-Frameworks

An dieser Stelle möchte ich noch einmal das Beispielneuron für das Wort ‘der’ vom Anfang aufgreifen. Das Wort-Neuron besteht aus drei Eingabesynapsen, die sich jeweils auf die einzelnen Buchstaben des Wortes beziehen. Über die Relationen werden die Eingabesynapsen nun zueinander in eine bestimmte Beziehung gesetzt, so dass das Wort ‘der’ nur erkannt wird, wenn alle Buchstaben in der korrekten Reihenfolge auftreten.
Als Aktivierungsfunktion des Neurons wird hier der im negativen Bereich abgeschnittene (rectified) hyperbolische Tangens verwendet. Dieser hat gerade bei einem UND-verknüpfenden Neuron den Vorteil, dass er selbst bei sehr großen Werten der gewichteten Summe auf den Wert 1 begrenzt ist. Alternativ kann auch die ReLU-Funktion (Rectified Linear Unit) verwendet werden. Diese eignet sich insbesondere für ODER-verknüpfende Neuronen, da sie die Eingabewerte unverzerrt weiterleitet.
Im Gegensatz zu herkömmlichen neuronalen Netzen gibt es hier mehrere Bias Werte, einen für das gesamte Neuron (in diesem Fall auf 5.0 gesetzt) und einen für jede Synapse. Intern werden diese Werte zu einem gemeinsamen Bias aufsummiert. Es ist schon klar, dass dieses Aufteilen des Bias nicht wirklich gut zu Lernregeln wie der Delta-Rule und dem Backpropagation passt, allerdings eignen sich diese Lernverfahren eh nur sehr begrenzt für diese Art von neuronalem Netzwerk. Als Lernverfahren kommen eher von den natürlichen Mechanismen Langzeit-Potenzierung und Langzeit-Depression inspirierte Ansätze in Betracht.

Neuron buchstabeD = m.createNeuron("B-d");
	Neuron buchstabeE = m.createNeuron("B-e");
	Neuron buchstabeR = m.createNeuron("B-r");

	Neuron wortDer = Neuron.init(
                m.createNeuron("W-der"),
                5.0,
                RECTIFIED_HYPERBOLIC_TANGENT,
                EXCITATORY,
                new Synapse.Builder()
                        .setSynapseId(0)
                        .setNeuron(buchstabeD)
                        .setWeight(10.0)
                        .setBias(-10.0)
                        .setRecurrent(false),
                new Synapse.Builder()
                        .setSynapseId(1)
                        .setNeuron(buchstabeE)
                        .setWeight(10.0)
                        .setBias(-10.0)
                        .setRecurrent(false),
                new Synapse.Builder()
                        .setSynapseId(2)
                        .setNeuron(buchstabeR)
                        .setWeight(10.0)
                        .setBias(-10.0)
                        .setRecurrent(false),
                new Relation.Builder()
                        .setFrom(0)
                        .setTo(1)
                        .setRelation(new Equals(END, BEGIN)),
                new Relation.Builder()
                        .setFrom(1)
                        .setTo(2)
                        .setRelation(new Equals(END, BEGIN)),
                new Relation.Builder()
                        .setFrom(0)
                        .setTo(OUTPUT)
                        .setRelation(new Equals(BEGIN, BEGIN)),
                new Relation.Builder()
                        .setFrom(2)
                        .setTo(OUTPUT)
                        .setRelation(new Equals(END, END))
	);

Fazit

Obwohl tiefe neuronale Netze bereits einen langen Weg zurückgelegt haben und mittlerweile beeindruckende Ergebnisse liefern, kann es sich doch lohnen, einen weiteren Blick auf das Original, das menschliche Gehirn und seine Schaltkreise zu werfen. Wenn eine so inhärent komplexe Struktur wie das menschliche Gehirn als Blaupause für ein neuronales Modell verwendet werden soll, müssen vereinfachende Annahmen getroffen werden. Allerdings ist bei diesem Prozess Vorsicht geboten, da sonst wichtige Aspekte des Originals verloren gehen können.

Referenzen

  1. Der Aika-Algorithm
    Lukas Molzberger
  2. Neuroscience: Exploring the Brain
    Mark F. Bear, Barry W. Connors, Michael A. Paradiso
  3. Neural-Symbolic Learning and Reasoning: A Survey and Interpretation
    Tarek R. Besold, Artur d’Avila Garcez, Sebastian Bader; Howard Bowman, Pedro Domingos, Pascal Hitzler, Kai-Uwe Kuehnberger, Luis C. Lamb, ; Daniel Lowd, Priscila Machado Vieira Lima, Leo de Penning, Gadi Pinkas, Hoifung Poon, Gerson Zaverucha
  4. Deep Learning: A Critical Appraisal
    Gary Marcus
  5. Nonmonotonic Reasoning
    Gerhard Brewka, Ilkka Niemela, Mirosław Truszczynski

Dem Wettbewerb voraus mit Künstlicher Intelligenz

Was KI schon heute kann und was bis 2020 auf deutsche Unternehmen zukommt

Künstliche Intelligenz ist für die Menschheit wichtiger als die Erfindung von Elektrizität oder die Beherrschung des Feuers – davon sind der Google-CEO Sundar Pichai und viele weitere Experten überzeugt. Doch was steckt wirklich dahinter? Welche Anwendungsfälle funktionieren schon heute? Und was kommt bis 2020 auf deutsche Unternehmen zu?

Big Data war das Buzzword der vergangenen Jahre und war – trotz mittlerweile etablierter Tools wie SAP Hana, Hadoop und weitere – betriebswirtschaftlich zum Scheitern verurteilt. Denn Big Data ist ein passiver Begriff und löst keinesfalls alltägliche Probleme in den Unternehmen.

Dabei wird völlig verkannt, dass Big Data die Vorstufe für den eigentlichen Problemlöser ist, der gemeinhin als Künstliche Intelligenz (KI) bezeichnet wird. KI ist ein Buzzword, dessen langfristiger Erfolg und Aktivismus selbst von skeptischen Experten nicht infrage gestellt wird. Daten-Ingenieure sprechen im Kontext von KI hier aktuell bevorzugt von Deep Learning; wissenschaftlich betrachtet ein Teilgebiet der KI.

Was KI schon heute kann

Deep Learning Algorithmen laufen bereits heute in Nischen-Anwendungen produktiv, beispielsweise im Bereich der Chatbots oder bei der Suche nach Informationen. Sie übernehmen ferner das Rating für die Kreditwürdigkeit und sperren Finanzkonten, wenn sie erlernte Betrugsmuster erkennen. Im Handel findet Deep Learning bereits die optimalen Einkaufsparameter sowie den besten Verkaufspreis.

Getrieben wird Deep Learning insbesondere durch prestigeträchtige Vorhaben wie das autonome Fahren, dabei werden die vielfältigen Anwendungen im Geschäftsbereich oft vergessen.

Die Grenzen von Deep Learning

Und Big Data ist das Futter für Deep Learning. Daraus resultiert auch die Grenze des Möglichen, denn für strategische Entscheidungen eignet sich KI bestenfalls für das Vorbereitung einer Datengrundlage, aus denen menschliche Entscheider eine Strategie entwickeln. KI wird zumindest in dieser Dekade nur auf operativer Ebene Entscheidungen treffen können, insbesondere in der Disposition, Instandhaltung, Logistik und im Handel auch im Vertrieb – anfänglich jeweils vor allem als Assistenzsystem für die Menschen.

Genau wie das autonome Fahren mit Assistenzsystemen beginnt, wird auch im Unternehmen immer mehr die KI das Steuer übernehmen.

Was sich hinsichtlich KI bis 2020 tun wird

Derzeit stehen wir erst am Anfang der Möglichkeiten, die Künstliche Intelligenz uns bietet. Das Markt-Wachstum für KI-Systeme und auch die Anwendungen erfolgt exponentiell. Entsprechend wird sich auch die Arbeitsweise für KI-Entwickler ändern müssen. Mit etablierten Deep Learning Frameworks, die mehrheitlich aus dem Silicon Valley stammen, zeichnet sich der Trend ab, der für die Zukunft noch weiter professionalisiert werden wird: KI-Frameworks werden Enterprise-fähig und Distributionen dieser Plattformen werden es ermöglichen, dass KI-Anwendungen als universelle Kernintelligenz für das operative Geschäft für fast alle Unternehmen binnen weniger Monate implementierbar sein werden.

Wir können bis 2020 also mit einer Alexa oder Cortana für das Unternehmen rechnen, die Unternehmensprozesse optimiert, Risiken berichtet und alle alltäglichen Fragen des Geschäftsführers beantwortet – in menschlich-verbal formulierten Sätzen.

Der Einsatz von Künstlicher Intelligenz zur Auswertung von Geschäfts- oder Maschinendaten ist auch das Leit-Thema der zweitägigen Data Leader Days 2018 in Berlin. Am 14. November 2018 sprechen renommierte Data Leader über Anwendungsfälle, Erfolge und Chancen mit Geschäfts- und Finanzdaten. Der 15. November 2018 konzentriert sich auf Automotive- und Maschinendaten mit hochrangigen Anwendern aus der produzierenden Industrie und der Automobilzuliefererindustrie. Seien Sie dabei und nutzen Sie die Chance, sich mit führenden KI-Anwendern auszutauschen.

Kiano – visuelle Exploration mit Deep Learning

Kiano – eine iOS-App zur visuellen Exploration und Suche der eigenen Fotos.

Menschen haben kein Problem, komplexe Bilder zu verstehen, es fällt ihnen aber schwer, gezielt Bilder in großen Bildersammlungen (wieder) zu finden. Da die Anzahl von Bildern, insbesondere auch auf Smartphones zusehends zunimmt – mehrere tausend Bilder pro Gerät sind keine Seltenheit, wird die Suche nach bestimmten Bildern immer schwieriger. Ist bei einem gesuchten Foto dessen Aufnahmedatum unbekannt, so kann es sehr lange dauern, bis es gefunden ist. Werden dem Nutzer zu viele Bilder auf einmal präsentiert, so geht der Überblick schnell verloren. Aus diesem Grund besteht eine typische Bildsuche heutzutage meist im endlosen Scrollen über viele Bildschirmseiten mit langen Bilderlisten.

Dieser Artikel stellt das Prinzip und die Funktionsweise der neuen iOS-App “Kiano” vor, die es Nutzern ermöglicht, alle ihre Bilder explorativ mittels visuellem Browsen zu erkunden. Der Name “Kiano” steht hierbei für “Keep Images Arranged & Neatly Organized”. Mit der App ist es außerdem möglich, zu einem Beispielbild gezielt nach ähnlichen Fotos auf dem Gerät zu suchen.

Um Bilder visuell durchsuch- und sortierbar zu machen, werden sogenannte Merkmalsvektoren bzw. Featurevektoren verwendet, die Aussehen und Inhalt von Bildern kompakt repräsentieren können. Zu einem Bild lassen sich ähnliche Bilder finden, indem die Bilder bestimmt werden, deren Featurevektoren eine geringe Distanz zum Featurevektor des Suchbildes haben.

Werden Bilder zweidimensional so angeordnet, dass die Featurevektoren benachbarter Bilder sehr ähnlich sind, so erhält man eine visuell sortierte Bilderlandkarte. Bei einer visuell sortierten Anordnung der Bilder fällt es Menschen deutlich leichter, mehr Bilder gleichzeitig zu erfassen, als dies im unsortierten Fall möglich wäre. Durch die graduelle Veränderung der Bildinhalte wird es möglich, über diese Karte visuell zu navigieren.

Generierung von Featurevektoren zur Bildbeschreibung

Convolutional Neural Networks (CNNs) sind nicht nur in der Lage, Bilder mit hoher Genauigkeit zu klassifizieren, d.h. zu erkennen, welches Objekt – entsprechend einer Menge von gelernten Objektkategorien auf einem Bild zu sehen ist, die Aktivierungen der Netzwerkschichten lassen sich auch als universelle Featurevektoren zur Bildbeschreibung nutzen. Während die vorderen Netzwerkschichten von CNNs einfache visuelle Bildmerkmale wie Farben und einfache Muster detektieren, repräsentieren die Ausgangsschichten des Netzwerks die semantischen Informationen bezüglich der gelernten Objektkategorien. Die Zwischenschichten des Netzwerks sind weniger von den Objektkategorien abhängig und können somit als generelle abstrakte Repräsentationen des Inhalts der Bilder angesehen werden. Hierbei ist es möglich, bereits fertig trainierte Klassifikationsnetzwerke für die Featureextraktion wiederzuverwenden. In der Visual Computing Gruppe der HTW Berlin wurden umfangreiche Evaluierungen durchgeführt, um zu bestimmen, welche Netzwerkschichten von welchen CNNs mit welchen zusätzlichen Transformationen zu verwenden sind, um aus Netzwerkaktivierungen Feature-Vektoren zu erzeugen, die sehr gut für die Suche nach beliebigen Bildern geeignet sind.

Beste Ergebnisse hinsichtlich der Suchgenauigkeit (der Mean Average Precision) wurden mit einem Deep Residual Learning Network (ResNet-200) erzielt. Die 2048 Aktivierungen vor dem vollvernetzten letzten Layer werden als initiale Featurevektoren verwendet, wobei sich die Suchgenauigkeit durch eine L1-Normierung, gefolgt von einer PCA-Transformation (Principal Component Analysis) sogar noch verbessern lässt. Hierdurch ist es möglich, die Featurevektoren auf eine Größe von nur 64 Bytes zu reduzieren. Leider ist die rechnerische Komplexität der Bestimmung dieser hochwertigen Featurevektoren zu groß, um sie auf mobilen Geräten verwenden zu können. Eine gute Alternative stellen die Mobilenets dar, die sich durch eine erheblich reduzierte Komplexität auszeichnen. Als Kompromiss zwischen Klassifikationsgenauigkeit und Komplexität wurde für die Kiano-App das Mobilenet_v2_0.5_128 verwendet. Die mit diesem Netzwerk bestimmten Featurevektoren wurden ebenfalls auf eine Größe von 64 Bytes reduziert.

Die aus CNNs erzeugten Featurevektoren sind gut für die Suche nach Bildern mit ähnlichem Inhalt geeignet. Für die Suche nach Bilder, mit ähnlichen visuellen Eigenschaften (z.B. die auftretenden Farben oder deren örtlichen Verteilung) sind diese Featurevektoren nur bedingt geeignet. Hierfür eignen sich klassische sogenannte “Low-Level”-Featurevektoren besser. Da für eine ansprechende und leicht erfassbare Bildsortierung auch eine Übereinstimmung dieser visuellen Bildattribute wichtig ist, kommt bei Kiano ein weiterer Featurevektor zum Einsatz, mit dem sich diese “primitiven” visuellen Bildattribute beschreiben lassen. Dieser Featurevektor hat eine Größe von 50 Bytes. Bei Kiano kann der Nutzer in den Einstellungen wählen, ob bei der visuellen Sortierung und Bildsuche größerer Wert auf den Bildinhalt oder die visuelle Erscheinung eines Bildes gelegt werden soll.

Visuelle Bildsortierung

Werden Bilder entsprechend ihrer Ähnlichkeiten sortiert angeordnet, so können mehrere hundert Bilder gleichzeitig wahrgenommen bzw. erfasst werden. Dies hilft, Regionen interessanter Bildern leichter zu erkennen und gesuchte Bilder schneller zu entdecken. Die Möglichkeit, viele Bilder gleichzeitig präsentieren zu können, ist neben Bildverwaltungssystemen besonders auch für E-Commerce-Anwendungen interessant.

Herkömmliche Dimensionsreduktionsverfahren, die hochdimensionale Featurevektoren auf zwei Dimensionen projizieren, sind für die Bildsortierung ungeeignet, da sie die Bilder so anordnen, dass Lücken und Bildüberlappungen entstehen. Sollen Bilder sortiert auf einem dichten regelmäßigen 2D-Raster angeordnet werden, kommen als Verfahren nur selbstorganisierende Karten oder selbstsortierende Karten in Frage.

Eine selbstorganisierende Karte (Self Organizing Map / SOM) ist ein künstliches neuronales Netzwerk, das durch unbeaufsichtigtes Lernen trainiert wird, um eine niedrigdimensionale, diskrete Darstellung der Daten des Eingangsraums als sogenannte Karte (Map) zu erzeugen. Im Gegensatz zu anderen künstlichen neuronalen Netzen, werden SOMs nicht durch Fehlerkorrektur, sondern durch ein Wettbewerbsverfahren trainiert, wobei eine Nachbarschaftsfunktion verwendet wird, um die lokalen Ähnlichkeiten der Eingangsdaten zu bewahren.

Eine selbstorganisierende Karte besteht aus Knoten, denen einerseits ein Gewichtsvektor der gleichen Dimensionalität wie die Eingangsdaten und anderseits eine Position auf der 2D-Karte zugeordnet sind. Die SOM-Knoten sind als zweidimensionales Rechteckgitter angeordnet. Das vom der SOM erzeugte Mapping ist diskret, da jeder Eingangsvektor einem bestimmten Knoten zugeordnet wird. Zu Beginn werden die Gewichtsvektoren aller Knoten mit Zufallswerten initialisiert. Wird ein hochdimensionaler Eingangsvektor in das Netz eingespeist, so wird dessen euklidischer Abstand zu allen Gewichtsvektoren berechnet. Der Knoten, dessen Gewichtsvektor dem Eingangsvektor am ähnlichsten ist, wird als Best Matching Unit (BMU) bezeichnet. Die Gewichte des BMU und seiner auf der Karte örtlich benachbarten Knoten werden an den Eingangsvektor angepasst. Dieser Vorgang wird iterativ wiederholt. Das Ausmaß dieser Anpassung nimmt im Laufe der Iterationen und der örtlichen Entfernung zum BMU-Knoten ab.

Um SOMs an die Bildsortierung anzupassen, sind zwei Modifikationen notwendig. Jeder Knoten darf nicht von mehr als einem Featurevektor (der ein Bild repräsentiert) ausgewählt werden. Eine Mehrfachauswahl würde zu einer Überlappung der Bilder führen. Aus diesem Grund muss die Anzahl der SOM-Knoten mindestens so groß wie die Anzahl der Bilder sein. Eine sinnvolle Erweiterung einer SOM verwendet ein Gitter, bei dem gegenüberliegende Kanten verbunden sind. Werden diese Torus-förmigen Karten für große SOMs verwendet, kann der Eindruck einer endlosen Karte erzeugt werden, wie es in Kiano umgesetzt ist. Ein Problem der SOMs ist ihre hohe rechnerische Komplexität, die quadratisch mit der Anzahl der zu sortierenden Bilder wächst, wodurch die maximale Anzahl an zu sortierenden Bildern beschränkt wird. Eine Lösung stellt eine selbstsortierende Karte (Self Sorting Map / SSM) dar, deren Komplexität nur n log(n) beträgt.

Selbstsortierende Karten beginnen mit einer zufälligen Positionierung der Bilder auf der Karte. Diese Karte wird dann in 4×4-Blöcke aufgeteilt und für jeden Block wird der Mittelwert der zugehörigen Featurevektoren bestimmt. Als nächstes werden aus 2×2 benachbarten Blöcken jeweils vier korrespondierende Bild-Featurevektoren untersucht und ihre zugehörigen Bilder gegebenenfalls getauscht. Aus den 4! = 24 Anordnungsmöglichkeiten wird diejenige gewählt, die die Summe der quadrierten Differenzen zwischen den jeweiligen Featurevektoren und den Featuremittelwerten der Blöcke minimiert. Nach mehreren Iterationen wird jeder Block in vier kleinere Blöcke halber Breite und Höhe aufgeteilt und wiederum in der beschriebenen Weise überprüft, wie die Bildpositionen dieser kleineren Blöcke getauscht werden sollten. Dieser Vorgang wird solange wiederholt, bis die Blockgröße auf 1×1 Bild reduziert ist.

In der Visual-Computing Gruppe der HTW Berlin wurde untersucht, wie die Sortierqualität des SSM-Algorithmus verbessert werden kann. Anstatt die Mittelwerte der Featurevektoren als konstanten Durchschnittsvektor für den gesamten Block zu berechnen, verwenden wir gleitende Tiefpassfilter, die sich effizient mittels Integralbildern berechnen lassen. Hierdurch entstehen weichere Übergänge auf der sortierten Bilderkarte. Weiterhin wird die Blockgröße nicht für mehrere Iterationen konstant gehalten, sondern kontinuierlich zusammen mit dem Radius des Filterkernels reduziert. Durch die Verwendung von optimierten Algorithmen von “Linear Assignment” Algorithmen wird es weiterhin möglich, den optimalen Positionstausch nicht nur für jeweils vier Featurevektoren bzw. Bildern sondern für eine deutlich größere Anzahl zu überprüfen. All diese Maßnahmen führen zu einer deutlich verbesserten Sortierungsqualität bei gleicher Komplexität.

Effiziente Umsetzung für iOS

Wie so oft, liegen die softwaretechnischen Herausforderungen an ganz anderen Stellen, als man zunächst vermutet. Für eine effiziente Implementierung der zuvor beschriebenen Algorithmen, insbesondere der SSM, stellte es sich heraus, dass die Programmiersprache Swift, in der iOS Apps normaler Weise entwickelt werden, erheblich mehr Rechenzeit benötigt, als eine Umsetzung in der Sprache C. Im Zuge der stetigen Weiterentwicklung von Swift und dessen Compiler mag sich die Lücke zu C zwar immer weiter schließen, zum Zeitpunkt der Umsetzung war die Implementierung in C aber um einen Faktor vier schneller als in Swift. Hierbei liegt die Vermutung nahe, dass der Zugriff auf und das Umsortieren von Featurevektoren als native C-Arrays deutlich effektiver passiert, als bei der Verwendung von Swift-Arrays. Da Swift-Arrays Value-Type sind, kommt es in Swift vermutlich zu unnötigen Kopieroperationen der Fließkommazahlen in den einzelnen Featurevektoren.

Die Berechnung des Mobilenet-Anteils der Featurevektoren konnte sehr komfortabel mit Apples CoreML Machine Learning Framework umgesetzt werden. Hierbei ist zu beachten, dass es sich wie oben beschrieben, nicht um eine Klassifikation handelt, sondern um das Abgreifen der Aktivierungen einer tieferen Schicht. Für Klassifikationen findet man praktisch sofort nutzbare Beispiele, für den Zugriff auf die Aktivierungen waren jedoch Anpassungen notwendig, die bei der Portierung eines vortrainierten Mobilenet nach CoreML vorgenommen wurden. Das stellte sich als erheblich einfacher heraus, als der Versuch, auf die tieferen Schichten eines Klassifizierungsnetzes in CoreML zuzugreifen.

Für die Verwaltung der Bilder, ihrer Featurevektoren und ihrer Position in der sortieren Karte wird in Kiano eine eigene Datenstruktur verwendet, die es zu persistieren gilt. Es ist dem Nutzer ja nicht zuzumuten, bei jedem Start der App auf die Berechnung aller Featurevektoren zu warten. Die Strategie ist es hierbei, bereits bekannte Bilder zu identifizieren und deren Features nur dann neu zu berechnen, falls sich das Bild verändert hat. Die über Appels Photos Framework zur Verfügung gestellten local Identifier identifizieren dabei die Bilder. Veränderungen werden über das Modifikationsdatum eines Bildes detektiert. Die größte Herausforderung ist hierbei das Zeichnen der Karte. Die Benutzerinteraktion soll schnell und flüssig erscheinen, auf Animationen wie das Nachlaufen der Karte beim Verschieben möchte man nicht verzichten. Die Umsetzung geschieht hierbei nicht in OpenGL ES, welches ab iOS 12 ohnehin als deprecated bezeichnet wird. Auf der anderen Seite wird aber auch nicht der „Standardweg“ des Überschreibens der draw-Methode einer Ableitung von UIView gewählt. Letztes führt bekanntlich zu Performanceeinbußen. Insbesondere deshalb, weil das System sehr oft Backing-Images der Ansichten erstellt. Um die Kontrolle über das Neuzeichnen zu behalten, wird in Kiano ein eigenes Backing-Image implementiert, das auf Ebene des Core Animation Frameworks dem View als Layer zugweisen wird. Diesem Layer kann dann sehr komfortabel eine 3D-Transformation zugewiesen werden und man profitiert von der GPU-Beschleunigung, ohne OpenGL ES direkt verwenden zu müssen.

 

Trotz der Verwendung eines Core Animation Layers ist das Zeichnen der Karte immer noch sehr zeitaufwendig. Das liegt an der Tatsache, dass je nach Zoomstufe tausende von Bildern darzustellen sind, die alle über das Photos Framework angefordert werden müssen. Das Nadelöhr ist dann weniger das Zeichnen, als die Zeit, die vergeht, bis einem das Bild zur Verfügung gestellt wird. Diese Vorgänge sind praktisch alle nebenläufig. Zur Erinnerung: Ein Foto kann in der iCloud liegen und zum Zeitpunkt der Anfrage noch gar nicht (oder noch nicht in geeigneter Auflösung) heruntergeladen sein. Netzwerkbedingt gibt es keine Vorhersage, wann oder ob überhaupt das Bild zur Verfügung gestellt wird. In Kiano werden zum einen Bilder in sehr kleiner Auflösung gecached, zum anderen wird beim Navigieren auf der Karte im Hintergrund ein neues Kartenteil als Backing-Image vorbereitet, das dem Nutzer nach Fertigstellung angezeigt wird. Die vorberechneten Kartenteile sind dabei drei Mal so breit und drei Mal so hoch wie das Display, so dass man diese „Hintergrundaktivität“ beim Verschieben der Karte in der Regel nicht bemerkt. Nur wenn die Bewegung zu schnell wird oder die Bilder zu langsam „geliefert“ werden, erkennt man schwarze Flächen, die sich dann verzögert mit Bildern füllen.

Vergleichbares passiert beim Hineinzoomen in die Karte. Der Nutzer sieht zunächst eine vergrößerte und damit unscharfe Version des aktuellen Kartenteils, während im Hintergrund ein Kartenteil in höherer Auflösung und mit weniger Bildern vorbereitet wird. In der Summe geht Kiano hier einen Kompromiss ein. Die Pixeldichte der Geräte würde eine schärfere Darstellung der Bilder auf der Karte erlauben. Allerdings müssten dann die Bilder in so höher Auflösung angefordert werden, dass eine flüssige Kartennavigation nicht mehr möglich wäre. So sieht der Nutzer in der Regel eine Karte mit Bildern in halber Auflösung gemessen an den physikalischen Pixeln seines Displays.

Ein anfangs unterschätzter Arbeitsaufwand bei der Umsetzung von Kiano liegt darin begründet, dass sich die Photo Library des Nutzers jederzeit während der Benutzung der App verändern kann. Bilder können durch Synchronisationen mit der iCloud oder mit iTunes verschwinden, sich in andere Alben bewegen, oder neue können auftauchen. Der Nutzer kann Bildschirmfotos machen. Das Photos Framework stellt komfortable Benachrichtigungen für solche Events zur Verfügung. Der Implementierung obliegt es dabei aber herauszubekommen, ob die Karte neu zu sortieren ist oder nicht, ob das gerade anzeigte Bild überhaupt noch existiert und was zu tun ist, wenn es verschwunden ist.

Zusammenfassend kann man feststellen, dass natürlich die Umsetzung der Algorithmen und die Darstellung dessen auf einer Karte zu den spannendsten Teilen der Arbeiten an Kiano zählen, dass aber der Umgang mit einer sich dynamisch ändernden Datenbasis nicht unterschätzt werden sollte.

Autoren

Prof. Dr. Klaus JungProf. Dr. Klaus Jung studierte Physik an der TU Berlin, wo er im Bereich der Mathematischen Physik promovierte. Bis 2008 arbeitete er als Leiter F&E bei der Firma LuraTech im Bereich der Dokumentenverarbeitung und Langzeitarchivierung. In der JPEG-Gruppe leitete er die deutsche Delegation bei der Standardisierung von JPEG2000. Seit 2008 ist er Professor für Medieninformatik an der HTW Berlin mit dem Schwerpunkt „Visual Computing“.

Prof. Dr. Kai Uwe Barthel

Prof. Dr. Kai Uwe Barthel studierte Elektrotechnik an der TU Berlin, bevor er Assistent am Institut für Nachrichtentechnik wurde und im Bereich Bildkompression promovierte. Seit 2001 ist er Professor der HTW Berlin. Hauptforschungsbereiche sind visuelle Bildsuche und automatisches Bildverstehen. 2009 gründete er die pixolution GmbH www.pixolution.de, ein Unternehmen, das Technologien für die visuelle Bildsuche anbietet.

I. Einführung in TensorFlow: Einleitung und Inhalt

 

 

 

1. Einleitung und Inhalt

Früher oder später wird jede Person, welche sich mit den Themen Daten, KI, Machine Learning und Deep Learning auseinander setzt, mit TensorFlow in Kontakt geraten. Für diejenigen wird der Zeitpunkt kommen, an dem sie sich damit befassen möchten/müssen/wollen.

Und genau für euch ist diese Artikelserie ausgelegt. Gemeinsam wollen wir die ersten Schritte in die Welt von Deep Learning und neuronalen Netzen mit TensorFlow wagen und unsere eigenen Beispiele realisieren. Dabei möchten wir uns auf das Wesentlichste konzentrieren und die Thematik Schritt für Schritt in 4 Artikeln angehen, welche wie folgt aufgebaut sind:

  1. In diesem und damit ersten Artikel wollen wir uns erst einmal darauf konzentrieren, was TensorFlow ist und wofür es genutzt wird.
  2. Im zweiten Artikel befassen wir uns mit der grundlegenden Handhabung von TensorFlow und gehen den theoretischen Ablauf durch.
  3. Im dritten Artikel wollen wir dann näher auf die Praxis eingehen und ein Perzeptron – ein einfaches künstliches Neuron – entwickeln. Dabei werden wir die Grundlagen anwenden, die wir im zweiten Artikel erschlossen haben.

Wenn ihr die Praxisbeispiele in den Artikeln 3 & 4 aktiv mit bestreiten wollt, dann ist es vorteilhaft, wenn ihr bereits mit Python gearbeitet habt und die Grundlagen dieser Programmiersprache beherrscht. Jedoch werden alle Handlungen und alle Zeilen sehr genau kommentiert, so dass es leicht verständlich bleibt.

Neben den Programmierfähigkeiten ist es hilfreich, wenn ihr euch mit der Funktionsweise von neuronalen Netzen auskennt, da wir im späteren Verlauf diese modellieren wollen. Jedoch gehen wir vor der Programmierung  kurz auf die Theorie ein und werden das Wichtigste nochmal erwähnen.

Zu guter Letzt benötigen wir für unseren Theorie-Teil ein Mindestmaß an Mathematik um die Grundlagen der neuronalen Netze zu verstehen. Aber auch hier sind die Anforderungen nicht hoch und wir sind vollkommen gut  damit bedient, wenn wir unser Wissen aus dem Abitur noch nicht ganz vergessen haben.

2. Ziele dieser Artikelserie

Diese Artikelserie ist speziell an Personen gerichtet, welche einen ersten Schritt in die große und interessante Welt von Deep Learning wagen möchten, die am Anfang nicht mit zu vielen Details überschüttet werden wollen und lieber an kleine und verdaulichen Häppchen testen wollen, ob dies das Richtige für sie ist. Unser Ziel wird sein, dass wir ein Grundverständnis für TensorFlow entwickeln und die Grundlagen zur Nutzung beherrschen, um mit diesen erste Modelle zu erstellen.

3. Was ist TensorFlow?

Viele von euch haben bestimmt von TensorFlow in Verbindung mit Deep Learning bzw. neuronalen Netzen gehört. Allgemein betrachtet ist TensorFlow ein Software-Framework zur numerischen Berechnung von Datenflussgraphen mit dem Fokus maschinelle Lernalgorithmen zu beschreiben. Kurz gesagt: Es ist ein Tool um Deep Learning Modelle zu realisieren.

Zusatz: Python ist eine Programmiersprache in der wir viele Paradigmen (objektorientiert, funktional, etc.) verwenden können. Viele Tutorials im Bereich Data Science nutzen das imperative Paradigma; wir befehlen Python also Was gemacht und Wie es ausgeführt werden soll. TensorFlow ist dahingehend anders, da es eine datenstrom-orientierte Programmierung nutzt. In dieser Form der Programmierung wird ein Datenfluss-Berechnungsgraph (kurz: Datenflussgraph) erzeugt, welcher durch die Zusammensetzung von Kanten und Knoten charakterisiert wird. Die Kanten enthalten Daten und können diese an Knoten weiterleiten. In den Knoten werden Operationen wie z. B. Addition, Multiplikation oder auch verschiedenste Variationen von Funktionen ausgeführt. Bekannte Programme mit datenstrom-orientierten Paradigmen sind Simulink, LabView oder Knime.

Für das Verständnis von TensorFlow verrät uns der Name bereits erste Informationen über die Funktionsweise. In neuronalen Netzen bzw. in Deep-Learning-Netzen können Eingangssignale, Gewichte oder Bias verschiedene Erscheinungsformen haben; von Skalaren, zweidimensionalen Tabellen bis hin zu mehrdimensionalen Matrizen kann alles dabei sein. Diese Erscheinungsformen werden in Deep-Learning-Anwendungen allgemein als Tensoren bezeichnet, welche durch ein Datenflussgraph ‘fließen’. [1]

Abb.1 Namensbedeutung von TensorFlow: Links ein Tensor in Form einer zweidimensionalen Matrix; Rechts ein Beispiel für einen Datenflussgraph

 

4. Warum TensorFlow?

Wer in die Welt der KI einsteigen und Deep Learning lernen will, hat heutzutage die Qual der Wahl. Neben TensorFlow gibt es eine Vielzahl von Alternativen wie Keras, Theano, Pytorch, Torch, Caffe, Caffe2, Mxnet und vielen anderen. Warum also TensorFlow?

Das wohl wichtigste Argument besteht darin, dass TensorFlow eine der besten Dokumentationen hat. Google – Herausgeber von TensorFlow – hat TensorFlow stets mit neuen Updates beliefert. Sicherlich aus genau diesen Gründen ist es das meistgenutzte Framework. Zumindest erscheint es so, wenn wir die Stars&Forks auf Github betrachten. [3] Das hat zur Folge, dass neben der offiziellen Dokumentation auch viele Tutorials und Bücher existieren, was die Doku nur noch besser macht.

Natürlich haben alle Frameworks ihre Vor- und Nachteile. Gerade Pytorch von Facebook erfreut sich derzeit großer Beliebtheit, da die Berechnungsgraphen dynamischer Natur sind und damit einige Vorteile gegenüber TensorFlow aufweisen.[2] Auch Keras wäre für den Einstieg eine gute Alternative, da diese Bibliothek großen Wert auf eine einsteiger- und nutzerfreundliche Handhabung legt. Keras kann man sich als eine Art Bedienoberfläche über unsere Frameworks vorstellen, welche vorgefertigte neuronale Netze bereitstellt und uns einen Großteil der Arbeit abnimmt.

Möchte man jedoch ein detailreiches und individuelles Modell bauen und die Theorie dahinter nachvollziehen können, dann ist TensorFlow der beste Einstieg in Deep Learning! Es wird einige Schwierigkeiten bei der Gestaltung unserer Modelle geben, aber durch die gute Dokumentation, der großen Community und der Vielzahl an Beispielen, werden wir gewiss eine Lösung für aufkommende Problemstellungen finden.

 

Abb.2 Beliebtheit von DL-Frameworks basierend auf Github Stars & Forks (10.06.2018)

 

5. Zusammenfassung und Ausblick

Fassen wir das Ganze nochmal zusammen: TensorFlow ist ein Framework, welches auf der datenstrom-orientierten Programmierung basiert und speziell für die Implementierung von Machine/Deep Learning-Anwendungen ausgelegt ist. Dabei fließen unsere Daten durch eine mehr oder weniger komplexe Anordnung von Berechnungen, welche uns am Ende ein Ergebnis liefert.

Die wichtigsten Argumente zur Wahl von TensorFlow als Einstieg in die Welt des Deep Learnings bestehen darin, dass TensorFlow ausgezeichnet dokumentiert ist, eine große Community besitzt und relativ einfach zu lesen ist. Außerdem hat es eine Schnittstelle zu Python, welches durch die meisten Anwender im Bereich der Datenanalyse bereits genutzt wird.

Wenn ihr es bis hier hin geschafft habt und immer noch motiviert seid den Einstieg mit TensorFlow zu wagen, dann seid gespannt auf den nächsten Artikel. In diesem werden wir dann auf die Funktionsweise von TensorFlow eingehen und einfache Berechnungsgraphen aufbauen, um ein Grundverständnis von TensorFlow zu bekommen. Bleibt also gespannt!

Quellen

[1] Hope, Tom (2018): Einführung in TensorFlow: DEEP-LEARNING-SYSTEME PROGRAMMIEREN, TRAINIEREN, SKALIEREN UND DEPLOYEN, 1. Auflage

[2] https://www.marutitech.com/top-8-deep-learning-frameworks/

[3] https://github.com/mbadry1/Top-Deep-Learning

[4] https://www.bigdata-insider.de/was-ist-keras-a-726546/

Funktionsweise künstlicher neuronaler Netze

Künstliche neuronale Netze sind ein Spezialbereich des maschinellen Lernens, der sogar einen eigenen Trendbegriff hat: Deep Learning.
Doch wie funktioniert ein künstliches neuronales Netz überhaupt? Und wie wird es in Python realisiert? Dies ist Artikel 2 von 6 der Artikelserie –Einstieg in Deep Learning.

Gleich vorweg, wir beschränken uns hier auf die künstlichen neuronalen Netze des überwachten maschinellen Lernens. Dafür ist es wichtig, dass das Prinzip des Trainings und Testens von überwachten Verfahren verstanden ist. Künstliche neuronale Netze können aber auch zur unüberwachten Dimensionsreduktion und zum Clustering eingesetzt werden. Das bekannteste Verfahren ist das AE-Net (Auto Encoder Network), das hier aus der Betrachtung herausgenommen wird.

Beginnen wir mit einfach künstlichen neuronalen Netzen, die alle auf dem Perzeptron als Kernidee beruhen. Das Vorbild für künstliche neuronale Netze sind natürliche neuronale Netze, wie Sie im menschlichen Gehirn zu finden sind.

Perzeptron

Das Perzeptron (engl. Perceptron) ist ein „Klassiker“ unter den künstlichen neuronalen Netzen. Wenn von einem neuronalen Netz gesprochen wird, ist meistens ein Perzeptron oder eine Variation davon gemeint. Perzeptrons sind mehrschichtige Netze ohne Rückkopplung, mit festen Eingabe- und Ausgabeschichten. Es gibt keine absolut einheitliche Definition eines Perzeptrons, in der Regel ist es jedoch ein reines FeedForward-Netz mit einer Input-Schicht (auch Abtast-Schicht oder Retina genannt) mit statisch oder dynamisch gewichteten Verbindungen zur Ausgabe-Schicht, die (als Single-Layer-Perceptron) aus einem einzigen Neuron besteht. Das eine Neuron setzt sich aus zwei mathematischen Funktionen zusammen: Einer Berechnung der Nettoeingabe und einer Aktivierungsfunktion, die darüber entscheidet, ob die berechnete Nettoeingabe im Brutto nun “feuert” oder nicht. Es ist in seiner Ausgabe folglich binär: Man kann es sich auch als kleines Lämpchen vorstellen, so dass abhängig von den Eingabewerten und den Gewichtungen eine Nettoeingabe (Summe) bildet und eine Sprungfunktion darüber entscheidet, ob am Ende das Lämpchen leuchtet oder nicht. Dieses Konzept der Ausgabeerzeugung wird Forward-Propagation genannt.

Single-Layer-Perceptron

Auch wenn “Netz” für ein einzelnes Perzeptron mit seinem einen Neuron etwas übertrieben wirken mag, ist es doch die Grundlage für viele größere und mehrschichtige Netze.

Betrachten wir nun die Mathematik der Forward-Propagation.

Wir haben eine Menge an Eingabewerten x_0, x_1 \dots x_n. Wobei für x_0 als Bias-Input stets gilt: x_0 = 1,0. Der Bias-Input ist nur ein Platzhalter für das wichtige Bias-Gewicht.

    \[ x = \begin{bmatrix} x_0\\ x_1\\ x_2\\ x_3\\ \vdots\\ x_n \end{bmatrix} \]


Für jede Eingabevariable wird eine Gewichtsvariable benötigt: w_0, w_1 \dots w_n

    \[ w = \begin{bmatrix} w_0\\ w_1\\ w_2\\ w_3\\ \vdots\\ w_n \end{bmatrix} \]

Jedes Produkt aus Eingabewert und Gewichtung soll in Summe die Nettoeingabe z bilden. Hier zeigt sich z als lineare mathematische Funktion, die zwei-dimensional leicht als z = w_0 + w_1 \cdot x_1 mit w_0 als Y-Achsenschnitt wenn x_1 = 0.

    \[ z = w_0 \cdot x_0 + w_1 \cdot x_1 + \dots + w_n \cdot x_n \]

Die lineare Funktion wird nur durch die Sprungfunktion als sogenannte Aktivierungsfunktion zu einer binären Klasseneinteilung (siehe hierzu: Machine Learning – Regression vs Klassifikation), denn wenn z einen festzulegenden Schwellwert \theta überschreitet, liefert die Sprungfunktion \phi mit der Eingabe z einen anderen Wert als wenn dieser Schwellwert nicht überschritten wird.

(1)   \begin{equation*} \phi(z) = \begin{cases} 1 & \text{wenn } z \le \theta \\ -1 & \text{wenn } z < \theta \\ \end{cases} \end{equation*}

Die Definition dieser Aktivierungsfunktion ist der Kern der Klassifikation und viele erweiterte künstliche neuronale Netze unterscheiden sich im Wesentlichen vom Perzeptron dadurch, dass die Aktivierungsfunktion komplexer ist, als eine reine Sprungfunktion, beispielsweise als Sigmoid-Funktion (basierend auf der logistischen Funktion) oder die Tangens hyperbolicus (tanh) -Funktion. Mehr darüber dann im nächsten Artikel dieser Artikelserie, bleiben wir also bei der einfachen Sprungfunktion.

Künstliche neuronale Netze sind im Grunde nichts anderes als viel-dimensionale, mathematische Funktionen, die durch Schaltung als Neuronen nebeneinander (Neuronen einer Schicht) und hintereinander (mehrere Schichten) eine enorme Komplexität erfassen können. Die Gewichtungen sind dabei die Stellschraube, die die Form der mathematischen Funktion gestaltet, aus Geraden und Kurven, um eine Punktwolke zu beschreiben (Regression) oder um Klassengrenzen zu identifizieren (Klassifikation).

Eine andere Sichtweise auf künstliche neuronale ist die des Filters: Ein künstliches neuronales Netz nimmt alle Eingabe-Variablen entgegen (z. B. alle Pixel eines Bildes) und über ein Training werden die Gewichtungen (die Form des Filters) so gestaltet, dass der Filter immer zu richtigen Klasse (im Kontext der Bildklassifikation: die Objektklasse) führt.


Kommen wir nochmal kurz zurück zu der Berechnung der Nettoeingabe z. Da diese Schreibweise…

    \[ z = w_0 \cdot x_0 + w_1 \cdot x_1 + \dots + w_n \cdot x_n \]

… recht anstrengend ist, schreiben Fortgeschrittene der linearen Algebra lieber z = w^T \cdot x.

    \[ z = w^T \cdot x \]

Das hochgestellte T steht dabei für transponieren. Transponieren bedeutet, dass Spalten zu Zeilen werden – oder umgekehrt.

Beispielsweise befüllen wir zwei Vektoren x und w mit beispielhaften Inhalten:

Eingabewerte:

    \[ x = \begin{bmatrix} 5\\ 12\\ 30\\ 2 \end{bmatrix} \]

Gewichtungen:

    \[ w = \begin{bmatrix} 1\\ 2\\ 5\\ 12 \end{bmatrix} \]

Kann nun die Nettoeingabe z berechnet werden, denn der Gewichtungsvektor wird vom Spaltenvektor zum Zeilenvektor. So kann – mathematisch korrekt dargestellt – jedes Element des einen Vektors mit dem zugehörigen Element des anderen Vektors multipliziert werden, die dabei entstehenden Ergebniswerte werden summiert.

    \[ z = w^T \cdot x = \big[1\text{ }2\text{ }5\text{ }12\big] \cdot \begin{bmatrix} 5\\ 12\\ 30\\ 2 \end{bmatrix} = 1 \cdot 5 + 2 \cdot 12 + 5 \cdot 30 + 12 \cdot 2 = 203 \]


Zurück zur eigentlichen Aufgabe des künstlichen neuronalen Netzes: Klassifikation! (Regression, Clustering und Dimensionsreduktion blenden wir ja in diesem Artikel als Aufgabe aus 🙂

Das Perzeptron soll zwei Klassen trennen. Dafür sollen alle Eingaben richtig gewichtet werden, so dass die entstehende Nettoeingabe z die Sprungfunktion dann aktiviert, wenn der Datensatz nicht für die eine, sondern für die andere Klasse ausweist.

Da wir es mit einer linearen Funktion z zutun haben, ist die Konvergenz (= Passgenauigkeit des Models mit der Realität) eines Single-Layer-Perzeptrons nur für lineare Trennbarkeit möglich!

Training des Perzeptron-Netzes

Die Aufgabe ist nun, die richtigen Gewichte zu finden – und nicht nur irgendwelche richtigen, sondern genau die optimalen. Die Frage, die sich für jedes künstliche neuronale Netz stellt, ist die nach den richtigen Gewichtungen. Das Training eines Perzeptron ist vergleichsweise einfach, gerade weil es binär ist. Denn binär bedeutet auch, dass wenn eine falsche Antwort gegeben wurde, muss das jeweils andere mögliche Ergebnis korrekt sein.

Das Training eines Perzeptrons funktioniert wie folgt:

  1. Setze alle Gewichtungen auf den Wert 0,00
  2. Mit jedem Datensatz des Trainings
    1. Berechne den Ausgabewert \^{y}
    2. Vergleiche den Ausgabewert \^{y} mit dem tatsächlichen Ergebnis y
    3. Aktualisiere die Gewichtungen entgegen des Fehlers: w_i = w_i + \Delta w_i

Wobei die Gewichtsanpassung \Delta w_i entgegen des Fehlers (bzw. hin zur jeweils anderen möglichen Antwort) geschieht:

\Delta w_i = (\^{y}_j - y_j ) \cdot x_i

Anmerkung für die Experten: Die Schrittweite \eta blenden wir hier einfach mal aus. Bitte einfach von \eta = 1.0 ausgehen.

\Delta w_i ist die Differenz aus der Prädiktion und dem tatsächlichen Ergebnis (Klasse). Alle Gewichtungen werden mit jedem Fehler gleichzeitig aktualisiert. Sind alle Gewichtungen aktualisiert, kommt der nächste Durchlauf (erneuter Vergleich zwischen \^{y} und y), nicht zu vergessen ist dabei natürlich die Abhängigkeit von den Eingabewerten x:

\Delta w_0 = (\^{y}_j - y_j ) \cdot x_0

\Delta w_2 = (\^{y}_j - y_j ) \cdot x_1

\Delta w_2 = (\^{y}_j - y_j) \cdot x_2

\Delta w_n = (\^{y}_j - y_j) \cdot x_n

Training eines Perzeptrons

Das Training im überwachten Lernen basiert immer auf der Idee, den Ausgabe-Fehler (die Differenz zwischen Prädiktion und tatsächlich korrektem Ergebnis) zu betrachten und die Klassifikationslogik an den richtigen Stellschrauben (bei neuronalen Netzen sind das die Gewichtungen) entgegen des Fehlers anzupassen.

Richtige Klassifikations-Situationen können True-Positives und True-Negatives darstellen, die zu keiner Gewichtsanpassung führen sollen:

True-Positive -> Klassifikation: 1 | korrekte Klasse: 1

\Delta w_i = (\^{y}_j - y_j) \cdot x_i = (1 - 1) \cdot x_i = 0

True-Negative-> Klassifikation: -1 | korrekte Klasse: -1

\Delta w_i = (\^{y}_j - y_j) \cdot x_i = (-1 - -1) \cdot x_i = 0

Falsche Klassifikationen erzeugen einen Fehler, der zu einer Gewichtsanpassung entgegen des Fehlers führen soll:

False-Positive -> Klassifikation: 1 | korrekte Klasse: -1

\Delta w_i = (\^{y}_j - y_j) \cdot x_i = (1 - -1) \cdot x_i = 2 \cdot x_i

False-Negative -> Klassifikation: -1 | korrekte Klasse: 1

\Delta w_i = (\^{y}_j - y_j) \cdot x_i = (-1 - 1) \cdot x_i = -2 \cdot x_i

Imaginäres Trainingsbeispiel eines Single-Layer-Perzeptrons (SLP)

Nehmen wir an, dass x_1 = 0,5 ist und das SLP irrtümlicherweise die Klasse \^{y_1} = -1 ausgewiesen hat, obwohl die korrekte Klasse y_1 = +1 wäre. (Und die Schrittweite lassen wir bei \eta = 1,0)

Dann passiert folgendes:

\Delta w_1 = (\^{y}_1 - y_1) \cdot x_1 = (-1 - 1) \cdot 0,5 = -2,0 \cdot 0,5 = -1,0

Die Gewichtung w_1 verringert sich entsprechend w_1 = w_1 + \Delta w_1 = w_1 - 1,0 und somit wird die Wahrscheinlichkeit größer, dass wenn bei der nächsten Iteration (j=1) wieder die Klasse +1 korrekt sei,  den Schwellwert \phi(z) zu unterschreiten und auf eben diese korrekte Klasse zu stoßen.

Die Aktualisierung der Gewichtung \Delta w_i ist proportional zu x_i. So würde beispielsweise ein neues x_1=2,0 (bei Iteration j=2) zu einer irrtümlichen Klassifikation \^(y_2) = -1 (y_2 = +1) führen, würde die Entscheidungsgrenze zur korrekten Prädiktion der Klasse beim nächsten Durchlauf (j = 3) an w_1 noch weiter in die gleiche Richtung verschoben werden:

\Delta w_1 = (\^{y}_2 - y_2) \cdot x_1 = (-1 - 1) \cdot 2,0 = -2,0 \cdot 2,0 = -4,0

Mehr zum Training von künstlichen neuronalen Netzen ist im nächsten Artikel dieser Artikelserie zu erfahren.

Single-Layer-Perzeptrons (SLP) – Beispiel mit der boolischen Trennung

Verlassen wir nun das Training des Perzeptrons und gehen einfach mal davon aus, dass die idealen Gewichte schon gefunden wurden und schauen uns nun an, was ein Perzeptron alles (nicht) kann. Denn nicht vergessen, es soll eigentlich Klassen unterscheiden bzw. die dafür nötigen Entscheidungsgrenzen finden.

Boolische Operatoren unterscheiden Fälle nach boolischen Werten. Sie sind ein beliebtes “Hello World” für die Einarbeitung in die lineare Entscheidungslogik eines Perzeptrons. Es gibt drei grundlegende boolische Vergleichsoperatoren: AND, OR und XOR

  x1     x2   AND OR XOR
0 0 0 0 0
0 1 0 1 1
1 0 0 1 1
1 1 1 1 0

Ein Perzeptron zur Lösung dieser Aufgabe bräuchte also zwei Dimensionen (+ Bias): x_1 und x_2
Und es müsste Gewichtungen haben, die dafür sorgen, dass die Vorhersage entsprechend der Logik AND, OR oder XOR mit \^{y} = \phi(z) = \phi (w_0 \cdot 1 + w_1 \cdot x_1 + w_2 \cdot x_2) funktioniert.

Dabei ist es wichtig, dass wir auch phi \phi als Sprungfunktion definieren. Sie könnte beispielsweise so aussehen, dass sie auf den Wert \phi(z) = 1 springt, wenn z > 0 ist, ansonsten aber \phi(z) = 0 bleibt.

Das Netz und die Gewichtungen (w-Setup) könnten für die AND- und die OR-Logik so aussehen:

Die Gewichtungen funktionieren beim SLP problemlos, denn wir haben es mit linear trennbaren Problemen zutun:

Kleiner Test gefällig? So nehmen wir uns erstmal die AND-Logik vor:

  • Wenn x1 = 0 und x2 = 0 ist, gilt: z = -1,5 \cdot 1 + 1 \cdot 0 + 1 \cdot 0 = - 1,5,
    wie erhalten als Prädiktion \phi(z) = \phi(-1,5) = 0
  • Wenn x1 = 1 und x2 = 0 ist, gilt: z = -1,5 \cdot 1 + 1 \cdot 1 + 1 \cdot 0 = - 0,5,
    wie erhalten als Prädiktion \phi(z) = \phi(-0,5) = 0
  • Wenn x1 = 1 und x2 = 1 ist, gilt: z = -1,5 \cdot 1 + 1 \cdot 1 + 1 \cdot 1 = + 0,5,
    wie erhalten als Prädiktion \phi(z) = \phi(0,5) = 1

Scheint zu funktionieren!

Und dann die OR-Logik mit

  • Wenn x1 = 0 und x2 = 0 ist, gilt: z = -0,5 \cdot 1 + 1 \cdot 0 + 1 \cdot 0 = - 0,5,
    wie erhalten als Prädiktion \phi(z) = \phi(-0,5) = 0
  • Wenn x1 = 1 und x2 = 0 ist, gilt: z = -0,5 \cdot 1 + 1 \cdot 1 + 1 \cdot 0 = + 0,5,
    wie erhalten als Prädiktion \phi(z) = \phi(0,5) = 1
  • Wenn x1 = 1 und x2 = 1 ist, gilt: z = -0,5 \cdot 1 + 1 \cdot 1 + 1 \cdot 1 = + 1,5,
    wie erhalten als Prädiktion \phi(z) = \phi(1,5) = 1

Super! Jedoch stellt sich nun die Frage, wie das XOR-Problem zu lösen ist, denn das bedingt sowohl die Grenzen von AND als auch jene des OR-Operators.

Multi-Layer-Perzeptron (MLP) bzw. (Deep) Feed Forward (FF) Net

Denn ein XOR kann mathematisch auch so korrekt beschrieben werden: x_1 \text{ xor } x_2 = (x_1 \text{ and } \neg x_2) \text{ or } (\neg x_1 \text{ and } x_2)

Testen wir es aus!

  • Wenn x1 = 0 und x2 = 0 ist, gilt:
    z_1 = w_{10} \cdot 1 + w_{11} \cdot x1 + w_{12} \cdot  x2 = -0.5 \cdot 1 + 1,0 \cdot 0 - 1,0 \cdot 0 = -0,5 und somit \phi(z_1) = \phi(-0,5) = 0
    z_2 = w_{20} \cdot 1 + w_{21} \cdot x1 + w_{22} \cdot  x2 = -0.5 \cdot 1 - 1,0 \cdot 0 + 1,0 \cdot 0 = -0,5 und somit \phi(z_2) = \phi(-0,5) = 0
    z_3 = w_{30} \cdot 1 + w_{31} \cdot \phi(z_1) + w_{32} \cdot \phi(z_2) = -0,5 \cdot 1 + 1,0 \cdot 0 + 1,0 \cdot 0 = -0,5 und somit \phi(z_3) = \phi(-0,5) = 0
  • Wenn x1 = 1 und x2 = 0 ist, gilt:
    z_1 = w_{10} \cdot 1 + w_{11} \cdot x1 + w_{12} \cdot  x2 = -0.5 \cdot 1 + 1,0 \cdot 1 - 1,0 \cdot 0 = 0,5 und somit \phi(z_1) = \phi(0,5) = 1
    z_2 = w_{20} \cdot 1 + w_{21} \cdot x1 + w_{22} \cdot  x2 = -0.5 \cdot 1 - 1,0 \cdot 1 + 1,0 \cdot 0 = -1,5 und somit \phi(z_2) = \phi(-1,5) = 0
    z_3 = w_{30} \cdot 1 + w_{31} \cdot \phi(z_1) + w_{32} \cdot \phi(z_2) = -0,5 \cdot 1 + 1,0 \cdot 1 + 1,0 \cdot 0 = 0,5 und somit \phi(z_3) = \phi(0,5) = 1
  • Wenn x1 = 0 und x2 = 1 ist, gilt:
    z_1 = w_{10} \cdot 1 + w_{11} \cdot x1 + w_{12} \cdot  x2 = -0.5 \cdot 1 + 1,0 \cdot 0 - 1,0 \cdot 1 = -1,5 und somit \phi(z_1) = \phi(-1,5) = 0
    z_2 = w_{20} \cdot 1 + w_{21} \cdot x1 + w_{22} \cdot  x2 = -0.5 \cdot 1 - 1,0 \cdot 0 + 1,0 \cdot 1 = 0,5 und somit \phi(z_2) = \phi(0,5) = 1
    z_3 = w_{30} \cdot 1 + w_{31} \cdot \phi(z_1) + w_{32} \cdot \phi(z_2) = -0,5 \cdot 1 + 1,0 \cdot 0 + 1,0 \cdot 1 = 0,5 und somit \phi(z_3) = \phi(0,5) = 1
  • Wenn x1 = 1 und x2 = 1 ist, gilt:
    z_1 = w_{10} \cdot 1 + w_{11} \cdot x1 + w_{12} \cdot  x2 = -0.5 \cdot 1 + 1,0 \cdot 1 - 1,0 \cdot 1 = -1,5 und somit \phi(z_1) = \phi(-0,5) = 0
    z_2 = w_{20} \cdot 1 + w_{21} \cdot x1 + w_{22} \cdot  x2 = -0.5 \cdot 1 - 1,0 \cdot 1 + 1,0 \cdot 1 = 0,5 und somit \phi(z_2) = \phi(-0,5) = 0
    z_3 = w_{30} \cdot 1 + w_{31} \cdot \phi(z_1) + w_{32} \cdot \phi(z_2) = -0,5 \cdot 1 + 1,0 \cdot 0 + 1,0 \cdot 0 = -0,5 und somit \phi(z_3) = \phi(-0,5) = 0

Es funktioniert!

Mehrfachklassifikation mit dem Perzeptron

Ein Perzeptron-Netz klassifiziert binär, die Ausgabe beschränkt sich auf 1 oder -1 bzw. 0 oder 1.

Jedoch wird in der Praxis oftmals eine One-vs-All (OvA) bzw. One-vs-Rest (OvR) Klassifikation implementiert. In diesem Fall steht die 1 für die Erkennung einer konkreten Klasse, während alle anderen übrigen Klassen als negativ betrachtet werden.

Um jede Klasse erkennen zu können, werden n Klassifizierer (= n Perzeptron-Netze) benötigt. Jedes Perzeptron-Netz ist auf die Erkennung einer bestimmten Klasse trainiert.

Adaline – Oder: die Limitation des Perzeptrons

Das Perzeptron wird nur über eine Sprungfunktion aktiviert. Das schränkt die Feinabstimmung des Trainings enorm ein. Besser sind Aktivierungen über stetige Funktionen, die dann nämlich differenzierbar (ableitbar) sind. Das ergibt eine konvexe Fehlerfunktion mit einem eindeutigen Minimum. Der Adaline-Algorithmus (ADAptive Linear NEuron) erweitert die Idee des Perzeptrons um genau diese Idee. Der wesentliche Fortschritt der Adaline-Regel gegenüber der des Perzeptrons ist demnach, dass die Aktualisierung der Gewichtungen nicht wie beim Perzeptron auf einer einfachen Sprungfunktion, sondern auf einer linearen, stetigen Aktivierungsfunktion beruht.

Single-Layer-Adaline

Wie ein künstliches neuronales Netz mit der Kategorie Adaline trainiert werden kann, wird im nächsten Artikel dieser Artikelserie erläutert.

Weiterführende Netz-Konzepte (CNN und RNN)

Wer bereits mit Frameworks wie TensorFlow in das Deep Learning eingestiegen ist, hat möglicherweise schon erweiterte Konzepte der künstlichen neuronalen Netze kennen gelernt. Die CNNs (Convolutional Neuronal Network) sind im Moment die Wahl für die Verarbeitung von hochdimensionalen Aufgaben, beispielsweise die Bilderkennung (Computer Vision) und Texterkennung (NLP). Das CNN erweitert die Möglichkeiten mit neuronalen Netzen deutlich, indem ein Netz zur Dimensionsreduktion vorgeschaltet wird, im Kern steckt jedoch weiterhin die Idee der MLPs. Beim Einsatz in der Bilderkennung funktionieren CNNs vereinfacht gesprochen so, dass der vorgeschaltete Netzbereich die Millionen Bildpixel sektorweise ausliest (Convolution, Faltung durch Auslesen über Sektoren, die sich gegenseitig überlappen), verdichtet (Pooling, beispielsweise über nicht-lineare Funktionen wie max()) und dann – nach diesem Prozedere – ähnlich eim MLP klassifiziert.

 

Eine andere erweiterte Form sind RNNs (Recurrent Neuronal Network), die ebenfalls auf der Idee des MLPs basieren, dieses Konzept jedoch dank Rückverbindungen (Neuronen senden an vorherige Schichten) und Selbstverbindungen (Neuronen senden an sich selbst) wiederum auf den Kopf stellen.

 

Dennoch ist es für das tiefere Verständnis von CNNs und RNNs essenziell, dass vorher das Konzept des MLPs verstanden ist. Es ist die einfachste Form der auch heute noch am meisten eingesetzten und sehr mächtigen Netz-Topologien.

Im Jahr 2016 hatte Fjodor van Veen von asimovinstitute.org hatte – dankenswerterweise – mal eine Zusammenstellung von Netz-Topologien erstellt, auf die ich heute noch immer mal wieder einen Blick werfe:

Künstliche neuronale Netze – Topologie-Übersicht von Fjodor van Veen

Buchempfehlungen

Die folgenden Bücher nutze ich für mein Selbststudium von Machine Learning und Deep Learning und sind teilweise Gedankenvorlagen auch für diesen Artikel gewesen:

 

Machine Learning mit Python und Scikit-Learn und TensorFlow: Das umfassende Praxis-Handbuch für Data Science, Predictive Analytics und Deep Learning (mitp Professional) Deep Learning mit Python und Keras: Das Praxis-Handbuch vom Entwickler der Keras-Bibliothek(mitp Professional)

 

Interview – Die Bedeutung von Machine Learning für das Data Driven Business

Um das Optimum aus ihren Daten zu holen, müssen Unternehmen Data Analytics vorantreiben, um Entscheidungsprozesse für Innovation und Differenzierung stärker zu automatisieren. Die Data Science scheint hier der richtige Ansatz zu sein, ist aber ein neues und schnelllebiges Feld, das viele Sackgassen kennt. Cloudera Fast Forward Labs unterstützt Unternehmen dabei sich umzustrukturieren, Prozesse zu automatisieren und somit neue Innovationen zu schaffen.

Alice Albrecht ist Research Engineer bei Cloudera Fast Forward Labs. Dort widmet sie sich der Weiterentwicklung von Machine Learning und Künstlicher Intelligenz. Die Ergebnisse ihrer Forschungen nutzt sie, um ihren Kunden konkrete Ratschläge und funktionierende Prototypen anzubieten. Bevor sie zu Fast Forward Labs kam, arbeitete sie in Finanz- und Technologieunternehmen als Data Science Expertin und Produkt Managerin. Alice Albrecht konzentriert sich nicht nur darauf, Maschinen “coole Dinge” beizubringen, sondern setzt sich auch als Mentorin für andere Wissenschaftler ein. Während ihrer Promotion der kognitiven Neurowissenschaften in Yale untersuchte Alice, wie Menschen sensorische Informationen aus ihrer Umwelt verarbeiten und zusammenfassen.

english-flagRead this article in English:
“Interview – The Importance of Machine Learning for the Data Driven Business”


Data Science Blog: Frau Albrecht, Sie sind eine bekannte Keynote-Referentin für Data Science und Künstliche Intelligenz. Während Data Science bereits im Alltag vieler Unternehmen angekommen ist, scheint Deep Learning der neueste Trend zu sein. Ist Künstliche Intelligenz für Unternehmen schon normal oder ein überbewerteter Hype?

Ich würde sagen, nichts von beidem stimmt. Data Science ist inzwischen zwar weit verbreitet, aber die Unternehmen haben immer noch Schwierigkeiten, diese neue Disziplin in ihr bestehendes Geschäft zu integrieren. Ich denke nicht, dass Deep Learning mittlerweile Teil des Business as usual ist – und das sollte es auch nicht sein. Wie jedes andere Tool, braucht auch die Integration von Deep Learning Modellen in die Strukturen eines Unternehmens eine klar definierte Vorgehensweise. Alles andere führt ins Chaos.

Data Science Blog: Nur um sicherzugehen, worüber wir reden: Was sind die Unterschiede und Überschneidungen zwischen Data Analytics, Data Science, Machine Learning, Deep Learning und Künstlicher Intelligenz?

Hier bei Cloudera Fast Forward Labs verstehen wir unter Data Analytics das Sammeln und Addieren von Daten – meist für schnelle Diagramme und Berichte. Data Science hingegen löst Geschäftsprobleme, indem sie sie analysiert, Prozesse mit den gesammelten Daten abgleicht und anschließend entsprechende Vorgänge prognostiziert. Beim Machine Learning geht es darum, Probleme mit neuartigen Feedbackschleifen zu lösen, die sich mit der Anzahl der zur Verfügung stehenden Daten noch detaillierter bearbeiten lassen. Deep Learning ist eine besondere Form des Machine Learnings und ist selbst kein eigenständiges Konzept oder Tool. Künstliche Intelligenz zapft etwas Komplizierteres an, als das, was wir heute sehen. Hier geht es um weit mehr als nur darum, Maschinen darauf zu trainieren, immer wieder dasselbe zu tun oder begrenzte Probleme zu lösen.

Data Science Blog: Und wie können wir hier den Kontext zu Big Data herstellen?

Theoretisch gesehen gibt es Data Science ja bereits seit Jahrzehnten. Die Bausteine für modernes Machine Learning, Deep Learning und Künstliche Intelligenz basieren auf mathematischen Theoremen, die bis in die 40er und 50er Jahre zurückreichen. Die Herausforderung bestand damals darin, dass Rechenleistung und Datenspeicherkapazität einfach zu teuer für die zu implementierenden Ansätze waren. Heute ist das anders. Nicht nur die Kosten für die Datenspeicherung sind erheblich gesunken, auch Open-Source-Technologien wie etwa Apache Hadoop haben es möglich gemacht, jedes Datenvolumen zu geringen Kosten zu speichern. Rechenleistung, Cloud-Lösungen und auch hoch spezialisierte Chip-Architekturen, sind jetzt auch auf Anfrage für einen bestimmten Zeitraum verfügbar. Die geringeren Kosten für Datenspeicherung und Rechenleistung sowie eine wachsende Liste von Tools und Ressourcen, die über die Open-Source-Community verfügbar sind, ermöglichen es Unternehmen jeder Größe, von sämtlichen Daten zu profitieren.

Data Science Blog: Was sind die Herausforderungen beim Einstieg in Data Science?

Ich sehe zwei große Herausforderungen: Eine davon ist die Sicherstellung der organisatorischen Ausrichtung auf Ergebnisse, die die Data Scientists liefern werden (und das Timing für diese Projekte).  Die zweite Hürde besteht darin, sicherzustellen, dass sie über die richtigen Daten verfügen, bevor sie mit dem Einstellen von Data Science Experten beginnen. Das kann “tricky” sein, wenn man im Unternehmen nicht bereits über Know-how in diesem Segment verfügt. Daher ist es manchmal besser, im ersten Schritt einen Data Engineer oder Data Strategist einzustellen, bevor man mit dem Aufbau eines Data Science Team beginnt.

Data Science Blog: Es gibt viele Diskussionen darüber, wie man ein datengesteuertes Unternehmen aufbauen kann. Geht es bei Data Science nur darum, am Ende das Kundenverhalten besser zu verstehen?

Nein “Data Driven” bedeutet nicht nur, die Kunden besser zu verstehen – obwohl das eine Möglichkeit ist, wie Data Science einem Unternehmen helfen kann. Abgesehen vom Aufbau einer Organisation, die sich auf Daten und Analysen stützt, um Entscheidungen über das Kundenverhalten oder andere Aspekte zu treffen, bedeutet es, dass Daten das Unternehmen und seine Produkte voranbringen.

Data Science Blog: Die Zahl der Technologien, Tools und Frameworks nimmt zu, was zu mehr Komplexität führt. Müssen Unternehmen immer auf dem Laufenden bleiben oder könnte es ebenso hilfreich sein, zu warten und Pioniere zu imitieren?

Obwohl es generell für Unternehmen nicht ratsam ist, pauschal jede neue Entwicklung zu übernehmen, ist es wichtig, dass sie mit den neuen Rahmenbedingungen Schritt halten. Wenn ein Unternehmen wartet, um zu sehen, was andere tun, und deshalb nicht in neue Entwicklungen investiert, haben sie den Anschluss meist schon verpasst.

Data Science Blog: Global Player verfügen meist über ein großes Budget für Forschung und den Aufbau von Data Labs. Mittelständische Unternehmen stehen immer unter dem Druck, den Break-Even schnell zu erreichen. Wie können wir die Wertschöpfung von Data Science beschleunigen?

Ein Team zu haben, das sich auf ein bestimmtes Set von Projekten konzentriert, die gut durchdacht und auf das Geschäft ausgerichtet sind, macht den Unterschied aus. Data Science und Machine Learning müssen nicht auf Forschung und Innovation verzichten, um Werte zu schaffen. Der größte Unterschied besteht darin, dass sich kleinere Teams stärker bewusst sein müssen, wie sich ihre Projektwahl in neue Rahmenbedingungen und ihre besonderen akuten und kurzfristigen Geschäftsanforderungen einfügt.

Data Science Blog: Wie hilft Cloudera Fast Forward Labs anderen Unternehmen, den Einstieg in Machine Learning zu beschleunigen?

Wir beraten Unternehmen, basierend auf ihren speziellen Bedürfnissen, über die neuesten Trends im Bereich Machine Learning und Data Science. Und wir zeigen ihnen, wie sie ihre Datenteams aufbauen und strukturieren können, um genau die Fähigkeiten zu entwickeln, die sie benötigen, um ihre Ziele zu erreichen.

Data Science Blog: Zum Schluss noch eine Frage an unsere jüngeren Leser, die eine Karriere als Datenexperte anstreben: Was macht einen guten Data Scientist aus? Arbeiten sie lieber mit introvertierten Coding-Nerds oder den Data-loving Business-Experten?

Ein guter Data Scientist sollte sehr neugierig sein und eine Liebe für die Art und Weise haben, wie Daten zu neuen Entdeckungen und Innovationen führen und die nächste Generation von Produkten antreiben können.  Menschen, die im Data Science Umfeld erfolgreich sind, kommen nicht nur aus der IT. Sie können aus allen möglichen Bereichen kommen und über die unterschiedlichsten Backgrounds verfügen.

Machine Learning vs Deep Learning – Wo liegt der Unterschied?

Machine Learning gehört zu den Industrie-Trends dieser Jahre, da besteht kein Zweifel. Oder war es Deep Learning? Oder Artificial Intelligence? Worin liegt da eigentlich der Unterschied? Dies ist Artikel 1 von 6 der Artikelserie –Einstieg in Deep Learning.

Machine Learning

Maschinelles Lernen (ML) ist eine Sammlung von mathematischen Methoden der Mustererkennung. Diese Methoden erkennen Muster beispielsweise durch bestmögliche, auf eine bestmögliche Entropie gerichtete, Zerlegung von Datenbeständen in hierarchische Strukturen (Entscheidungsbäume). Oder über Vektoren werden Ähnlichkeiten zwischen Datensätzen ermittelt und daraus trainiert (z. B. k-nearest-Neighbour, nachfolgend einfach kurz: k-nN) oder untrainiert (z.B. k-Means) Muster erschlossen.

Algorithmen des maschinellen Lernens sind tatsächlich dazu in der Lage, viele alltägliche oder auch sehr spezielle Probleme zu lösen. In der Praxis eines Entwicklers für Machine Learning stellen sich jedoch häufig Probleme, wenn es entweder zu wenige Daten gibt oder wenn es zu viele Dimensionen der Daten gibt. Entropie-getriebene Lern-Algorithmen wie Entscheidungsbäume werden bei vielen Dimensionen zu komplex, und auf Vektorräumen basierende Algorithmen wie der k-nächste-Nachbarn-Algorithmus sind durch den Fluch der Dimensionalität in ihrer Leistung eingeschränkt.


Der Fluch der Dimensionalität

Datenpunkte sind in einem zwei-dimensionalen Raum gut vorstellbar und auch ist es vorstellbar, das wir einen solchen Raum (z. B. ein DIN-A5-Papierblatt) mit vielen Datenpunkten vollschreiben. Belassen wir es bei der Anzahl an Datenpunkten, nehmen jedoch weitere Dimensionen hinzu (zumindest die 3. Dimension können wir uns noch gut vorstellen), werden die Abstände zwischen den Punkten größer. n-dimensionale Räume können gewaltig groß sein, so dass Algorithmen wie der k-nN nicht mehr gut funktionieren (der n-dimensionale Raum ist einfach zu leer).


Auch wenn es einige Konzepte zum besseren Umgang mit vielen Dimensionen gibt (z. B. einige Ideen des Ensemble Learnings)

Feature Engineering

Um die Anzahl an Dimensionen zu reduzieren, bedienen sich Machine Learning Entwickler statistischer Methoden, um viele Dimensionen auf die (wahrscheinlich) nützlichsten zu reduzieren: sogenannte Features. Dieser Auswahlprozess nennt sich Feature Engineering und bedingt den sicheren Umgang mit Statistik sowie idealerweise auch etwas Fachkenntnisse des zu untersuchenden Fachgebiets.
Bei der Entwicklung von Machine Learning für den produktiven Einsatz arbeiten Data Scientists den Großteil ihrer Arbeitszeit nicht an der Feinjustierung ihrer Algorithmen des maschinellen Lernens, sondern mit der Auswahl passender Features.

Deep Learning

Deep Learning (DL) ist eine Disziplin des maschinellen Lernes unter Einsatz von künstlichen neuronalen Netzen. Während die Ideen für Entscheidungsbäume, k-nN oder k-Means aus einer gewissen mathematischen Logik heraus entwickelt wurden, gibt es für künstliche neuronale Netze ein Vorbild aus der Natur: Biologische neuronale Netze.

Prinzip-Darstellung eines künstlichen neuronalen Netzes mit zwei Hidden-Layern zwischen einer Eingabe- und Ausgabe-Schicht.

Wie künstliche neuronale Netze im Detail funktionieren, erläutern wir in den nächsten zwei Artikeln dieser Artikelserie, jedoch vorab schon mal so viel: Ein Eingabe-Vektor (eine Reihe von Dimensionen) stellt eine erste Schicht dar, die über weitere Schichten mit sogenannten Neuronen erweitert oder reduziert und über Gewichtungen abstrahiert wird, bis eine Ausgabeschicht erreicht wird, die einen Ausgabe-Vektor erzeugt (im Grunde ein Ergebnis-Schlüssel, der beispielsweise eine bestimmte Klasse ausweist: z. B. Katze oder Hund). Durch ein Training werden die Gewichte zwischen den Neuronen so angepasst, dass bestimmte Eingabe-Muster (z. B. Fotos von Haustieren) immer zu einem bestimmten Ausgabe-Muster führen (z. B. “Das Foto zeigt eine Katze”).

Der Vorteil von künstlichen neuronalen Netzen ist die sehr tiefgehende Abstraktion von Zusammenhängen zwischen Eingabe-Daten und zwischen den abstrahierten Neuronen-Werten mit den Ausgabe-Daten. Dies geschieht über mehrere Schichten (Layer) der Netze, die sehr spezielle Probleme lösen können. Aus diesen Tatsachen leitet sich der übergeordnete Name ab: Deep Learning

Deep Learning kommt dann zum Einsatz, wenn andere maschinelle Lernverfahren an Grenzen stoßen und auch dann, wenn auf ein separates Feature Engineering verzichtet werden muss, denn neuronale Netze können über mehrere Schichten viele Eingabe-Dimensionen von selbst auf die Features reduzieren, die für die korrekte Bestimmung der Ausgabe notwendig sind.

Convolutional Neuronal Network

Convolutional Neuronal Networks (CNN) sind neuronale Netze, die vor allem für die Klassifikation von Bilddaten verwendet werden. Sie sind im Kern klassische neuronale Netze, die jedoch eine Faltungs- und eine Pooling-Schicht vorgeschaltet haben. Die Faltungsschicht ließt den Daten-Input (z. B. ein Foto) mehrfach hintereinander, doch jeweils immer nur einen Ausschnitt daraus (bei Fotos dann einen Sektor des Fotos), die Pooling-Schicht reduzierte die Ausschnittsdaten (bei Fotos: Pixel) auf reduzierte Informationen. Daraufhin folgt das eigentliche neuronale Netz.

CNNs sind im Grunde eine spezialisierte Form von künstlichen neuronalen Netzen, die das Feature-Engineering noch geschickter handhaben.

Deep Autoencoder

Gegenwärtig sind die meisten künstlichen neuronalen Netze ein Algorithmen-Modell für das überwachte maschinelle Lernen (Klassifikation oder Regression), jedoch kommen sie auch zum unüberwachten Lernen (Clustering oder Dimensionsreduktion) zum Einsatz, die sogenannten Deep Autoencoder.

Deep Autoencoder sind neuronale Netze, die im ersten Schritt eine große Menge an Eingabe-Dimensionen auf vergleichsweise wenige Dimensionen reduzieren. Die Reduktion (Encoder) erfolgt nicht abrupt, sondern schrittweise über mehrere Schichten, die reduzierten Dimensionen werden zum Feature-Vektor. Daraufhin kommt der zweite Teil des neuronalen Netzes zum Einsatz: Die reduzierten Dimensionen werden über weitere Schichten wieder erweitert, die ursprünglichen Dimensionen als abstrakteres Modell wieder rekonstruiert (Decoder). Der Sinn von Deep Autoencodern sind abstrakte Ähnlichkeitsmodelle zu erstellen. Ein häufiges Einsatzgebiet sind beispielsweise das maschinelle Identifizieren von ähnlichen Bildern, Texten oder akkustischen Signalmustern.

Artificial Intelligence

Artificial Intelligence (AI) oder künstliche Intelligenz (KI) ist ein wissenschaftlicher Bereich, der das maschinelle Lernen beinhaltet, jedoch noch weitere Bereiche kennt, die für den Aufbau einer KI von Nöten sind. Eine künstliche Intelligenz muss nicht nur Lernen, sie muss auch Wissen effizient abspeichern, einordnen bzw. sortieren und abrufen können. Sie muss ferner über eine Logik verfügen, wie sie das Wissen und das Gelernte einsetzen muss. Denken wir an biologische Intelligenzen, ist es etwa nicht so, dass jegliche Fähigkeiten erlernt wurden, einige sind mit der Geburt bereits ausgebildet oder liegen als sogenannter Instinkt vor.

Ein einzelner Machine Learning Algorithmus würde wohl kaum einen Turing-Test bestehen oder einen Roboter komplexe Aufgaben bewältigen lassen. Daher muss eine künstliche Intelligenz weit mehr können, als bestimmte Dinge zu erlernen. Zum wissenschaftlichen Gebiet der künstlichen Intelligenz gehören zumindest:

  • Machine Learning (inkl. Deep Learning und Ensemble Learning)
  • Mathematische Logik
    • Aussagenlogik
    • Prädikatenlogik
    • Default-Logik
    • Modal-Logik
  • Wissensbasierte Systeme
    • relationale Algebra
    • Graphentheorie
  • Such- und Optimierungsverfahren:
    • Gradientenverfahren
    • Breitensuche & Tiefensuche

AI(ML(DL))

Buch-Empfehlungen

Grundkurs Künstliche Intelligenz: Eine praxisorientierte Einführung (Computational Intelligence) Praxiseinstieg Deep Learning: Mit Python, Caffe, TensorFlow und Spark eigene Deep-Learning-Anwendungen erstellen

Machine Learning: Online vs Offline

Das ist Artikel 4 von 4 aus der Artikelserie – Was ist eigentlich Machine Learning?

Die Begriffe online und offline sind mit vielen Bedeutungen versehen und so ist – wie bei vielen Unterscheidungsmöglichkeiten des maschinellen Lernens – die Verwirrung vorprogrammiert. Diese Unterscheidung betrifft die Trainingsphasen der parametrischen Verfahren des maschinellen Lernens.

Offline Learning

Mit Offline Learning ist nicht gemeint, dass der Algorithmus nicht ans Internet angebunden ist, sondern dass es sich bei der Trainingsprozedure um eine Stapelverarbeitung handelt. Daher wird manchmal auch vom Batch Learning gesprochen. Beim Batch Learning werden die Parameter bzw. das Modell erst angepasst, nachdem der gesamte Batch (Stapel an Datensätzen) das Training durchlaufen hat. Die gewöhnliche Gradientenmethode als ein Optimierungsverfahren ist das Gradientenabstiegsverfahren als Stapelverarbeitung. Dabei wird der Gradient, der die Richtung für die Anpassung der Gewichtungen der Funktionsparameter vorgibt, anhand der gesamten Trainingsdatenmenge berechnet.

Der Vorteil dieser Vorgehensweise ist, dass das Training als Prozess sehr schnell läuft und die Funktionsparameter direkt aus dem gesamten Datenbestand heraus bestimmt werden.

Demgegenüber steht der Nachteil, dass der ganze Stapel in den Arbeitsspeicher geladen werden muss, was eine entsprechend leistungsfähige Hardware voraussetzt. Soll das Lern-System für das Training live an einer Datenquelle (z. B. ein Data Stream aus dem Social Media) angebunden werden, müssen die Daten erstmal gespeichert werden (Bildung des Stapels), bevor sie verarbeitet und dann verworfen werden können, was den dafür nötigen Speicherplatz bedingt.

Online Learning

Beim Online-Learning wird nicht über einen Stapel (Batch) trainiert, sondern jeder einzelne Datensatz (aus einer großen Menge an Datensätzen oder live hinzugefügte Datensätze) wird dem Training einzeln hinzugefügt, trainiert und umgehend in eine Parameteranpassung (Modellanpassung) umgesetzt. Dies lässt sich beispielsweise mit der stochastischen Gradientenmethode realsieren, die iterativ arbeiten und den Gradienten zur Gewichtungsanpassung für jeden einzelnen Datensatz bestimmt, statt einen ganzen Batch zu verarbeiten und daraus einen Fehler zu berechnen. Online-Learning ist ein inkrementell arbeitendes Lernen, welches das Modell kontinuierlich – nämlich nach jedem Datensatz (Sample) – anpasst.

Die Optimierung läuft somit – wenn auf eine große Datenmenge angewendet wird – natürlich langsamer und ist eher nicht geeignet, wenn ein Training schnell verlaufen muss oder eine große Datenmenge die Hardware sowieso schon auslastet. Dafür wird das Modell beim Online-Learning in Echtzeit trainiert, wenn neue Daten zur Verfügung stehen. Neu hinzugefügte Daten fließen sofort ins Modell ein, so kann ein Lern-System als ein Live-System gleich auf Änderungen reagieren und die Trainingsdaten wieder verworfen werden (da sie bereits ins Training eingeflossen sind).

Mini-Batch-Verfahren

Während beim Online Learning alle Datensätze einzeln durchgegangen werden (dauert lange) und beim Offline Learning der gesamte Stapel an Datensätzen durchgearbeitet wird (viel Speicherplatzbedarf), ist der sogenannte Mini-Batch der Mittelweg. Wie der Name bereits andeutet, wird ein kleinerer Stapel (z. B. 50 Datensätze) gesammelt und verarbeitet.