{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "provenance": []
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    },
    "language_info": {
      "name": "python"
    }
  },
  "cells": [
    {
      "cell_type": "code",
      "source": [
        "import pickle\n",
        "import numpy as np\n",
        "import os\n",
        "import tensorflow as tf\n",
        "from tensorflow.keras.utils import to_categorical\n",
        "from tensorflow.keras.preprocessing.image import ImageDataGenerator\n",
        "from tensorflow.keras import layers, models\n",
        "from sklearn.model_selection import train_test_split"
      ],
      "metadata": {
        "collapsed": true,
        "id": "coBwT6yHEyET"
      },
      "execution_count": 8,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "extract_path = r'cifar-10-python\\cifar-10-batches-py'\n",
        "\n",
        "def load_batch(batch_filename):\n",
        "    with open(batch_filename, 'rb') as f:\n",
        "        dict = pickle.load(f, encoding='bytes')\n",
        "        images = dict[b'data']\n",
        "        labels = dict[b'labels']\n",
        "        images = images.reshape(-1, 3, 32, 32).transpose(0, 2, 3, 1)\n",
        "        return images, labels\n",
        "\n",
        "# 2. Load all data\n",
        "x_train, y_train = [], []\n",
        "for i in range(1, 6):\n",
        "    data_batch = os.path.join(extract_path, f'data_batch_{i}')\n",
        "    images, labels = load_batch(data_batch)\n",
        "    x_train.append(images)\n",
        "    y_train += labels\n",
        "\n",
        "x_train = np.concatenate(x_train)\n",
        "y_train = np.array(y_train)\n",
        "\n",
        "# Load test batch\n",
        "x_test, y_test = load_batch(os.path.join(extract_path, 'test_batch'))\n",
        "y_test = np.array(y_test)\n",
        "\n",
        "# Normalize\n",
        "x_train, x_test = x_train / 255.0, x_test / 255.0\n",
        "y_train_cat = to_categorical(y_train, 10)\n",
        "y_test_cat = to_categorical(y_test, 10)"
      ],
      "metadata": {
        "id": "kfKNFE5eGoNo"
      },
      "execution_count": 9,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "# 3. Split train into train/validation\n",
        "x_train, x_val, y_train_cat, y_val_cat = train_test_split(\n",
        "    x_train, y_train_cat, test_size=0.2, random_state=42\n",
        ")"
      ],
      "metadata": {
        "id": "M5-sPyXCGeDK"
      },
      "execution_count": 10,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "# 4. Data augmentation\n",
        "datagen = ImageDataGenerator(\n",
        "    rotation_range=15,\n",
        "    width_shift_range=0.1,\n",
        "    height_shift_range=0.1,\n",
        "    horizontal_flip=True,\n",
        "    zoom_range=0.1\n",
        ")\n",
        "datagen.fit(x_train)"
      ],
      "metadata": {
        "id": "NSLLMOI3GzSQ"
      },
      "execution_count": 11,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "# 5. Build model\n",
        "model = models.Sequential([\n",
        "    layers.Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3)),\n",
        "    layers.MaxPooling2D(2, 2),\n",
        "    layers.Conv2D(64, (3, 3), activation='relu'),\n",
        "    layers.MaxPooling2D(2, 2),\n",
        "    layers.Conv2D(128, (3, 3), activation='relu'),\n",
        "    layers.Flatten(),\n",
        "    layers.Dense(128, activation='relu'),\n",
        "    layers.Dense(10, activation='softmax')\n",
        "])\n",
        "\n",
        "model.compile(optimizer='adam',\n",
        "              loss='categorical_crossentropy',\n",
        "              metrics=['accuracy'])"
      ],
      "metadata": {
        "id": "V6m_4qCfG0mh"
      },
      "execution_count": 12,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "# 6. Train model\n",
        "history = model.fit(\n",
        "    datagen.flow(x_train, y_train_cat, batch_size=64),\n",
        "    epochs=10,\n",
        "    validation_data=(x_val, y_val_cat)\n",
        ")"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "OVjV8KtnG2tI",
        "outputId": "4608acb7-8393-4dcf-fda7-d4a2fc09a330"
      },
      "execution_count": 13,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stderr",
          "text": [
            "Exception ignored in: <function _xla_gc_callback at 0x7c9c2823eb60>\n",
            "Traceback (most recent call last):\n",
            "  File \"/usr/local/lib/python3.11/dist-packages/jax/_src/lib/__init__.py\", line 96, in _xla_gc_callback\n",
            "    def _xla_gc_callback(*args):\n",
            "    \n",
            "KeyboardInterrupt: \n"
          ]
        },
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Epoch 1/10\n",
            "\u001b[1m625/625\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m79s\u001b[0m 123ms/step - accuracy: 0.3055 - loss: 1.8630 - val_accuracy: 0.4735 - val_loss: 1.4581\n",
            "Epoch 2/10\n",
            "\u001b[1m625/625\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m77s\u001b[0m 123ms/step - accuracy: 0.4821 - loss: 1.4293 - val_accuracy: 0.5702 - val_loss: 1.2072\n",
            "Epoch 3/10\n",
            "\u001b[1m625/625\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m81s\u001b[0m 122ms/step - accuracy: 0.5456 - loss: 1.2678 - val_accuracy: 0.6050 - val_loss: 1.1447\n",
            "Epoch 4/10\n",
            "\u001b[1m625/625\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m74s\u001b[0m 119ms/step - accuracy: 0.5823 - loss: 1.1765 - val_accuracy: 0.6205 - val_loss: 1.0881\n",
            "Epoch 5/10\n",
            "\u001b[1m625/625\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m75s\u001b[0m 120ms/step - accuracy: 0.6072 - loss: 1.1097 - val_accuracy: 0.6321 - val_loss: 1.0511\n",
            "Epoch 6/10\n",
            "\u001b[1m625/625\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m74s\u001b[0m 119ms/step - accuracy: 0.6261 - loss: 1.0612 - val_accuracy: 0.6890 - val_loss: 0.9018\n",
            "Epoch 7/10\n",
            "\u001b[1m625/625\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m79s\u001b[0m 126ms/step - accuracy: 0.6454 - loss: 1.0061 - val_accuracy: 0.6455 - val_loss: 1.0249\n",
            "Epoch 8/10\n",
            "\u001b[1m625/625\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m76s\u001b[0m 121ms/step - accuracy: 0.6556 - loss: 0.9678 - val_accuracy: 0.6838 - val_loss: 0.9276\n",
            "Epoch 9/10\n",
            "\u001b[1m625/625\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m74s\u001b[0m 119ms/step - accuracy: 0.6680 - loss: 0.9417 - val_accuracy: 0.7000 - val_loss: 0.8686\n",
            "Epoch 10/10\n",
            "\u001b[1m625/625\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m73s\u001b[0m 116ms/step - accuracy: 0.6767 - loss: 0.9129 - val_accuracy: 0.6907 - val_loss: 0.8937\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# 7. Evaluate on test set\n",
        "test_loss, test_acc = model.evaluate(x_test, y_test_cat, verbose=2)\n",
        "print(f\"Test accuracy: {test_acc:.4f}\")"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "7ssfhxE8G5wQ",
        "outputId": "8ff7cd59-118c-4aca-ff3c-123a61177f16"
      },
      "execution_count": 14,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "313/313 - 4s - 12ms/step - accuracy: 0.6897 - loss: 0.9111\n",
            "Test accuracy: 0.6897\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# 8. Save model\n",
        "model.save('cifar10_model.h5')\n",
        "print(\"Model saved as 'cifar10_model.h5'.\")"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "alThAiHrG7Co",
        "outputId": "84f3ba9e-8a7a-45fb-e044-19e5203f13f1"
      },
      "execution_count": 15,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stderr",
          "text": [
            "WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n"
          ]
        },
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Model saved as 'cifar10_model.h5'.\n"
          ]
        }
      ]
    }
  ]
}