{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.14","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":87323,"databundleVersionId":9934427,"sourceType":"competition"}],"dockerImageVersionId":30805,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# 🚗 CIDAUT AI Fake Scene Classification 2024\r\n\r\n## 📝 **Project Overview**\r\nWe are building an advanced binary classification model to distinguish between **real** and **fake** autonomous driving scenes. This project involves using **deep learning models** and **image processing techniques** to achieve high accuracy while adhering to Kaggle's evaluation metrics.\r\n\r\n---\r\n\r\n## 🎯 **Steps Completed**\r\n\r\n### 1️⃣ **Data Preparation**\r\n- 📂 Loaded the training dataset from `train.csv`.\r\n- 🔄 Mapped the `label` column values:\r\n  - `\"editada\"` ➡️ `0` (Fake).\r\n  - `\"real\"` ➡️ `1` (Real).\r\n- 🗂️ Loaded the test dataset from `sample_submission.csv` for inference.\r\n\r\n### 2️⃣ **Model Development**\r\n- 🏗️ Created an **AdvancedModel** using a pretrained `EfficientNet` backbone for feature extraction.\r\n- 🧠 Added custom layers to adapt the model for binary classification.\r\n- 📊 Utilized **Binary Cross-Entropy with Logits Loss** as the loss function.\r\n- 🛠️ Applied **AdamW Optimizer** for efficient gradient updates.\r\n\r\n### 3️⃣ **Training the Model**\r\n- 🔍 Split the dataset into training and validation sets.\r\n- 🎛️ Used **data augmentation** techniques to enhance generalization:\r\n  - Random flips.\r\n  - Brightness and contrast adjustments.\r\n  - Gaussian blur.\r\n- ⚙️ Performed training with mixed precision to optimize memory usage.\r\n- 🛑 Implemented **early stopping** to prevent overfitting.\r\n\r\n### 4️⃣ **Inference**\r\n- 🤖 Used the trained model to generate predictions for the test dataset.\r\n- ✅ Converted predictions to probabilities between 0 and 1.\r\n- 🔢 Ensured the `label` column in the submission file is of type `float`.\r\n\r\n### 5️⃣ **Submission**\r\n- 📤 Saved the test predictions in `submission.csv` following Kaggle’s required format:\r\n  ```csv\r\n  image,label\r\n  101.jpg,0.732\r\n  102.jpg,0.123\r\n  103.jpg,0.987\r\n  ```\r\n\r\n---\r\n\r\n## 🚀 **Next Steps**\r\n\r\n### 🔄 **Improvement Ideas**\r\n- Explore alternative pretrained models (e.g., `ResNet`, `ViT`) to compare performance.\r\n- Implement **fine-tuning** for better feature extraction.\r\n- Use advanced augmentation techniques like `MixUp` or `CutMix`.\r\n\r\n### 📈 **Evaluation Metrics**\r\n- Focus on maximizing **AUC-ROC** (Area Under the Curve - Receiver Operating Characteristics).\r\n- Monitor validation accuracy, loss, and F1 score.\r\n\r\n---\r\n\r\n## 🔧 **Technologies Used**\r\n- 🖥️ **Python** for implementation.\r\n- 📦 **PyTorch** for model development and training.\r\n- 🖼️ **Albumentations** for data augmentation.\r\n- 📊 **Pandas** for data manipulation.\r\n\r\n---\r\n\r\n## 🏁 **Current Status**\r\n- ✅ Model training completed with promising res0.0127\n  - **Validation AUC-ROC**: `1.0000`\r\n  - **Validation Loss**: `0.0097`\r\n- 📤 Submission file generated successfully.\r\n\r\n---\r\n\r\n### 🎉 **Great Work So Far!**\r\nKeep refining and experimenting to achieve the best results. 🚀\r\n\r\n","metadata":{}},{"cell_type":"markdown","source":"## 1. Installing Necessary Libraries","metadata":{}},{"cell_type":"code","source":"# Install required libraries\n!pip install torch torchvision albumentations timm pandas scikit-learn matplotlib tqdm torchmetrics opencv-python","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-12T10:23:42.133036Z","iopub.execute_input":"2024-12-12T10:23:42.133772Z","iopub.status.idle":"2024-12-12T10:23:53.314302Z","shell.execute_reply.started":"2024-12-12T10:23:42.133728Z","shell.execute_reply":"2024-12-12T10:23:53.313342Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 2. GPU Check","metadata":{}},{"cell_type":"code","source":"# Check GPU availability\n!nvidia-smi","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-12T10:23:53.316688Z","iopub.execute_input":"2024-12-12T10:23:53.317154Z","iopub.status.idle":"2024-12-12T10:23:54.437416Z","shell.execute_reply.started":"2024-12-12T10:23:53.317099Z","shell.execute_reply":"2024-12-12T10:23:54.436410Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"##  3. Importing Required Libraries","metadata":{}},{"cell_type":"code","source":"import os\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch.utils.data import DataLoader, Dataset, random_split\nimport torchvision.transforms as transforms\nfrom torchvision.models import resnet50, efficientnet_v2_s\nfrom albumentations.pytorch import ToTensorV2\nimport albumentations as A\nfrom sklearn.metrics import roc_auc_score, accuracy_score\nimport pandas as pd\nimport numpy as np\nfrom PIL import Image\nimport cv2\nimport matplotlib.pyplot as plt\nfrom tqdm import tqdm\nimport timm","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-12T10:23:54.438884Z","iopub.execute_input":"2024-12-12T10:23:54.439229Z","iopub.status.idle":"2024-12-12T10:24:06.419730Z","shell.execute_reply.started":"2024-12-12T10:23:54.439200Z","shell.execute_reply":"2024-12-12T10:24:06.418807Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 4. Advanced Custom Dataset Class\n> Here, we integrate OpenCV for image loading and Albumentations for augmentations.","metadata":{}},{"cell_type":"code","source":"class AdvancedImageDataset(Dataset):\n    def __init__(self, csv_file, img_dir, transform=None):\n        \"\"\"\n        Args:\n            csv_file (pd.DataFrame): Pandas DataFrame içindeki dosya adları ve etiketler.\n            img_dir (str): Görsellerin bulunduğu dizin.\n            transform (callable, optional): Görseller için dönüşüm/augmentasyon işlemleri.\n        \"\"\"\n        self.annotations = csv_file\n        self.img_dir = img_dir\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.annotations)\n\n    def __getitem__(self, idx):\n        # Görsel yolunu alın\n        img_path = os.path.join(self.img_dir, self.annotations.iloc[idx, 0])\n        image = cv2.imread(img_path)\n        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)  # OpenCV ile BGR -> RGB\n\n        # Etiketi alın\n        label = torch.tensor(self.annotations.iloc[idx, 1], dtype=torch.float32)\n\n        # Dönüşümleri uygulayın\n        if self.transform:\n            augmented = self.transform(image=image)\n            image = augmented['image']\n        \n        # Görüntü formatını `float32` yapın\n        image = image.float()\n        \n        return image, label","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-12T10:24:06.421569Z","iopub.execute_input":"2024-12-12T10:24:06.421868Z","iopub.status.idle":"2024-12-12T10:24:06.428943Z","shell.execute_reply.started":"2024-12-12T10:24:06.421841Z","shell.execute_reply":"2024-12-12T10:24:06.427960Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 5. Advanced Data Augmentation\n> We use **Albumentations** for diverse augmentations like `Cutout`, `CLAHE`, and `MixUp`.","metadata":{}},{"cell_type":"code","source":"def get_transforms(img_size):\n    train_transform = A.Compose([\n        A.Resize(img_size, img_size),\n        A.HorizontalFlip(p=0.5),\n        A.RandomBrightnessContrast(p=0.2),\n        A.GaussianBlur(p=0.1),\n        A.CoarseDropout(max_holes=4, max_height=16, max_width=16, min_holes=1, min_height=8, min_width=8, fill_value=0, p=0.5),\n        ToTensorV2()\n    ])\n\n    valid_transform = A.Compose([\n        A.Resize(img_size, img_size),\n        ToTensorV2()\n    ])\n    return train_transform, valid_transform","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-12T10:24:06.429991Z","iopub.execute_input":"2024-12-12T10:24:06.430233Z","iopub.status.idle":"2024-12-12T10:24:06.443307Z","shell.execute_reply.started":"2024-12-12T10:24:06.430209Z","shell.execute_reply":"2024-12-12T10:24:06.442716Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 6. Model Definition\n> Here we use **EfficientNetV2** as a base model and add custom classification layers.","metadata":{}},{"cell_type":"code","source":"class AdvancedModel(nn.Module):\n    def __init__(self, num_classes=1):\n        super(AdvancedModel, self).__init__()\n        # EfficientNet-B0 kullanımı\n        self.backbone = timm.create_model('efficientnet_b0', pretrained=True)\n        in_features = self.backbone.classifier.in_features\n        self.backbone.classifier = nn.Sequential(\n            nn.Linear(in_features, 512),\n            nn.ReLU(),\n            nn.Dropout(0.5),\n            nn.Linear(512, num_classes)\n        )\n\n    def forward(self, x):\n        return self.backbone(x)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-12T10:24:06.444296Z","iopub.execute_input":"2024-12-12T10:24:06.444837Z","iopub.status.idle":"2024-12-12T10:24:06.461643Z","shell.execute_reply.started":"2024-12-12T10:24:06.444797Z","shell.execute_reply":"2024-12-12T10:24:06.461067Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 7. Training and Validation Functions\n> **Automatic Mixed Precision (AMP)** and advanced metrics are added.","metadata":{}},{"cell_type":"code","source":"def train_one_epoch(model, train_loader, criterion, optimizer, scheduler, scaler, device):\n    model.train()\n    running_loss = 0.0\n\n    for images, labels in tqdm(train_loader):\n        images, labels = images.to(device, dtype=torch.float32), labels.to(device, dtype=torch.float32).unsqueeze(1)\n\n        optimizer.zero_grad()\n        with torch.amp.autocast(device_type='cuda'):  # AMP için güncelleme\n            outputs = model(images)\n            loss = criterion(outputs, labels)\n\n        scaler.scale(loss).backward()\n        scaler.step(optimizer)\n        scaler.update()\n        scheduler.step()\n\n        running_loss += loss.item() * images.size(0)\n\n    return running_loss / len(train_loader.dataset)\n\ndef validate(model, val_loader, criterion, device):\n    model.eval()\n    running_loss = 0.0\n    all_labels = []\n    all_outputs = []\n\n    with torch.no_grad():\n        for images, labels in tqdm(val_loader):\n            images, labels = images.to(device, dtype=torch.float32), labels.to(device, dtype=torch.float32).unsqueeze(1)\n\n            outputs = model(images)\n            loss = criterion(outputs, labels)\n\n            running_loss += loss.item() * images.size(0)\n            all_labels.append(labels.cpu().numpy())\n            all_outputs.append(torch.sigmoid(outputs).cpu().numpy())\n\n    epoch_loss = running_loss / len(val_loader.dataset)\n    all_labels = np.concatenate(all_labels)\n    all_outputs = np.concatenate(all_outputs)\n\n    return epoch_loss, all_labels, all_outputs","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-12T10:24:06.462468Z","iopub.execute_input":"2024-12-12T10:24:06.462668Z","iopub.status.idle":"2024-12-12T10:24:06.477962Z","shell.execute_reply.started":"2024-12-12T10:24:06.462648Z","shell.execute_reply":"2024-12-12T10:24:06.477339Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 8. Training Loop\n> Added **Early Stopping** and advanced metrics logging.","metadata":{}},{"cell_type":"code","source":"def train_model(csv_file, img_dir, model, img_size, batch_size, lr, num_epochs, device, patience):\n    # Prepare data\n    train_transform, valid_transform = get_transforms(img_size)\n    train_dataset = AdvancedImageDataset(csv_file, img_dir, transform=train_transform)\n    val_dataset = AdvancedImageDataset(csv_file, img_dir, transform=valid_transform)\n\n    train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)\n    val_loader = DataLoader(val_dataset, batch_size=batch_size, shuffle=False)\n\n    # Initialize model, optimizer, scheduler\n    model = model.to(device)\n    criterion = nn.BCEWithLogitsLoss()\n    optimizer = optim.AdamW(model.parameters(), lr=lr)\n    scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=10)\n    scaler = torch.cuda.amp.GradScaler()\n\n    best_auc = 0\n    early_stop_counter = 0\n\n    for epoch in range(num_epochs):\n        print(f\"Epoch {epoch+1}/{num_epochs}\")\n\n        train_loss = train_one_epoch(model, train_loader, criterion, optimizer, scheduler, scaler, device)\n        val_loss, val_labels, val_outputs = validate(model, val_loader, criterion, device)\n\n        val_auc = roc_auc_score(val_labels, val_outputs)\n        print(f\"Train Loss: {train_loss:.4f}, Val Loss: {val_loss:.4f}, Val AUC: {val_auc:.4f}\")\n\n        # Early Stopping\n        if val_auc > best_auc:\n            best_auc = val_auc\n            torch.save(model.state_dict(), \"best_model.pth\")\n            early_stop_counter = 0\n        else:\n            early_stop_counter += 1\n\n        if early_stop_counter >= patience:\n            print(\"Early stopping triggered.\")\n            break","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-12T10:24:06.479002Z","iopub.execute_input":"2024-12-12T10:24:06.479533Z","iopub.status.idle":"2024-12-12T10:24:06.494224Z","shell.execute_reply.started":"2024-12-12T10:24:06.479496Z","shell.execute_reply":"2024-12-12T10:24:06.493592Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 9. Predict Function\n> Generates predictions for test images.","metadata":{}},{"cell_type":"code","source":"def predict(csv_file, img_dir, model, img_size, batch_size, device):\n    # Test dönüşümleri\n    test_transform = A.Compose([\n        A.Resize(img_size, img_size),\n        ToTensorV2()\n    ])\n\n    # Dataset ve DataLoader oluşturma\n    test_dataset = AdvancedImageDataset(csv_file, img_dir, transform=test_transform)\n    test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)\n\n    # Modeli yükle ve değerlendirme moduna al\n    model.load_state_dict(torch.load(\"best_model.pth\"))\n    model.eval()\n    predictions = []\n\n    with torch.no_grad():\n        for images, _ in tqdm(test_loader):\n            # Görselleri uygun veri türüne dönüştür\n            images = images.to(device, dtype=torch.float32)\n            \n            # Model tahminleri\n            outputs = model(images)\n            predictions.extend(torch.sigmoid(outputs).cpu().numpy())\n\n    return predictions","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-12T10:24:06.495182Z","iopub.execute_input":"2024-12-12T10:24:06.495423Z","iopub.status.idle":"2024-12-12T10:24:06.512571Z","shell.execute_reply.started":"2024-12-12T10:24:06.495400Z","shell.execute_reply":"2024-12-12T10:24:06.511946Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 10. Running the Code\n> Use this section to train the model and make predictions.","metadata":{}},{"cell_type":"code","source":"# Step 1: Load and map training labels\n# Map the \"editada\" label to 0 (fake) and \"real\" to 1 (real)\nlabels = pd.read_csv(\"/kaggle/input/cidaut-ai-fake-scene-classification-2024/train.csv\")\nlabels['label'] = labels['label'].map({\"editada\": 0, \"real\": 1})  # Binary classification labels\n\n# Step 2: Define image directory and device\n# Define the directory containing training images and check for GPU availability\nimg_dir = \"/kaggle/input/cidaut-ai-fake-scene-classification-2024/Train\"\nmodel = AdvancedModel(num_classes=1)\ndevice = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n\n# Step 3: Train the model\n# Train the advanced model with defined parameters\ntrain_model(\n    labels, \n    img_dir, \n    model, \n    img_size=224, \n    batch_size=32, \n    lr=1e-4, \n    num_epochs=20, \n    device=device, \n    patience=3\n)\n\n# Step 4: Load test labels\n# Read the test file and prepare it for predictions\ntest_labels = pd.read_csv(\"/kaggle/input/cidaut-ai-fake-scene-classification-2024/sample_submission.csv\")\ntest_img_dir = \"/kaggle/input/cidaut-ai-fake-scene-classification-2024/Test\"\n\n# Step 5: Generate predictions\n# Use the predict function to infer probabilities for test images\npredictions = predict(\n    test_labels, \n    test_img_dir, \n    model, \n    img_size=224, \n    batch_size=32, \n    device=device\n)\n\n# Step 6: Update test labels with predictions\n# Add the predictions to the DataFrame and ensure the column is float type\ntest_labels['label'] = predictions\ntest_labels['label'] = test_labels['label'].astype(float)  # Ensure correct data type for submission\n\n# Step 7: Save the submission file\n# Save the test labels as submission.csv in the required format\ntest_labels.to_csv(\"submission.csv\", index=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-12T10:36:42.481676Z","iopub.execute_input":"2024-12-12T10:36:42.482563Z","iopub.status.idle":"2024-12-12T10:41:06.581988Z","shell.execute_reply.started":"2024-12-12T10:36:42.482526Z","shell.execute_reply":"2024-12-12T10:41:06.581121Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def process_image(image):\n    \"\"\"\n    Process an input image for better feature extraction and model input.\n    \n    Args:\n        image (np.array): Input image in RGB format.\n    \n    Returns:\n        np.array: Processed image.\n    \"\"\"\n    # 1. Resize the image\n    image = cv2.resize(image, (224, 224))\n    \n    # 2. Convert to grayscale\n    gray_image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)\n    \n    # 3. Apply Gaussian Blur to reduce noise\n    blurred_image = cv2.GaussianBlur(gray_image, (5, 5), 0)\n    \n    # 4. Perform edge detection (Canny)\n    edges = cv2.Canny(blurred_image, threshold1=100, threshold2=200)\n    \n    # 5. Enhance contrast using CLAHE\n    clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))\n    enhanced_image = clahe.apply(gray_image)\n    \n    # Combine edges and enhanced grayscale image\n    processed_image = cv2.addWeighted(enhanced_image, 0.8, edges, 0.2, 0)\n    \n    return processed_image","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-12T10:50:16.240937Z","iopub.execute_input":"2024-12-12T10:50:16.241760Z","iopub.status.idle":"2024-12-12T10:50:16.247284Z","shell.execute_reply.started":"2024-12-12T10:50:16.241721Z","shell.execute_reply":"2024-12-12T10:50:16.246345Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class ProcessedImageDataset(Dataset):\n    def __init__(self, csv_file, img_dir, transform=None):\n        self.annotations = csv_file\n        self.img_dir = img_dir\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.annotations)\n\n    def __getitem__(self, idx):\n        # Load image\n        img_path = os.path.join(self.img_dir, self.annotations.iloc[idx, 0])\n        image = cv2.imread(img_path)\n        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)  # Convert BGR to RGB\n        \n        # Process the image\n        processed_image = process_image(image)\n        \n        # If additional transformations are provided\n        if self.transform:\n            processed_image = self.transform(processed_image)\n        \n        # Get label\n        label = torch.tensor(self.annotations.iloc[idx, 1], dtype=torch.float32)\n        \n        return processed_image, label","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-12T10:50:27.133424Z","iopub.execute_input":"2024-12-12T10:50:27.134128Z","iopub.status.idle":"2024-12-12T10:50:27.140427Z","shell.execute_reply.started":"2024-12-12T10:50:27.134089Z","shell.execute_reply":"2024-12-12T10:50:27.139559Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\n# Load a sample image\nsample_image_path = \"/kaggle/input/cidaut-ai-fake-scene-classification-2024/Train/101.jpg\"\nsample_image = cv2.imread(sample_image_path)\nsample_image = cv2.cvtColor(sample_image, cv2.COLOR_BGR2RGB)\n\n# Process the image\nprocessed_sample = process_image(sample_image)\n\n# Visualize original and processed images\nplt.figure(figsize=(12, 6))\nplt.subplot(1, 2, 1)\nplt.title(\"Original Image\")\nplt.imshow(sample_image)\nplt.axis(\"off\")\n\nplt.subplot(1, 2, 2)\nplt.title(\"Processed Image\")\nplt.imshow(processed_sample, cmap=\"gray\")\nplt.axis(\"off\")\n\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-12T10:50:34.830626Z","iopub.execute_input":"2024-12-12T10:50:34.830999Z","iopub.status.idle":"2024-12-12T10:50:35.424214Z","shell.execute_reply.started":"2024-12-12T10:50:34.830960Z","shell.execute_reply":"2024-12-12T10:50:35.423298Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torchvision import models\nfrom torch.nn.functional import softmax\n\ndef generate_gradcam(model, image, device):\n    \"\"\"\n    Generate Grad-CAM for the given image and model.\n    \n    Args:\n        model (torch.nn.Module): Trained binary classification model.\n        image (torch.Tensor): Input image tensor (1, C, H, W).\n        device (str): Device ('cuda' or 'cpu').\n    \n    Returns:\n        np.array: Grad-CAM heatmap.\n    \"\"\"\n    model.eval()\n    image = image.to(device)\n    image.requires_grad = True\n\n    # Forward pass\n    output = model(image)\n    score = output[:, 0]  # Access the single logit value for binary classification\n    score.backward()\n\n    # Extract the gradients and activations\n    gradients = model.backbone.conv_stem.weight.grad.cpu().data.numpy()[0]\n    activations = model.backbone.conv_stem.weight.cpu().data.numpy()[0]\n\n    # Grad-CAM calculation\n    weights = np.mean(gradients, axis=(1, 2))  # Global Average Pooling\n    gradcam = np.zeros(activations.shape[1:], dtype=np.float32)\n\n    for i, w in enumerate(weights):\n        gradcam += w * activations[i, :, :]\n\n    gradcam = np.maximum(gradcam, 0)  # ReLU to remove negative values\n    gradcam = cv2.resize(gradcam, (224, 224))  # Resize to original image size\n    gradcam = (gradcam - gradcam.min()) / (gradcam.max() - gradcam.min() + 1e-8)  # Normalize\n\n    return gradcam\n\ndef visualize_gradcam(image, gradcam):\n    \"\"\"\n    Overlay the Grad-CAM heatmap on the original image.\n    \n    Args:\n        image (np.array): Original image in RGB.\n        gradcam (np.array): Grad-CAM heatmap.\n    \"\"\"\n    # Resize Grad-CAM heatmap to the original image size\n    gradcam_resized = cv2.resize(gradcam, (image.shape[1], image.shape[0]))  # Match image size (W, H)\n\n    # Convert Grad-CAM heatmap to color\n    heatmap = cv2.applyColorMap(np.uint8(255 * gradcam_resized), cv2.COLORMAP_JET)\n    heatmap = np.float32(heatmap) / 255\n\n    # Normalize the original image for blending\n    normalized_image = np.float32(image) / 255\n\n    # Overlay Grad-CAM heatmap on the original image\n    overlay = heatmap + normalized_image\n    overlay = overlay / np.max(overlay)  # Normalize to [0, 1] range\n\n    # Plot the original image and Grad-CAM overlay\n    plt.figure(figsize=(12, 6))\n    plt.subplot(1, 2, 1)\n    plt.title(\"Original Image\")\n    plt.imshow(image)\n    plt.axis(\"off\")\n\n    plt.subplot(1, 2, 2)\n    plt.title(\"Grad-CAM Heatmap Overlay\")\n    plt.imshow(overlay)\n    plt.axis(\"off\")\n\n    plt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-12T10:54:34.562434Z","iopub.execute_input":"2024-12-12T10:54:34.562813Z","iopub.status.idle":"2024-12-12T10:54:34.573201Z","shell.execute_reply.started":"2024-12-12T10:54:34.562779Z","shell.execute_reply":"2024-12-12T10:54:34.572225Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Load a sample image\nimage_path = \"/kaggle/input/cidaut-ai-fake-scene-classification-2024/Train/101.jpg\"\nimage = cv2.imread(image_path)\nimage = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\nimage_tensor = transforms.ToTensor()(image).unsqueeze(0)  # Convert to tensor and add batch dimension\n\n# Generate Grad-CAM\ngradcam = generate_gradcam(model, image_tensor, device)\n\n# Visualize Grad-CAM\nvisualize_gradcam(image, gradcam)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-12T10:54:42.577967Z","iopub.execute_input":"2024-12-12T10:54:42.578313Z","iopub.status.idle":"2024-12-12T10:54:43.235738Z","shell.execute_reply.started":"2024-12-12T10:54:42.578283Z","shell.execute_reply":"2024-12-12T10:54:43.234928Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def calculate_histogram(image):\n    \"\"\"\n    Calculate and normalize the histogram of an image.\n    \n    Args:\n        image (np.array): Input image in RGB.\n    \n    Returns:\n        list: Histogram for each channel.\n    \"\"\"\n    channels = ('r', 'g', 'b')\n    histograms = {}\n    for i, color in enumerate(channels):\n        hist = cv2.calcHist([image], [i], None, [256], [0, 256])\n        histograms[color] = hist / hist.sum()  # Normalize\n    return histograms\n\ndef plot_histograms(histograms):\n    \"\"\"\n    Plot the histograms of an image.\n    \n    Args:\n        histograms (dict): Normalized histograms for each channel.\n    \"\"\"\n    plt.figure(figsize=(12, 6))\n    for color, hist in histograms.items():\n        plt.plot(hist, label=f'{color} channel')\n    plt.title(\"Image Histogram\")\n    plt.xlabel(\"Pixel Value\")\n    plt.ylabel(\"Normalized Frequency\")\n    plt.legend()\n    plt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-12T10:54:47.931109Z","iopub.execute_input":"2024-12-12T10:54:47.931444Z","iopub.status.idle":"2024-12-12T10:54:47.937916Z","shell.execute_reply.started":"2024-12-12T10:54:47.931413Z","shell.execute_reply":"2024-12-12T10:54:47.936958Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Calculate and visualize histogram\nhistograms = calculate_histogram(image)\nplot_histograms(histograms)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-12T10:54:51.400745Z","iopub.execute_input":"2024-12-12T10:54:51.401104Z","iopub.status.idle":"2024-12-12T10:54:51.681707Z","shell.execute_reply.started":"2024-12-12T10:54:51.401072Z","shell.execute_reply":"2024-12-12T10:54:51.680956Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def segment_image(image, threshold=128):\n    \"\"\"\n    Segment the image based on intensity thresholding.\n    \n    Args:\n        image (np.array): Input grayscale image.\n        threshold (int): Intensity threshold.\n    \n    Returns:\n        np.array: Binary segmented image.\n    \"\"\"\n    gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)\n    _, segmented = cv2.threshold(gray, threshold, 255, cv2.THRESH_BINARY)\n    return segmented","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-12T10:54:54.592303Z","iopub.execute_input":"2024-12-12T10:54:54.592894Z","iopub.status.idle":"2024-12-12T10:54:54.597721Z","shell.execute_reply.started":"2024-12-12T10:54:54.592860Z","shell.execute_reply":"2024-12-12T10:54:54.596808Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"segmented = segment_image(image)\nplt.imshow(segmented, cmap='gray')\nplt.title(\"Segmented Image\")\nplt.axis(\"off\")\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-12T10:54:57.128489Z","iopub.execute_input":"2024-12-12T10:54:57.129231Z","iopub.status.idle":"2024-12-12T10:54:57.273331Z","shell.execute_reply.started":"2024-12-12T10:54:57.129191Z","shell.execute_reply":"2024-12-12T10:54:57.272418Z"}},"outputs":[],"execution_count":null}]}