{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "provenance": []
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    },
    "language_info": {
      "name": "python"
    }
  },
  "cells": [
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "oKiN_ZdLvPFI"
      },
      "outputs": [],
      "source": [
        "# Import Required Libraries\n",
        "import tensorflow as tf\n",
        "from tensorflow.keras.models import Sequential\n",
        "from tensorflow.keras.layers import Flatten, Dense\n",
        "from tensorflow.keras.callbacks import EarlyStopping\n",
        "import matplotlib.pyplot as plt\n",
        "\n",
        "# Load and Preprocess the Dataset\n",
        "(x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data()\n",
        "\n",
        "x_train = x_train / 255.0\n",
        "x_test = x_test / 255.0"
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# Build the Neural Network\n",
        "model = Sequential([\n",
        "    Flatten(input_shape=(28, 28)),\n",
        "    Dense(128, activation=\"relu\"),\n",
        "    Dense(10, activation=\"softmax\")\n",
        "])\n",
        "\n",
        "model.compile(\n",
        "    optimizer=\"adam\",\n",
        "    loss=\"sparse_categorical_crossentropy\",\n",
        "    metrics=[\"accuracy\"]\n",
        ")"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "7MCHHP7r1Giw",
        "outputId": "5d44744a-0d3c-4d3f-f639-a165b2507f93"
      },
      "execution_count": 2,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stderr",
          "text": [
            "/usr/local/lib/python3.12/dist-packages/keras/src/layers/reshaping/flatten.py:37: UserWarning: Do not pass an `input_shape`/`input_dim` argument to a layer. When using Sequential models, prefer using an `Input(shape)` object as the first layer in the model instead.\n",
            "  super().__init__(**kwargs)\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# Create the Early Stopping Callback\n",
        "early_stopping = EarlyStopping(\n",
        "    monitor=\"val_loss\",\n",
        "    patience=3,\n",
        "    restore_best_weights=True\n",
        ")\n",
        "\n",
        "# Train the Model with Early Stopping\n",
        "history = model.fit(\n",
        "    x_train,\n",
        "    y_train,\n",
        "    epochs=20,\n",
        "    batch_size=32,\n",
        "    validation_split=0.2,\n",
        "    callbacks=[early_stopping],\n",
        "    verbose=1\n",
        ")"
      ],
      "metadata": {
        "id": "0uzyzw8P1TcJ"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "# Evaluate the Model\n",
        "test_loss, test_accuracy = model.evaluate(x_test, y_test)\n",
        "\n",
        "print(f\"Test Loss: {test_loss:.4f}\")\n",
        "print(f\"Test Accuracy: {test_accuracy:.4f}\")\n",
        "\n",
        "# Visualize the Training Process\n",
        "plt.figure(figsize=(8, 5))\n",
        "\n",
        "plt.plot(history.history[\"loss\"], label=\"Training Loss\")\n",
        "plt.plot(history.history[\"val_loss\"], label=\"Validation Loss\")\n",
        "\n",
        "plt.xlabel(\"Epoch\")\n",
        "plt.ylabel(\"Loss\")\n",
        "plt.title(\"Training and Validation Loss\")\n",
        "plt.legend()\n",
        "\n",
        "plt.show()"
      ],
      "metadata": {
        "id": "mtm4DC-w1ZXh"
      },
      "execution_count": null,
      "outputs": []
    }
  ]
}