Trainiere ein eignes Modell mit Keras 3

Download this notebook

Was ist Keras

Keras wurde im März 2015 von François Chollet veröffentlicht, um die Entwicklung von Deep-Learning-Modellen zu vereinfachen. Die eigenständige Pythonbibliothek wurde später zur offiziellen High-Level-API von TensorFlow, welches zur Integration mit dessen Ökosystem führte. Seither wird Keras in einer Vielzahl von Anwendungen im Bereich des Deep Learnings verwendet. Es zeichnet sich dabei vor allem als benutzerfreundliche API zur schnellen Prototypentwicklung aus. Neben der Unterstützung von TensorFlow wurden weitere Backend-Engines wie Theano oder das kommerzielle Microsoft Cognitive Toolkit unterstützt.

Keras 3.0

Am 28.11.2023 wurde Keras 3.0 für die Backend-Engines JAX, TensorFlow und PyTorch veröffentlicht. Die Multi-Framework Deep Learning API zeichnet sich vor allem durch eine Backend-unabhängige Struktur aus, ohne dafür Änderungen im Code vornehmen zu müssen. Die mögliche dynamische Anpassung sorgt dafür, dass Modelle immer mit der höchsten erreichbaren Effizienz trainiert werden können.

Dabei lassen sich Keras 3.0-Modelle nahtlos mit PyTorch, TensorFlow und JAX integrieren. Zudem können alle Modelle ohne Framework-Präferenz exportiert und von anderen Nutzern genutzt werden. Hierzu nutzt Keras 3.0 verschiedene Datenquellen (tf.data.Dataset, PyTorch, DataLoader, NumPy-Arrays und Pandas), welches das Training über Frameworks und Datentypen hinweg verbessert.

Keras 3 Car Price Prediction

In dem folgenden Beispiel wollen wir im ersten Abschnitt noch einmal auf das Beispiel aus den vorherigen Kapiteln Trainiere ein eigenes Modell mit TensorFlow und Einführung in Torch eingehen. Es bietet sich daher an, für das eigene Verständnis sowie die einfachere Einrichtung von Keras 3.0, diese Kapitel vorher zu bearbeiten.

Keras mit dem JAX Backend

In den vorherigen Notebooks haben wir bis jetzt das Modul: TensorFlow kennengelernt. Jedoch ist TensorFlow kein eigens Python-Paket, sondern in der Programmiersprache C geschrieben. Dadurch muss es für jede Python-Version neu aufgelegt (recompiled) werden. Um Kompatibilitätsproblemen mit Python 3.12 aus dem Weg zu gehen, nutzen wir die Python-Version 3.11.7. Deshalb wäre es ratsam, die Programmierumgebung JETZT anzupassen. Das bedeutet nicht, dass die bereits vorhandene Python-Version gelöscht werden soll. Dafür bietet es sich an, wenn möglich, eine virtuelle Umgebung in bspw. Visual Studies einzurichten. Als Backend für Keras 3.0 nutzen wir in den folgenden Abschnitten JAX.

Backend konfigurierung

Die Einrichtung des Backends muss vor der Installation von Keras 3.0 erfolgen. Hierfür rufen wir das Terminal auf und installieren mit dem bekannten Befehl pip das Paket JAX (pip install jax), TensorFlow oder PyTorch . Anschließend installieren wir mit pip install keras die aktuellste Keras-Version. Grund dafür ist, dass TensorFlow an Keras 2 gebunden ist, welche ab der Version 2.16 von TensorFlow aufgehoben ist.

Zudem ist es zu empfehlen, folgende Module und ggf. auch Keras durch ein Update zu aktualisieren:

KerasCV: Computer Vision Workflow mit pip install –upgrade keras-cv

KerasNLP: Natural Language Workflows mit –upgrade keras-nlp

Keras mit –upgrade keras

Jetzt sollte die Installation und Einrichtung des neuen Backends abgeschlossen sein. Sollte dies nicht der Fall sein, sollten Keras 3 erneut installiert werden.

pip uninstall Keras pip install Keras

import os
import jax 
os.environ["KERAS_BACKEND"] = "jax"
import keras
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import LabelEncoder, StandardScaler
from keras.models import Sequential
from keras.layers import Dense, Input
from keras import ops #load model

Laden von Daten

Wie auch schon in den vorigen Beispielen nutzen wir zum Einlesen unsere Daten die Methode read_csv aus dem Python-Package Pandas. Vergleichen wir jedoch die Vorbereitung von Daten in den anderen Kapiteln, so ist diese deutlich kürzer.

Mit data.shape lassen wir uns die Dimensionen oder die Form der Daten ausgeben. In unserem Beispiel enthält der Datensatz 15157 Zeilen (Autos) und neun Spalten (Merkmale).

data = pd.read_csv('../data/vw.csv')

data.shape

Weiter können wir uns auch einfach die Tabelle ausgeben lasssen. Dabei enthält die erste Zeile die Überschriften der neun Spalten

data.head()
print(data)

Merkmale und Zielvariable definieren

In dem folgenden Abschnitt werden die Merkmale (Featurs) aus den Daten extrahiert und in der Varibale “X” bespeichert. Der Preis als Zielvariabel wird in der Variable “Y” bespeichert. Dies ist für die Vorbereitung wichtig und unterschiedet sich daher zu anderen Beispielen, dass eine Konvertierung (Beispiel: TensorFlow) oder die Anpassung an einen Tensor (Beispiel: PyTorch) nicht erforderlich ist.

X = data[['model','year','transmission','mileage','fuelType','tax','mpg','engineSize']]
y = data['price']

Kodierung kategorischer Variablen

Die Datentabelle enthält neben numerischen Werten (bspw. 1.2 engineSize) auch kategorische Merkmale (Model, Getriebeart, Kraftstoff), welche qualitativen Merkmalen entspricht. Diese müssen für die Lesbarkeit in diskrete Klassen (bspw. 1, 2, 3) umgewandelt werden.

Mit pd.get_dummies(X) lassen sich die kategorischen Merkmale in Dummy-Variablen umwandeln. Dies ist auch unter One-Hot-Encoding oder 1-aus-n-Code bekannt. Für jede kategoriale Variable erstellt get_dummies() neue Spalten im DataFrame, wobei jede Spalte einer eindeutigen Kategorie entspricht. Wenn eine Zeile der ursprünglichen kategorialen Variable entspricht, ist der Wert in der entsprechenden Dummy-Spalte 1, andernfalls ist er 0. Diese Methode ist nützlich, wenn es keine natürliche Ordnung zwischen den Kategorien gibt, wie z. B. bei verschiedenen Autotypen.

X = pd.get_dummies(X)

Davon unterscheidet sich label_encoder(), welcher kategorialen Variablen mit natürlicher Reihenfolge z.B. verschiedenen Getriebetypen (manuell, automatisch usw.) eindeutigen Ganzzahlenwerten zuweist.

label_encoders = {}
for column in ['model','transmission', 'fuelType']:
    label_encoders[column] = LabelEncoder()
# Split dataset into train and test data
X_train, X_test, y_train, y_test = train_test_split(
    X, 
    y, 
    test_size=0.2, 
    random_state=42
    )
#Standardize numerical featurs
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

Erstellung und Training des Modells

Im folgenden Abschnitten wird das Keras-Modell für die Vorhersage des Autopreises definiert. Dafür wird mit input_shape = X_train_scaled.shape[1] die Anzahl der genutzten Spalten im skalierten Trainingsdatensatz angegeben. Weiter wird mit model = Sequential([]) das sequenzielle Keras-Modell deiniert. Hierbei handelt es sich um eine linerare Stapelung von Schichten (Layers).

Die erste Schicht (Input-Layer) des Modells ist die Eingabeschicht, in welchem das zuvor genutzte input_shape verwendet wird. Bei den folgenden Dense-Layern wird eine Anzahl von 64 Neuronen sowie die Aktivierungsfunktion activation= relu (ReLu = Rectified Linear Unit) definiert. Bei der ReLu-Funktion handelt es sich um eine nicht lineare Aktivierungsfunktion, welche in neuronalen Netzwerken häufig Verwendung findet. Mit dem letzten Layer Dense(1) ist die Ausgangsschicht mit einem Neuron definiert. Diese Schicht benötigt keine Aktivierungsfunktion, da sie einen kontinuierlichen Wert vorhersagen wollen. Anschließend wird mit model.summary() eine Zusammenfassung des Modells ausgegeben.

# Define the Keras model

input_shape = X_train_scaled.shape[1]

model = Sequential([
    Input(shape=(input_shape,)),
    Dense(64, activation='relu'),  # Adjusted input shape
    Dense(64, activation='relu'),
    Dense(1)  # Output layer (single neuron for regression)
])

model.summary()
Model: "sequential"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Layer (type)                     Output Shape                  Param # ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ dense (Dense)                   │ (None, 64)             │         2,560 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense_1 (Dense)                 │ (None, 64)             │         4,160 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense_2 (Dense)                 │ (None, 1)              │            65 │
└─────────────────────────────────┴────────────────────────┴───────────────┘
 Total params: 6,785 (26.50 KB)
 Trainable params: 6,785 (26.50 KB)
 Non-trainable params: 0 (0.00 B)
# Compile model
model.compile(
    optimizer='adam', 
    loss='mean_squared_error', 
    metrics=['mae'])
# Train model
model.fit(
    X_train_scaled, 
    y_train, 
    epochs=10, 
    batch_size=9, 
    validation_split=0.2
    )
# Evaluate model
loss, mae = model.evaluate(X_test_scaled, y_test)
print(f'Test Mean Absolute Error: {mae}')
# Make predictions
predictions = model.predict(X_test_scaled)

Um das evaluierte Modell zu speichern, verwenden wir model.save(name). Dies unterscheidet sich bei Keras 3 von bspw. Torch, wo wir alle unsere Encoder und Scaler separat dem Speichervorgang hinzufügen mussten.

model.save("../models/car_price_prediction_model.keras")

Verwendung des Modells

Das Modell wird bei Keras 3 einfach durch model = keras.models.load_model(name) geladen. Weiter werden die von uns bereits in den anderen Notebooks verwendeten Werte definiert.

model = keras.models.load_model(
    "../models/car_price_prediction_model.keras"
    )
# Define the input values
input_data = {
    'model': ['T-Roc'],
    'year': [2019],
    'transmission': ['manual'],
    'mileage': [10000],
    'fuelType': ['Petrol'],
    'tax': [145],
    'mpg': [49.6],
    'engineSize': [1.5]
}
input_df = pd.DataFrame(input_data)
print(input_df)
for column in ['model', 'transmission', 'fuelType']:
    input_df[column] = label_encoders[column].fit_transform(
        input_df[column]
        )

Preisvorhersage

# Make prediction
predicted_price = model.predict(X_test_scaled)[1][0]

print("Predicted price:", predicted_price)

Der Preis der Vorhersage liegt etwas unter den anderen Modellen. Ein Check auf Vergleichsportalen verrät uns aber, dass der Preis für ein Modell mit dieser Motorleitung jedoch realistisch ist.