In diesem Kapitel lernen wir, wie man in Keras die Suche nach “guten” Hyperparametern automatisieren kann. Zur Erinnerung: Hyperparameter sind z.B. die Anzahl der Schichten, der Neuronen pro Schicht oder die Lernrate. Man nennt das automatisierte und systematische Suchen nach guten Hyperparametern Hyperparameter Tuning. Diese Methode erfordert viel Rechenpower und Zeit.
C.1 Motivation
Wenn man ein Neuronales Netz erstellt und später trainiert, muss man verschiedene Entscheidungen treffen:
Anzahl der Schichten
Typ einer Schicht (z.B. Dense vs. Conv2D)
Anzahl der Neuronen pro Schicht
Einfügen einer Dropout-Schicht (oder nicht)
Optimierungsmethode (SGD, Adam etc.)
Lernrate (zu Trainingsbeginn)
Diese Aspekte fallen alle unter den Begriff Hyperparameter, weil dies Parameter sind, die sich während des Trainings nicht ändern.
Wie trifft man diese Entscheidungen? In der Regel orientiert man sich an Netzen, die man schonmal gesehen hat oder die in wissenschaftlichen Publikationen dargestellt sind, und anschließend “probiert” man mehr oder weniger systematisch, an den Hyperparametern zu drehen (und protokolliert hoffentlich die jeweiligen Outcomes). Natürlich kommt man schnell auf die Idee, diesen Prozess zu automatisieren. Das nennt man auch Hyperparameter Tuning oder Hyperparameter Optimization.
/var/folders/lm/zb9jvwpj09551m21zr3dd8440000gn/T/ipykernel_62551/2350946801.py:2: DeprecationWarning: `import kerastuner` is deprecated, please use `import keras_tuner`.
from kerastuner import HyperModel
Objekt vom Typ HyperParameters
Wir erstellen ein Objekt vom Typ HyperParameters, das später Werte für unsere Hyperparameter (z.B. Anzahl der Neuronen einer Schicht).
hp = keras_tuner.HyperParameters()
Ein Objekt hp vom Typ HyperParameters hat mehrere Funktionen. Bei diesen Funktionen wird ein Wert vom entsprechenden Typ generiert:
hp.Int()
hp.Float()
hp.Boolean()
Beim Funktionsaufruf wird auch ein Bezeichner (z.B. “units”) übergeben, damit das Objekt die verschiedenen Werte unterscheiden kann (z.B. Neuronenanzahl für Schicht 2 und Schicht 3).
Bei der folgenden Funktion wird eine Menge von Werten mit einer Liste definiert:
hp.Choice()
Beispiel:
hp.Choice("activation", ["relu", "tanh"])
'relu'
Die komplette Liste von Funktionen und ihrer Parameter finden Sie hier: https://keras.io/api/keras_tuner/hyperparameters
C.3 Modell
Wir spielen alle Schritte anhand eines einfachen Versuchs durch, wo wir in einem Netz lediglich die Größe der versteckten Schicht ändern. Wir haben also einen einzigen Hyperparameter.
C.3.1 Daten (CIFAR-10)
Wir nehmen die CIFAR-10-Daten für unsere Versuche.
CIFAR-10 enthält 60000 Farbbilder (32x32x3) mit Abbildungen aus 10 Kategorien (= Label), z.B “ship” oder “dog”.
Wir definieren eine Funktion, die ein Modell mit Hilfe eine HyperParameter-Objekts baut. Das Objekt trifft die Entscheidung über die Hyperparameter des generierten Modells.
Wir spezifizieren den Input hier explizit, weil wir sonst die Funktion summary nicht aufrufen können.
from tensorflow.keras import Inputfrom tensorflow.keras.models import Sequentialfrom tensorflow.keras.layers import Dense, Flattendef build_model(hp): model = Sequential() model.add(Input(shape=train_x[0].shape)) model.add(Flatten()) model.add(Dense(hp.Int("num_hidden", min_value=50, max_value=1000, step=50), activation="relu")) model.add(Dense(10, activation="softmax")) model.compile(optimizer="adam", loss="categorical_crossentropy", metrics=["acc"])return model
Sanity check: Wird ein Modell erzeugt und wie sieht es aus?
model = build_model(hp)model.summary()
Metal device set to: Apple M1 Max
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
flatten (Flatten) (None, 3072) 0
dense (Dense) (None, 50) 153650
dense_1 (Dense) (None, 10) 510
=================================================================
Total params: 154,160
Trainable params: 154,160
Non-trainable params: 0
_________________________________________________________________
2022-06-21 18:08:26.965512: I tensorflow/core/common_runtime/pluggable_device/pluggable_device_factory.cc:305] Could not identify NUMA node of platform GPU ID 0, defaulting to 0. Your kernel may not have been built with NUMA support.
2022-06-21 18:08:26.965646: I tensorflow/core/common_runtime/pluggable_device/pluggable_device_factory.cc:271] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 0 MB memory) -> physical PluggableDevice (device: 0, name: METAL, pci bus id: <undefined>)
C.4 Tuning
C.4.1 Suchmethode
Keras bietet verschiedene Suchmethoden an, um den Raum der Hyperparameter zu durchlaufen:
RandomSearch
BayesianOptimization
Hyperband
RandomSearch
Wir wählen die einfachste Methode RandomSearch. Zunächst wird ein Objekt mit Konfigurationsdaten erstellt. Ein “Versuch” (trial) bezieht sich auf ein spezifisches Modell mit festgelegten Hyperparametern.
objective: Metrik, anhand der die Modelle bewertet werden sollen
max_trials: Maximale Anzahl der Versuche
executions_per_trial: Für jeden Versuche kann man mehrere Läufe anstellen
overwrite: Wenn man eine Suche fortsetzen möchte, kann man hier False angeben
directory: Hier werden Log-Informationen hineingeschrieben
Jetzt können wir die Suche starten. Für die Anzahl der Epochen nimmt man einen relativ niedrigen Wert, z.B. 4 oder 10, damit man auch viele Durchläufe in realistischer Zeit schafft. Wir haben wir nur wenige Durchläufe (6 Versuche). In einem realistischen Beispiel würde man die Anzahl der Versuche erhöhen. Eine Epochenzahl von 4-10 ist auch bei größeren Versuchen realistisch.
Während der Suche wird immer der bislang beste Wert angezeigt. Die Suche dauert natürlich etwas…
Mit der Funktion results_summary können Sie ausgeben, welche Versuche unternommen wurden, wie die jeweiligen Parameter gewählt wurden (hier nur “num_hidden”) und welche Performance erzielt wurde.
[<keras_tuner.engine.hyperparameters.HyperParameters at 0x31636ed30>,
<keras_tuner.engine.hyperparameters.HyperParameters at 0x3165031c0>,
<keras_tuner.engine.hyperparameters.HyperParameters at 0x314e134f0>]
2022-06-21 18:13:07.739950: I tensorflow/core/grappler/optimizers/custom_graph_optimizer_registry.cc:112] Plugin optimizer for device_type GPU is enabled.
2022-06-21 18:13:18.659267: I tensorflow/core/grappler/optimizers/custom_graph_optimizer_registry.cc:112] Plugin optimizer for device_type GPU is enabled.
Wir haben also herausgefunden, dass ein Netz mit 950 Neuronen besser performt als ein Netz mit weniger Neuronen. Weil wir die Suche auf 6 Trials beschränkt hatten, wurde ein Netz mit 1000 Neuronen gar nicht ausprobiert. Und natürlich gibt es eine Reihe von anderen Möglichkeiten, die Netzarchitektur oder das Training zu ändern, etwa mehrere Schichten oder eine andere Lernrate.
Mit dem gefundenen Netz haben wir ca. 48% auf den Testdaten erzielt.
Ganz allgemein können Sie mit Hyperparameter-Tuning praktisch alle Hyperparameter addressieren, sowohl für Feedforward-Netze als auch für Konvolutionsnetze.
Zu den wichtigsten Hyperparametern gehören sicherlich:
Anzahl der Schichten
Typ und Reihenfolge der Schichten (insbes. bei CNN: ConvLayer, Dense, Pooling)
Anzahl der Neuronen einer Schicht (bei Konv-Schichten auch Filtergröße und Filteranzahl, bei Pooling-Schichten Filtergröße und Stride)
Lernrate
Weitere Hyperparameter, die evtl. untersuchenswert sind: