Verschachtelte neuronale Netzwerke (Nested Models, Transfer-Learning)

Einleitung

Mit steigender Komplexität von Deep-Learning-Projekten werden modulare, wiederverwendbare Architekturen immer wichtiger. Insbesondere beim Transfer Learning (die Übertragen von bestehenden in neue neuronale Netzwerken) und Data Augmentation (künstliche Erweiterung des Training-Datensatzes) ist es notwendig bzw. sinnvoll, die einzelnen Schichten zu gruppieren und zu verschachteln. Auch lassen sich Schichten nicht nur „aufeinander“ staplen, sondern parallel anordnen. TensorFlow/Keras bietet hierfür eine leistungsfähige Methode: Verschachtelte Layers und Modelle – auch bekannt als Nested Layers/Models.

Dieser Beitrag erklärt:

  • die Funktionsweise von verschachtelten Layers und Modellen,
  • deren Einsatzmöglichkeiten in der Praxis,
  • Kombination von Sequential() und Functional API von TensorFlow/Keras
  • konkrete Beispiele inklusive Data Augmentation und Transfer Learning,
  • Vorteile, Herausforderungen und Best Practices.

Definition: Nested Layers/Models

In den bisherigen Tutorials wurden die Netzwerke immer durch die Sequential()-Funktion erzeugt. Mit dieser können die Schichten einfach aufeinander gestapelt werden, was für einfache und übersichtliche neuronale Netzwerke die beste Erstellungsoption ist. In TensorFlow/Keras sind aber sowohl Layers als auch Modelle sogenannte Callables. Sie lassen sich deshalb wie Funktionen auf Eingabedaten anwenden. Dadurch ist es z.B. möglich, ein Modell als Teil eines anderen Modells zu verwenden – eine Technik, die als Verschachtelung (Nesting) bzw. Functional-API-Modell bezeichnet wird.

Konkret bedeutet das:

  • Ein Sequential()-Modell kann als Layer in ein Functional-API-Modell eingebettet werden.
  • Vorgefertigte Modelle (z. B. InceptionV3, MobileNetV2) können für das Transfer-Learning modular integriert werden.
  • Auch individuell erstellte Submodelle lassen sich verschachteln und mehrfach nutzen.

Beispiel 1: Data Augmentation als verschachtelter Layer

Problemstellung

Data Augmentation soll nicht außerhalb des Modells, sondern direkt in der Modellarchitektur erfolgen, z. B. um GPU-Beschleunigung zu nutzen oder Prozesse zu standardisieren.

Lösung

Ein Sequential()-Modell wird als Verschachtelung für Augmentierungs-Layers verwendet und in ein Functional-API-Modell integriert.

import tensorflow as tf

data_augmentation = tf.keras.Sequential([
    tf.keras.layers.RandomFlip("horizontal"),
    tf.keras.layers.RandomRotation(0.4),
    tf.keras.layers.RandomZoom(0.2),
], name="data_augmentation")

base_model = tf.keras.applications.MobileNetV2(input_shape=(150,150,3),
                                               include_top=False,
                                               weights='imagenet')
base_model.trainable = False

inputs = tf.keras.Input(shape=(150,150,3))
x = data_augmentation(inputs)
x = base_model(x)
x = tf.keras.layers.GlobalAveragePooling2D()(x)
outputs = tf.keras.layers.Dense(1, activation='sigmoid')(x)

model = tf.keras.Model(inputs, outputs)
model.summary()

Mit dieser Struktur werden Daten bei jeder Batch-Verarbeitung augmentiert, ohne dass ein separater Preprocessing-Schritt nötig ist. Das verschachtelte Sequential()-Modell wird hierbei wie ein Layer behandelt.

Beispiel 2: Extraktion von Layern aus dem neuronalen Netzwerk

Auf der keras-Dokumentation (https://keras.io/api/models/model/) findet sich ein besonders schönes Beispiel:

inputs = keras.Input(shape=(None, None, 3))
processed = keras.layers.RandomCrop(width=128, height=128)(inputs)
conv = keras.layers.Conv2D(filters=32, kernel_size=3)(processed)
pooling = keras.layers.GlobalAveragePooling2D()(conv)
feature = keras.layers.Dense(10)(pooling)

full_model = keras.Model(inputs, feature)
backbone = keras.Model(processed, conv)
activations = keras.Model(conv, feature)

Das Netzwerk ist so einfach, dass man es auch mit Sequential() erstellen könnte, aber es wird in diesem Beispiel mit der Functional API gebaut. Es ist ersichtlich, dass jeweils die Ausgaben einer Schicht an die nächste Schicht übergeben werden. Diese „Übergabe-Tensore“ enthalten – für den Programmierer nicht direkt ersichtliche -Informationen, wie sie entstanden sind, so dass die Funktion keras.Model() sie nutzen kann um alle Schichten zu erzeugen. Das vollständige Netzwerk ist hier full_model und kann wie bei einem aus Sequential() entstandenen Model trainiert werden. Darüberhinaus kann man in die Ergebnisse der Conv2D-Schicht extrahieren in dem man backbone nutzt (nützlich um z.B. die von der Conv2D-Schicht gefalteten Bilder zu visualisieren und zu überprüfen welche Features hier extrahiert werden wie z.B. Kantenschärfung etc.).


Visualisierung – verschachtelte Modelle analysieren

Die Funktion plot_model() zeigt die Modellstruktur grafisch und unterstützt die Darstellung verschachtelter Modelle:

tf.keras.utils.plot_model(model, show_shapes=True, expand_nested=True)

Die Option expanded_nested=True sorgt dafür, dass alle Submodelle vollständig sichtbar sind (diese Option gibt es auch bei der Methode summary()).


Vorteile verschachtelter Layers/Modelle

VorteilBeschreibung
ModularisierungSubmodelle lassen sich mehrfach verwenden und leicht warten
EffizienzAugmentation und Preprocessing werden GPU-beschleunigt
FlexibilitätIntegration komplexer Strukturen (z. B. mehrere Inputs/Outputs)
KompatibilitätVolle Unterstützung durch model.fit(), Speichern

Best Practices

EmpfehlungHinweis
Klare BenennungSubmodelle sollten mit name=… gekennzeichnet werden
VisualisierungMit summary() oder plot_model() verschachtelte Strukturen prüfen
Separates TestenSubmodelle sollten unabhängig getestet werden
Modell-Speicherung beachtenmodel.save() speichert auch verschachtelte Modelle vollständig

Herausforderungen

Bei stark verschachtelten Strukturen kann die Übersichtlichkeit leiden. Eine saubere Dokumentation und strukturierte Benennung aller Submodelle helfen, die Wartbarkeit auch in größeren Projekten sicherzustellen.


Nach oben scrollen