ML - Workshop 2; Protokoll

Reckmeyer/Aichinger-Fankhauser

In diesem Workshop haben wir wieder einige theoretische Aufgabenstellungen behandelt sowie die bereits begonnenen Tensorflow-Tutorials weitergefuehrt inkl. ersten Implementierungen.

Theoretisches

Theoretische Aufgabenstellung 1: Gradientenabstieg

Frage: “Versuche den Gradientenabstieg und seine Herausforderungen darzustellen - was entwickelt sich in der Literatur? Welche Besonderheiten konntet ihr identifizieren.”

Wird die Fehlermetrik (“Loss”) als Funktion definiert, dann ist klar, dass es fuer diese Funktion eine Loesung geben muss (oder mehrere), wo der Loss am geringsten ist. Ein lokales Minimum laesst sich ueber das Derivat identifizieren. Eine Kurve mit einer Steigung von 0 ist an einem lokalen Minimum (oder Maximum) angelangt. Nichts anderes, als diese zu suchen, macht der Gradientenabstieg. Die Gewichte innerhalb des neuronalen Netzes werden so angepasst, dass schrittweise in die Richtung des negativen Gradienten “abgestiegen” wird. Die Schrittweite wird dabei durch die Lernrate bestimmt (alpha) - wobei eine falsche Groessenordnung hier zu Problemen fuehren kann (overshooting, exploding, lange Konvergenzzeiten).

Was fuer eine Kurve gilt, gilt uebertragen auch fuer den Fehlerraum, der durch den Loss multipler Variablen aufgespannt wird. Die grosse Problematik: Wie wird verhindert, in lokalen Minima haengen zu bleiben? Das wird in diesem Artikel (https://www.notion.so/An-Introduction-to-Gradient-Descent-Towards-Data-Science-d9a9284ea4e5410181e890984b8e0ea1) anhand dreier Ansaetze gezeigt (Batch, Stochastic und Mini-batch gradient descent), die sich hauptsaechlich anhand der Menge an Daten unterscheiden, die fuer einzelne Trainingsschritte herangezogen werden. Mini-batch vereint dabei die Effizienz des stochastischen Ansatzes mit dem guten Ergebnis des Batch gradient descent.

How to build a three-layer neural network from scratch (https://medium.freecodecamp.org/building-a-3-layer-neural-network-from-scratch-99239c4af5d3): Dieser Code wurde versucht zu uebernehmen, aber einige Funktionen scheinen nicht definiert (“initialise_parameters” und “train”). Nachbau hat nach aktuellem Stand noch nicht funktioniert.

Theoretische Aufgabenstellung 2: Daten

“Wie viele Daten sind notwendig? Wo bekommt man diese? Wie gehen Cloud-Provider damit um?”:

Dass es sich nur mit grossen Datenmengen gut arbeiten laesst, ist ein Mythos. Oft liegt schlechte Planung zugrunde und ein Beduerfnis viel zu experimentieren. Im Vergleich zu frueher, braucht man nicht mehr so grosse Datenmengen, weil es fuer einige Bereiche bereits robuste Algorithmen gibt, die einfach weiterverwendet werden koennen. Ausserdem wird Rechenleistung immer guenstiger, eine modulare Bauweise von AI-Diensten kommt immer haeufiger vor und einige Provider bieten AI (Transfer learning) als auch die noetigen CPUs und GPUs ueber die Cloud an. Die Qualitaet der Daten spielt auch eine grosse Rolle. Mangelnde Qualitaet kann nicht einfach mit mehr Daten ausgeglichen werden. (How Much Training Data is Required for Machine Learning?: https://machinelearningmastery.com/much-training-data-required-machine-learning/)

Theoretische Aufgabenstellung 3: Architektur

“Wie geht man bei der Suche nach der”Idealen" Architektur vor? Welche Limitationen treten auf?"

NAS (Neural Architecture Search) ist eine auf Algorithmen basierende Herangehensweise, um die passende Architektur fuer ein neuronales Netzwerk zu finden. Ziel ist es, den Zeit- und Kostenaufwand beim Design zu verringern und eine bessere Performance zu erreichen. Es ist unmoeglich, die beste Architektur zu finden, ohne jede zu trainieren. Man kann sich auch nicht sicher sein, ob der Controller den Raum an moeglichen Architekturen effektiv durchsucht oder ob er Modelle bevorzugt, die in der Vergangenheit bereits gute Werte erzielt haben. (Neural Architecture Search - Limitations and Extensions: https://towardsdatascience.com/neural-architecture-search-limitations-and-extensions-8141bec7681f)

Praktisches

Im Rahmen des Software-Entwicklung Labs im letzten Semester haben wir einen Single Layer Perzeptron programiert und dabei auch schon den Tensorflow-Playground entdeckt. Mit diesem haben wir uns im 2. WS noch weiter beschaeftigt und versucht, verschiedene NN-Architekturen nachzuvollziehen (ebenfalls Beispiel Spirale).

Praktische Umsetzung 1: Lobe

Lobe installiert und auf Spielkarten trainiert. Mit Bildern aus dem Internet und einigen ueber die Webcam aufgenommene Bilder haben wir Lobe trainiert fuenf verschiedene Grundtypen des Kartenspiels zu erkennen. Dafuer dass es sich recht schnell einrichten und trainieren laesst, hat das schon ganz gut funktioniert - und das, obwohl die Trainingsdaten aus dem Internet ganz andere Voraussetzungen haben.

Lobe Test Lobe Test

Tensorflow Tutorials + Experimentieren

Praktische Umsetzung 2: Versuch Vanilla CNN mit Tensorflow

https://www.notion.so/Tensorflow-2-0-Create-and-Train-a-Vanilla-CNN-on-Google-Colab-c46e2b9a384a4446881abccd3ebd1ff1

Dieses Tutorial arbeitet mit Daten, auf die es keinen Zugriff mehr gibt. Es ist schwierig nachzuvollziehen, welches Datenset das Richtige ist (und ob es eines gibt), wenn man es von der deutschen Quelle holt. Zwar haben wir ein verwandtes Datenset (GTSRB: https://benchmark.ini.rub.de/?section=gtsrb&subsection=news) in ein Google-Drive geladen und verknuepft, aber schon beim entpacken hat sich herausgestellt, dass dieses unterschiedlich aufgebaut ist.

Praktische Umsetzung 3: DNN Klassifikation mit Tensorflow (2 versch. Datensets)

Hier wurde als Teil eines Tutorials eine Klassifikation des Iris-Datensatzes durchgefuehrt. Urspruenglich haben wir in PyCharm gearbeitet.

from __future__ import absolute_import, division, print_function, unicode_literals
import tensorflow as tf
import pandas as pd

# Zur uebung klassifizieren wir den bereits bekannten Iris-Datensatz

CSV_COLUMN_NAMES = ["SepalLength", "SepalWidth", "PetalLength", "PetalWidth", "Species"]
SPECIES = ["Setosa", "Versicolor", "Virginica"]

# Holen wir uns die Daten
train_path = tf.keras.utils.get_file("iris_training.csv", "http://download.tensorflow.org/data/iris_training.csv")
test_path = tf.keras.utils.get_file("iris_test.csv", "http://download.tensorflow.org/data/iris_test.csv")

train = pd.read_csv(train_path, names=CSV_COLUMN_NAMES, header=0)
test = pd.read_csv(test_path, names=CSV_COLUMN_NAMES, header=0)

train_y = train.pop("Species")
test_y = test.pop("Species")

# Input-Funktion definieren
def input_fn(features, labels, training=True, batch_size=256):
    # Inputs konvertieren
    dataset = tf.data.Dataset.from_tensor_slices((dict(features), labels))

    # Shuffeln
    if training:
        dataset = dataset.shuffle(1000).repeat()

    return dataset.batch(batch_size)

# Feature Spalten angeben
my_feature_columns = []
for key in train.keys():
    my_feature_columns.append(tf.feature_column.numeric_column(key=key))

classifier = tf.estimator.DNNClassifier(
    feature_columns=my_feature_columns,
    # Zwei Hidden-Layers
    hidden_units=[50,20],
    # Anzahl der Klassen
    n_classes=3,
    activation_fn=tf.nn.relu,
    optimizer='Adam')

# Training mit Angabe wie vieler Steps, statt Epochs
classifier.train(
    input_fn=lambda: input_fn(train, train_y, training=True), steps=150)

# Evalutation und Drucken der Accuracy
eval_result = classifier.evaluate(
    input_fn=lambda: input_fn(test, test_y, training=False))

print('\nTest Accuaracy: {accuracy:0.4f}\n'.format(**eval_result))

Wir haben hier mit der Anzahl der hidden units experimentiert, ebenso mit dem optimizer (z.B. Adam vs. Adagrad). Auch verschiedene activation functions haben wir ausprobiert und die Effekte auf das Resultat betrachtet. Die Intuition fehlt immer noch, wird aber besser.

Labelling 1Labelling 2

2. Datenset (Wein)

Wir haben danach versucht, das obige Beispiel auch mit einem anderen Datensatz zum Laufen zu bringen und haben uns dabei fuer den Wein-Datensatz entschieden, der von Daphne Cornelisse verwendet wird. (https://www.freecodecamp.org/news/building-a-3-layer-neural-network-from-scratch-99239c4af5d3/). Dabei hatten wir zuerst Probleme - die Fehlermeldungen liessen vermuten, dass die Klassenanzahl nicht uebereinstimmte (obwohl es sich ebenfalls um drei Klassen handelt). Am Ende haben wir festgestellt, dass Tensorflow erwartet, dass das Labelling der Klassen bei 0 beginnt und darum bei einer Zaehlung bis 3 von 4 Klassen ausgegangen ist. Der Code ist am Ende gelaufen und hat ab ca 600+ Steps zu einer Accuracy von 1.0 gefuehrt. Das liegt vermutlich daran, dass es sich um ein kleines Testdatenset mit vielen Features handelt.

Wine classifier step function Wince classifier accuracy

Beim Experimentieren haben sich knapp ueber 600 Steps als Grenze herausgestellt, wo die Accuracy von 1.0 noch tlw. unterschritten wird.

Praktische Umsetzung 4: Klassifkation mittels MNIST Fashion Datensatz

import tensorflow as tf
from tensorflow import keras

import numpy as np
import matplotlib.pyplot as plt

# Get Data
fashion = keras.datasets.fashion_mnist

# Split
(train_images, train_labels), (test_images, test_labels) = fashion.load_data()

# Klassen labeln
classes = ["T-Shirt", "Hose", "Pullover", "Kleid", "Mantel", "Sandalen", "Hemd", "Sneaker", "Tasche", "Stiefel"]

'''
plt.figure()
plt.imshow(train_images[55000])
plt.colorbar()
plt.grid(True)
plt.show()
'''

# Pre-Processing (um die Werte zwischen 0 und 1 zu bekommen)
train_images = train_images/255
test_images = test_images/255

# Model Architektur definieren (3 Layer)
model = keras.Sequential([
    keras.layers.Flatten(input_shape=(28, 28)), # input
    keras.layers.Dense(128, activation="tanh"), # hidden layer
    keras.layers.Dense(10, activation="softmax")]) # output layer

# Compile
model.compile(optimizer="Adagrad", loss="sparse_categorical_crossentropy", metrics=["accuracy"])

# Model trainieren
model.fit(train_images, train_labels, epochs=50)

# Model evaluieren
test_loss, test_acc = model.evaluate(test_images, test_labels, verbose=1)

print("Accuracy: " + str(test_acc))

Auch hier haben wir mit den verschiedenen Aktivierungsfunktionen sowie mit verschiedenen Layer-Anzahlen herumgespielt. Tanh hat weniger gute Ergebnisse im Training geliefert als ReLu, mehr als ein hidden Layer hat zu keiner Verbesserung gefuehrt. Auch diverse Optimizer haben wir ausprobiert. Wir konnten aber kaum Unterschiede feststellen und wollen uns diese noch weiter ansehen bzw. uns dazu einlesen. Beim Adaptieren der Epochenanzahl haben wir festgestellt, dass es schon sehr frueh zu einer hohen Accuracy am Trainings-Datenset kommt (mit Relu) und wir bald in den Bereich des Overfittings hineinkommen, wo die Accuracy am Test-Datenset sinkt (und beim Trainings-Datenset steigt).

12.03.2021