Zum Inhalt springen

Neuronales Netzwerk mit MNIST und TensorFlow

    Dieser Code zeigt, wie ein künstliches neuronales Netzwerk mit dem MNIST-Datensatz trainiert wird, um handgeschriebene Ziffern (0-9) zu klassifizieren. Ziel ist es, dass das Modell anhand der Bilddaten vorhersagen kann, welche Ziffer abgebildet ist.

    Dies wird erreicht durch:
    1. Laden und Vorverarbeiten der MNIST-Bilddaten.
    2. Erstellen eines neuronalen Netzwerks mit mehreren Schichten (Layers).
    3. Trainieren des Netzwerks mit Trainingsdaten.
    4. Evaluieren der Leistung des Modells auf Testdaten.
    5. Testen des Modells auf neuen Beispieldaten.

    Das Klassifizieren von Ziffern ist ein klassisches maschinelles Lernproblem, das Anfängern hilft, die Grundlagen neuronaler Netzwerke zu verstehen. Der MNIST-Datensatz ist ideal, da er klein genug ist, um schnell trainiert zu werden, aber dennoch komplex genug, um sinnvolle Modelle zu erstellen.

    Visualisierung des Modells

    try:
    # TensorFlow ist eine Open-Source-Bibliothek für maschinelles Lernen und neuronale Netzwerke.
    # Sie bietet die grundlegenden Werkzeuge, um Modelle zu erstellen, zu trainieren und zu evaluieren.
    import tensorflow as tf

    # Keras ist eine High-Level-API (Programmierschnittstelle), die ursprünglich als eigenständiges Framework für maschinelles Lernen entwickelt wurde, jedoch inzwischen vollständig in TensorFlow integriert ist.
    # Keras hilft, Netzwerke auf einfache und intuitive Weise zu definieren.
    # `Sequential` ist eine einfache API in Keras, um neuronale Netzwerke zu definieren.
    # Damit können Schichten (Layers) nacheinander in einer linearen Reihenfolge (Sequenziell) hinzugefügt werden.
    from tensorflow.keras import Sequential

    # Dense, Flatten, Input sind verschiedene Schichttypen:
    # - Dense: Vollständig verbundene Schicht. Jedes Neuron ist mit allen Neuronen der vorherigen Schicht verbunden.
    # - Flatten: Diese Schicht reduziert die Dimension der Daten. Bei Bildern bedeutet dies, dass ein zweidimensionales Bild (z. B. 28x28 Pixel) in eine eindimensionale Liste von Zahlen umgewandelt wird.
    # Diese Umwandlung ist notwendig, damit die Dense-Schichten die Daten verarbeiten können.
    # - Input: Definiert die Form der Eingabedaten, z. B. 28x28 Pixel für Bilder.
    from tensorflow.keras.layers import Dense, Flatten, Input

    # Adam ist ein Algorithmus zur Optimierung der Gewichte im Netzwerk, um Fehler zu minimieren.
    from tensorflow.keras.optimizers import Adam

    except ModuleNotFoundError as e:
    print("TensorFlow ist nicht installiert. Installieren Sie es mit: pip install tensorflow")
    raise SystemExit

    # 1. Datensatz laden
    # Der MNIST-Datensatz enthält handgeschriebene Ziffern von 0 bis 9. Jedes Bild ist 28x28 Pixel groß und in Graustufen (0-255).
    (x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data()

    # 2. Daten vorverarbeiten
    # Die Pixelwerte bzw. Graustufen der Bilder liegen ursprünglich im Bereich von 0 bis 255. 0 bedeutet schwarz und 255 bedeutet weiß.
    # Um die Daten für das neuronale Netzwerk besser nutzbar zu machen, werden sie auf den Bereich 0 bis 1 normalisiert. Dies geschieht durch Division jedes Pixelwerts durch 255.0.
    # Vorteile der Normalisierung:
    # - Verbesserte Stabilität während des Trainings (verhindert numerische Probleme).
    # - Schnellere Konvergenz (das Modell lernt schneller, da kleinere Werte stabiler verarbeitet werden).
    x_train = x_train / 255.0
    x_test = x_test / 255.0

    # 3. Labels überprüfen
    # Labels geben an, welche Ziffer jedes Bild darstellt (z. B. 0, 1, ..., 9). Die ersten 10 Labels aus den Trainingsdaten werden angezeigt.
    # Dies dient dazu, die Labels zu verifizieren und sicherzustellen, dass die Daten korrekt geladen wurden.
    print("Beispiel-Label aus den Trainingsdaten:", y_train[:10])

    # 4. Modell definieren
    # Hier wird ein neuronales Netzwerk mit der Sequential-API erstellt.
    # Jede Schicht verarbeitet die Daten und reicht sie an die nächste weiter.
    # Verarbeitet bedeutet:
    # - Jede Schicht wendet eine mathematische Funktion auf die Eingaben an, z. B. Multiplikation mit Gewichten und Addition eines Bias.
    # - Aktivierungsfunktionen wie "relu" führen Nichtlinearitäten ein, um komplexe Muster zu lernen.
    #
    # Die Schichten im Netzwerk:
    # - Input: Legt fest, dass jedes Bild 28x28 Pixel groß ist d.h. es werden 28*28=784 input Neuronen benötigt.
    # - Flatten: Wandelt das Bild (2D) in eine flache Liste (784 Werte), damit es von Dense-Schichten verarbeitet werden kann.

    # Das Netzwerk hat 3 Dense-Layers (Architektur), wobei jede Schicht ihre eigene spezifische Rolle im Lernprozess übernimmt.
    # Layer 1: Dense(128, activation='relu')
    # - Diese Schicht hat 128 Neuronen. Jedes dieser Neuronen ist mit allen Neuronen der vorherigen Schicht (der Eingabedaten oder der Flatten-Schicht) verbunden.
    # - Es extrahiert Muster oder Merkmale aus den Daten und verwendet die ReLU-Aktivierungsfunktion, um nur positive Werte weiterzugeben.

    # Layer 2: Dense(64, activation='relu')
    # - Diese Schicht hat 64 Neuronen, die auf den Ausgaben von Layer 1 arbeiten. Sie verdichten und filtern die Informationen aus Layer 1.
    # - Auch hier wird die ReLU-Aktivierung verwendet, um komplexe Beziehungen in den Daten zu lernen.

    # Layer 3: Dense(10, activation='softmax')
    # - Diese Schicht hat 10 Neuronen, die jeweils einer Klasse (den Ziffern 0 bis 9) entsprechen
    # - Sie verwendet die Softmax-Aktivierungsfunktion, die sicherstellt, dass die Ausgaben als Wahrscheinlichkeiten interpretiert werden können. Die Summe der Ausgaben beträgt immer 1.
    model = Sequential([
    Input(shape=(28, 28)),
    Flatten(),
    # Layer 1 (128 Neuronen): Lernt viele Merkmale aus den Rohdaten.
    Dense(128, activation='relu'),
    # Layer 2 (64 Neuronen): Verdichtet die Merkmale aus Layer 1.
    Dense(64, activation='relu'),
    # Layer 3 (10 Neuronen): Gibt Wahrscheinlichkeiten für jede der 10 Klassen (Ziffern 0 bis 9) zurück.
    Dense(10, activation='softmax')
    ])

    # 5. Modell kompilieren
    # - optimizer=Adam: Optimierungsalgorithmus, der die Gewichte im Netzwerk anpasst, um den Fehler zu minimieren.
    # - loss=sparse_categorical_crossentropy: Verlustfunktion für Klassifikationsprobleme.
    # Ein Klassifikationsproblem liegt vor, wenn das Ziel darin besteht, Daten einer von mehreren Kategorien (hier Ziffern 0-9) zuzuordnen.
    # Der "Verlust" ist eine Zahl, die angibt, wie weit die Vorhersage des Modells von der tatsächlichen Antwort entfernt ist.
    # - metrics=['accuracy']: Metriken sind Kennzahlen, die die Leistung des Modells bewerten. "accuracy" misst den Prozentsatz der korrekt vorhergesagten Ziffern.
    model.compile(
    optimizer=Adam(learning_rate=0.001),
    loss='sparse_categorical_crossentropy',
    # Accuracy misst die Genauigkeit des Modells, also den Prozentsatz der richtig klassifizierten Datenpunkte. Die Range reicht von 0 bis 1.
    # 0.0 bedeutet: Keine Vorhersage war korrekt. 1.0 bedeutet: Alle Vorhersagen waren korrekt.
    # Bei der Ausgabe bedeutet z.B. 0.8790, dass 87,90 % der Daten korrekt klassifiziert wurden.
    metrics=['accuracy']
    )

    # 6. Modell trainieren
    # - epochs=5: Das Modell durchläuft die gesamten Trainingsdaten 5-mal. Jede Wiederholung wird als "Epoche" bezeichnet. Mehr Epochen geben dem Modell mehr Chancen, Muster in den Daten zu lernen.
    # - batch_size=32: Die Daten werden in Gruppen (Batches) von 32 Bildern verarbeitet. Dies reduziert den Speicherbedarf und beschleunigt die Berechnungen, da nicht alle Daten gleichzeitig geladen werden.
    # - validation_data: Testdaten werden während des Trainings verwendet, um die Leistung zu bewerten, ohne die Gewichte anzupassen.
    history = model.fit(x_train, y_train, epochs=5, batch_size=32, validation_data=(x_test, y_test))

    # 7. Modell evaluieren
    # - model.evaluate: Misst den Verlust (Fehler) und die Genauigkeit auf den Testdaten.
    # Verlust gibt an, wie gut oder schlecht das Modell ist, und Genauigkeit zeigt den Prozentsatz korrekt klassifizierter Ziffern.
    # Loss misst den Fehler des Modells während des Trainings. Es gibt an, wie weit die Vorhersagen des Modells von den tatsächlichen Labels entfernt sind.
    # Ob ein Loss-Wert „gut“ oder „schlecht“ ist, hängt vom Problem ab. Für MNIST ist ein Loss von unter 0.1 in der Regel gut.
    test_loss, test_accuracy = model.evaluate(x_test, y_test, verbose=2)
    print(f"\nTest Accuracy: {test_accuracy * 100:.2f}%")

    # 8. Modell testen
    # Vorhersage für ein einzelnes Bild. Gibt Wahrscheinlichkeiten für jede Ziffer (0-9) zurück.
    # Jede "Klasse" entspricht hier einer Ziffer (z. B. Klasse 0 für Ziffer 0, Klasse 1 für Ziffer 1 usw.).
    import numpy as np
    sample_image = x_test[0].reshape(1, 28, 28)
    prediction = model.predict(sample_image)
    predicted_label = np.argmax(prediction)
    print(f"\nVorhersage: {predicted_label}")
    print(f"Tatsächliches Label: {y_test[0]}")

    # Zusätzliche Tests
    # Testet 10 Bilder aus den Testdaten.
    def test_multiple_images(model, images, labels, num_tests=5):
    for i in range(min(num_tests, len(images))):
    img = images[i].reshape(1, 28, 28)
    pred = np.argmax(model.predict(img))
    print(f"Bild {i 1}: Vorhergesagt: {pred}, Tatsächlich: {labels[i]}")

    test_multiple_images(model, x_test, y_test, num_tests=10)


    # Eine Verbesserung des Modells zeigt sich durch:
    # - Sinkenden Loss: Sowohl loss als auch val_loss sollten kleiner werden.
    # - Steigende Accuracy: Sowohl accuracy als auch val_accuracy sollten größer werden.
    mnist.py

    Bash Ausgabe

    (tensorflow) PS C:\sources\ki> python mnist.py
    Beispiel-Label aus den Trainingsdaten: [5 0 4 1 9 2 1 3 1 4]
    2025-01-31 22:49:47.380377: I tensorflow/core/platform/cpu_feature_guard.cc:193] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations: AVX AVX2
    To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.
    2025-01-31 22:49:47.875419: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1616] Created device /job:localhost/replica:0/task:0/device:GPU:0 with 9388 MB memory: -> device: 0, name: NVIDIA GeForce RTX 4070 Ti, pci bus id: 0000:01:00.0, compute capability: 8.9
    Epoch 1/5
    2025-01-31 22:49:48.901733: I tensorflow/stream_executor/cuda/cuda_blas.cc:1614] TensorFloat-32 will be used for the matrix multiplication. This will only be logged once.
    1875/1875 [==============================] - 3s 1ms/step - loss: 0.2411 - accuracy: 0.9305 - val_loss: 0.1258 - val_accuracy: 0.9602
    Epoch 2/5
    1875/1875 [==============================] - 2s 1ms/step - loss: 0.1012 - accuracy: 0.9696 - val_loss: 0.1035 - val_accuracy: 0.9669
    Epoch 3/5
    1875/1875 [==============================] - 3s 1ms/step - loss: 0.0709 - accuracy: 0.9785 - val_loss: 0.0857 - val_accuracy: 0.9730
    Epoch 4/5
    1875/1875 [==============================] - 3s 1ms/step - loss: 0.0532 - accuracy: 0.9829 - val_loss: 0.0915 - val_accuracy: 0.9725
    Epoch 5/5
    1875/1875 [==============================] - 3s 2ms/step - loss: 0.0419 - accuracy: 0.9862 - val_loss: 0.0718 - val_accuracy: 0.9793
    313/313 - 0s - loss: 0.0718 - accuracy: 0.9793 - 314ms/epoch - 1ms/step

    Test Accuracy: 97.93%
    1/1 [==============================] - 0s 94ms/step

    Vorhersage: 7
    Tatsächliches Label: 7
    1/1 [==============================] - 0s 10ms/step
    Bild 1: Vorhergesagt: 7, Tatsächlich: 7
    1/1 [==============================] - 0s 9ms/step
    Bild 2: Vorhergesagt: 2, Tatsächlich: 2
    1/1 [==============================] - 0s 11ms/step
    Bild 3: Vorhergesagt: 1, Tatsächlich: 1
    1/1 [==============================] - 0s 12ms/step
    Bild 4: Vorhergesagt: 0, Tatsächlich: 0
    1/1 [==============================] - 0s 10ms/step
    Bild 5: Vorhergesagt: 4, Tatsächlich: 4
    1/1 [==============================] - 0s 10ms/step
    Bild 6: Vorhergesagt: 1, Tatsächlich: 1
    1/1 [==============================] - 0s 10ms/step
    Bild 7: Vorhergesagt: 4, Tatsächlich: 4
    1/1 [==============================] - 0s 10ms/step
    Bild 8: Vorhergesagt: 9, Tatsächlich: 9
    1/1 [==============================] - 0s 11ms/step
    Bild 9: Vorhergesagt: 5, Tatsächlich: 5
    1/1 [==============================] - 0s 10ms/step
    Bild 10: Vorhergesagt: 9, Tatsächlich: 9
    (tensorflow) PS C:\sources\ki>
    Bash Ausgabe

    Erklärung der Bash Ausgabe

    Das sind die tatsächlichen Ziffern (Labels) der ersten zehn Bilder aus dem MNIST-Trainingsdatensatz.Dies dient dazu, die Labels zu verifizieren und sicherzustellen, dass die Daten korrekt geladen wurden.

    Beispiel-Label aus den Trainingsdaten: [5 0 4 1 9 2 1 3 1 4]

    Diese Meldung bedeutet, dass TensorFlow die CPU-Beschleunigungsfeatures AVX und AVX2 erkennt und nutzt.

    2025-01-31 22:49:47.380377: I tensorflow/core/platform/cpu_feature_guard.cc:193] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations:  AVX AVX2
    To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.

    TensorFlow erkennt und nutzt die NVIDIA GeForce RTX 4070 Ti als GPU für das Training. Compute Capability 8.9 bedeutet, dass die GPU Tensor Cores und andere CUDA-optimierte Berechnungen unterstützt.

    2025-01-31 22:49:47.875419: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1616] Created device /job:localhost/replica:0/task:0/device:GPU:0 with 9388 MB memory:  -> device: 0, name: NVIDIA GeForce RTX 4070 Ti, pci bus id: 0000:01:00.0, compute capability: 8.9

    Epoch 1/5 bedeutet, dass die erste von fünf Trainingsepochen beginnt.
    1875/1875 zeigt, dass das Modell alle 60.000 Trainingsbilder in 1875 Batches mit je 32 Bildern verarbeitet hat.
    Dauer: 3 Sekunden
    Loss (Fehlerrate auf Trainingsdaten): 0.2411
    Accuracy (Genauigkeit auf Trainingsdaten): 93.05%
    val_loss (Fehlerrate auf Validierungsdaten): 0.1258
    val_accuracy (Genauigkeit auf Validierungsdaten): 96.02%

    Epoch 1/5
    2025-01-31 22:49:48.901733: I tensorflow/stream_executor/cuda/cuda_blas.cc:1614] TensorFloat-32 will be used for the matrix multiplication. This will only be logged once.
    1875/1875 [==============================] - 3s 1ms/step - loss: 0.2411 - accuracy: 0.9305 - val_loss: 0.1258 - val_accuracy: 0.9602

    Schon nach der ersten Epoche hat das Modell eine sehr hohe Genauigkeit von 93% auf den Trainingsdaten und 96% auf den Testdaten. Das Modell verbessert sich mit jeder Epoche. Epoch 5: Die endgültige Genauigkeit ist 98.62% auf den Trainingsdaten und 97.93% auf den Testdaten.

    Epoch 2/5
    1875/1875 [==============================] - 2s 1ms/step - loss: 0.1012 - accuracy: 0.9696 - val_loss: 0.1035 - val_accuracy: 0.9669
    Epoch 3/5
    1875/1875 [==============================] - 3s 1ms/step - loss: 0.0709 - accuracy: 0.9785 - val_loss: 0.0857 - val_accuracy: 0.9730
    Epoch 4/5
    1875/1875 [==============================] - 3s 1ms/step - loss: 0.0532 - accuracy: 0.9829 - val_loss: 0.0915 - val_accuracy: 0.9725
    Epoch 5/5
    1875/1875 [==============================] - 3s 2ms/step - loss: 0.0419 - accuracy: 0.9862 - val_loss: 0.0718 - val_accuracy: 0.9793

    Das Modell wird mit den Testdaten geprüft (10.000 Bilder). Genauigkeit: 97.93% auf den Testdaten. Das bedeutet, dass das Modell in 97.93% der Fälle die richtige Ziffer vorhersagt.

    313/313 - 0s - loss: 0.0718 - accuracy: 0.9793 - 314ms/epoch - 1ms/step

    Test Accuracy: 97.93%

    Ein einzelnes Testbild wurde dem Modell gegeben. Modell sagt: 7

    1/1 [==============================] - 0s 94ms/step
    Vorhersage: 7
    Tatsächliches Label: 7