Im Bereich von Fahrassistenzsystemen und autonomen Fahren wurde machine Learning mithilfe neuronaler Netze
wieder wichtig. Am Beispiel eines Netzes zur Erkennung von Quadratzahlen wie 9, 16, 121 etc. sollen hier
ein konkretes Beispiel für machine learning mit python-frameworks sklearn,keras,caffe2,tensorflow gegeben werden.
Dies kann dann z.B. mit einem azure cloud notebook nachvollzogen werden.
Die Beschreibung ist kurz gehalten, da machine learning auch aktuelles Forschungsgebiet ist, worüber
man vieeel schreiben kann.
Modell des neuronalen Netzwerks
Sei n die Anzahl der Eingabebits, so lassen sich damit 2n Zahlen darstellen. Davon sind einige Quadratzahlen,
welche Label==1 erhalten, sonst 0. Mit numpy kann man so einen Datensatz damit erstellen:
import numpy as np
import math
n = 7
Xp = []
Yp = []
for a in range(0,2**n):
neu = []
temp = a
for b in range(0,n):
neu.append((temp & 1) == 1)
temp = temp >> 1
Xp.append(neu)
temp = int(math.sqrt(a))
Yp.append(True if temp * temp == a else False)
# arrays fuer learning frameworks aufbauen
merkmale = np.array(Xp,dtype=bool)
labels = np.array(Yp,dtype=bool)
sklearn und Nearest Neighbour([NgZe18],S.35 ff)
Bei sklearn kann man den Klassifikator nearest neighbor trainieren. Dazu unterteilt man die Datenmenge in
Trainingsdaten / Testdaten und trainiert diese mit .fit.
Mit .score kann man dann prüfen, wie gut diese Trainingsdaten vom
Klassifikator erkannt wurden. Dann kann man mit .score auch die Testdaten bewerten, also sozusagen
unbekannte Daten validieren, um z.B. Overfitting zu erkennen.
Mit .predict kann man einen gegebenen oder neuen Datensatz prüfen.
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn import neighbors
X_train, X_test, Y_train, Y_test = train_test_split(merkmale, labels, test_size=0.20) # s.o.
classifier = neighbors.KNeighborsClassifier(1)
classifier.fit(X_train, Y_train)
neun = [[True,False,False,True,False,False,False]] # 9d = b1001000 niedrigstes Bit links
print("Ist 9 Quadratzahl", classifier.predict(neun))
vierundsechzig = [[False,False,False,False,False,False,True]] # 64d = b0000001 niedrigstes Bit links
print("Ist 64 Quadratzahl", classifier.predict(vierundsechzig))
print("Trefferquote Trainingsdaten", classifier.score(X_train, Y_train))
print("Trefferquote Testdaten", classifier.score(X_test, Y_test))
Ausgabe ist:
Ist 9 Quadratzahl [ True]
Ist 64 Quadratzahl [ True]
Trefferquote Trainingsdaten 1.0
Trefferquote Testdaten 0.8076923076923077
Bei zwei nächsten Nachbarn ergibt sich:
Ist 9 Quadratzahl [ True]
Ist 64 Quadratzahl [False]
Trefferquote Trainingsdaten 0.9019607843137255
Trefferquote Testdaten 0.8846153846153846
Wie man anhand der Testdaten sieht, kann der nächste Nachbar-Klassifikator Quadratzahlen für kleine n wie 8 nicht gut erkennen !
Interessant ist, dass bei n == 12 die Testdaten mit über 95% erkannt werden, auch bei n == 14 oder 16.
keras,tensorflow ([NgZe18],Kapitel 7)
Damit lässt sich ein neuronales Netz erstellen. Keras ist mittlerweile Teil von tensorflow und
vereinfacht die Erstellung eines neuronalen Netzes.
from keras.layers import Input
from keras.layers import Dense
from keras.models import Model
import numpy as np
inputs = Input(shape=(n,))
fullyConnected = Dense(2)(inputs)
model = Model(input=inputs, output=fullyConnected)
model.compile(optimizer="adam", loss="categorical_crossentropy",metrics=["accuracy"])
model.summary()
X_train, X_test, Y_train, Y_test = train_test_split(merkmale, labels, test_size=0.20) # s.o.
# Mit Y_train, Y_test: "ValueError: Error when checking target: expected dense_1 to have shape (2,) but got array with shape (1,)," deshalb
from keras.utils.np_utils import to_categorical
Y2_train = to_categorical(Y_train,2) # One-hot-encoding, 2 Labels
Y2_test = to_categorical(Y_test,2)
model.fit(X_train, Y2_train, epochs=100, validation_split=0.2) # trainieren
neun = np.array([[True,False,False,True,False,False,False]]) # 9d = b1001000 niedrigstes Bit links
print("Ist 9 Quadratzahl", model.predict(neun))
vierundsechzig = np.array([[False,False,False,False,False,False,True]]) # 64d = b0000001 niedrigstes Bit links
print("Ist 64 Quadratzahl", model.predict(vierundsechzig))
train_loss, train_accurancy = model.evaluate(X_train, Y2_train)
print("Verlust, Genauigkeit Trainingsdaten", train_loss, train_accurancy)
test_loss, test_accurancy = model.evaluate(X_test, Y2_test)
print("Verlust, Genauigkeit Testdaten", test_loss, test_accurancy)
Die Ausgaben sind:
Using TensorFlow backend.
...
Train on 81 samples, validate on 21 samples
Epoch 1/100
81/81 [==============================] - 0s 3ms/step - loss: 1.7562 - accuracy: 0.9136 - val_loss: 1.1993 - val_accuracy: 1.0000
Epoch 2/100
81/81 [==============================] - 0s 134us/step - loss: 1.9497 - accuracy: 0.9136 - val_loss: 1.1934 - val_accuracy: 1.0000
Epoch 3/100
81/81 [==============================] - 0s 243us/step - loss: 1.9447 - accuracy: 0.9136 - val_loss: 1.1876 - val_accuracy: 1.0000
Epoch 4/100
81/81 [==============================] - 0s 265us/step - loss: 1.9393 - accuracy: 0.9136 - val_loss: 1.1819 - val_accuracy: 1.0000
...
Epoch 100/100
81/81 [==============================] - 0s 324us/step - loss: 2.2733 - accuracy: 0.9136 - val_loss: 1.8151 - val_accuracy: 0.9524
Ist 9 Quadratzahl [[ 0.07645273 -0.27839324]]
Ist 64 Quadratzahl [[0.06014035 0.12270345]]
102/102 [==============================] - 0s 108us/step
Verlust, Genauigkeit Trainingsdaten 1.1971028131597183 0.8333333134651184
26/26 [==============================] - 0s 2ms/step
Verlust, Genauigkeit Testdaten 1.4804003238677979 0.807692289352417
=> Fazit: so lassen sich die Quadratzahlen wie 9 oder 64 schwer erkennen anhand der beiden Ausgabewerte.
Caffe2
Dieses framework für neuronale Netze arbeitet deutlich anders als tensorflow2.Hier gibt es einen workspace, in welchem
Daten als sog. Blobs abgelegt werden. Mit der Klasse Net kann man anhand der Blobs ein neuronales Netz erstellen
Intern wird ein Netz als Protobuf-Struktur abgelegt, damit kann man CNN-Modelle leicht austauschen.
import numpy as np
from caffe2.python import core, workspace
from caffe2.proto import caffe2_pb2
workspace.FeedBlob("merkmale", merkmale, device_option=None)
workspace.FeedBlob("labels", labels, device_option=None)
net = core.Net("Ein Cafe Network fuer Quadtratzahlen")
X = net.ConstantFill([], ["merkmale"], mean=0.0, std=1.0, shape=[1,n], run_once=0)
W = net.GaussianFill([], ["gewichte"], mean=0, std=1, shape=[n,2], run_once=0)
b = net.ConstantFill([], ["labels"], shape=[2], value=merkmale, run_once=0)
Y = net.FC([X,W,b], ["Y"])
#finalLabelVector = np.zeros((1,2))
#finalLabelVector[0,b] = 1
if true:
workspace.CreateNet(net)
for i in range(1000):
workspace.RunNet(net.Proto().name)
else:
for i in range(1000):
workspace.RunNetOnce(net) # langsamer !
#backwardpassData = net.backward(**{net.outputs[0]: finalLabelVector})
#delta = backwardpassData['merkmale']
Oder mit fertigen Modellen von Caffe2:
man braucht die Definition des Netztes und Eingabegewichte im Protobuf-Format, z.B. am Zoo-Modell(Zoo).
with open("init_net.pb") as f:
init_net = f.read()
with open("predict_net.pb") as f:
predict_net = f.read()
p = workspace.Predictor(init_net, predict_net)
#
predict_net.name = "quadratic_predict"
data = np.array([1,0,0,1])
workspace.FeedBlob("data", data)
workspace.RunNetOnce(init_net)
workspace.CreateNet(predict_net)
p = workspace.Predictor(init_net.SerializeToString(), predict_net.SerializeToString())
Natürlich muss man oben noch ein Training machen, was die Gewichte anpasst.
Vorverarbeitung/Filterung
Hier müssen data scientists unterstützen, indem Modelle entwickelt werden,
- welche Teilmenge z.B. von Sensordaten beim Fahren relevant ist
- wie man Eingabedaten normieren kann
- Auswirkung von Pixelfehler, Rauschen
- welche Teilmerkmale stärker für Klassifikation ist
TODO im Aufbau, ist spannend ...
Deep Learning Netze
Netze mit mehr als einer verborgenen Schicht werden für deep learning verwendet. Damit kann
man schrittweise die Lernfähigkeit verbessern, weil mehr interner Speicher zum Lernen da ist, also
Gewichte.
Performance
Netze (Perzeptrons) mit mehreren Schichten sind zeitaufwändig zu trainieren, deshalb
lässt man die z.B. in einer cloud wie Microsoft azure berechnen, wo dann auch Graphikprozessoren (GPU)
wie z.B. von Nvidia schneller rechnen können. Hier ist auch das Verwenden von Vektoroperationen
sinnvoll, weshalb z.B. numpy verwendet wird.
Danksagung
Danke an Microsoft für die Bereitstellung von jupiter notebooks azure preview (bis 10/2020).
Danke an Bertrandt AG für die Möglichkeit des TechTalks mit skype und des Harri. Viel Erfolg !
Quellen (gelesener und empfehlenswerter Bücher)
| Kürzel | Autor | Titel | Verlag |
| [NgZe18] | Chi Nhan Nguyen, Oliver Zeigermann | Machine Learning kurz&gut | O'Really 1. Auflage 2018 |
| [RaMi18] | Sebastian Raschka, Vahid Mirjalili | Machine Learning mit Python | MITP-Verlag 2.Auflage 2018 |