{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceType":"competition","sourceId":3649,"databundleVersionId":46718}],"dockerImageVersionId":31329,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nfrom sklearn.model_selection import train_test_split\nimport tensorflow as tf\nfrom tensorflow import keras\nfrom tensorflow.keras import layers, datasets\nimport warnings\nfrom tensorflow.keras.layers import RandomFlip, RandomRotation, RandomZoom\n\nwarnings.filterwarnings('ignore')","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-05-18T11:34:09.574515Z","iopub.execute_input":"2026-05-18T11:34:09.574970Z","iopub.status.idle":"2026-05-18T11:34:38.500024Z","shell.execute_reply.started":"2026-05-18T11:34:09.574938Z","shell.execute_reply":"2026-05-18T11:34:38.499409Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 1. Load the CIFAR-10 dataset directly from Keras","metadata":{}},{"cell_type":"code","source":"from tensorflow.keras import datasets\n\n# Load CIFAR-10 dataset\n(X_train_full, y_train_full), (X_test, y_test) = datasets.cifar10.load_data()\n\n# Convert image data type to float32 for better processing in neural networks\nX_train_full = X_train_full.astype('float32')\nX_test = X_test.astype('float32')\n\n# Flatten labels from shape (n, 1) to (n,)\ny_train_full = y_train_full.flatten()\ny_test = y_test.flatten()\n\n# Print dataset shapes\nprint(f\"Training data shape: {X_train_full.shape}\")  # (50000, 32, 32, 3)\nprint(f\"Test data shape: {X_test.shape}\")            # (10000, 32, 32, 3)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-18T11:34:38.501307Z","iopub.execute_input":"2026-05-18T11:34:38.501965Z","iopub.status.idle":"2026-05-18T11:34:45.971814Z","shell.execute_reply.started":"2026-05-18T11:34:38.501938Z","shell.execute_reply":"2026-05-18T11:34:45.970916Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 2. Normalize pixel values (0–255 → 0–1)","metadata":{}},{"cell_type":"code","source":"X_train_full = X_train_full / 255.0\nX_test = X_test / 255.0","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-18T11:34:45.973008Z","iopub.execute_input":"2026-05-18T11:34:45.973397Z","iopub.status.idle":"2026-05-18T11:34:46.187686Z","shell.execute_reply.started":"2026-05-18T11:34:45.973358Z","shell.execute_reply":"2026-05-18T11:34:46.187040Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 3. Split training data into training and validation sets (80% / 20%)","metadata":{}},{"cell_type":"code","source":"\nX_train, X_val, y_train, y_val = train_test_split(\n    X_train_full,\n    y_train_full,\n    test_size=0.2,\n    random_state=42,\n    stratify=y_train_full\n)\n\n# Print dataset shapes\nprint(f\"Training set shape: {X_train.shape}, Validation set shape: {X_val.shape}\")\n\n# Print class distribution in training set\nprint(f\"Training label distribution: {np.bincount(y_train)}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-18T11:34:46.189087Z","iopub.execute_input":"2026-05-18T11:34:46.189363Z","iopub.status.idle":"2026-05-18T11:34:46.398353Z","shell.execute_reply.started":"2026-05-18T11:34:46.189343Z","shell.execute_reply":"2026-05-18T11:34:46.397657Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 4. Define class names","metadata":{}},{"cell_type":"code","source":"class_names = ['airplane', 'automobile', 'bird', 'cat', 'deer',\n               'dog', 'frog', 'horse', 'ship', 'truck']\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-18T11:34:46.399194Z","iopub.execute_input":"2026-05-18T11:34:46.399504Z","iopub.status.idle":"2026-05-18T11:34:46.402959Z","shell.execute_reply.started":"2026-05-18T11:34:46.399470Z","shell.execute_reply":"2026-05-18T11:34:46.402379Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 5. Visualization: sample images from each class","metadata":{}},{"cell_type":"code","source":"fig, axes = plt.subplots(5, 2, figsize=(8, 10))\n\nfor class_idx in range(10):\n    # Find all images belonging to the current class\n    indices = np.where(y_train == class_idx)[0]\n    \n    # Select the first image from that class\n    idx = indices[0] if len(indices) > 0 else 0\n    \n    # Convert class index to row and column position\n    row, col = class_idx // 2, class_idx % 2\n    \n    # Display the image\n    axes[row, col].imshow(X_train[idx])\n    axes[row, col].set_title(class_names[class_idx])\n    axes[row, col].axis('off')\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-18T11:34:46.404059Z","iopub.execute_input":"2026-05-18T11:34:46.404446Z","iopub.status.idle":"2026-05-18T11:34:46.827564Z","shell.execute_reply.started":"2026-05-18T11:34:46.404410Z","shell.execute_reply":"2026-05-18T11:34:46.826778Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 6. Check image samples (data shape and pixel value range)","metadata":{}},{"cell_type":"code","source":"\nprint(f\"Image min value: {X_train.min():.3f}, max value: {X_train.max():.3f}\")\nprint(f\"Mean: {X_train.mean():.3f}, Standard deviation: {X_train.std():.3f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-18T11:34:46.828724Z","iopub.execute_input":"2026-05-18T11:34:46.829005Z","iopub.status.idle":"2026-05-18T11:34:47.230657Z","shell.execute_reply.started":"2026-05-18T11:34:46.828981Z","shell.execute_reply":"2026-05-18T11:34:47.229710Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 1. Build CNN model","metadata":{}},{"cell_type":"code","source":"model = keras.Sequential([\n    layers.Input(shape=(32, 32, 3)),\n    RandomFlip('horizontal'),\n    RandomRotation(0.1),\n    RandomZoom(0.1),\n    \n    layers.Conv2D(64, (3, 3), activation='relu', padding='same'),\n    layers.MaxPooling2D(pool_size=(2, 2)),\n    \n    layers.Conv2D(128, (3, 3), activation='relu', padding='same'),\n    layers.MaxPooling2D(pool_size=(2, 2)),\n    \n    layers.Conv2D(256, (3, 3), activation='relu', padding='same'),\n    layers.MaxPooling2D(pool_size=(2, 2)),\n    \n    layers.Flatten(),\n    layers.Dense(256, activation='relu'),\n    layers.Dropout(0.5),\n    layers.Dense(10, activation='softmax')\n])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-18T11:34:47.231787Z","iopub.execute_input":"2026-05-18T11:34:47.232931Z","iopub.status.idle":"2026-05-18T11:34:50.338084Z","shell.execute_reply.started":"2026-05-18T11:34:47.232904Z","shell.execute_reply":"2026-05-18T11:34:50.337535Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 2. Compile the model\n","metadata":{}},{"cell_type":"code","source":"model.compile(\n    optimizer=keras.optimizers.Adam(learning_rate=0.001),\n    # Choose loss function\n    # Options: 'categorical_crossentropy', 'sparse_categorical_crossentropy'\n    loss='sparse_categorical_crossentropy',\n    metrics=['accuracy']\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-18T11:34:50.339015Z","iopub.execute_input":"2026-05-18T11:34:50.339294Z","iopub.status.idle":"2026-05-18T11:34:50.351179Z","shell.execute_reply.started":"2026-05-18T11:34:50.339265Z","shell.execute_reply":"2026-05-18T11:34:50.350595Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 3. Model summary","metadata":{}},{"cell_type":"code","source":"model.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-18T11:34:50.353211Z","iopub.execute_input":"2026-05-18T11:34:50.353884Z","iopub.status.idle":"2026-05-18T11:34:50.373485Z","shell.execute_reply.started":"2026-05-18T11:34:50.353861Z","shell.execute_reply":"2026-05-18T11:34:50.372890Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Early stopping (to prevent overfitting)","metadata":{}},{"cell_type":"code","source":"early_stop = keras.callbacks.EarlyStopping(\n    monitor='val_loss',\n    patience=10,\n    restore_best_weights=True\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-18T11:34:50.374415Z","iopub.execute_input":"2026-05-18T11:34:50.374638Z","iopub.status.idle":"2026-05-18T11:34:50.378053Z","shell.execute_reply.started":"2026-05-18T11:34:50.374619Z","shell.execute_reply":"2026-05-18T11:34:50.377443Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Training the model","metadata":{}},{"cell_type":"code","source":"history = model.fit(\n    X_train, y_train,\n    validation_data=(X_val, y_val),\n    epochs=100,\n    batch_size=128,  # CIFAR-10 has small images, so larger batch size is possible\n    callbacks=[early_stop],\n    verbose=1\n)\n\nprint(f\"Training complete! Total epochs run: {len(history.history['loss'])}\")\n\nimport pandas as pd\npd.DataFrame(history.history).tail(10)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-18T11:34:50.378872Z","iopub.execute_input":"2026-05-18T11:34:50.379181Z","iopub.status.idle":"2026-05-18T11:37:42.701575Z","shell.execute_reply.started":"2026-05-18T11:34:50.379119Z","shell.execute_reply":"2026-05-18T11:37:42.700907Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 1. Visualization: training & validation loss and accuracy\n","metadata":{}},{"cell_type":"code","source":"fig, axes = plt.subplots(1, 2, figsize=(12, 4))\n\naxes[0].plot(history.history['loss'], label='Train Loss')\naxes[0].plot(history.history['val_loss'], label='Val Loss')\naxes[0].set_xlabel('Epoch')\naxes[0].set_ylabel('Loss')\naxes[0].set_title('Model Loss')\naxes[0].legend()\naxes[0].grid(True)\n\naxes[1].plot(history.history['accuracy'], label='Train Acc')\naxes[1].plot(history.history['val_accuracy'], label='Val Acc')\naxes[1].set_xlabel('Epoch')\naxes[1].set_ylabel('Accuracy')\naxes[1].set_title('Model Accuracy')\naxes[1].legend()\naxes[1].grid(True)\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-18T11:37:42.986459Z","iopub.execute_input":"2026-05-18T11:37:42.986805Z","iopub.status.idle":"2026-05-18T11:37:43.274992Z","shell.execute_reply.started":"2026-05-18T11:37:42.986782Z","shell.execute_reply":"2026-05-18T11:37:43.274180Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 2. Final model evaluation","metadata":{}},{"cell_type":"code","source":"# Validation performance\nval_loss, val_acc = model.evaluate(X_val, y_val)\n\nprint(\"\\n=== Validation Performance ===\")\nprint(f\"Loss: {val_loss:.4f}\")\n\nprint(f\"Training accuracy (last epoch): {history.history['accuracy'][-1] * 100:.2f}%\")\n\nprint(f\"Improvement note: 75.67% → After data augmentation: {val_acc * 100:.2f}%\")\n\nprint(f\"Validation Accuracy: {val_acc:.4f} ({val_acc * 100:.2f}%)\")\n\n\n# Final test performance\ntest_loss, test_acc = model.evaluate(X_test, y_test)\n\nprint(\"\\n=== Final Test Performance ===\")\nprint(f\"Loss: {test_loss:.4f}\")\nprint(f\"Accuracy: {test_acc:.4f} ({test_acc * 100:.2f}%)\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-18T11:37:43.275850Z","iopub.execute_input":"2026-05-18T11:37:43.276038Z","iopub.status.idle":"2026-05-18T11:37:46.202434Z","shell.execute_reply.started":"2026-05-18T11:37:43.276020Z","shell.execute_reply":"2026-05-18T11:37:46.201839Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 3. Prediction probability analysis","metadata":{}},{"cell_type":"code","source":"# Predict class probabilities on validation set\ny_val_pred_proba = model.predict(X_val)\n\n# Convert probabilities → class labels\ny_val_pred = np.argmax(y_val_pred_proba, axis=1)\n\n# Compute prediction confidence (max probability per sample)\nconfidence = np.max(y_val_pred_proba, axis=1)\n\n# Print confidence statistics\nprint(\"\\nPrediction confidence:\")\nprint(f\"  Mean: {confidence.mean():.4f}\")\nprint(f\"  Min: {confidence.min():.4f}\")\nprint(f\"  Max: {confidence.max():.4f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-18T11:37:46.204079Z","iopub.execute_input":"2026-05-18T11:37:46.204383Z","iopub.status.idle":"2026-05-18T11:37:47.520038Z","shell.execute_reply.started":"2026-05-18T11:37:46.204361Z","shell.execute_reply":"2026-05-18T11:37:47.519181Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 1. Prediction (10 classes)","metadata":{}},{"cell_type":"code","source":"# Predict class probabilities on validation set\ny_val_pred_proba = model.predict(X_val)\n\n# Convert probabilities → class labels\ny_val_pred = np.argmax(y_val_pred_proba, axis=1)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-18T11:37:47.520975Z","iopub.execute_input":"2026-05-18T11:37:47.521328Z","iopub.status.idle":"2026-05-18T11:37:48.607197Z","shell.execute_reply.started":"2026-05-18T11:37:47.521291Z","shell.execute_reply":"2026-05-18T11:37:48.606509Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}