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, 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ürzelAutor TitelVerlag
[NgZe18]Chi Nhan Nguyen, Oliver ZeigermannMachine Learning kurz&gut O'Really 1. Auflage 2018
[RaMi18]Sebastian Raschka, Vahid MirjaliliMachine Learning mit PythonMITP-Verlag 2.Auflage 2018