{"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":[{"sourceId":5048,"databundleVersionId":868335,"sourceType":"competition"}],"dockerImageVersionId":31260,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-01-29T12:58:43.376314Z","iopub.execute_input":"2026-01-29T12:58:43.376629Z","iopub.status.idle":"2026-01-29T13:02:02.969012Z","shell.execute_reply.started":"2026-01-29T12:58:43.376596Z","shell.execute_reply":"2026-01-29T13:02:02.967844Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import classification_report, confusion_matrix\nimport cv2\nimport os\nimport tensorflow as tf\nfrom tensorflow import keras\nfrom tensorflow.keras import layers\nfrom tensorflow.keras.applications import MobileNetV2, EfficientNetB0\nimport warnings\nwarnings.filterwarnings('ignore')\n\n# Suppress TF warnings and enable mixed precision\nos.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'\ntf.get_logger().setLevel('ERROR')\nfrom tensorflow.keras import mixed_precision\nmixed_precision.set_global_policy('mixed_float16')\n\n# Set random seeds for reproducibility\nnp.random.seed(42)\ntf.random.set_seed(42)\n\n# ============================================================================\n# 1. CONFIGURATION\n# ============================================================================\n\nclass Config:\n    # Paths\n    TRAIN_DIR = '/kaggle/input/state-farm-distracted-driver-detection/imgs/train'\n    TEST_DIR = '/kaggle/input/state-farm-distracted-driver-detection/imgs/test'\n    \n    # Image settings\n    IMG_SIZE = (224, 224)  \n    BATCH_SIZE = 64        \n    \n    # Training settings\n    EPOCHS = 20\n    LEARNING_RATE = 0.001\n    \n    # Classes\n    CLASSES = ['c0', 'c1', 'c2', 'c3', 'c4', 'c5', 'c6', 'c7', 'c8', 'c9']\n    CLASS_NAMES = {\n        'c0': 'Safe driving',\n        'c1': 'Texting - right',\n        'c2': 'Talking on phone - right',\n        'c3': 'Texting - left',\n        'c4': 'Talking on phone - left',\n        'c5': 'Operating radio',\n        'c6': 'Drinking',\n        'c7': 'Reaching behind',\n        'c8': 'Hair and makeup',\n        'c9': 'Talking to passenger'\n    }\n\nconfig = Config()\n\nprint(\"GPU Available:\", len(tf.config.list_physical_devices('GPU')))\n\n# ============================================================================\n# 2. DATA EXPLORATION\n# ============================================================================\n\ndef explore_dataset():\n    \"\"\"Explore the dataset structure and distribution\"\"\"\n    print(\"Dataset Structure:\")\n    print(\"=\" * 50)\n    \n    class_counts = {}\n    for class_name in config.CLASSES:\n        class_path = os.path.join(config.TRAIN_DIR, class_name)\n        if os.path.exists(class_path):\n            count = len(os.listdir(class_path))\n            class_counts[class_name] = count\n            print(f\"{class_name} ({config.CLASS_NAMES[class_name]}): {count} images\")\n    \n    print(f\"\\nTotal training images: {sum(class_counts.values())}\")\n    \n    # Visualize distribution\n    plt.figure(figsize=(12, 6))\n    plt.bar(class_counts.keys(), class_counts.values(), color='steelblue')\n    plt.xlabel('Class')\n    plt.ylabel('Number of Images')\n    plt.title('Distribution of Training Images')\n    plt.xticks(rotation=45)\n    for i, (k, v) in enumerate(class_counts.items()):\n        plt.text(i, v + 50, str(v), ha='center')\n    plt.tight_layout()\n    plt.show()\n    \n    return class_counts\n\n# Explore dataset\nclass_counts = explore_dataset()\n\n# ============================================================================\n# 3. DISPLAY SAMPLE IMAGES\n# ============================================================================\n\ndef display_samples(num_samples=2):\n    \"\"\"Display sample images from each class\"\"\"\n    fig, axes = plt.subplots(len(config.CLASSES), num_samples, \n                             figsize=(num_samples*3, len(config.CLASSES)*3))\n    \n    for i, class_name in enumerate(config.CLASSES):\n        class_path = os.path.join(config.TRAIN_DIR, class_name)\n        images = os.listdir(class_path)[:num_samples]\n        \n        for j, img_name in enumerate(images):\n            img_path = os.path.join(class_path, img_name)\n            img = cv2.imread(img_path)\n            img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n            \n            axes[i, j].imshow(img)\n            axes[i, j].axis('off')\n            if j == 0:\n                axes[i, j].set_title(f\"{class_name}: {config.CLASS_NAMES[class_name]}\", \n                                     fontsize=10)\n    \n    plt.tight_layout()\n    plt.show()\n\ndisplay_samples(num_samples=3)\n\n# ============================================================================\n# 4. DATA PREPARATION\n# ============================================================================\n\ndef create_dataframe():\n    \"\"\"Create DataFrame with image paths and labels\"\"\"\n    data = []\n    for class_name in config.CLASSES:\n        class_path = os.path.join(config.TRAIN_DIR, class_name)\n        for img_name in os.listdir(class_path):\n            img_path = os.path.join(class_path, img_name)\n            data.append({\n                'filepath': img_path,\n                'class': class_name,\n                'class_name': config.CLASS_NAMES[class_name],\n                'label': config.CLASSES.index(class_name)\n            })\n    \n    df = pd.DataFrame(data)\n    print(f\"Total images loaded: {len(df)}\")\n    return df\n\ndf = create_dataframe()\n\n# Split data into train and validation\ntrain_df, val_df = train_test_split(df, test_size=0.2, \n                                     stratify=df['class'], \n                                     random_state=42)\n\nprint(f\"Training samples: {len(train_df)}\")\nprint(f\"Validation samples: {len(val_df)}\")\n\n# ============================================================================\n# 5. FAST DATA PIPELINE\n# ============================================================================\n\ndef load_and_preprocess_image(filepath, label):\n    \"\"\"Load and preprocess image - OPTIMIZED\"\"\"\n    img = tf.io.read_file(filepath)\n    img = tf.image.decode_jpeg(img, channels=3)\n    img = tf.image.resize(img, config.IMG_SIZE)\n    img = img / 255.0\n    return img, label\n\ndef augment(img, label):\n    \"\"\"Data augmentation - OPTIMIZED\"\"\"\n    img = tf.image.random_flip_left_right(img)\n    img = tf.image.random_brightness(img, 0.2)\n    img = tf.image.random_contrast(img, 0.8, 1.2)\n    # Random rotation\n    img = tf.image.rot90(img, k=tf.random.uniform(shape=[], minval=0, maxval=4, dtype=tf.int32))\n    return img, label\n\n# Create tf.data datasets\nAUTOTUNE = tf.data.AUTOTUNE\n\ndef create_dataset(dataframe, is_training=True):\n    \"\"\"Create optimized tf.data dataset\"\"\"\n    filepaths = dataframe['filepath'].values\n    labels = dataframe['label'].values\n    \n    dataset = tf.data.Dataset.from_tensor_slices((filepaths, labels))\n    \n    if is_training:\n        dataset = dataset.shuffle(buffer_size=1000)\n    \n    dataset = dataset.map(load_and_preprocess_image, num_parallel_calls=AUTOTUNE)\n    \n    if is_training:\n        dataset = dataset.map(augment, num_parallel_calls=AUTOTUNE)\n    \n    dataset = dataset.batch(config.BATCH_SIZE)\n    dataset = dataset.prefetch(AUTOTUNE)\n    dataset = dataset.cache() \n    \n    return dataset\n\ntrain_dataset = create_dataset(train_df, is_training=True)\nval_dataset = create_dataset(val_df, is_training=False)\n\nprint(\"\\n✅ Using optimized tf.data pipeline (2-3x faster than ImageDataGenerator)\")\n\n# ============================================================================\n# 6. MODEL BUILDING\n# ============================================================================\n\ndef create_model(model_name='mobilenet'):\n    \"\"\"Create model using transfer learning\"\"\"\n    \n    if model_name == 'mobilenet':\n        base_model = MobileNetV2(\n            input_shape=(*config.IMG_SIZE, 3),\n            include_top=False,\n            weights='imagenet'\n        )\n    elif model_name == 'efficientnet':\n        base_model = EfficientNetB0(\n            input_shape=(*config.IMG_SIZE, 3),\n            include_top=False,\n            weights='imagenet'\n        )\n    \n    # Freeze base model\n    base_model.trainable = False\n    \n    # Build model\n    model = keras.Sequential([\n        base_model,\n        layers.GlobalAveragePooling2D(),\n        layers.BatchNormalization(),\n        layers.Dropout(0.5),\n        layers.Dense(256, activation='relu'),\n        layers.BatchNormalization(),\n        layers.Dropout(0.3),\n        layers.Dense(128, activation='relu'),\n        layers.Dropout(0.2),\n        layers.Dense(len(config.CLASSES), activation='softmax', dtype='float32') \n    ])\n    \n    return model\n\n# Create model\nmodel = create_model('mobilenet')\nmodel.summary()\n\n# ============================================================================\n# 7. COMPILE MODEL\n# ============================================================================\n\nmodel.compile(\n    optimizer=keras.optimizers.Adam(learning_rate=config.LEARNING_RATE),\n    loss='sparse_categorical_crossentropy',  # Using sparse for integer labels\n    metrics=['accuracy', keras.metrics.SparseTopKCategoricalAccuracy(k=3, name='top_3_accuracy')]\n)\n\n# ============================================================================\n# 8. CALLBACKS\n# ============================================================================\n\ncallbacks = [\n    # Early stopping\n    keras.callbacks.EarlyStopping(\n        monitor='val_loss',\n        patience=5,\n        restore_best_weights=True\n    ),\n    \n    # Reduce learning rate\n    keras.callbacks.ReduceLROnPlateau(\n        monitor='val_loss',\n        factor=0.5,\n        patience=3,\n        min_lr=1e-7,\n        verbose=1\n    ),\n    \n    # Model checkpoint\n    keras.callbacks.ModelCheckpoint(\n        'best_model.h5',\n        monitor='val_accuracy',\n        save_best_only=True,\n        verbose=1\n    )\n]\n\n# ============================================================================\n# 9. TRAINING\n# ============================================================================\n\nprint(\"\\n\" + \"=\"*50)\nprint(\"Starting OPTIMIZED training...\")\nprint(\"Expected: ~3-5 min/epoch (vs 20+ min before)\")\nprint(\"=\"*50 + \"\\n\")\n\nhistory = model.fit(\n    train_dataset,\n    epochs=config.EPOCHS,\n    validation_data=val_dataset,\n    callbacks=callbacks,\n    verbose=1\n)\n\n# ============================================================================\n# 10. PLOT TRAINING HISTORY\n# ============================================================================\n\ndef plot_history(history):\n    \"\"\"Plot training history\"\"\"\n    fig, axes = plt.subplots(1, 2, figsize=(15, 5))\n    \n    # Accuracy\n    axes[0].plot(history.history['accuracy'], label='Train Accuracy')\n    axes[0].plot(history.history['val_accuracy'], label='Val Accuracy')\n    axes[0].set_title('Model Accuracy')\n    axes[0].set_xlabel('Epoch')\n    axes[0].set_ylabel('Accuracy')\n    axes[0].legend()\n    axes[0].grid(True)\n    \n    # Loss\n    axes[1].plot(history.history['loss'], label='Train Loss')\n    axes[1].plot(history.history['val_loss'], label='Val Loss')\n    axes[1].set_title('Model Loss')\n    axes[1].set_xlabel('Epoch')\n    axes[1].set_ylabel('Loss')\n    axes[1].legend()\n    axes[1].grid(True)\n    \n    plt.tight_layout()\n    plt.show()\n\nplot_history(history)\n\n# ============================================================================\n# 11. EVALUATION\n# ============================================================================\n\n# Evaluate on validation set\nval_loss, val_acc, val_top3 = model.evaluate(val_dataset)\nprint(f\"\\nValidation Results:\")\nprint(f\"Loss: {val_loss:.4f}\")\nprint(f\"Accuracy: {val_acc:.4f}\")\nprint(f\"Top-3 Accuracy: {val_top3:.4f}\")\n\n# Get predictions\ny_pred = []\ny_true = []\n\nfor images, labels in val_dataset:\n    predictions = model.predict(images, verbose=0)\n    y_pred.extend(np.argmax(predictions, axis=1))\n    y_true.extend(labels.numpy())\n\ny_pred = np.array(y_pred)\ny_true = np.array(y_true)\n\n# Classification report\nprint(\"\\nClassification Report:\")\nprint(classification_report(y_true, y_pred, \n                          target_names=[config.CLASS_NAMES[c] for c in config.CLASSES]))\n\n# ============================================================================\n# 12. CONFUSION MATRIX\n# ============================================================================\n\ndef plot_confusion_matrix(y_true, y_pred):\n    \"\"\"Plot confusion matrix\"\"\"\n    cm = confusion_matrix(y_true, y_pred)\n    \n    plt.figure(figsize=(12, 10))\n    sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',\n                xticklabels=[config.CLASS_NAMES[c] for c in config.CLASSES],\n                yticklabels=[config.CLASS_NAMES[c] for c in config.CLASSES])\n    plt.title('Confusion Matrix')\n    plt.ylabel('True Label')\n    plt.xlabel('Predicted Label')\n    plt.xticks(rotation=45, ha='right')\n    plt.yticks(rotation=0)\n    plt.tight_layout()\n    plt.show()\n\nplot_confusion_matrix(y_true, y_pred)\n\n# ============================================================================\n# 13. PREDICT ON SINGLE IMAGE\n# ============================================================================\n\ndef predict_image(img_path, model):\n    \"\"\"Predict class for a single image\"\"\"\n    img = cv2.imread(img_path)\n    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n    img_resized = cv2.resize(img, config.IMG_SIZE)\n    img_array = img_resized / 255.0\n    img_array = np.expand_dims(img_array, axis=0)\n    predictions = model.predict(img_array, verbose=0)\n    predicted_class = config.CLASSES[np.argmax(predictions)]\n    confidence = np.max(predictions) * 100\n    plt.figure(figsize=(10, 6))\n    plt.imshow(img)\n    plt.axis('off')\n    plt.title(f\"Predicted: {config.CLASS_NAMES[predicted_class]}\\n\"\n              f\"Confidence: {confidence:.2f}%\", fontsize=14)\n    plt.tight_layout()\n    plt.show()\n    top_3_idx = np.argsort(predictions[0])[-3:][::-1]\n    print(\"\\nTop 3 Predictions:\")\n    for i, idx in enumerate(top_3_idx, 1):\n        class_name = config.CLASSES[idx]\n        prob = predictions[0][idx] * 100\n        print(f\"{i}. {config.CLASS_NAMES[class_name]}: {prob:.2f}%\")\n    return predicted_class, confidence\nsample_img = val_df.iloc[0]['filepath']\npredict_image(sample_img, model)\n\n# ============================================================================\n# 14. FINE-TUNING\n# ============================================================================\n\ndef fine_tune_model(model, base_model_name='mobilenet'):\n    \"\"\"Fine-tune the model by unfreezing some layers\"\"\"\n    model.layers[0].trainable = True\n    if base_model_name == 'mobilenet':\n        fine_tune_at = 100\n    else:\n        fine_tune_at = 150\n    for layer in model.layers[0].layers[:fine_tune_at]:\n        layer.trainable = False\n    model.compile(\n        optimizer=keras.optimizers.Adam(learning_rate=config.LEARNING_RATE/10),\n        loss='sparse_categorical_crossentropy',\n        metrics=['accuracy', keras.metrics.SparseTopKCategoricalAccuracy(k=3)]\n    )\n    \n    return model\n\n# ============================================================================\n# 15. SAVE MODEL\n# ============================================================================\n\nmodel.save('distracted_driver_model.h5')\nprint(\"\\nModel saved as 'distracted_driver_model.h5'\")\nprint(\"\\n\" + \"=\"*50)\nprint(\"Training Complete!\")\nprint(\"=\"*50)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-29T15:50:56.947322Z","iopub.execute_input":"2026-01-29T15:50:56.947608Z","iopub.status.idle":"2026-01-29T15:57:21.685016Z","shell.execute_reply.started":"2026-01-29T15:50:56.947582Z","shell.execute_reply":"2026-01-29T15:57:21.684402Z"}},"outputs":[],"execution_count":null}]}